Kaynağa Gözat

[FL-2369] NFC refactoring (#1095)

* nfc: clean up scenes
* nfc worker: remove field on from worker
* nfc worker: move full data exchange to furi hal
* nfc_device: check UID length
* nfc protocol: introduce mifare common API
* nfc: move common data to furi hal nfc
* nfc: rename emv_decoder -> emv
* nfc: move emv data structure to emv lib
* nfc: remove deactivate after detection
* nfc: rework furi hal nfc detect
* nfc: clean up CLI commands and type
* nfc: remove unused includes and function
* nfc: add TxRxType enum
* nfc: read mifare ultralight refactoring
* nfc: refactore mifare ultralight start
* rfal: fix custom data exchange
* nfc: refactor read bank card
* nfc: refactor read emv application
* nfc: refactor emv test emulation
* nfc: refactor uid emulation
* nfc: add limit to uid emulation logger
* fix source formatting
* furi_hal_nfc: fix data exchange full
* nfc: fix mifare ultralight type load

Co-authored-by: あく <alleteam@gmail.com>
gornekich 3 yıl önce
ebeveyn
işleme
956788c09b
58 değiştirilmiş dosya ile 1292 ekleme ve 1544 silme
  1. 3 3
      applications/nfc/nfc.c
  2. 19 25
      applications/nfc/nfc_cli.c
  3. 15 14
      applications/nfc/nfc_device.c
  4. 6 31
      applications/nfc/nfc_device.h
  5. 1 1
      applications/nfc/nfc_i.h
  6. 5 39
      applications/nfc/nfc_types.c
  7. 2 10
      applications/nfc/nfc_types.h
  8. 138 547
      applications/nfc/nfc_worker.c
  9. 3 3
      applications/nfc/nfc_worker.h
  10. 1 14
      applications/nfc/nfc_worker_i.h
  11. 5 5
      applications/nfc/scenes/nfc_scene_card_menu.c
  12. 0 1
      applications/nfc/scenes/nfc_scene_config.h
  13. 4 4
      applications/nfc/scenes/nfc_scene_debug.c
  14. 24 25
      applications/nfc/scenes/nfc_scene_delete.c
  15. 9 15
      applications/nfc/scenes/nfc_scene_delete_success.c
  16. 21 28
      applications/nfc/scenes/nfc_scene_device_info.c
  17. 8 10
      applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c
  18. 7 9
      applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c
  19. 10 6
      applications/nfc/scenes/nfc_scene_emulate_uid.c
  20. 4 7
      applications/nfc/scenes/nfc_scene_field.c
  21. 1 1
      applications/nfc/scenes/nfc_scene_file_select.c
  22. 9 8
      applications/nfc/scenes/nfc_scene_mifare_desfire_app.c
  23. 9 8
      applications/nfc/scenes/nfc_scene_mifare_desfire_data.c
  24. 8 6
      applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c
  25. 11 9
      applications/nfc/scenes/nfc_scene_mifare_ul_menu.c
  26. 0 42
      applications/nfc/scenes/nfc_scene_not_implemented.c
  27. 9 12
      applications/nfc/scenes/nfc_scene_read_card.c
  28. 13 9
      applications/nfc/scenes/nfc_scene_read_card_success.c
  29. 10 11
      applications/nfc/scenes/nfc_scene_read_emv_app.c
  30. 41 43
      applications/nfc/scenes/nfc_scene_read_emv_app_success.c
  31. 10 13
      applications/nfc/scenes/nfc_scene_read_emv_data.c
  32. 20 20
      applications/nfc/scenes/nfc_scene_read_emv_data_success.c
  33. 9 12
      applications/nfc/scenes/nfc_scene_read_mifare_desfire.c
  34. 5 6
      applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c
  35. 2 1
      applications/nfc/scenes/nfc_scene_read_mifare_ul.c
  36. 9 13
      applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c
  37. 5 12
      applications/nfc/scenes/nfc_scene_restore_original.c
  38. 10 17
      applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c
  39. 8 7
      applications/nfc/scenes/nfc_scene_save_name.c
  40. 5 12
      applications/nfc/scenes/nfc_scene_save_success.c
  41. 4 4
      applications/nfc/scenes/nfc_scene_saved_menu.c
  42. 7 6
      applications/nfc/scenes/nfc_scene_set_atqa.c
  43. 7 6
      applications/nfc/scenes/nfc_scene_set_sak.c
  44. 8 7
      applications/nfc/scenes/nfc_scene_set_type.c
  45. 6 5
      applications/nfc/scenes/nfc_scene_set_uid.c
  46. 4 4
      applications/nfc/scenes/nfc_scene_start.c
  47. 111 44
      firmware/targets/f7/furi_hal/furi_hal_nfc.c
  48. 56 30
      firmware/targets/furi_hal_include/furi_hal_nfc.h
  49. 1 1
      lib/ST25RFAL002/source/rfal_isoDep.c
  50. 13 7
      lib/ST25RFAL002/source/rfal_nfc.c
  51. 216 76
      lib/nfc_protocols/emv.c
  52. 87 0
      lib/nfc_protocols/emv.h
  53. 0 67
      lib/nfc_protocols/emv_decoder.h
  54. 8 10
      lib/nfc_protocols/mifare_classic.c
  55. 17 0
      lib/nfc_protocols/mifare_common.c
  56. 12 0
      lib/nfc_protocols/mifare_common.h
  57. 226 187
      lib/nfc_protocols/mifare_ultralight.c
  58. 30 31
      lib/nfc_protocols/mifare_ultralight.h

+ 3 - 3
applications/nfc/nfc.c

@@ -3,19 +3,19 @@
 
 
 bool nfc_custom_event_callback(void* context, uint32_t event) {
 bool nfc_custom_event_callback(void* context, uint32_t event) {
     furi_assert(context);
     furi_assert(context);
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     return scene_manager_handle_custom_event(nfc->scene_manager, event);
     return scene_manager_handle_custom_event(nfc->scene_manager, event);
 }
 }
 
 
 bool nfc_back_event_callback(void* context) {
 bool nfc_back_event_callback(void* context) {
     furi_assert(context);
     furi_assert(context);
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     return scene_manager_handle_back_event(nfc->scene_manager);
     return scene_manager_handle_back_event(nfc->scene_manager);
 }
 }
 
 
 void nfc_tick_event_callback(void* context) {
 void nfc_tick_event_callback(void* context) {
     furi_assert(context);
     furi_assert(context);
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     scene_manager_handle_tick_event(nfc->scene_manager);
     scene_manager_handle_tick_event(nfc->scene_manager);
 }
 }
 
 

+ 19 - 25
applications/nfc/nfc_cli.c

@@ -16,40 +16,35 @@ static void nfc_cli_print_usage() {
     }
     }
 }
 }
 
 
-void nfc_cli_detect(Cli* cli, string_t args) {
+static void nfc_cli_detect(Cli* cli, string_t args) {
     // Check if nfc worker is not busy
     // Check if nfc worker is not busy
     if(furi_hal_nfc_is_busy()) {
     if(furi_hal_nfc_is_busy()) {
         printf("Nfc is busy\r\n");
         printf("Nfc is busy\r\n");
         return;
         return;
     }
     }
-    rfalNfcDevice* dev_list;
-    uint8_t dev_cnt = 0;
+
+    FuriHalNfcDevData dev_data = {};
     bool cmd_exit = false;
     bool cmd_exit = false;
     furi_hal_nfc_exit_sleep();
     furi_hal_nfc_exit_sleep();
     printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
     printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
     while(!cmd_exit) {
     while(!cmd_exit) {
         cmd_exit |= cli_cmd_interrupt_received(cli);
         cmd_exit |= cli_cmd_interrupt_received(cli);
-        cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true);
-        if(dev_cnt > 0) {
-            printf("Found %d devices\r\n", dev_cnt);
-            for(uint8_t i = 0; i < dev_cnt; i++) {
-                printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type));
-                if(dev_list[i].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
-                    printf("type: %s, ", nfc_get_nfca_type(dev_list[i].dev.nfca.type));
-                }
-                printf("UID length: %d, UID:", dev_list[i].nfcidLen);
-                for(uint8_t j = 0; j < dev_list[i].nfcidLen; j++) {
-                    printf("%02X", dev_list[i].nfcid[j]);
-                }
-                printf("\r\n");
+        if(furi_hal_nfc_detect(&dev_data, 400)) {
+            printf("found: %s ", nfc_get_dev_type(dev_data.type));
+            printf("UID length: %d, UID:", dev_data.uid_len);
+            for(size_t i = 0; i < dev_data.uid_len; i++) {
+                printf("%02X", dev_data.uid[i]);
             }
             }
+            printf("\r\n");
+            break;
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(50);
         osDelay(50);
     }
     }
-    furi_hal_nfc_deactivate();
+    furi_hal_nfc_sleep();
 }
 }
 
 
-void nfc_cli_emulate(Cli* cli, string_t args) {
+static void nfc_cli_emulate(Cli* cli, string_t args) {
     // Check if nfc worker is not busy
     // Check if nfc worker is not busy
     if(furi_hal_nfc_is_busy()) {
     if(furi_hal_nfc_is_busy()) {
         printf("Nfc is busy\r\n");
         printf("Nfc is busy\r\n");
@@ -60,26 +55,25 @@ void nfc_cli_emulate(Cli* cli, string_t args) {
     printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
     printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
     printf("Press Ctrl+C to abort\r\n");
     printf("Press Ctrl+C to abort\r\n");
 
 
-    NfcDeviceCommonData params = {
+    FuriHalNfcDevData params = {
         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
         .uid_len = 7,
         .uid_len = 7,
         .atqa = {0x44, 0x00},
         .atqa = {0x44, 0x00},
         .sak = 0x00,
         .sak = 0x00,
-        .device = NfcDeviceNfca,
-        .protocol = NfcDeviceProtocolMifareUl,
+        .type = FuriHalNfcTypeA,
     };
     };
 
 
     while(!cli_cmd_interrupt_received(cli)) {
     while(!cli_cmd_interrupt_received(cli)) {
         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
             printf("Reader detected\r\n");
             printf("Reader detected\r\n");
-            furi_hal_nfc_deactivate();
+            furi_hal_nfc_sleep();
         }
         }
         osDelay(50);
         osDelay(50);
     }
     }
-    furi_hal_nfc_deactivate();
+    furi_hal_nfc_sleep();
 }
 }
 
 
-void nfc_cli_field(Cli* cli, string_t args) {
+static void nfc_cli_field(Cli* cli, string_t args) {
     // Check if nfc worker is not busy
     // Check if nfc worker is not busy
     if(furi_hal_nfc_is_busy()) {
     if(furi_hal_nfc_is_busy()) {
         printf("Nfc is busy\r\n");
         printf("Nfc is busy\r\n");
@@ -97,7 +91,7 @@ void nfc_cli_field(Cli* cli, string_t args) {
     }
     }
 
 
     furi_hal_nfc_field_off();
     furi_hal_nfc_field_off();
-    furi_hal_nfc_deactivate();
+    furi_hal_nfc_sleep();
 }
 }
 
 
 static void nfc_cli(Cli* cli, string_t args, void* context) {
 static void nfc_cli(Cli* cli, string_t args, void* context) {

+ 15 - 14
applications/nfc/nfc_device.c

@@ -41,31 +41,31 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_str
 static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
 static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
     if(string_start_with_str_p(format_string, "UID")) {
     if(string_start_with_str_p(format_string, "UID")) {
         dev->format = NfcDeviceSaveFormatUid;
         dev->format = NfcDeviceSaveFormatUid;
-        dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown;
+        dev->dev_data.protocol = NfcDeviceProtocolUnknown;
         return true;
         return true;
     }
     }
     if(string_start_with_str_p(format_string, "Bank card")) {
     if(string_start_with_str_p(format_string, "Bank card")) {
         dev->format = NfcDeviceSaveFormatBankCard;
         dev->format = NfcDeviceSaveFormatBankCard;
-        dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV;
+        dev->dev_data.protocol = NfcDeviceProtocolEMV;
         return true;
         return true;
     }
     }
     // Check Mifare Ultralight types
     // Check Mifare Ultralight types
     for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
     for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
-        if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) {
+        if(string_equal_str_p(format_string, nfc_mf_ul_type(type, true))) {
             dev->format = NfcDeviceSaveFormatMifareUl;
             dev->format = NfcDeviceSaveFormatMifareUl;
-            dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl;
+            dev->dev_data.protocol = NfcDeviceProtocolMifareUl;
             dev->dev_data.mf_ul_data.type = type;
             dev->dev_data.mf_ul_data.type = type;
             return true;
             return true;
         }
         }
     }
     }
     if(string_start_with_str_p(format_string, "Mifare Classic")) {
     if(string_start_with_str_p(format_string, "Mifare Classic")) {
         dev->format = NfcDeviceSaveFormatMifareClassic;
         dev->format = NfcDeviceSaveFormatMifareClassic;
-        dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic;
+        dev->dev_data.protocol = NfcDeviceProtocolMifareClassic;
         return true;
         return true;
     }
     }
     if(string_start_with_str_p(format_string, "Mifare DESFire")) {
     if(string_start_with_str_p(format_string, "Mifare DESFire")) {
         dev->format = NfcDeviceSaveFormatMifareDesfire;
         dev->format = NfcDeviceSaveFormatMifareDesfire;
-        dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
+        dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
         return true;
         return true;
     }
     }
     return false;
     return false;
@@ -73,7 +73,7 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_strin
 
 
 static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
 static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
     bool saved = false;
     bool saved = false;
-    MifareUlData* data = &dev->dev_data.mf_ul_data;
+    MfUltralightData* data = &dev->dev_data.mf_ul_data;
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
 
 
@@ -122,7 +122,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev)
 
 
 bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
 bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
     bool parsed = false;
     bool parsed = false;
-    MifareUlData* data = &dev->dev_data.mf_ul_data;
+    MfUltralightData* data = &dev->dev_data.mf_ul_data;
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
 
 
@@ -548,7 +548,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
 
 
 static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
 static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
     bool saved = false;
     bool saved = false;
-    NfcEmvData* data = &dev->dev_data.emv_data;
+    EmvData* data = &dev->dev_data.emv_data;
     uint32_t data_temp = 0;
     uint32_t data_temp = 0;
 
 
     do {
     do {
@@ -577,8 +577,8 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev)
 
 
 bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
 bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
     bool parsed = false;
     bool parsed = false;
-    NfcEmvData* data = &dev->dev_data.emv_data;
-    memset(data, 0, sizeof(NfcEmvData));
+    EmvData* data = &dev->dev_data.emv_data;
+    memset(data, 0, sizeof(EmvData));
     uint32_t data_cnt = 0;
     uint32_t data_cnt = 0;
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
@@ -700,7 +700,7 @@ static bool nfc_device_save_file(
 
 
     bool saved = false;
     bool saved = false;
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
-    NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
+    FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
 
 
@@ -758,7 +758,7 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
 static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
 static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
     bool parsed = false;
     bool parsed = false;
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
-    NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
+    FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
     uint32_t data_cnt = 0;
     uint32_t data_cnt = 0;
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
@@ -789,6 +789,7 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
         if(!nfc_device_parse_format_string(dev, temp_str)) break;
         if(!nfc_device_parse_format_string(dev, temp_str)) break;
         // Read and parse UID, ATQA and SAK
         // Read and parse UID, ATQA and SAK
         if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
         if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
+        if(!(data_cnt == 4 || data_cnt == 7)) break;
         data->uid_len = data_cnt;
         data->uid_len = data_cnt;
         if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
         if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
         if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
         if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
@@ -863,7 +864,7 @@ bool nfc_file_select(NfcDevice* dev) {
 }
 }
 
 
 void nfc_device_data_clear(NfcDeviceData* dev_data) {
 void nfc_device_data_clear(NfcDeviceData* dev_data) {
-    if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
+    if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
         mf_df_clear(&dev_data->mf_df_data);
         mf_df_clear(&dev_data->mf_df_data);
     }
     }
 }
 }

+ 6 - 31
applications/nfc/nfc_device.h

@@ -5,6 +5,8 @@
 #include <storage/storage.h>
 #include <storage/storage.h>
 #include <dialogs/dialogs.h>
 #include <dialogs/dialogs.h>
 
 
+#include <furi_hal_nfc.h>
+#include <lib/nfc_protocols/emv.h>
 #include <lib/nfc_protocols/mifare_ultralight.h>
 #include <lib/nfc_protocols/mifare_ultralight.h>
 #include <lib/nfc_protocols/mifare_classic.h>
 #include <lib/nfc_protocols/mifare_classic.h>
 #include <lib/nfc_protocols/mifare_desfire.h>
 #include <lib/nfc_protocols/mifare_desfire.h>
@@ -17,13 +19,6 @@
 #define NFC_APP_EXTENSION ".nfc"
 #define NFC_APP_EXTENSION ".nfc"
 #define NFC_APP_SHADOW_EXTENSION ".shd"
 #define NFC_APP_SHADOW_EXTENSION ".shd"
 
 
-typedef enum {
-    NfcDeviceNfca,
-    NfcDeviceNfcb,
-    NfcDeviceNfcf,
-    NfcDeviceNfcv,
-} NfcDeviceType;
-
 typedef enum {
 typedef enum {
     NfcDeviceProtocolUnknown,
     NfcDeviceProtocolUnknown,
     NfcDeviceProtocolEMV,
     NfcDeviceProtocolEMV,
@@ -40,38 +35,18 @@ typedef enum {
     NfcDeviceSaveFormatMifareDesfire,
     NfcDeviceSaveFormatMifareDesfire,
 } NfcDeviceSaveFormat;
 } NfcDeviceSaveFormat;
 
 
-typedef struct {
-    uint8_t uid_len;
-    uint8_t uid[10];
-    uint8_t atqa[2];
-    uint8_t sak;
-    NfcDeviceType device;
-    NfcProtocol protocol;
-} NfcDeviceCommonData;
-
-typedef struct {
-    char name[32];
-    uint8_t aid[16];
-    uint16_t aid_len;
-    uint8_t number[10];
-    uint8_t number_len;
-    uint8_t exp_mon;
-    uint8_t exp_year;
-    uint16_t country_code;
-    uint16_t currency_code;
-} NfcEmvData;
-
 typedef struct {
 typedef struct {
     uint8_t data[NFC_READER_DATA_MAX_SIZE];
     uint8_t data[NFC_READER_DATA_MAX_SIZE];
     uint16_t size;
     uint16_t size;
 } NfcReaderRequestData;
 } NfcReaderRequestData;
 
 
 typedef struct {
 typedef struct {
-    NfcDeviceCommonData nfc_data;
+    FuriHalNfcDevData nfc_data;
+    NfcProtocol protocol;
     NfcReaderRequestData reader_data;
     NfcReaderRequestData reader_data;
     union {
     union {
-        NfcEmvData emv_data;
-        MifareUlData mf_ul_data;
+        EmvData emv_data;
+        MfUltralightData mf_ul_data;
         MfClassicData mf_classic_data;
         MfClassicData mf_classic_data;
         MifareDesfireData mf_df_data;
         MifareDesfireData mf_df_data;
     };
     };

+ 1 - 1
applications/nfc/nfc_i.h

@@ -40,7 +40,7 @@ struct Nfc {
     NotificationApp* notifications;
     NotificationApp* notifications;
     SceneManager* scene_manager;
     SceneManager* scene_manager;
     NfcDevice* dev;
     NfcDevice* dev;
-    NfcDeviceCommonData dev_edit_data;
+    FuriHalNfcDevData dev_edit_data;
 
 
     char text_store[NFC_TEXT_STORE_SIZE + 1];
     char text_store[NFC_TEXT_STORE_SIZE + 1];
     string_t text_box_store;
     string_t text_box_store;

+ 5 - 39
applications/nfc/nfc_types.c

@@ -1,48 +1,14 @@
 #include "nfc_types.h"
 #include "nfc_types.h"
 
 
-const char* nfc_get_rfal_type(rfalNfcDevType type) {
-    if(type == RFAL_NFC_LISTEN_TYPE_NFCA) {
+const char* nfc_get_dev_type(FuriHalNfcType type) {
+    if(type == FuriHalNfcTypeA) {
         return "NFC-A";
         return "NFC-A";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) {
+    } else if(type == FuriHalNfcTypeB) {
         return "NFC-B";
         return "NFC-B";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) {
+    } else if(type == FuriHalNfcTypeF) {
         return "NFC-F";
         return "NFC-F";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) {
+    } else if(type == FuriHalNfcTypeV) {
         return "NFC-V";
         return "NFC-V";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
-        return "NFC-ST25TB";
-    } else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) {
-        return "NFC-AP2P";
-    } else {
-        return "Unknown";
-    }
-}
-
-const char* nfc_get_dev_type(NfcDeviceType type) {
-    if(type == NfcDeviceNfca) {
-        return "NFC-A";
-    } else if(type == NfcDeviceNfcb) {
-        return "NFC-B";
-    } else if(type == NfcDeviceNfcf) {
-        return "NFC-F";
-    } else if(type == NfcDeviceNfcv) {
-        return "NFC-V";
-    } else {
-        return "Unknown";
-    }
-}
-
-const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
-    if(type == RFAL_NFCA_T1T) {
-        return "T1T";
-    } else if(type == RFAL_NFCA_T2T) {
-        return "T2T";
-    } else if(type == RFAL_NFCA_T4T) {
-        return "T4T";
-    } else if(type == RFAL_NFCA_NFCDEP) {
-        return "NFCDEP";
-    } else if(type == RFAL_NFCA_T4T_NFCDEP) {
-        return "T4T_NFCDEP";
     } else {
     } else {
         return "Unknown";
         return "Unknown";
     }
     }

+ 2 - 10
applications/nfc/nfc_types.h

@@ -1,16 +1,8 @@
 #pragma once
 #pragma once
 
 
-#include "st_errno.h"
-#include "rfal_nfc.h"
+#include "nfc_device.h"
 
 
-#include <gui/view_dispatcher.h>
-#include "nfc_worker.h"
-
-const char* nfc_get_rfal_type(rfalNfcDevType type);
-
-const char* nfc_get_dev_type(NfcDeviceType type);
-
-const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type);
+const char* nfc_get_dev_type(FuriHalNfcType type);
 
 
 const char* nfc_guess_protocol(NfcProtocol protocol);
 const char* nfc_guess_protocol(NfcProtocol protocol);
 
 

+ 138 - 547
applications/nfc/nfc_worker.c

@@ -2,7 +2,8 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 
 
 #include <lib/nfc_protocols/nfc_util.h>
 #include <lib/nfc_protocols/nfc_util.h>
-#include <lib/nfc_protocols/emv_decoder.h>
+#include <lib/nfc_protocols/emv.h>
+#include <lib/nfc_protocols/mifare_common.h>
 #include <lib/nfc_protocols/mifare_ultralight.h>
 #include <lib/nfc_protocols/mifare_ultralight.h>
 #include <lib/nfc_protocols/mifare_classic.h>
 #include <lib/nfc_protocols/mifare_classic.h>
 #include <lib/nfc_protocols/mifare_desfire.h>
 #include <lib/nfc_protocols/mifare_desfire.h>
@@ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) {
         nfc_worker_emulate(nfc_worker);
         nfc_worker_emulate(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
     } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
         nfc_worker_read_emv_app(nfc_worker);
         nfc_worker_read_emv_app(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateReadEMV) {
+    } else if(nfc_worker->state == NfcWorkerStateReadEMVData) {
         nfc_worker_read_emv(nfc_worker);
         nfc_worker_read_emv(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
     } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
         nfc_worker_emulate_apdu(nfc_worker);
         nfc_worker_emulate_apdu(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
-        nfc_worker_read_mifare_ul(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
+    } else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
+        nfc_worker_read_mifare_ultralight(nfc_worker);
+    } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
         nfc_worker_emulate_mifare_ul(nfc_worker);
         nfc_worker_emulate_mifare_ul(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
     } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
         nfc_worker_mifare_classic_dict_attack(nfc_worker);
         nfc_worker_mifare_classic_dict_attack(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
     } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
         nfc_worker_read_mifare_desfire(nfc_worker);
         nfc_worker_read_mifare_desfire(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateField) {
-        nfc_worker_field(nfc_worker);
     }
     }
-    furi_hal_nfc_deactivate();
+    furi_hal_nfc_sleep();
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
     furi_hal_power_insomnia_exit();
     furi_hal_power_insomnia_exit();
 
 
@@ -117,579 +116,225 @@ int32_t nfc_worker_task(void* context) {
 }
 }
 
 
 void nfc_worker_detect(NfcWorker* nfc_worker) {
 void nfc_worker_detect(NfcWorker* nfc_worker) {
-    rfalNfcDevice* dev_list;
-    rfalNfcDevice* dev;
-    uint8_t dev_cnt;
     nfc_device_data_clear(nfc_worker->dev_data);
     nfc_device_data_clear(nfc_worker->dev_data);
-    NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data;
+    NfcDeviceData* dev_data = nfc_worker->dev_data;
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
 
 
     while(nfc_worker->state == NfcWorkerStateDetect) {
     while(nfc_worker->state == NfcWorkerStateDetect) {
-        if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) {
+        if(furi_hal_nfc_detect(nfc_data, 1000)) {
             // Process first found device
             // Process first found device
-            dev = &dev_list[0];
-            result->uid_len = dev->nfcidLen;
-            memcpy(result->uid, dev->nfcid, dev->nfcidLen);
-            if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
-                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 = NfcDeviceProtocolMifareUl;
+            if(nfc_data->type == FuriHalNfcTypeA) {
+                if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
+                    dev_data->protocol = NfcDeviceProtocolMifareUl;
                 } else if(mf_classic_check_card_type(
                 } else if(mf_classic_check_card_type(
-                              dev->dev.nfca.sensRes.anticollisionInfo,
-                              dev->dev.nfca.sensRes.platformInfo,
-                              dev->dev.nfca.selRes.sak)) {
-                    result->protocol = NfcDeviceProtocolMifareClassic;
+                              nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
+                    dev_data->protocol = NfcDeviceProtocolMifareClassic;
                 } else if(mf_df_check_card_type(
                 } else if(mf_df_check_card_type(
-                              dev->dev.nfca.sensRes.anticollisionInfo,
-                              dev->dev.nfca.sensRes.platformInfo,
-                              dev->dev.nfca.selRes.sak)) {
-                    result->protocol = NfcDeviceProtocolMifareDesfire;
-                } else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
-                    result->protocol = NfcDeviceProtocolEMV;
+                              nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
+                    dev_data->protocol = NfcDeviceProtocolMifareDesfire;
+                } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
+                    dev_data->protocol = NfcDeviceProtocolEMV;
                 } else {
                 } else {
-                    result->protocol = NfcDeviceProtocolUnknown;
+                    dev_data->protocol = NfcDeviceProtocolUnknown;
                 }
                 }
-            } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
-                result->device = NfcDeviceNfcb;
-            } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
-                result->device = NfcDeviceNfcf;
-            } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) {
-                result->device = NfcDeviceNfcv;
             }
             }
+
             // Notify caller and exit
             // Notify caller and exit
             if(nfc_worker->callback) {
             if(nfc_worker->callback) {
                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
             }
             }
             break;
             break;
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(100);
         osDelay(100);
     }
     }
 }
 }
 
 
-bool nfc_worker_emulate_uid_callback(
-    uint8_t* buff_rx,
-    uint16_t buff_rx_len,
-    uint8_t* buff_tx,
-    uint16_t* buff_tx_len,
-    uint32_t* data_type,
-    void* context) {
-    furi_assert(context);
-    NfcWorker* nfc_worker = context;
+void nfc_worker_emulate(NfcWorker* nfc_worker) {
+    FuriHalNfcTxRxContext tx_rx = {};
+    FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
-    reader_data->size = buff_rx_len / 8;
-    if(reader_data->size > 0) {
-        memcpy(reader_data->data, buff_rx, reader_data->size);
-        if(nfc_worker->callback) {
-            nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-        }
-    }
-    return true;
-}
 
 
-void nfc_worker_emulate(NfcWorker* nfc_worker) {
-    NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
     while(nfc_worker->state == NfcWorkerStateEmulate) {
     while(nfc_worker->state == NfcWorkerStateEmulate) {
-        furi_hal_nfc_emulate_nfca(
-            data->uid,
-            data->uid_len,
-            data->atqa,
-            data->sak,
-            nfc_worker_emulate_uid_callback,
-            nfc_worker,
-            1000);
+        if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
+            if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
+                reader_data->size = tx_rx.rx_bits / 8;
+                if(reader_data->size > 0) {
+                    memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
+                    if(nfc_worker->callback) {
+                        nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
+                    }
+                }
+            } else {
+                FURI_LOG_E(TAG, "Failed to get reader commands");
+            }
+        }
     }
     }
 }
 }
 
 
 void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
 void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
-    ReturnCode err;
-    rfalNfcDevice* dev_list;
+    FuriHalNfcTxRxContext tx_rx = {};
     EmvApplication emv_app = {};
     EmvApplication emv_app = {};
-    uint8_t dev_cnt = 0;
-    uint8_t tx_buff[255] = {};
-    uint16_t tx_len = 0;
-    uint8_t* rx_buff;
-    uint16_t* rx_len;
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     nfc_device_data_clear(result);
     nfc_device_data_clear(result);
 
 
     while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
     while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
-        memset(&emv_app, 0, sizeof(emv_app));
-        if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
+        if(furi_hal_nfc_detect(nfc_data, 1000)) {
             // Card was found. Check that it supports EMV
             // Card was found. Check that it supports EMV
-            if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
-                result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
-                result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
-                result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
-                result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
-                memcpy(
-                    result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
-                result->nfc_data.protocol = NfcDeviceProtocolEMV;
-
-                FURI_LOG_D(TAG, "Send select PPSE command");
-                tx_len = emv_prepare_select_ppse(tx_buff);
-                err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-                if(err != ERR_NONE) {
-                    FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
-                if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
-                    FURI_LOG_D(TAG, "Select PPSE responce parced");
+            if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
+                result->protocol = NfcDeviceProtocolEMV;
+                if(emv_search_application(&tx_rx, &emv_app)) {
                     // Notify caller and exit
                     // Notify caller and exit
                     result->emv_data.aid_len = emv_app.aid_len;
                     result->emv_data.aid_len = emv_app.aid_len;
                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
                     if(nfc_worker->callback) {
                     if(nfc_worker->callback) {
                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                     }
                     }
-                    break;
-                } else {
-                    FURI_LOG_D(TAG, "Can't find pay application");
-                    furi_hal_nfc_deactivate();
-                    continue;
                 }
                 }
             } else {
             } else {
-                // Can't find EMV card
                 FURI_LOG_W(TAG, "Card doesn't support EMV");
                 FURI_LOG_W(TAG, "Card doesn't support EMV");
-                furi_hal_nfc_deactivate();
             }
             }
         } else {
         } else {
-            // Can't find EMV card
             FURI_LOG_D(TAG, "Can't find any cards");
             FURI_LOG_D(TAG, "Can't find any cards");
-            furi_hal_nfc_deactivate();
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(20);
         osDelay(20);
     }
     }
 }
 }
 
 
 void nfc_worker_read_emv(NfcWorker* nfc_worker) {
 void nfc_worker_read_emv(NfcWorker* nfc_worker) {
-    ReturnCode err;
-    rfalNfcDevice* dev_list;
+    FuriHalNfcTxRxContext tx_rx = {};
     EmvApplication emv_app = {};
     EmvApplication emv_app = {};
-    uint8_t dev_cnt = 0;
-    uint8_t tx_buff[255] = {};
-    uint16_t tx_len = 0;
-    uint8_t* rx_buff;
-    uint16_t* rx_len;
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     nfc_device_data_clear(result);
     nfc_device_data_clear(result);
 
 
-    while(nfc_worker->state == NfcWorkerStateReadEMV) {
-        memset(&emv_app, 0, sizeof(emv_app));
-        if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
+    while(nfc_worker->state == NfcWorkerStateReadEMVData) {
+        if(furi_hal_nfc_detect(nfc_data, 1000)) {
             // Card was found. Check that it supports EMV
             // Card was found. Check that it supports EMV
-            if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
-                result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
-                result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
-                result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
-                result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
-                memcpy(
-                    result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
-                result->nfc_data.protocol = NfcDeviceProtocolEMV;
-
-                FURI_LOG_D(TAG, "Send select PPSE command");
-                tx_len = emv_prepare_select_ppse(tx_buff);
-                err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-                if(err != ERR_NONE) {
-                    FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
-                if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
-                    FURI_LOG_D(TAG, "Select PPSE responce parced");
+            if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
+                result->protocol = NfcDeviceProtocolEMV;
+                if(emv_read_bank_card(&tx_rx, &emv_app)) {
+                    result->emv_data.number_len = emv_app.card_number_len;
+                    memcpy(
+                        result->emv_data.number, emv_app.card_number, result->emv_data.number_len);
                     result->emv_data.aid_len = emv_app.aid_len;
                     result->emv_data.aid_len = emv_app.aid_len;
                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
-                } else {
-                    FURI_LOG_D(TAG, "Can't find pay application");
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                FURI_LOG_D(TAG, "Starting application ...");
-                tx_len = emv_prepare_select_app(tx_buff, &emv_app);
-                err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-                if(err != ERR_NONE) {
-                    FURI_LOG_D(TAG, "Error during application selection request: %d", err);
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                FURI_LOG_D(TAG, "Select application response received. Start parsing response");
-                if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) {
-                    FURI_LOG_D(TAG, "Card name: %s", emv_app.name);
-                    memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
-                } else if(emv_app.pdol.size > 0) {
-                    FURI_LOG_D(TAG, "Can't find card name, but PDOL is present.");
-                } else {
-                    FURI_LOG_D(TAG, "Can't find card name or PDOL");
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                FURI_LOG_D(TAG, "Starting Get Processing Options command ...");
-                tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app);
-                err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-                if(err != ERR_NONE) {
-                    FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err);
-                    furi_hal_nfc_deactivate();
-                    continue;
-                }
-                if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) {
-                    FURI_LOG_D(TAG, "Card number parsed");
-                    result->emv_data.number_len = emv_app.card_number_len;
-                    memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
+                    if(emv_app.name_found) {
+                        memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
+                    }
+                    if(emv_app.exp_month) {
+                        result->emv_data.exp_mon = emv_app.exp_month;
+                        result->emv_data.exp_year = emv_app.exp_year;
+                    }
+                    if(emv_app.country_code) {
+                        result->emv_data.country_code = emv_app.country_code;
+                    }
+                    if(emv_app.currency_code) {
+                        result->emv_data.currency_code = emv_app.currency_code;
+                    }
                     // Notify caller and exit
                     // Notify caller and exit
                     if(nfc_worker->callback) {
                     if(nfc_worker->callback) {
                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                     }
                     }
                     break;
                     break;
-                } else {
-                    // Mastercard doesn't give PAN / card number as GPO response
-                    // Iterate over all files found in application
-                    bool pan_found = false;
-                    for(uint8_t i = 0; (i < emv_app.afl.size) && !pan_found; i += 4) {
-                        uint8_t sfi = emv_app.afl.data[i] >> 3;
-                        uint8_t record_start = emv_app.afl.data[i + 1];
-                        uint8_t record_end = emv_app.afl.data[i + 2];
-
-                        // Iterate over all records in file
-                        for(uint8_t record = record_start; record <= record_end; ++record) {
-                            tx_len = emv_prepare_read_sfi_record(tx_buff, sfi, record);
-                            err = furi_hal_nfc_data_exchange(
-                                tx_buff, tx_len, &rx_buff, &rx_len, false);
-                            if(err != ERR_NONE) {
-                                FURI_LOG_D(
-                                    TAG,
-                                    "Error reading application sfi %d, record %d",
-                                    sfi,
-                                    record);
-                            }
-                            if(emv_decode_read_sfi_record(rx_buff, *rx_len, &emv_app)) {
-                                pan_found = true;
-                                break;
-                            }
-                        }
-                    }
-                    if(pan_found) {
-                        FURI_LOG_D(TAG, "Card PAN found");
-                        result->emv_data.number_len = emv_app.card_number_len;
-                        memcpy(
-                            result->emv_data.number,
-                            emv_app.card_number,
-                            result->emv_data.number_len);
-                        if(emv_app.exp_month) {
-                            result->emv_data.exp_mon = emv_app.exp_month;
-                            result->emv_data.exp_year = emv_app.exp_year;
-                        }
-                        if(emv_app.country_code) {
-                            result->emv_data.country_code = emv_app.country_code;
-                        }
-                        if(emv_app.currency_code) {
-                            result->emv_data.currency_code = emv_app.currency_code;
-                        }
-                        // Notify caller and exit
-                        if(nfc_worker->callback) {
-                            nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-                        }
-                        break;
-                    } else {
-                        FURI_LOG_D(TAG, "Can't read card number");
-                    }
-                    furi_hal_nfc_deactivate();
                 }
                 }
             } else {
             } else {
-                // Can't find EMV card
                 FURI_LOG_W(TAG, "Card doesn't support EMV");
                 FURI_LOG_W(TAG, "Card doesn't support EMV");
-                furi_hal_nfc_deactivate();
             }
             }
         } else {
         } else {
-            // Can't find EMV card
             FURI_LOG_D(TAG, "Can't find any cards");
             FURI_LOG_D(TAG, "Can't find any cards");
-            furi_hal_nfc_deactivate();
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(20);
         osDelay(20);
     }
     }
 }
 }
 
 
 void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
 void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
-    ReturnCode err;
-    uint8_t tx_buff[255] = {};
-    uint16_t tx_len = 0;
-    uint8_t* rx_buff;
-    uint16_t* rx_len;
-    NfcDeviceCommonData params = {
+    FuriHalNfcTxRxContext tx_rx = {};
+    FuriHalNfcDevData params = {
         .uid = {0xCF, 0x72, 0xd4, 0x40},
         .uid = {0xCF, 0x72, 0xd4, 0x40},
         .uid_len = 4,
         .uid_len = 4,
         .atqa = {0x00, 0x04},
         .atqa = {0x00, 0x04},
         .sak = 0x20,
         .sak = 0x20,
-        .device = NfcDeviceNfca,
-        .protocol = NfcDeviceProtocolEMV,
+        .type = FuriHalNfcTypeA,
     };
     };
-    // Test RX data
-    const uint8_t debug_rx[] = {
-        0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
-        0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
-        0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
-        0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
-        0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
-        0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
-        0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
-        0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
-        0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
-        0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
-        0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
-        0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
-        0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
-        0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
-        0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
-        0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
-        0x88, 0x00};
-    // Test TX data
-    const uint8_t debug_tx[] = {
-        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
-        0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
-        0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
-        0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
-        0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
-        0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
-        0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
-        0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
-        0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
-        0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
-        0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
-        0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
-        0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
-        0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
-        0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
-        0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
-        0x00, 0x00};
 
 
     while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
     while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
             FURI_LOG_D(TAG, "POS terminal detected");
             FURI_LOG_D(TAG, "POS terminal detected");
-            // Read data from POS terminal
-            err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
-            if(err == ERR_NONE) {
-                FURI_LOG_D(TAG, "Received Select PPSE");
-            } else {
-                FURI_LOG_D(TAG, "Error in 1st data exchange: select PPSE");
-                furi_hal_nfc_deactivate();
-                continue;
+            if(emv_card_emulation(&tx_rx)) {
+                FURI_LOG_D(TAG, "EMV card emulated");
             }
             }
-            FURI_LOG_D(TAG, "Transive SELECT PPSE ANS");
-            tx_len = emv_select_ppse_ans(tx_buff);
-            err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-            if(err == ERR_NONE) {
-                FURI_LOG_D(TAG, "Received Select APP");
-            } else {
-                FURI_LOG_D(TAG, "Error in 2nd data exchange: select APP");
-                furi_hal_nfc_deactivate();
-                continue;
-            }
-
-            FURI_LOG_D(TAG, "Transive SELECT APP ANS");
-            tx_len = emv_select_app_ans(tx_buff);
-            err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-            if(err == ERR_NONE) {
-                FURI_LOG_D(TAG, "Received PDOL");
-            } else {
-                FURI_LOG_D(TAG, "Error in 3rd data exchange: receive PDOL");
-                furi_hal_nfc_deactivate();
-                continue;
-            }
-
-            FURI_LOG_D(TAG, "Transive PDOL ANS");
-            tx_len = emv_get_proc_opt_ans(tx_buff);
-            err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-            if(err == ERR_NONE) {
-                FURI_LOG_D(TAG, "Transive PDOL ANS");
-            } else {
-                FURI_LOG_D(TAG, "Error in 4rd data exchange: Transive PDOL ANS");
-                furi_hal_nfc_deactivate();
-                continue;
-            }
-
-            if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
-                FURI_LOG_D(TAG, "Failed long message test");
-            } else {
-                FURI_LOG_D(TAG, "Correct debug message received");
-                tx_len = sizeof(debug_tx);
-                err = furi_hal_nfc_data_exchange(
-                    (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
-                if(err == ERR_NONE) {
-                    FURI_LOG_D(TAG, "Transive Debug message");
-                }
-            }
-            furi_hal_nfc_deactivate();
         } else {
         } else {
             FURI_LOG_D(TAG, "Can't find reader");
             FURI_LOG_D(TAG, "Can't find reader");
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(20);
         osDelay(20);
     }
     }
 }
 }
 
 
-void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) {
-    ReturnCode err;
-    rfalNfcDevice* dev_list;
-    uint8_t dev_cnt = 0;
-    uint8_t tx_buff[255] = {};
-    uint16_t tx_len = 0;
-    uint8_t* rx_buff;
-    uint16_t* rx_len;
-    MifareUlDevice mf_ul_read;
+void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
+    FuriHalNfcTxRxContext tx_rx = {};
+    MfUltralightReader reader = {};
+    MfUltralightData data = {};
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
-    nfc_device_data_clear(result);
-
-    while(nfc_worker->state == NfcWorkerStateReadMifareUl) {
-        furi_hal_nfc_deactivate();
-        memset(&mf_ul_read, 0, sizeof(mf_ul_read));
-        if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
-            if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA &&
-               mf_ul_check_card_type(
-                   dev_list[0].dev.nfca.sensRes.anticollisionInfo,
-                   dev_list[0].dev.nfca.sensRes.platformInfo,
-                   dev_list[0].dev.nfca.selRes.sak)) {
-                // Get Mifare Ultralight version
-                FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Reading tag version");
-                tx_len = mf_ul_prepare_get_version(tx_buff);
-                err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
-                if(err == ERR_NONE) {
-                    mf_ul_parse_get_version_response(rx_buff, &mf_ul_read);
-                    FURI_LOG_D(
-                        TAG,
-                        "Mifare Ultralight Type: %d, Pages: %d",
-                        mf_ul_read.data.type,
-                        mf_ul_read.pages_to_read);
-                    FURI_LOG_D(TAG, "Reading signature ...");
-                    tx_len = mf_ul_prepare_read_signature(tx_buff);
-                    if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
-                        FURI_LOG_D(TAG, "Failed reading signature");
-                        memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature));
-                    } else {
-                        mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read);
-                    }
-                } else if(err == ERR_TIMEOUT) {
-                    FURI_LOG_D(
-                        TAG,
-                        "Card doesn't respond to GET VERSION command. Setting default read parameters");
-                    err = ERR_NONE;
-                    mf_ul_set_default_version(&mf_ul_read);
-                    // Reinit device
-                    furi_hal_nfc_deactivate();
-                    if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
-                        FURI_LOG_D(TAG, "Lost connection. Restarting search");
-                        continue;
-                    }
-                } else {
-                    FURI_LOG_D(
-                        TAG, "Error getting Mifare Ultralight version. Error code: %d", err);
-                    continue;
-                }
-
-                if(mf_ul_read.support_fast_read) {
-                    FURI_LOG_D(TAG, "Reading pages ...");
-                    tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1);
-                    if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
-                        FURI_LOG_D(TAG, "Failed reading pages");
-                        continue;
-                    } else {
-                        mf_ul_parse_fast_read_response(
-                            rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read);
-                    }
-
-                    FURI_LOG_D(TAG, "Reading 3 counters ...");
-                    for(uint8_t i = 0; i < 3; i++) {
-                        tx_len = mf_ul_prepare_read_cnt(tx_buff, i);
-                        if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
-                            FURI_LOG_W(TAG, "Failed reading Counter %d", i);
-                            mf_ul_read.data.counter[i] = 0;
-                        } else {
-                            mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read);
-                        }
-                    }
-
-                    FURI_LOG_D(TAG, "Checking tearing flags ...");
-                    for(uint8_t i = 0; i < 3; i++) {
-                        tx_len = mf_ul_prepare_check_tearing(tx_buff, i);
-                        if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
-                            FURI_LOG_D(TAG, "Error checking tearing flag %d", i);
-                            mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
-                        } else {
-                            mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read);
-                        }
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
+
+    while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
+        if(furi_hal_nfc_detect(nfc_data, 300)) {
+            if(nfc_data->type == FuriHalNfcTypeA &&
+               mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
+                FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading");
+                if(mf_ul_read_card(&tx_rx, &reader, &data)) {
+                    result->protocol = NfcDeviceProtocolMifareUl;
+                    result->mf_ul_data = data;
+                    // Notify caller and exit
+                    if(nfc_worker->callback) {
+                        nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                     }
                     }
+                    break;
                 } else {
                 } else {
-                    // READ card with READ command (4 pages at a time)
-                    for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) {
-                        FURI_LOG_D(TAG, "Reading pages %d - %d ...", page, page + 3);
-                        tx_len = mf_ul_prepare_read(tx_buff, page);
-                        if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
-                            FURI_LOG_D(TAG, "Read pages %d - %d failed", page, page + 3);
-                            continue;
-                        } else {
-                            mf_ul_parse_read_response(rx_buff, page, &mf_ul_read);
-                        }
-                    }
+                    FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
                 }
                 }
-
-                // 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;
-                result->nfc_data.protocol = NfcDeviceProtocolMifareUl;
-                memcpy(
-                    result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
-                result->mf_ul_data = mf_ul_read.data;
-
-                // Notify caller and exit
-                if(nfc_worker->callback) {
-                    nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-                }
-                break;
             } else {
             } else {
-                FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight");
+                FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
             }
             }
         } else {
         } else {
             FURI_LOG_D(TAG, "Can't find any tags");
             FURI_LOG_D(TAG, "Can't find any tags");
         }
         }
+        furi_hal_nfc_sleep();
         osDelay(100);
         osDelay(100);
     }
     }
 }
 }
 
 
 void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
 void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
-    NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data;
-    MifareUlDevice mf_ul_emulate;
-    mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data);
-    while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
+    MfUltralightEmulator emulator = {};
+    mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
+    while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
         furi_hal_nfc_emulate_nfca(
         furi_hal_nfc_emulate_nfca(
-            nfc_common->uid,
-            nfc_common->uid_len,
-            nfc_common->atqa,
-            nfc_common->sak,
+            nfc_data->uid,
+            nfc_data->uid_len,
+            nfc_data->atqa,
+            nfc_data->sak,
             mf_ul_prepare_emulation_response,
             mf_ul_prepare_emulation_response,
-            &mf_ul_emulate,
+            &emulator,
             5000);
             5000);
         // Check if data was modified
         // Check if data was modified
-        if(mf_ul_emulate.data_changed) {
-            nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
+        if(emulator.data_changed) {
+            nfc_worker->dev_data->mf_ul_data = emulator.data;
             if(nfc_worker->callback) {
             if(nfc_worker->callback) {
                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
             }
             }
-            mf_ul_emulate.data_changed = false;
+            emulator.data_changed = false;
         }
         }
     }
     }
 }
 }
 
 
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
     furi_assert(nfc_worker->callback);
     furi_assert(nfc_worker->callback);
-    rfalNfcDevice* dev_list;
-    rfalNfcDevice* dev;
-    NfcDeviceCommonData* nfc_common;
-    uint8_t dev_cnt = 0;
     FuriHalNfcTxRxContext tx_rx_ctx = {};
     FuriHalNfcTxRxContext tx_rx_ctx = {};
     MfClassicAuthContext auth_ctx = {};
     MfClassicAuthContext auth_ctx = {};
     MfClassicReader reader = {};
     MfClassicReader reader = {};
@@ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
     uint16_t curr_sector = 0;
     uint16_t curr_sector = 0;
     uint8_t total_sectors = 0;
     uint8_t total_sectors = 0;
     NfcWorkerEvent event;
     NfcWorkerEvent event;
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
 
 
     // Open dictionary
     // Open dictionary
     nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
     nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
@@ -710,14 +356,13 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
 
 
     // Detect Mifare Classic card
     // Detect Mifare Classic card
     while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
     while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
-        if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
-            dev = &dev_list[0];
+        if(furi_hal_nfc_detect(nfc_data, 300)) {
             if(mf_classic_get_type(
             if(mf_classic_get_type(
-                   dev->nfcid,
-                   dev->nfcidLen,
-                   dev->dev.nfca.sensRes.anticollisionInfo,
-                   dev->dev.nfca.sensRes.platformInfo,
-                   dev->dev.nfca.selRes.sak,
+                   nfc_data->uid,
+                   nfc_data->uid_len,
+                   nfc_data->atqa[0],
+                   nfc_data->atqa[1],
+                   nfc_data->sak,
                    &reader)) {
                    &reader)) {
                 total_sectors = mf_classic_get_total_sectors_num(&reader);
                 total_sectors = mf_classic_get_total_sectors_num(&reader);
                 if(reader.type == MfClassicType1k) {
                 if(reader.type == MfClassicType1k) {
@@ -745,7 +390,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
             mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
             mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
             bool sector_key_found = false;
             bool sector_key_found = false;
             while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
             while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
-                furi_hal_nfc_deactivate();
+                furi_hal_nfc_sleep();
                 if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
                 if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
                     if(!card_found_notified) {
                     if(!card_found_notified) {
                         if(reader.type == MfClassicType1k) {
                         if(reader.type == MfClassicType1k) {
@@ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
         uint8_t sectors_read =
         uint8_t sectors_read =
             mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
             mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
         if(sectors_read) {
         if(sectors_read) {
-            dev = &dev_list[0];
-            nfc_common = &nfc_worker->dev_data->nfc_data;
-            nfc_common->uid_len = dev->dev.nfca.nfcId1Len;
-            nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
-            nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
-            nfc_common->sak = dev->dev.nfca.selRes.sak;
-            nfc_common->protocol = NfcDeviceProtocolMifareClassic;
-            memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len);
             event = NfcWorkerEventSuccess;
             event = NfcWorkerEventSuccess;
+            nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
             FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
             FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
         } else {
         } else {
             event = NfcWorkerEventFail;
             event = NfcWorkerEventFail;
@@ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
     stream_free(nfc_worker->dict_stream);
     stream_free(nfc_worker->dict_stream);
 }
 }
 
 
-ReturnCode nfc_exchange_full(
-    uint8_t* tx_buff,
-    uint16_t tx_len,
-    uint8_t* rx_buff,
-    uint16_t rx_cap,
-    uint16_t* rx_len) {
-    ReturnCode err;
-    uint8_t* part_buff;
-    uint16_t* part_len;
-
-    err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false);
-    if(*part_len > rx_cap) {
-        return ERR_OVERRUN;
-    }
-    memcpy(rx_buff, part_buff, *part_len);
-    *rx_len = *part_len;
-    while(err == ERR_NONE && rx_buff[0] == 0xAF) {
-        err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false);
-        if(*part_len > rx_cap - *rx_len) {
-            return ERR_OVERRUN;
-        }
-        if(*part_len == 0) {
-            return ERR_PROTO;
-        }
-        memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1);
-        *rx_buff = *part_buff;
-        *rx_len += *part_len - 1;
-    }
-
-    return err;
-}
-
 void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
 void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
     ReturnCode err;
     ReturnCode err;
-    rfalNfcDevice* dev_list;
-    uint8_t dev_cnt = 0;
     uint8_t tx_buff[64] = {};
     uint8_t tx_buff[64] = {};
     uint16_t tx_len = 0;
     uint16_t tx_len = 0;
     uint8_t rx_buff[512] = {};
     uint8_t rx_buff[512] = {};
@@ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
     nfc_device_data_clear(result);
     nfc_device_data_clear(result);
     MifareDesfireData* data = &result->mf_df_data;
     MifareDesfireData* data = &result->mf_df_data;
+    FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
 
 
     while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
     while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
-        furi_hal_nfc_deactivate();
-        if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
+        furi_hal_nfc_sleep();
+        if(!furi_hal_nfc_detect(nfc_data, 300)) {
             osDelay(100);
             osDelay(100);
             continue;
             continue;
         }
         }
         memset(data, 0, sizeof(MifareDesfireData));
         memset(data, 0, sizeof(MifareDesfireData));
-        if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA ||
-           !mf_df_check_card_type(
-               dev_list[0].dev.nfca.sensRes.anticollisionInfo,
-               dev_list[0].dev.nfca.sensRes.platformInfo,
-               dev_list[0].dev.nfca.selRes.sak)) {
+        if(nfc_data->type != FuriHalNfcTypeA ||
+           !mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
             FURI_LOG_D(TAG, "Tag is not DESFire");
             FURI_LOG_D(TAG, "Tag is not DESFire");
             osDelay(100);
             osDelay(100);
             continue;
             continue;
@@ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
 
 
         FURI_LOG_D(TAG, "Found DESFire tag");
         FURI_LOG_D(TAG, "Found DESFire tag");
 
 
-        // Fill non-DESFire 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;
-        result->nfc_data.device = NfcDeviceNfca;
-        result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
-        memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
+        result->protocol = NfcDeviceProtocolMifareDesfire;
 
 
         // Get DESFire version
         // Get DESFire version
         tx_len = mf_df_prepare_get_version(tx_buff);
         tx_len = mf_df_prepare_get_version(tx_buff);
-        err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+        err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
         if(err != ERR_NONE) {
         if(err != ERR_NONE) {
             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
             continue;
             continue;
@@ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
         }
         }
 
 
         tx_len = mf_df_prepare_get_free_memory(tx_buff);
         tx_len = mf_df_prepare_get_free_memory(tx_buff);
-        err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+        err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
         if(err == ERR_NONE) {
         if(err == ERR_NONE) {
             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
             memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
             memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
@@ -935,7 +530,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
         }
         }
 
 
         tx_len = mf_df_prepare_get_key_settings(tx_buff);
         tx_len = mf_df_prepare_get_key_settings(tx_buff);
-        err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+        err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
         if(err != ERR_NONE) {
         if(err != ERR_NONE) {
             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
         } else {
         } else {
@@ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
                 &data->master_key_settings->key_version_head;
                 &data->master_key_settings->key_version_head;
             for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
             for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
                 tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
                 tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
-                err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+                err =
+                    furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
                 if(err != ERR_NONE) {
                 if(err != ERR_NONE) {
                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
                     continue;
                     continue;
@@ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
         }
         }
 
 
         tx_len = mf_df_prepare_get_application_ids(tx_buff);
         tx_len = mf_df_prepare_get_application_ids(tx_buff);
-        err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+        err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
         if(err != ERR_NONE) {
         if(err != ERR_NONE) {
             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
         } else {
         } else {
@@ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
 
 
         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
             tx_len = mf_df_prepare_select_application(tx_buff, app->id);
             tx_len = mf_df_prepare_select_application(tx_buff, app->id);
-            err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+            err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
             if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
             if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
                 continue;
                 continue;
             }
             }
             tx_len = mf_df_prepare_get_key_settings(tx_buff);
             tx_len = mf_df_prepare_get_key_settings(tx_buff);
-            err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+            err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
             if(err != ERR_NONE) {
             if(err != ERR_NONE) {
                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
             } else {
             } else {
@@ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
                 MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
                 MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
                 for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
                 for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
                     tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
                     tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
-                    err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+                    err = furi_hal_nfc_exchange_full(
+                        tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
                     if(err != ERR_NONE) {
                     if(err != ERR_NONE) {
                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
                         continue;
                         continue;
@@ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
             }
             }
 
 
             tx_len = mf_df_prepare_get_file_ids(tx_buff);
             tx_len = mf_df_prepare_get_file_ids(tx_buff);
-            err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+            err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
             if(err != ERR_NONE) {
             if(err != ERR_NONE) {
                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
             } else {
             } else {
@@ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
 
 
             for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
             for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
                 tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
                 tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
-                err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+                err =
+                    furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
                 if(err != ERR_NONE) {
                 if(err != ERR_NONE) {
                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
                     continue;
                     continue;
@@ -1054,7 +652,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
                     tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
                     tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
                     break;
                     break;
                 }
                 }
-                err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
+                err =
+                    furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
                 if(err != ERR_NONE) {
                 if(err != ERR_NONE) {
                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
                     continue;
                     continue;
@@ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
         break;
         break;
     }
     }
 }
 }
-
-void nfc_worker_field(NfcWorker* nfc_worker) {
-    furi_hal_nfc_field_on();
-    while(nfc_worker->state == NfcWorkerStateField) {
-        osDelay(50);
-    }
-    furi_hal_nfc_field_off();
-}

+ 3 - 3
applications/nfc/nfc_worker.h

@@ -13,11 +13,11 @@ typedef enum {
     NfcWorkerStateDetect,
     NfcWorkerStateDetect,
     NfcWorkerStateEmulate,
     NfcWorkerStateEmulate,
     NfcWorkerStateReadEMVApp,
     NfcWorkerStateReadEMVApp,
-    NfcWorkerStateReadEMV,
+    NfcWorkerStateReadEMVData,
     NfcWorkerStateEmulateApdu,
     NfcWorkerStateEmulateApdu,
     NfcWorkerStateField,
     NfcWorkerStateField,
-    NfcWorkerStateReadMifareUl,
-    NfcWorkerStateEmulateMifareUl,
+    NfcWorkerStateReadMifareUltralight,
+    NfcWorkerStateEmulateMifareUltralight,
     NfcWorkerStateReadMifareClassic,
     NfcWorkerStateReadMifareClassic,
     NfcWorkerStateReadMifareDesfire,
     NfcWorkerStateReadMifareDesfire,
     // Transition
     // Transition

+ 1 - 14
applications/nfc/nfc_worker_i.h

@@ -4,19 +4,8 @@
 #include "nfc_worker.h"
 #include "nfc_worker.h"
 
 
 #include <furi.h>
 #include <furi.h>
-#include <stdbool.h>
 #include <lib/toolbox/stream/file_stream.h>
 #include <lib/toolbox/stream/file_stream.h>
 
 
-#include <rfal_analogConfig.h>
-#include <rfal_rf.h>
-#include <rfal_nfc.h>
-#include <rfal_nfca.h>
-#include <rfal_nfcb.h>
-#include <rfal_nfcf.h>
-#include <rfal_nfcv.h>
-#include <st25r3916.h>
-#include <st25r3916_irq.h>
-
 struct NfcWorker {
 struct NfcWorker {
     FuriThread* thread;
     FuriThread* thread;
     Storage* storage;
     Storage* storage;
@@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker);
 
 
 void nfc_worker_emulate(NfcWorker* nfc_worker);
 void nfc_worker_emulate(NfcWorker* nfc_worker);
 
 
-void nfc_worker_field(NfcWorker* nfc_worker);
-
-void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker);
+void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
 
 
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
 
 

+ 5 - 5
applications/nfc/scenes/nfc_scene_card_menu.c

@@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
     Nfc* nfc = context;
     Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
-    if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
+    if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
         submenu_add_item(
         submenu_add_item(
             submenu,
             submenu,
             "Run Compatible App",
             "Run Compatible App",
@@ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
         if(event.event == SubmenuIndexRunApp) {
         if(event.event == SubmenuIndexRunApp) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
-            if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
+            if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
-            } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
+            } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
-            } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
+            } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
-            } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) {
+            } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
             }
             }
             consumed = true;
             consumed = true;

+ 0 - 1
applications/nfc/scenes/nfc_scene_config.h

@@ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start)
 ADD_SCENE(nfc, read_card, ReadCard)
 ADD_SCENE(nfc, read_card, ReadCard)
 ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
 ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
 ADD_SCENE(nfc, card_menu, CardMenu)
 ADD_SCENE(nfc, card_menu, CardMenu)
-ADD_SCENE(nfc, not_implemented, NotImplemented)
 ADD_SCENE(nfc, emulate_uid, EmulateUid)
 ADD_SCENE(nfc, emulate_uid, EmulateUid)
 ADD_SCENE(nfc, save_name, SaveName)
 ADD_SCENE(nfc, save_name, SaveName)
 ADD_SCENE(nfc, save_success, SaveSuccess)
 ADD_SCENE(nfc, save_success, SaveSuccess)

+ 4 - 4
applications/nfc/scenes/nfc_scene_debug.c

@@ -6,13 +6,13 @@ enum SubmenuDebugIndex {
 };
 };
 
 
 void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_debug_on_enter(void* context) {
 void nfc_scene_debug_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
     submenu_add_item(
     submenu_add_item(
@@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_debug_on_exit(void* context) {
 void nfc_scene_debug_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 24 - 25
applications/nfc/scenes/nfc_scene_delete.c

@@ -1,29 +1,28 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
 void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     if(type == InputTypeShort) {
     if(type == InputTypeShort) {
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     }
     }
 }
 }
 
 
 void nfc_scene_delete_on_enter(void* context) {
 void nfc_scene_delete_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup Custom Widget view
     // Setup Custom Widget view
-    char delete_str[64];
-    snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
-    widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
+    char temp_str[64];
+    snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
+    widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str);
     widget_add_button_element(
     widget_add_button_element(
         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
     widget_add_button_element(
     widget_add_button_element(
         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
-    char uid_str[32];
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
     if(data->uid_len == 4) {
     if(data->uid_len == 4) {
         snprintf(
         snprintf(
-            uid_str,
-            sizeof(uid_str),
+            temp_str,
+            sizeof(temp_str),
             "UID: %02X %02X %02X %02X",
             "UID: %02X %02X %02X %02X",
             data->uid[0],
             data->uid[0],
             data->uid[1],
             data->uid[1],
@@ -31,8 +30,8 @@ void nfc_scene_delete_on_enter(void* context) {
             data->uid[3]);
             data->uid[3]);
     } else if(data->uid_len == 7) {
     } else if(data->uid_len == 7) {
         snprintf(
         snprintf(
-            uid_str,
-            sizeof(uid_str),
+            temp_str,
+            sizeof(temp_str),
             "UID: %02X %02X %02X %02X %02X %02X %02X",
             "UID: %02X %02X %02X %02X %02X %02X %02X",
             data->uid[0],
             data->uid[0],
             data->uid[1],
             data->uid[1],
@@ -42,12 +41,13 @@ void nfc_scene_delete_on_enter(void* context) {
             data->uid[5],
             data->uid[5],
             data->uid[6]);
             data->uid[6]);
     }
     }
-    widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, uid_str);
+    widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str);
 
 
     const char* protocol_name = NULL;
     const char* protocol_name = NULL;
-    if(data->protocol == NfcDeviceProtocolEMV) {
-        protocol_name = nfc_guess_protocol(data->protocol);
-    } else if(data->protocol == NfcDeviceProtocolMifareUl) {
+    NfcProtocol protocol = nfc->dev->dev_data.protocol;
+    if(protocol == NfcDeviceProtocolEMV) {
+        protocol_name = nfc_guess_protocol(protocol);
+    } else if(protocol == NfcDeviceProtocolMifareUl) {
         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
     }
     }
     if(protocol_name) {
     if(protocol_name) {
@@ -56,18 +56,17 @@ void nfc_scene_delete_on_enter(void* context) {
     }
     }
     // TODO change dinamically
     // TODO change dinamically
     widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
     widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
-    char sak_str[16];
-    snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
-    widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str);
-    char atqa_str[16];
-    snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
-    widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, atqa_str);
+    snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
+    widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str);
+    snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
+    widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str);
 
 
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 }
 }
 
 
 bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
         if(event.event == GuiButtonTypeLeft) {
@@ -79,14 +78,14 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
                 scene_manager_search_and_switch_to_previous_scene(
                 scene_manager_search_and_switch_to_previous_scene(
                     nfc->scene_manager, NfcSceneStart);
                     nfc->scene_manager, NfcSceneStart);
             }
             }
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_delete_on_exit(void* context) {
 void nfc_scene_delete_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     widget_reset(nfc->widget);
     widget_reset(nfc->widget);
 }
 }

+ 9 - 15
applications/nfc/scenes/nfc_scene_delete_success.c

@@ -1,12 +1,12 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_delete_success_popup_callback(void* context) {
 void nfc_scene_delete_success_popup_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 }
 }
 
 
 void nfc_scene_delete_success_on_enter(void* context) {
 void nfc_scene_delete_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     Popup* popup = nfc->popup;
     Popup* popup = nfc->popup;
@@ -20,27 +20,21 @@ void nfc_scene_delete_success_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventViewExit) {
         if(event.event == NfcCustomEventViewExit) {
-            return scene_manager_search_and_switch_to_previous_scene(
+            consumed = scene_manager_search_and_switch_to_previous_scene(
                 nfc->scene_manager, NfcSceneStart);
                 nfc->scene_manager, NfcSceneStart);
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_delete_success_on_exit(void* context) {
 void nfc_scene_delete_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
-    popup_set_callback(popup, NULL);
-    popup_set_context(popup, NULL);
-    popup_set_timeout(popup, 0);
-    popup_disable_timeout(popup);
-}
+    popup_reset(nfc->popup);
+}

+ 21 - 28
applications/nfc/scenes/nfc_scene_device_info.c

@@ -43,12 +43,12 @@ void nfc_scene_device_info_on_enter(void* context) {
         widget_add_button_element(
         widget_add_button_element(
             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
     }
     }
-    char uid_str[32];
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
+    char temp_str[32];
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
     if(data->uid_len == 4) {
     if(data->uid_len == 4) {
         snprintf(
         snprintf(
-            uid_str,
-            sizeof(uid_str),
+            temp_str,
+            sizeof(temp_str),
             "UID: %02X %02X %02X %02X",
             "UID: %02X %02X %02X %02X",
             data->uid[0],
             data->uid[0],
             data->uid[1],
             data->uid[1],
@@ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) {
             data->uid[3]);
             data->uid[3]);
     } else if(data->uid_len == 7) {
     } else if(data->uid_len == 7) {
         snprintf(
         snprintf(
-            uid_str,
-            sizeof(uid_str),
+            temp_str,
+            sizeof(temp_str),
             "UID: %02X %02X %02X %02X %02X %02X %02X",
             "UID: %02X %02X %02X %02X %02X %02X %02X",
             data->uid[0],
             data->uid[0],
             data->uid[1],
             data->uid[1],
@@ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) {
             data->uid[5],
             data->uid[5],
             data->uid[6]);
             data->uid[6]);
     }
     }
-    widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str);
+    widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str);
 
 
     const char* protocol_name = NULL;
     const char* protocol_name = NULL;
-    if(data->protocol == NfcDeviceProtocolEMV ||
-       data->protocol == NfcDeviceProtocolMifareDesfire) {
-        protocol_name = nfc_guess_protocol(data->protocol);
-    } else if(data->protocol == NfcDeviceProtocolMifareUl) {
+    NfcProtocol protocol = nfc->dev->dev_data.protocol;
+    if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) {
+        protocol_name = nfc_guess_protocol(protocol);
+    } else if(protocol == NfcDeviceProtocolMifareUl) {
         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
-    } else if(data->protocol == NfcDeviceProtocolMifareClassic) {
+    } else if(protocol == NfcDeviceProtocolMifareClassic) {
         protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
         protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
     }
     }
     if(protocol_name) {
     if(protocol_name) {
@@ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) {
     }
     }
     // TODO change dinamically
     // TODO change dinamically
     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
-    char sak_str[16];
-    snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
-    widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str);
-    char atqa_str[16];
-    snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
-    widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
+    snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
+    widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
+    snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
+    widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str);
 
 
     // Setup Data View
     // Setup Data View
     if(nfc->dev->format == NfcDeviceSaveFormatUid) {
     if(nfc->dev->format == NfcDeviceSaveFormatUid) {
@@ -99,7 +97,7 @@ void nfc_scene_device_info_on_enter(void* context) {
         dialog_ex_set_context(dialog_ex, nfc);
         dialog_ex_set_context(dialog_ex, nfc);
         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
-        MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
+        MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
         TextBox* text_box = nfc->text_box;
         TextBox* text_box = nfc->text_box;
         text_box_set_font(text_box, TextBoxFontHex);
         text_box_set_font(text_box, TextBoxFontHex);
         for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
         for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
@@ -130,7 +128,7 @@ void nfc_scene_device_info_on_enter(void* context) {
         widget_add_string_element(
         widget_add_string_element(
             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
-        NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
+        EmvData* emv_data = &nfc->dev->dev_data.emv_data;
         BankCard* bank_card = nfc->bank_card;
         BankCard* bank_card = nfc->bank_card;
         bank_card_set_name(bank_card, emv_data->name);
         bank_card_set_name(bank_card, emv_data->name);
         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
@@ -212,21 +210,16 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_device_info_on_exit(void* context) {
 void nfc_scene_device_info_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
-    // Clear Custom Widget
+    // Clear views
     widget_reset(nfc->widget);
     widget_reset(nfc->widget);
-
     if(nfc->dev->format == NfcDeviceSaveFormatUid) {
     if(nfc->dev->format == NfcDeviceSaveFormatUid) {
-        // Clear Dialog
-        DialogEx* dialog_ex = nfc->dialog_ex;
-        dialog_ex_reset(dialog_ex);
+        dialog_ex_reset(nfc->dialog_ex);
     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
-        // Clear TextBox
         text_box_reset(nfc->text_box);
         text_box_reset(nfc->text_box);
         string_reset(nfc->text_box_store);
         string_reset(nfc->text_box_store);
     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
-        // Clear Bank Card
         bank_card_clear(nfc->bank_card);
         bank_card_clear(nfc->bank_card);
     }
     }
 }
 }

+ 8 - 10
applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c

@@ -1,36 +1,34 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
 void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     Popup* popup = nfc->popup;
     Popup* popup = nfc->popup;
-
     popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
     popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
 
 
     // Setup and start worker
     // Setup and start worker
-
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
 }
 }
 
 
 bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeTick) {
     if(event.type == SceneManagerEventTypeTick) {
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         notification_message(nfc->notifications, &sequence_blink_blue_10);
-        return true;
+        consumed = true;
     }
     }
-    return false;
+
+    return consumed;
 }
 }
 
 
 void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
 void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
-
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_reset(popup);
+    popup_reset(nfc->popup);
 }
 }

+ 7 - 9
applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c

@@ -5,13 +5,14 @@
 #define NFC_MF_UL_DATA_CHANGED (1UL)
 #define NFC_MF_UL_DATA_CHANGED (1UL)
 
 
 void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
 void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+
     scene_manager_set_scene_state(
     scene_manager_set_scene_state(
         nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
         nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
 }
 }
 
 
 void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
 void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcEmulate);
     DOLPHIN_DEED(DolphinDeedNfcEmulate);
 
 
     // Setup view
     // Setup view
@@ -26,14 +27,14 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     nfc_worker_start(
     nfc_worker_start(
         nfc->worker,
         nfc->worker,
-        NfcWorkerStateEmulateMifareUl,
+        NfcWorkerStateEmulateMifareUltralight,
         &nfc->dev->dev_data,
         &nfc->dev->dev_data,
         nfc_emulate_mifare_ul_worker_callback,
         nfc_emulate_mifare_ul_worker_callback,
         nfc);
         nfc);
 }
 }
 
 
 bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeTick) {
     if(event.type == SceneManagerEventTypeTick) {
@@ -55,11 +56,8 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
 }
 }
 
 
 void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
 void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
+    popup_reset(nfc->popup);
 }
 }

+ 10 - 6
applications/nfc/scenes/nfc_scene_emulate_uid.c

@@ -1,6 +1,8 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
+#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200)
+
 enum {
 enum {
     NfcSceneEmulateUidStateWidget,
     NfcSceneEmulateUidStateWidget,
     NfcSceneEmulateUidStateTextBox,
     NfcSceneEmulateUidStateTextBox,
@@ -28,7 +30,7 @@ void nfc_emulate_uid_textbox_callback(void* context) {
 
 
 // Add widget with device name or inform that data received
 // Add widget with device name or inform that data received
 static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
 static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
     Widget* widget = nfc->widget;
     Widget* widget = nfc->widget;
     widget_reset(widget);
     widget_reset(widget);
     string_t info_str;
     string_t info_str;
@@ -95,13 +97,15 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
                 nfc_scene_emulate_uid_widget_config(nfc, true);
                 nfc_scene_emulate_uid_widget_config(nfc, true);
             }
             }
             // Update TextBox data
             // Update TextBox data
-            string_cat_printf(nfc->text_box_store, "R:");
-            for(uint16_t i = 0; i < reader_data->size; i++) {
-                string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
+            if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) {
+                string_cat_printf(nfc->text_box_store, "R:");
+                for(uint16_t i = 0; i < reader_data->size; i++) {
+                    string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
+                }
+                string_push_back(nfc->text_box_store, '\n');
+                text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
             }
             }
-            string_push_back(nfc->text_box_store, '\n');
             memset(reader_data, 0, sizeof(NfcReaderRequestData));
             memset(reader_data, 0, sizeof(NfcReaderRequestData));
-            text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
             consumed = true;
             consumed = true;
         } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
         } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);

+ 4 - 7
applications/nfc/scenes/nfc_scene_field.c

@@ -1,7 +1,7 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_field_on_enter(void* context) {
 void nfc_scene_field_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     furi_hal_nfc_field_on();
     furi_hal_nfc_field_on();
 
 
@@ -23,12 +23,9 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_field_on_exit(void* context) {
 void nfc_scene_field_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
-
-    notification_internal_message(nfc->notifications, &sequence_reset_blue);
-
-    Popup* popup = nfc->popup;
-    popup_reset(popup);
+    Nfc* nfc = context;
 
 
     furi_hal_nfc_field_off();
     furi_hal_nfc_field_off();
+    notification_internal_message(nfc->notifications, &sequence_reset_blue);
+    popup_reset(nfc->popup);
 }
 }

+ 1 - 1
applications/nfc/scenes/nfc_scene_file_select.c

@@ -1,7 +1,7 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_file_select_on_enter(void* context) {
 void nfc_scene_file_select_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     // Process file_select return
     // Process file_select return
     if(nfc_file_select(nfc->dev)) {
     if(nfc_file_select(nfc->dev)) {
         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);

+ 9 - 8
applications/nfc/scenes/nfc_scene_mifare_desfire_app.c

@@ -18,13 +18,13 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
 }
 }
 
 
 void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_mifare_desfire_app_on_enter(void* context) {
 void nfc_scene_mifare_desfire_app_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
     MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
     MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
     if(!app) {
     if(!app) {
@@ -73,7 +73,8 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -96,24 +97,24 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
-        return true;
+        consumed = true;
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
         if(state & 1) {
         if(state & 1) {
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
                 nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
-            return true;
+            consumed = true;
         }
         }
     }
     }
 
 
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_mifare_desfire_app_on_exit(void* context) {
 void nfc_scene_mifare_desfire_app_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
+    // Clear views
     text_box_reset(nfc->text_box);
     text_box_reset(nfc->text_box);
     string_reset(nfc->text_box_store);
     string_reset(nfc->text_box_store);
-
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 9 - 8
applications/nfc/scenes/nfc_scene_mifare_desfire_data.c

@@ -19,7 +19,7 @@ void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t inde
 }
 }
 
 
 void nfc_scene_mifare_desfire_data_on_enter(void* context) {
 void nfc_scene_mifare_desfire_data_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
@@ -61,7 +61,8 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
 
 
@@ -76,7 +77,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
                 nfc->scene_manager,
                 nfc->scene_manager,
                 NfcSceneMifareDesfireData,
                 NfcSceneMifareDesfireData,
                 MifareDesfireDataStateItem + SubmenuIndexCardInfo);
                 MifareDesfireDataStateItem + SubmenuIndexCardInfo);
-            return true;
+            consumed = true;
         } else {
         } else {
             uint16_t index = event.event - SubmenuIndexDynamic;
             uint16_t index = event.event - SubmenuIndexDynamic;
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
@@ -84,25 +85,25 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
                 nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
         if(state >= MifareDesfireDataStateItem) {
         if(state >= MifareDesfireDataStateItem) {
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
-            return true;
+            consumed = true;
         }
         }
     }
     }
 
 
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_mifare_desfire_data_on_exit(void* context) {
 void nfc_scene_mifare_desfire_data_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
+    // Clear views
     text_box_reset(nfc->text_box);
     text_box_reset(nfc->text_box);
     string_reset(nfc->text_box_store);
     string_reset(nfc->text_box_store);
-
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 8 - 6
applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c

@@ -5,13 +5,13 @@ enum SubmenuIndex {
 };
 };
 
 
 void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
 void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
     submenu_add_item(
     submenu_add_item(
@@ -24,7 +24,8 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexSave) {
         if(event.event == SubmenuIndexSave) {
@@ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
             // Clear device name
             // Clear device name
             nfc_device_set_name(nfc->dev, "");
             nfc_device_set_name(nfc->dev, "");
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
-            return true;
+            consumed = true;
         }
         }
     }
     }
 
 
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
 void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
+    // Clear view
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 11 - 9
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c

@@ -6,13 +6,13 @@ enum SubmenuIndex {
 };
 };
 
 
 void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_mifare_ul_menu_on_enter(void* context) {
 void nfc_scene_mifare_ul_menu_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
     submenu_add_item(
     submenu_add_item(
@@ -26,7 +26,8 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexSave) {
         if(event.event == SubmenuIndexSave) {
@@ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
             // Clear device name
             // Clear device name
             nfc_device_set_name(nfc->dev, "");
             nfc_device_set_name(nfc->dev, "");
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
-            return true;
+            consumed = true;
         } else if(event.event == SubmenuIndexEmulate) {
         } else if(event.event == SubmenuIndexEmulate) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
-        return scene_manager_search_and_switch_to_previous_scene(
-            nfc->scene_manager, NfcSceneStart);
+        consumed =
+            scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
     }
     }
 
 
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_mifare_ul_menu_on_exit(void* context) {
 void nfc_scene_mifare_ul_menu_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
+    // Clear view
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

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

@@ -1,42 +0,0 @@
-#include "../nfc_i.h"
-
-void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
-
-    view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
-}
-
-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->view_dispatcher, NfcViewDialogEx);
-}
-
-bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
-
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == DialogExResultLeft) {
-            return scene_manager_previous_scene(nfc->scene_manager);
-        }
-    }
-    return false;
-}
-
-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);
-}

+ 9 - 12
applications/nfc/scenes/nfc_scene_read_card.c

@@ -2,12 +2,12 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
 void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 }
 }
 
 
 void nfc_scene_read_card_on_enter(void* context) {
 void nfc_scene_read_card_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcRead);
     DOLPHIN_DEED(DolphinDeedNfcRead);
 
 
     // Setup view
     // Setup view
@@ -22,29 +22,26 @@ void nfc_scene_read_card_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventWorkerExit) {
         if(event.event == NfcCustomEventWorkerExit) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeTick) {
     } else if(event.type == SceneManagerEventTypeTick) {
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         notification_message(nfc->notifications, &sequence_blink_blue_10);
-        return true;
+        consumed = true;
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_card_on_exit(void* context) {
 void nfc_scene_read_card_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
-
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
+    popup_reset(nfc->popup);
 }
 }

+ 13 - 9
applications/nfc/scenes/nfc_scene_read_card_success.c

@@ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback(
     void* context) {
     void* context) {
     furi_assert(context);
     furi_assert(context);
     Nfc* nfc = context;
     Nfc* nfc = context;
+
     if(type == InputTypeShort) {
     if(type == InputTypeShort) {
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     }
     }
 }
 }
 
 
 void nfc_scene_read_card_success_on_enter(void* context) {
 void nfc_scene_read_card_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+
     string_t data_str;
     string_t data_str;
     string_t uid_str;
     string_t uid_str;
     string_init(data_str);
     string_init(data_str);
@@ -24,9 +26,9 @@ void nfc_scene_read_card_success_on_enter(void* context) {
     notification_message(nfc->notifications, &sequence_success);
     notification_message(nfc->notifications, &sequence_success);
 
 
     // Setup view
     // Setup view
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
     Widget* widget = nfc->widget;
     Widget* widget = nfc->widget;
-    string_set_str(data_str, nfc_get_dev_type(data->device));
+    string_set_str(data_str, nfc_get_dev_type(data->type));
     string_set_str(uid_str, "UID:");
     string_set_str(uid_str, "UID:");
     for(uint8_t i = 0; i < data->uid_len; i++) {
     for(uint8_t i = 0; i < data->uid_len; i++) {
         string_cat_printf(uid_str, " %02X", data->uid[i]);
         string_cat_printf(uid_str, " %02X", data->uid[i]);
@@ -34,7 +36,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
 
 
     widget_add_button_element(
     widget_add_button_element(
         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
-    if(data->device == NfcDeviceNfca) {
+    if(data->type == FuriHalNfcTypeA) {
         widget_add_button_element(
         widget_add_button_element(
             widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
             widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
         widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
         widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
@@ -44,7 +46,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
         string_printf(
         string_printf(
             data_str,
             data_str,
             "%s\nATQA: %02X%02X SAK: %02X",
             "%s\nATQA: %02X%02X SAK: %02X",
-            nfc_guess_protocol(data->protocol),
+            nfc_guess_protocol(nfc->dev->dev_data.protocol),
             data->atqa[0],
             data->atqa[0],
             data->atqa[1],
             data->atqa[1],
             data->sak);
             data->sak);
@@ -66,14 +68,14 @@ void nfc_scene_read_card_success_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
+    Nfc* nfc = context;
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
         if(event.event == GuiButtonTypeLeft) {
             consumed = scene_manager_previous_scene(nfc->scene_manager);
             consumed = scene_manager_previous_scene(nfc->scene_manager);
-        } else if(data->device == NfcDeviceNfca && event.event == GuiButtonTypeRight) {
+        } else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
             // Clear device name
             // Clear device name
             nfc_device_set_name(nfc->dev, "");
             nfc_device_set_name(nfc->dev, "");
             scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
@@ -84,6 +86,8 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
 }
 }
 
 
 void nfc_scene_read_card_success_on_exit(void* context) {
 void nfc_scene_read_card_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+
+    // Clear view
     widget_reset(nfc->widget);
     widget_reset(nfc->widget);
 }
 }

+ 10 - 11
applications/nfc/scenes/nfc_scene_read_emv_app.c

@@ -2,12 +2,12 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
 void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 }
 }
 
 
 void nfc_scene_read_emv_app_on_enter(void* context) {
 void nfc_scene_read_emv_app_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcRead);
     DOLPHIN_DEED(DolphinDeedNfcRead);
 
 
     // Setup view
     // Setup view
@@ -26,31 +26,30 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventWorkerExit) {
         if(event.event == NfcCustomEventWorkerExit) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeTick) {
     } else if(event.type == SceneManagerEventTypeTick) {
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         notification_message(nfc->notifications, &sequence_blink_blue_10);
-        return true;
+        consumed = true;
     }
     }
-    return false;
+
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_emv_app_on_exit(void* context) {
 void nfc_scene_read_emv_app_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
 
 
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
+    popup_reset(nfc->popup);
 }
 }

+ 41 - 43
applications/nfc/scenes/nfc_scene_read_emv_app_success.c

@@ -2,27 +2,38 @@
 #include "../helpers/nfc_emv_parser.h"
 #include "../helpers/nfc_emv_parser.h"
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
-#define NFC_SCENE_READ_SUCCESS_SHIFT "              "
-
-void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
-
-    view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
+void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) {
+    Nfc* nfc = context;
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
+    }
 }
 }
 
 
 void nfc_scene_read_emv_app_success_on_enter(void* context) {
 void nfc_scene_read_emv_app_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
 
 
     // Setup view
     // Setup view
-    NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
-    NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
-    DialogEx* dialog_ex = nfc->dialog_ex;
-    dialog_ex_set_left_button_text(dialog_ex, "Retry");
-    dialog_ex_set_right_button_text(dialog_ex, "Run app");
-    dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter);
-    dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21);
-    // Display UID and AID
+    FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
+    EmvData* emv_data = &nfc->dev->dev_data.emv_data;
+    Widget* widget = nfc->widget;
+    widget_add_button_element(
+        widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc);
+    widget_add_button_element(
+        widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc);
+    widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App");
+    widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21);
+    // Display UID
+    string_t temp_str;
+    string_init_printf(temp_str, "UID:");
+    for(size_t i = 0; i < nfc_data->uid_len; i++) {
+        string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
+    }
+    widget_add_string_element(
+        widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
+    string_reset(temp_str);
+    // Display application
+    string_printf(temp_str, "App: ");
     string_t aid;
     string_t aid;
     string_init(aid);
     string_init(aid);
     bool aid_found =
     bool aid_found =
@@ -32,19 +43,11 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
             string_cat_printf(aid, "%02X", emv_data->aid[i]);
             string_cat_printf(aid, "%02X", emv_data->aid[i]);
         }
         }
     }
     }
-    nfc_text_store_set(
-        nfc,
-        NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT
-                                     "Application:\n%s",
-        nfc_data->uid[0],
-        nfc_data->uid[1],
-        nfc_data->uid[2],
-        nfc_data->uid[3],
-        string_get_cstr(aid));
+    string_cat(temp_str, aid);
+    widget_add_string_element(
+        widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
+    string_clear(temp_str);
     string_clear(aid);
     string_clear(aid);
-    dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
-    dialog_ex_set_context(dialog_ex, nfc);
-    dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_emv_app_success_dialog_callback);
 
 
     // Send notification
     // Send notification
     if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
     if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
@@ -54,32 +57,27 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
             nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
             nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
     }
     }
 
 
-    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
+    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 }
 }
 
 
 bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == DialogExResultLeft) {
-            return scene_manager_previous_scene(nfc->scene_manager);
-        } else if(event.event == DialogExResultRight) {
+        if(event.event == GuiButtonTypeLeft) {
+            consumed = scene_manager_previous_scene(nfc->scene_manager);
+        } else if(event.event == GuiButtonTypeRight) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_emv_app_success_on_exit(void* context) {
 void nfc_scene_read_emv_app_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
-    DialogEx* dialog_ex = nfc->dialog_ex;
-    dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
-    dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
-    dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
-    dialog_ex_set_left_button_text(dialog_ex, NULL);
-    dialog_ex_set_right_button_text(dialog_ex, NULL);
-    dialog_ex_set_result_callback(dialog_ex, NULL);
-    dialog_ex_set_context(dialog_ex, NULL);
+    // Clear views
+    widget_reset(nfc->widget);
 }
 }

+ 10 - 13
applications/nfc/scenes/nfc_scene_read_emv_data.c

@@ -2,12 +2,12 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
 void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 }
 }
 
 
 void nfc_scene_read_emv_data_on_enter(void* context) {
 void nfc_scene_read_emv_data_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcRead);
     DOLPHIN_DEED(DolphinDeedNfcRead);
 
 
     // Setup view
     // Setup view
@@ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
     // Start worker
     // Start worker
     nfc_worker_start(
     nfc_worker_start(
         nfc->worker,
         nfc->worker,
-        NfcWorkerStateReadEMV,
+        NfcWorkerStateReadEMVData,
         &nfc->dev->dev_data,
         &nfc->dev->dev_data,
         nfc_read_emv_data_worker_callback,
         nfc_read_emv_data_worker_callback,
         nfc);
         nfc);
 }
 }
 
 
 bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventWorkerExit) {
         if(event.event == NfcCustomEventWorkerExit) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeTick) {
     } else if(event.type == SceneManagerEventTypeTick) {
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         notification_message(nfc->notifications, &sequence_blink_blue_10);
-        return true;
+        consumed = true;
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_emv_data_on_exit(void* context) {
 void nfc_scene_read_emv_data_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
-
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
+    popup_reset(nfc->popup);
 }
 }

+ 20 - 20
applications/nfc/scenes/nfc_scene_read_emv_data_success.c

@@ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback(
     GuiButtonType result,
     GuiButtonType result,
     InputType type,
     InputType type,
     void* context) {
     void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     if(type == InputTypeShort) {
     if(type == InputTypeShort) {
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
         view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     }
     }
 }
 }
 
 
 void nfc_scene_read_emv_data_success_on_enter(void* context) {
 void nfc_scene_read_emv_data_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
-    NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
-    NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
+    Nfc* nfc = context;
+    EmvData* emv_data = &nfc->dev->dev_data.emv_data;
+    FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
 
 
     // Setup Custom Widget view
     // Setup Custom Widget view
@@ -78,25 +78,23 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
         string_clear(disp_currency);
         string_clear(disp_currency);
     }
     }
     string_clear(currency_name);
     string_clear(currency_name);
+    char temp_str[32];
     // Add ATQA
     // Add ATQA
-    char atqa_str[16];
-    snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
-    widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str);
+    snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
+    widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str);
     // Add UID
     // Add UID
-    char uid_str[32];
     snprintf(
     snprintf(
-        uid_str,
-        sizeof(uid_str),
+        temp_str,
+        sizeof(temp_str),
         "UID: %02X %02X %02X %02X",
         "UID: %02X %02X %02X %02X",
         nfc_data->uid[0],
         nfc_data->uid[0],
         nfc_data->uid[1],
         nfc_data->uid[1],
         nfc_data->uid[2],
         nfc_data->uid[2],
         nfc_data->uid[3]);
         nfc_data->uid[3]);
-    widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str);
+    widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
     // Add SAK
     // Add SAK
-    char sak_str[16];
-    snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
-    widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
+    snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak);
+    widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str);
     // Add expiration date
     // Add expiration date
     if(emv_data->exp_mon) {
     if(emv_data->exp_mon) {
         char exp_str[16];
         char exp_str[16];
@@ -117,28 +115,30 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == GuiButtonTypeLeft) {
         if(event.event == GuiButtonTypeLeft) {
-            return scene_manager_search_and_switch_to_previous_scene(
+            consumed = scene_manager_search_and_switch_to_previous_scene(
                 nfc->scene_manager, NfcSceneReadEmvAppSuccess);
                 nfc->scene_manager, NfcSceneReadEmvAppSuccess);
         } else if(event.event == GuiButtonTypeRight) {
         } else if(event.event == GuiButtonTypeRight) {
             // Clear device name
             // Clear device name
             nfc_device_set_name(nfc->dev, "");
             nfc_device_set_name(nfc->dev, "");
             nfc->dev->format = NfcDeviceSaveFormatBankCard;
             nfc->dev->format = NfcDeviceSaveFormatBankCard;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeBack) {
     } else if(event.type == SceneManagerEventTypeBack) {
-        return scene_manager_search_and_switch_to_previous_scene(
+        consumed = scene_manager_search_and_switch_to_previous_scene(
             nfc->scene_manager, NfcSceneReadEmvAppSuccess);
             nfc->scene_manager, NfcSceneReadEmvAppSuccess);
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_emv_data_success_on_exit(void* context) {
 void nfc_scene_read_emv_data_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
+    // Clear view
     widget_reset(nfc->widget);
     widget_reset(nfc->widget);
 }
 }

+ 9 - 12
applications/nfc/scenes/nfc_scene_read_mifare_desfire.c

@@ -2,12 +2,12 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
 void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 }
 }
 
 
 void nfc_scene_read_mifare_desfire_on_enter(void* context) {
 void nfc_scene_read_mifare_desfire_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcRead);
     DOLPHIN_DEED(DolphinDeedNfcRead);
 
 
     // Setup view
     // Setup view
@@ -26,31 +26,28 @@ void nfc_scene_read_mifare_desfire_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventWorkerExit) {
         if(event.event == NfcCustomEventWorkerExit) {
             notification_message(nfc->notifications, &sequence_success);
             notification_message(nfc->notifications, &sequence_success);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
-            return true;
+            consumed = true;
         }
         }
     } else if(event.type == SceneManagerEventTypeTick) {
     } else if(event.type == SceneManagerEventTypeTick) {
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         notification_message(nfc->notifications, &sequence_blink_blue_10);
         DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
         DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
-        return true;
+        consumed = true;
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_read_mifare_desfire_on_exit(void* context) {
 void nfc_scene_read_mifare_desfire_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
-
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
+    popup_reset(nfc->popup);
 }
 }

+ 5 - 6
applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c

@@ -9,13 +9,13 @@ enum {
 };
 };
 
 
 void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
 void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 }
 }
 
 
 void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
 void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
     DialogEx* dialog_ex = nfc->dialog_ex;
     DialogEx* dialog_ex = nfc->dialog_ex;
@@ -67,9 +67,9 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
 
 
 bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
     Nfc* nfc = context;
     Nfc* nfc = context;
+    bool consumed = false;
     uint32_t state =
     uint32_t state =
         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
-    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
         if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
@@ -98,9 +98,8 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
 }
 }
 
 
 void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
 void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clean dialog
     // Clean dialog
-    DialogEx* dialog_ex = nfc->dialog_ex;
-    dialog_ex_reset(dialog_ex);
+    dialog_ex_reset(nfc->dialog_ex);
 }
 }

+ 2 - 1
applications/nfc/scenes/nfc_scene_read_mifare_ul.c

@@ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
     // Start worker
     // Start worker
     nfc_worker_start(
     nfc_worker_start(
         nfc->worker,
         nfc->worker,
-        NfcWorkerStateReadMifareUl,
+        NfcWorkerStateReadMifareUltralight,
         &nfc->dev->dev_data,
         &nfc->dev->dev_data,
         nfc_read_mifare_ul_worker_callback,
         nfc_read_mifare_ul_worker_callback,
         nfc);
         nfc);
@@ -43,6 +43,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
 
 
 void nfc_scene_read_mifare_ul_on_exit(void* context) {
 void nfc_scene_read_mifare_ul_on_exit(void* context) {
     Nfc* nfc = context;
     Nfc* nfc = context;
+
     // Stop worker
     // Stop worker
     nfc_worker_stop(nfc->worker);
     nfc_worker_stop(nfc->worker);
     // Clear view
     // Clear view

+ 9 - 13
applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c

@@ -9,21 +9,21 @@ enum {
 };
 };
 
 
 void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
 void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 }
 }
 
 
 void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
 void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
     DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
 
 
     // Send notification
     // Send notification
     notification_message(nfc->notifications, &sequence_success);
     notification_message(nfc->notifications, &sequence_success);
 
 
     // Setup dialog view
     // Setup dialog view
-    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
-    MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
+    FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
+    MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
     DialogEx* dialog_ex = nfc->dialog_ex;
     DialogEx* dialog_ex = nfc->dialog_ex;
     dialog_ex_set_left_button_text(dialog_ex, "Retry");
     dialog_ex_set_left_button_text(dialog_ex, "Retry");
     dialog_ex_set_right_button_text(dialog_ex, "More");
     dialog_ex_set_right_button_text(dialog_ex, "More");
@@ -69,9 +69,9 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
 
 
 bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
     Nfc* nfc = context;
     Nfc* nfc = context;
+    bool consumed = false;
     uint32_t state =
     uint32_t state =
         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
-    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
         if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
@@ -99,14 +99,10 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
 }
 }
 
 
 void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
 void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
-
-    // Clean dialog
-    DialogEx* dialog_ex = nfc->dialog_ex;
-    dialog_ex_reset(dialog_ex);
+    Nfc* nfc = context;
 
 
-    // Clean TextBox
-    TextBox* text_box = nfc->text_box;
-    text_box_reset(text_box);
+    // Clean views
+    dialog_ex_reset(nfc->dialog_ex);
+    text_box_reset(nfc->text_box);
     string_reset(nfc->text_box_store);
     string_reset(nfc->text_box_store);
 }
 }

+ 5 - 12
applications/nfc/scenes/nfc_scene_restore_original.c

@@ -1,12 +1,12 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_restore_original_popup_callback(void* context) {
 void nfc_scene_restore_original_popup_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 }
 }
 
 
 void nfc_scene_restore_original_on_enter(void* context) {
 void nfc_scene_restore_original_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     Popup* popup = nfc->popup;
     Popup* popup = nfc->popup;
@@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -32,15 +32,8 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event)
 }
 }
 
 
 void nfc_scene_restore_original_on_exit(void* context) {
 void nfc_scene_restore_original_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
-    popup_set_callback(popup, NULL);
-    popup_set_context(popup, NULL);
-    popup_set_timeout(popup, 0);
-    popup_disable_timeout(popup);
+    popup_reset(nfc->popup);
 }
 }

+ 10 - 17
applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c

@@ -1,15 +1,13 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
-#define NFC_SCENE_READ_SUCCESS_SHIFT "              "
-
 void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
 void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 }
 }
 
 
 void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
 void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     DialogEx* dialog_ex = nfc->dialog_ex;
     DialogEx* dialog_ex = nfc->dialog_ex;
     dialog_ex_set_left_button_text(dialog_ex, "Back");
     dialog_ex_set_left_button_text(dialog_ex, "Back");
@@ -29,28 +27,23 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == DialogExResultLeft) {
         if(event.event == DialogExResultLeft) {
-            return scene_manager_previous_scene(nfc->scene_manager);
+            consumed = scene_manager_previous_scene(nfc->scene_manager);
         } else if(event.event == DialogExResultRight) {
         } else if(event.event == DialogExResultRight) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
 void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
-    DialogEx* dialog_ex = nfc->dialog_ex;
-    dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
-    dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
-    dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
-    dialog_ex_set_left_button_text(dialog_ex, NULL);
-    dialog_ex_set_right_button_text(dialog_ex, NULL);
-    dialog_ex_set_result_callback(dialog_ex, NULL);
-    dialog_ex_set_context(dialog_ex, NULL);
+    // Clean view
+    dialog_ex_reset(nfc->dialog_ex);
 }
 }

+ 8 - 7
applications/nfc/scenes/nfc_scene_save_name.c

@@ -3,13 +3,13 @@
 #include <gui/modules/validators.h>
 #include <gui/modules/validators.h>
 
 
 void nfc_scene_save_name_text_input_callback(void* context) {
 void nfc_scene_save_name_text_input_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
 }
 }
 
 
 void nfc_scene_save_name_on_enter(void* context) {
 void nfc_scene_save_name_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     TextInput* text_input = nfc->text_input;
     TextInput* text_input = nfc->text_input;
@@ -37,7 +37,8 @@ void nfc_scene_save_name_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventTextInputDone) {
         if(event.event == NfcCustomEventTextInputDone) {
@@ -50,18 +51,18 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
             if(nfc_device_save(nfc->dev, nfc->text_store)) {
             if(nfc_device_save(nfc->dev, nfc->text_store)) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
-                return true;
+                consumed = true;
             } else {
             } else {
-                return scene_manager_search_and_switch_to_previous_scene(
+                consumed = scene_manager_search_and_switch_to_previous_scene(
                     nfc->scene_manager, NfcSceneStart);
                     nfc->scene_manager, NfcSceneStart);
             }
             }
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_save_name_on_exit(void* context) {
 void nfc_scene_save_name_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
     void* validator_context = text_input_get_validator_callback_context(nfc->text_input);
     void* validator_context = text_input_get_validator_callback_context(nfc->text_input);

+ 5 - 12
applications/nfc/scenes/nfc_scene_save_success.c

@@ -2,12 +2,12 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_scene_save_success_popup_callback(void* context) {
 void nfc_scene_save_success_popup_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 }
 }
 
 
 void nfc_scene_save_success_on_enter(void* context) {
 void nfc_scene_save_success_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     DOLPHIN_DEED(DolphinDeedNfcSave);
     DOLPHIN_DEED(DolphinDeedNfcSave);
 
 
     // Setup view
     // Setup view
@@ -22,7 +22,7 @@ void nfc_scene_save_success_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -47,15 +47,8 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_save_success_on_exit(void* context) {
 void nfc_scene_save_success_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
-    Popup* popup = nfc->popup;
-    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
-    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
-    popup_set_icon(popup, 0, 0, NULL);
-    popup_set_callback(popup, NULL);
-    popup_set_context(popup, NULL);
-    popup_set_timeout(popup, 0);
-    popup_disable_timeout(popup);
+    popup_reset(nfc->popup);
 }
 }

+ 4 - 4
applications/nfc/scenes/nfc_scene_saved_menu.c

@@ -9,13 +9,13 @@ enum SubmenuIndex {
 };
 };
 
 
 void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_saved_menu_on_enter(void* context) {
 void nfc_scene_saved_menu_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
     if(nfc->dev->format == NfcDeviceSaveFormatUid ||
     if(nfc->dev->format == NfcDeviceSaveFormatUid ||
@@ -56,7 +56,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -92,7 +92,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_saved_menu_on_exit(void* context) {
 void nfc_scene_saved_menu_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 7 - 6
applications/nfc/scenes/nfc_scene_set_atqa.c

@@ -1,13 +1,13 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_set_atqa_byte_input_callback(void* context) {
 void nfc_scene_set_atqa_byte_input_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 }
 }
 
 
 void nfc_scene_set_atqa_on_enter(void* context) {
 void nfc_scene_set_atqa_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     ByteInput* byte_input = nfc->byte_input;
     ByteInput* byte_input = nfc->byte_input;
@@ -23,19 +23,20 @@ void nfc_scene_set_atqa_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventByteInputDone) {
         if(event.event == NfcCustomEventByteInputDone) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_set_atqa_on_exit(void* context) {
 void nfc_scene_set_atqa_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

+ 7 - 6
applications/nfc/scenes/nfc_scene_set_sak.c

@@ -1,13 +1,13 @@
 #include "../nfc_i.h"
 #include "../nfc_i.h"
 
 
 void nfc_scene_set_sak_byte_input_callback(void* context) {
 void nfc_scene_set_sak_byte_input_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 }
 }
 
 
 void nfc_scene_set_sak_on_enter(void* context) {
 void nfc_scene_set_sak_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     ByteInput* byte_input = nfc->byte_input;
     ByteInput* byte_input = nfc->byte_input;
@@ -23,19 +23,20 @@ void nfc_scene_set_sak_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventByteInputDone) {
         if(event.event == NfcCustomEventByteInputDone) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_set_sak_on_exit(void* context) {
 void nfc_scene_set_sak_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

+ 8 - 7
applications/nfc/scenes/nfc_scene_set_type.c

@@ -6,13 +6,13 @@ enum SubmenuIndex {
 };
 };
 
 
 void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_set_type_on_enter(void* context) {
 void nfc_scene_set_type_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
     // Clear device name
     // Clear device name
     nfc_device_set_name(nfc->dev, "");
     nfc_device_set_name(nfc->dev, "");
@@ -24,26 +24,27 @@ void nfc_scene_set_type_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexNFCA7) {
         if(event.event == SubmenuIndexNFCA7) {
             nfc->dev->dev_data.nfc_data.uid_len = 7;
             nfc->dev->dev_data.nfc_data.uid_len = 7;
             nfc->dev->format = NfcDeviceSaveFormatUid;
             nfc->dev->format = NfcDeviceSaveFormatUid;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
-            return true;
+            consumed = true;
         } else if(event.event == SubmenuIndexNFCA4) {
         } else if(event.event == SubmenuIndexNFCA4) {
             nfc->dev->dev_data.nfc_data.uid_len = 4;
             nfc->dev->dev_data.nfc_data.uid_len = 4;
             nfc->dev->format = NfcDeviceSaveFormatUid;
             nfc->dev->format = NfcDeviceSaveFormatUid;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_set_type_on_exit(void* context) {
 void nfc_scene_set_type_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 6 - 5
applications/nfc/scenes/nfc_scene_set_uid.c

@@ -2,13 +2,13 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
 void nfc_scene_set_uid_byte_input_callback(void* context) {
 void nfc_scene_set_uid_byte_input_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 }
 }
 
 
 void nfc_scene_set_uid_on_enter(void* context) {
 void nfc_scene_set_uid_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Setup view
     // Setup view
     ByteInput* byte_input = nfc->byte_input;
     ByteInput* byte_input = nfc->byte_input;
@@ -26,19 +26,20 @@ void nfc_scene_set_uid_on_enter(void* context) {
 
 
 bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
     Nfc* nfc = (Nfc*)context;
     Nfc* nfc = (Nfc*)context;
+    bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == NfcCustomEventByteInputDone) {
         if(event.event == NfcCustomEventByteInputDone) {
             DOLPHIN_DEED(DolphinDeedNfcAdd);
             DOLPHIN_DEED(DolphinDeedNfcAdd);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
-            return true;
+            consumed = true;
         }
         }
     }
     }
-    return false;
+    return consumed;
 }
 }
 
 
 void nfc_scene_set_uid_on_exit(void* context) {
 void nfc_scene_set_uid_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     // Clear view
     // Clear view
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

+ 4 - 4
applications/nfc/scenes/nfc_scene_start.c

@@ -9,13 +9,13 @@ enum SubmenuIndex {
 };
 };
 
 
 void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
 void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
     view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
 }
 }
 
 
 void nfc_scene_start_on_enter(void* context) {
 void nfc_scene_start_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     Submenu* submenu = nfc->submenu;
     Submenu* submenu = nfc->submenu;
 
 
     submenu_add_item(
     submenu_add_item(
@@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) {
 }
 }
 
 
 bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
@@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
 }
 }
 
 
 void nfc_scene_start_on_exit(void* context) {
 void nfc_scene_start_on_exit(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
 
     submenu_reset(nfc->submenu);
     submenu_reset(nfc->submenu);
 }
 }

+ 111 - 44
firmware/targets/f7/furi_hal/furi_hal_nfc.c

@@ -48,13 +48,12 @@ void furi_hal_nfc_exit_sleep() {
     rfalLowPowerModeStop();
     rfalLowPowerModeStop();
 }
 }
 
 
-bool furi_hal_nfc_detect(
-    rfalNfcDevice** dev_list,
-    uint8_t* dev_cnt,
-    uint32_t timeout,
-    bool deactivate) {
-    furi_assert(dev_list);
-    furi_assert(dev_cnt);
+bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) {
+    furi_assert(nfc_data);
+
+    rfalNfcDevice* dev_list = NULL;
+    uint8_t dev_cnt = 0;
+    bool detected = false;
 
 
     rfalLowPowerModeStop();
     rfalLowPowerModeStop();
     rfalNfcState state = rfalNfcGetState();
     rfalNfcState state = rfalNfcGetState();
@@ -77,9 +76,13 @@ bool furi_hal_nfc_detect(
 
 
     uint32_t start = DWT->CYCCNT;
     uint32_t start = DWT->CYCCNT;
     rfalNfcDiscover(&params);
     rfalNfcDiscover(&params);
-    while(state != RFAL_NFC_STATE_ACTIVATED) {
+    while(true) {
         rfalNfcWorker();
         rfalNfcWorker();
         state = rfalNfcGetState();
         state = rfalNfcGetState();
+        if(state == RFAL_NFC_STATE_ACTIVATED) {
+            detected = true;
+            break;
+        }
         FURI_LOG_T(TAG, "Current state %d", state);
         FURI_LOG_T(TAG, "Current state %d", state);
         if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
         if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
             start = DWT->CYCCNT;
             start = DWT->CYCCNT;
@@ -91,16 +94,42 @@ bool furi_hal_nfc_detect(
         if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
         if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
             rfalNfcDeactivate(true);
             rfalNfcDeactivate(true);
             FURI_LOG_T(TAG, "Timeout");
             FURI_LOG_T(TAG, "Timeout");
-            return false;
+            break;
         }
         }
         osThreadYield();
         osThreadYield();
     }
     }
-    rfalNfcGetDevicesFound(dev_list, dev_cnt);
-    if(deactivate) {
-        rfalNfcDeactivate(false);
-        rfalLowPowerModeStart();
+    rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
+    if(detected) {
+        if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
+            nfc_data->type = FuriHalNfcTypeA;
+            nfc_data->atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
+            nfc_data->atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
+            nfc_data->sak = dev_list[0].dev.nfca.selRes.sak;
+            uint8_t* cuid_start = dev_list[0].nfcid;
+            if(dev_list[0].nfcidLen == 7) {
+                cuid_start = &dev_list[0].nfcid[3];
+            }
+            nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
+                             (cuid_start[3]);
+        } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) {
+            nfc_data->type = FuriHalNfcTypeB;
+        } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) {
+            nfc_data->type = FuriHalNfcTypeF;
+        } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) {
+            nfc_data->type = FuriHalNfcTypeV;
+        }
+        if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_RF) {
+            nfc_data->interface = FuriHalNfcInterfaceRf;
+        } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
+            nfc_data->interface = FuriHalNfcInterfaceIsoDep;
+        } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
+            nfc_data->interface = FuriHalNfcInterfaceNfcDep;
+        }
+        nfc_data->uid_len = dev_list[0].nfcidLen;
+        memcpy(nfc_data->uid, dev_list[0].nfcid, nfc_data->uid_len);
     }
     }
-    return true;
+
+    return detected;
 }
 }
 
 
 bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
 bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
@@ -326,12 +355,6 @@ bool furi_hal_nfc_emulate_nfca(
     return true;
     return true;
 }
 }
 
 
-bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) {
-    ReturnCode ret =
-        rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT);
-    return ret == ERR_NONE;
-}
-
 ReturnCode furi_hal_nfc_data_exchange(
 ReturnCode furi_hal_nfc_data_exchange(
     uint8_t* tx_buff,
     uint8_t* tx_buff,
     uint16_t tx_len,
     uint16_t tx_len,
@@ -370,6 +393,22 @@ ReturnCode furi_hal_nfc_data_exchange(
     return ret;
     return ret;
 }
 }
 
 
+static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) {
+    uint32_t flags = 0;
+
+    if(type == FuriHalNfcTxRxTypeRxNoCrc) {
+        flags = RFAL_TXRX_FLAGS_CRC_RX_KEEP;
+    } else if(type == FuriHalNfcTxRxTypeRxKeepPar) {
+        flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                RFAL_TXRX_FLAGS_PAR_RX_KEEP;
+    } else if(type == FuriHalNfcTxRxTypeRaw) {
+        flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE;
+    }
+
+    return flags;
+}
+
 static uint16_t furi_hal_nfc_data_and_parity_to_bitstream(
 static uint16_t furi_hal_nfc_data_and_parity_to_bitstream(
     uint8_t* data,
     uint8_t* data,
     uint16_t len,
     uint16_t len,
@@ -420,8 +459,8 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity(
     return curr_byte;
     return curr_byte;
 }
 }
 
 
-bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
-    furi_assert(tx_rx_ctx);
+bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
+    furi_assert(tx_rx);
 
 
     ReturnCode ret;
     ReturnCode ret;
     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
@@ -431,26 +470,18 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
     uint16_t* temp_rx_bits = NULL;
     uint16_t* temp_rx_bits = NULL;
 
 
     // Prepare data for FIFO if necessary
     // Prepare data for FIFO if necessary
-    if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
+    uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type);
+    if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
         temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream(
         temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream(
-            tx_rx_ctx->tx_data, tx_rx_ctx->tx_bits / 8, tx_rx_ctx->tx_parity, temp_tx_buff);
+            tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity, temp_tx_buff);
         ret = rfalNfcDataExchangeCustomStart(
         ret = rfalNfcDataExchangeCustomStart(
-            temp_tx_buff,
-            temp_tx_bits,
-            &temp_rx_buff,
-            &temp_rx_bits,
-            RFAL_FWT_NONE,
-            tx_rx_ctx->tx_rx_type);
+            temp_tx_buff, temp_tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
     } else {
     } else {
         ret = rfalNfcDataExchangeCustomStart(
         ret = rfalNfcDataExchangeCustomStart(
-            tx_rx_ctx->tx_data,
-            tx_rx_ctx->tx_bits,
-            &temp_rx_buff,
-            &temp_rx_bits,
-            RFAL_FWT_NONE,
-            tx_rx_ctx->tx_rx_type);
+            tx_rx->tx_data, tx_rx->tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
     }
     }
     if(ret != ERR_NONE) {
     if(ret != ERR_NONE) {
+        FURI_LOG_E(TAG, "Failed to start data exchange");
         return false;
         return false;
     }
     }
     uint32_t start = DWT->CYCCNT;
     uint32_t start = DWT->CYCCNT;
@@ -459,28 +490,64 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
         state = rfalNfcGetState();
         state = rfalNfcGetState();
         ret = rfalNfcDataExchangeGetStatus();
         ret = rfalNfcDataExchangeGetStatus();
         if(ret == ERR_BUSY) {
         if(ret == ERR_BUSY) {
-            if(DWT->CYCCNT - start > 4 * clocks_in_ms) {
+            if(DWT->CYCCNT - start > timeout_ms * clocks_in_ms) {
+                FURI_LOG_D(TAG, "Timeout during data exchange");
                 return false;
                 return false;
             }
             }
             continue;
             continue;
         } else {
         } else {
             start = DWT->CYCCNT;
             start = DWT->CYCCNT;
         }
         }
-        taskYIELD();
+        osThreadYield();
     }
     }
 
 
-    if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
-        tx_rx_ctx->rx_bits =
-            8 * furi_hal_nfc_bitstream_to_data_and_parity(
-                    temp_rx_buff, *temp_rx_bits, tx_rx_ctx->rx_data, tx_rx_ctx->rx_parity);
+    if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
+        tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity(
+                                 temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity);
     } else {
     } else {
-        memcpy(tx_rx_ctx->rx_data, temp_rx_buff, *temp_rx_bits / 8);
+        memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURI_HAL_NFC_DATA_BUFF_SIZE));
+        tx_rx->rx_bits = *temp_rx_bits;
     }
     }
 
 
     return true;
     return true;
 }
 }
 
 
-void furi_hal_nfc_deactivate() {
+ReturnCode furi_hal_nfc_exchange_full(
+    uint8_t* tx_buff,
+    uint16_t tx_len,
+    uint8_t* rx_buff,
+    uint16_t rx_cap,
+    uint16_t* rx_len) {
+    ReturnCode err;
+    uint8_t* part_buff;
+    uint16_t* part_len_bits;
+    uint16_t part_len_bytes;
+
+    err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false);
+    part_len_bytes = *part_len_bits / 8;
+    if(part_len_bytes > rx_cap) {
+        return ERR_OVERRUN;
+    }
+    memcpy(rx_buff, part_buff, part_len_bytes);
+    *rx_len = part_len_bytes;
+    while(err == ERR_NONE && rx_buff[0] == 0xAF) {
+        err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false);
+        part_len_bytes = *part_len_bits / 8;
+        if(part_len_bytes > rx_cap - *rx_len) {
+            return ERR_OVERRUN;
+        }
+        if(part_len_bytes == 0) {
+            return ERR_PROTO;
+        }
+        memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1);
+        *rx_buff = *part_buff;
+        *rx_len += part_len_bytes - 1;
+    }
+
+    return err;
+}
+
+void furi_hal_nfc_sleep() {
     rfalNfcDeactivate(false);
     rfalNfcDeactivate(false);
     rfalLowPowerModeStart();
     rfalLowPowerModeStart();
 }
 }

+ 56 - 30
firmware/targets/furi_hal_include/furi_hal_nfc.h

@@ -15,32 +15,31 @@ extern "C" {
 #endif
 #endif
 
 
 #define FURI_HAL_NFC_UID_MAX_LEN 10
 #define FURI_HAL_NFC_UID_MAX_LEN 10
-#define FURI_HAL_NFC_DATA_BUFF_SIZE (64)
+#define FURI_HAL_NFC_DATA_BUFF_SIZE (256)
 #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
 #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
 
 
 #define FURI_HAL_NFC_TXRX_DEFAULT                                                    \
 #define FURI_HAL_NFC_TXRX_DEFAULT                                                    \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |       \
-     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
 
 
 #define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC                                            \
 #define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC                                            \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |       \
-     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
 
 
 #define FURI_HAL_NFC_TXRX_WITH_PAR                                                     \
 #define FURI_HAL_NFC_TXRX_WITH_PAR                                                     \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |         \
-     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO |   \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
 
 
 #define FURI_HAL_NFC_TXRX_RAW                                                          \
 #define FURI_HAL_NFC_TXRX_RAW                                                          \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
     ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |         \
-     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE |   \
-     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE)
+
+typedef enum {
+    FuriHalNfcTxRxTypeDefault,
+    FuriHalNfcTxRxTypeRxNoCrc,
+    FuriHalNfcTxRxTypeRxKeepPar,
+    FuriHalNfcTxRxTypeRaw,
+} FuriHalNfcTxRxType;
 
 
 typedef bool (*FuriHalNfcEmulateCallback)(
 typedef bool (*FuriHalNfcEmulateCallback)(
     uint8_t* buff_rx,
     uint8_t* buff_rx,
@@ -50,6 +49,29 @@ typedef bool (*FuriHalNfcEmulateCallback)(
     uint32_t* flags,
     uint32_t* flags,
     void* context);
     void* context);
 
 
+typedef enum {
+    FuriHalNfcTypeA,
+    FuriHalNfcTypeB,
+    FuriHalNfcTypeF,
+    FuriHalNfcTypeV,
+} FuriHalNfcType;
+
+typedef enum {
+    FuriHalNfcInterfaceRf,
+    FuriHalNfcInterfaceIsoDep,
+    FuriHalNfcInterfaceNfcDep,
+} FuriHalNfcInterface;
+
+typedef struct {
+    FuriHalNfcType type;
+    FuriHalNfcInterface interface;
+    uint8_t uid_len;
+    uint8_t uid[10];
+    uint32_t cuid;
+    uint8_t atqa[2];
+    uint8_t sak;
+} FuriHalNfcDevData;
+
 typedef struct {
 typedef struct {
     uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
     uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
     uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
     uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
@@ -57,7 +79,7 @@ typedef struct {
     uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
     uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
     uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
     uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
     uint16_t rx_bits;
     uint16_t rx_bits;
-    uint32_t tx_rx_type;
+    FuriHalNfcTxRxType tx_rx_type;
 } FuriHalNfcTxRxContext;
 } FuriHalNfcTxRxContext;
 
 
 /** Init nfc
 /** Init nfc
@@ -95,11 +117,7 @@ void furi_hal_nfc_exit_sleep();
  *
  *
  * @return     true on success
  * @return     true on success
  */
  */
-bool furi_hal_nfc_detect(
-    rfalNfcDevice** dev_list,
-    uint8_t* dev_cnt,
-    uint32_t timeout,
-    bool deactivate);
+bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout);
 
 
 /** Activate NFC-A tag
 /** Activate NFC-A tag
  *
  *
@@ -138,15 +156,6 @@ bool furi_hal_nfc_emulate_nfca(
     void* context,
     void* context,
     uint32_t timeout);
     uint32_t timeout);
 
 
-/** Get first command from reader after activation in emulation mode
- *
- * @param      rx_buff  pointer to receive buffer
- * @param      rx_len   receive buffer length
- *
- * @return     true on success
- */
-bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len);
-
 /** NFC data exchange
 /** NFC data exchange
  *
  *
  * @param      tx_buff     transmit buffer
  * @param      tx_buff     transmit buffer
@@ -170,11 +179,28 @@ ReturnCode furi_hal_nfc_data_exchange(
  *
  *
  * @return      true on success
  * @return      true on success
  */
  */
-bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx);
+bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms);
+
+/** NFC data full exhange
+ *
+ * @param      tx_buff     transmit buffer
+ * @param      tx_len      transmit buffer length
+ * @param      rx_buff     receive buffer
+ * @param      rx_cap      receive buffer capacity
+ * @param      rx_len      receive buffer length
+ *
+ * @return     ST ReturnCode
+ */
+ReturnCode furi_hal_nfc_exchange_full(
+    uint8_t* tx_buff,
+    uint16_t tx_len,
+    uint8_t* rx_buff,
+    uint16_t rx_cap,
+    uint16_t* rx_len);
 
 
 /** NFC deactivate and start sleep
 /** NFC deactivate and start sleep
  */
  */
-void furi_hal_nfc_deactivate();
+void furi_hal_nfc_sleep();
 
 
 void furi_hal_nfc_stop();
 void furi_hal_nfc_stop();
 
 

+ 1 - 1
lib/ST25RFAL002/source/rfal_isoDep.c

@@ -3015,7 +3015,7 @@ ReturnCode rfalIsoDepGetApduTransceiveStatus(void) {
         }
         }
 
 
         /* Update output param rxLen */
         /* Update output param rxLen */
-        *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos;
+        *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos * 8;
 
 
         /* Wait for following I-Block or APDU TxRx has finished */
         /* Wait for following I-Block or APDU TxRx has finished */
         return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);
         return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);

+ 13 - 7
lib/ST25RFAL002/source/rfal_nfc.c

@@ -725,9 +725,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
         {
         {
         /*******************************************************************************/
         /*******************************************************************************/
         case RFAL_NFC_INTERFACE_RF:
         case RFAL_NFC_INTERFACE_RF:
-            ctx.rxBuf = gNfcDev.rxBuf.rfBuf, ctx.rxBufLen = sizeof(gNfcDev.rxBuf.rfBuf),
-            ctx.rxRcvdLen = &gNfcDev.rxLen, ctx.txBuf = txData, ctx.txBufLen = txDataLen,
-            ctx.flags = flags, ctx.fwt = fwt, *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
+            ctx.rxBuf = gNfcDev.rxBuf.rfBuf;
+            ctx.rxBufLen = 8 * sizeof(gNfcDev.rxBuf.rfBuf);
+            ctx.rxRcvdLen = &gNfcDev.rxLen;
+            ctx.txBuf = txData;
+            ctx.txBufLen = txDataLen;
+            ctx.flags = flags;
+            ctx.fwt = fwt;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
             *rvdLen = (uint16_t*)&gNfcDev.rxLen;
             *rvdLen = (uint16_t*)&gNfcDev.rxLen;
             err = rfalStartTransceive(&ctx);
             err = rfalStartTransceive(&ctx);
             break;
             break;
@@ -736,13 +741,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
         /*******************************************************************************/
         /*******************************************************************************/
         case RFAL_NFC_INTERFACE_ISODEP: {
         case RFAL_NFC_INTERFACE_ISODEP: {
             rfalIsoDepApduTxRxParam isoDepTxRx;
             rfalIsoDepApduTxRxParam isoDepTxRx;
+            uint16_t tx_bytes = txDataLen / 8;
 
 
-            if(txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
+            if(tx_bytes > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
                 return ERR_NOMEM;
                 return ERR_NOMEM;
             }
             }
 
 
-            if(txDataLen > 0U) {
-                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen);
+            if(tx_bytes > 0U) {
+                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, tx_bytes);
             }
             }
 
 
             isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
             isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
@@ -751,7 +757,7 @@ ReturnCode rfalNfcDataExchangeCustomStart(
             isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
             isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
             isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
             isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
             isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
             isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
-            isoDepTxRx.txBufLen = txDataLen;
+            isoDepTxRx.txBufLen = tx_bytes;
             isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
             isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
             isoDepTxRx.rxLen = &gNfcDev.rxLen;
             isoDepTxRx.rxLen = &gNfcDev.rxLen;
             isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;
             isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;

+ 216 - 76
lib/nfc_protocols/emv_decoder.c → lib/nfc_protocols/emv.c

@@ -1,4 +1,8 @@
-#include "emv_decoder.h"
+#include "emv.h"
+
+#include <furi/common_defines.h>
+
+#define TAG "Emv"
 
 
 const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information
 const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information
 const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type
 const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type
@@ -69,19 +73,6 @@ static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* i
     return false;
     return false;
 }
 }
 
 
-uint16_t emv_prepare_select_ppse(uint8_t* dest) {
-    const uint8_t emv_select_ppse[] = {
-        0x00, 0xA4, // SELECT ppse
-        0x04, 0x00, // P1:By name, P2: empty
-        0x0e, // Lc: Data length
-        0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
-        0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
-        0x00 // Le
-    };
-    memcpy(dest, emv_select_ppse, sizeof(emv_select_ppse));
-    return sizeof(emv_select_ppse);
-}
-
 bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
 bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
     uint16_t i = 0;
     uint16_t i = 0;
     bool app_aid_found = false;
     bool app_aid_found = false;
@@ -89,7 +80,7 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
     while(i < len) {
     while(i < len) {
         if(buff[i] == EMV_TAG_APP_TEMPLATE) {
         if(buff[i] == EMV_TAG_APP_TEMPLATE) {
             uint8_t app_len = buff[++i];
             uint8_t app_len = buff[++i];
-            for(uint16_t j = i; j < i + app_len; j++) {
+            for(uint16_t j = i; j < MIN(i + app_len, len - 1); j++) {
                 if(buff[j] == EMV_TAG_AID) {
                 if(buff[j] == EMV_TAG_AID) {
                     app_aid_found = true;
                     app_aid_found = true;
                     app->aid_len = buff[j + 1];
                     app->aid_len = buff[j + 1];
@@ -105,41 +96,89 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
     return app_aid_found;
     return app_aid_found;
 }
 }
 
 
-uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) {
-    const uint8_t emv_select_header[] = {
-        0x00,
-        0xA4, // SELECT application
-        0x04,
-        0x00 // P1:By name, P2:First or only occurence
+bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
+    bool app_aid_found = false;
+    const uint8_t emv_select_ppse_cmd[] = {
+        0x00, 0xA4, // SELECT ppse
+        0x04, 0x00, // P1:By name, P2: empty
+        0x0e, // Lc: Data length
+        0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
+        0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
+        0x00 // Le
     };
     };
-    uint16_t size = sizeof(emv_select_header);
-    // Copy header
-    memcpy(dest, emv_select_header, size);
-    // Copy AID
-    dest[size++] = app->aid_len;
-    memcpy(&dest[size], app->aid, app->aid_len);
-    size += app->aid_len;
-    dest[size++] = 0;
-    return size;
+
+    memcpy(tx_rx->tx_data, emv_select_ppse_cmd, sizeof(emv_select_ppse_cmd));
+    tx_rx->tx_bits = sizeof(emv_select_ppse_cmd) * 8;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+
+    FURI_LOG_D(TAG, "Send select PPSE");
+    if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
+        if(emv_decode_ppse_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
+            app_aid_found = true;
+        } else {
+            FURI_LOG_E(TAG, "Failed to parse application");
+        }
+    } else {
+        FURI_LOG_E(TAG, "Failed select PPSE");
+    }
+
+    return app_aid_found;
 }
 }
 
 
-bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
+static bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
     uint16_t i = 0;
     uint16_t i = 0;
-    bool found_name = false;
+    bool decode_success = false;
 
 
     while(i < len) {
     while(i < len) {
         if(buff[i] == EMV_TAG_CARD_NAME) {
         if(buff[i] == EMV_TAG_CARD_NAME) {
             uint8_t name_len = buff[i + 1];
             uint8_t name_len = buff[i + 1];
             emv_parse_TLV((uint8_t*)app->name, buff, &i);
             emv_parse_TLV((uint8_t*)app->name, buff, &i);
             app->name[name_len] = '\0';
             app->name[name_len] = '\0';
-            found_name = true;
+            app->name_found = true;
+            decode_success = true;
         } else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
         } else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
             i++;
             i++;
             app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
             app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
+            decode_success = true;
         }
         }
         i++;
         i++;
     }
     }
-    return found_name;
+
+    return decode_success;
+}
+
+bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
+    bool select_app_success = false;
+    const uint8_t emv_select_header[] = {
+        0x00,
+        0xA4, // SELECT application
+        0x04,
+        0x00 // P1:By name, P2:First or only occurence
+    };
+    uint16_t size = sizeof(emv_select_header);
+
+    // Copy header
+    memcpy(tx_rx->tx_data, emv_select_header, size);
+    // Copy AID
+    tx_rx->tx_data[size++] = app->aid_len;
+    memcpy(&tx_rx->tx_data[size], app->aid, app->aid_len);
+    size += app->aid_len;
+    tx_rx->tx_data[size++] = 0x00;
+    tx_rx->tx_bits = size * 8;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+
+    FURI_LOG_D(TAG, "Start application");
+    if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
+        if(emv_decode_select_app_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
+            select_app_success = true;
+        } else {
+            FURI_LOG_E(TAG, "Failed to read PAN or PDOL");
+        }
+    } else {
+        FURI_LOG_E(TAG, "Failed to start application");
+    }
+
+    return select_app_success;
 }
 }
 
 
 static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
 static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
@@ -175,53 +214,56 @@ static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
     return dest->size;
     return dest->size;
 }
 }
 
 
-uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app) {
-    // Get processing option header
-    const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
-    uint16_t size = sizeof(emv_gpo_header);
-    // Copy header
-    memcpy(dest, emv_gpo_header, size);
-    APDU pdol_data = {0, {0}};
-    // Prepare and copy pdol parameters
-    emv_prepare_pdol(&pdol_data, &app->pdol);
-    dest[size++] = 0x02 + pdol_data.size;
-    dest[size++] = 0x83;
-    dest[size++] = pdol_data.size;
-    memcpy(dest + size, pdol_data.data, pdol_data.size);
-    size += pdol_data.size;
-    dest[size++] = 0;
-    return size;
-}
+static bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
+    bool card_num_read = false;
 
 
-bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
     for(uint16_t i = 0; i < len; i++) {
     for(uint16_t i = 0; i < len; i++) {
         if(buff[i] == EMV_TAG_CARD_NUM) {
         if(buff[i] == EMV_TAG_CARD_NUM) {
             app->card_number_len = 8;
             app->card_number_len = 8;
             memcpy(app->card_number, &buff[i + 2], app->card_number_len);
             memcpy(app->card_number, &buff[i + 2], app->card_number_len);
-            return true;
+            card_num_read = true;
         } else if(buff[i] == EMV_TAG_AFL) {
         } else if(buff[i] == EMV_TAG_AFL) {
             app->afl.size = emv_parse_TLV(app->afl.data, buff, &i);
             app->afl.size = emv_parse_TLV(app->afl.data, buff, &i);
         }
         }
     }
     }
-    return false;
+
+    return card_num_read;
 }
 }
 
 
-uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num) {
-    const uint8_t sfi_param = (sfi << 3) | (1 << 2);
-    const uint8_t emv_sfi_header[] = {
-        0x00,
-        0xB2, // READ RECORD
-        record_num,
-        sfi_param, // P1:record_number and P2:SFI
-        0x00 // Le
-    };
-    uint16_t size = sizeof(emv_sfi_header);
-    memcpy(dest, emv_sfi_header, size);
-    return size;
+static bool emv_get_processing_options(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
+    bool card_num_read = false;
+    const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
+    uint16_t size = sizeof(emv_gpo_header);
+
+    // Copy header
+    memcpy(tx_rx->tx_data, emv_gpo_header, size);
+    APDU pdol_data = {0, {0}};
+    // Prepare and copy pdol parameters
+    emv_prepare_pdol(&pdol_data, &app->pdol);
+    tx_rx->tx_data[size++] = 0x02 + pdol_data.size;
+    tx_rx->tx_data[size++] = 0x83;
+    tx_rx->tx_data[size++] = pdol_data.size;
+    memcpy(tx_rx->tx_data + size, pdol_data.data, pdol_data.size);
+    size += pdol_data.size;
+    tx_rx->tx_data[size++] = 0;
+    tx_rx->tx_bits = size * 8;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+
+    FURI_LOG_D(TAG, "Get proccessing options");
+    if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
+        if(emv_decode_get_proc_opt(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
+            card_num_read = true;
+        }
+    } else {
+        FURI_LOG_E(TAG, "Failed to get processing options");
+    }
+
+    return card_num_read;
 }
 }
 
 
-bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
+static bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
     bool pan_parsed = false;
     bool pan_parsed = false;
+
     for(uint16_t i = 0; i < len; i++) {
     for(uint16_t i = 0; i < len; i++) {
         if(buff[i] == EMV_TAG_PAN) {
         if(buff[i] == EMV_TAG_PAN) {
             if(buff[i + 1] == 8 || buff[i + 1] == 10) {
             if(buff[i + 1] == 8 || buff[i + 1] == 10) {
@@ -240,20 +282,118 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app
             i += 2;
             i += 2;
         }
         }
     }
     }
+
     return pan_parsed;
     return pan_parsed;
 }
 }
 
 
-uint16_t emv_select_ppse_ans(uint8_t* buff) {
-    memcpy(buff, select_ppse_ans, sizeof(select_ppse_ans));
-    return sizeof(select_ppse_ans);
+static bool emv_read_sfi_record(
+    FuriHalNfcTxRxContext* tx_rx,
+    EmvApplication* app,
+    uint8_t sfi,
+    uint8_t record_num) {
+    bool card_num_read = false;
+    uint8_t sfi_param = (sfi << 3) | (1 << 2);
+    uint8_t emv_sfi_header[] = {
+        0x00,
+        0xB2, // READ RECORD
+        record_num, // P1:record_number
+        sfi_param, // P2:SFI
+        0x00 // Le
+    };
+
+    memcpy(tx_rx->tx_data, emv_sfi_header, sizeof(emv_sfi_header));
+    tx_rx->tx_bits = sizeof(emv_sfi_header) * 8;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+
+    if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
+        if(emv_decode_read_sfi_record(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
+            card_num_read = true;
+        }
+    } else {
+        FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num);
+    }
+
+    return card_num_read;
+}
+
+static bool emv_read_files(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
+    bool card_num_read = false;
+
+    if(app->afl.size == 0) {
+        return false;
+    }
+
+    FURI_LOG_D(TAG, "Search PAN in SFI");
+    // Iterate through all files
+    for(size_t i = 0; i < app->afl.size; i += 4) {
+        uint8_t sfi = app->afl.data[i] >> 3;
+        uint8_t record_start = app->afl.data[i + 1];
+        uint8_t record_end = app->afl.data[i + 2];
+        // Iterate through all records in file
+        for(uint8_t record = record_start; record <= record_end; ++record) {
+            card_num_read |= emv_read_sfi_record(tx_rx, app, sfi, record);
+        }
+    }
+
+    return card_num_read;
+}
+
+bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
+    furi_assert(tx_rx);
+    furi_assert(emv_app);
+    memset(emv_app, 0, sizeof(EmvApplication));
+
+    return emv_select_ppse(tx_rx, emv_app);
 }
 }
 
 
-uint16_t emv_select_app_ans(uint8_t* buff) {
-    memcpy(buff, select_app_ans, sizeof(select_app_ans));
-    return sizeof(select_app_ans);
+bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
+    furi_assert(tx_rx);
+    furi_assert(emv_app);
+    bool card_num_read = false;
+    memset(emv_app, 0, sizeof(EmvApplication));
+
+    do {
+        if(!emv_select_ppse(tx_rx, emv_app)) break;
+        if(!emv_select_app(tx_rx, emv_app)) break;
+        if(emv_get_processing_options(tx_rx, emv_app)) {
+            card_num_read = true;
+        } else {
+            card_num_read = emv_read_files(tx_rx, emv_app);
+        }
+    } while(false);
+
+    return card_num_read;
 }
 }
 
 
-uint16_t emv_get_proc_opt_ans(uint8_t* buff) {
-    memcpy(buff, pdol_ans, sizeof(pdol_ans));
-    return sizeof(pdol_ans);
+bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
+    furi_assert(tx_rx);
+    bool emulation_complete = false;
+    memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext));
+
+    do {
+        FURI_LOG_D(TAG, "Read select PPSE command");
+        if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
+
+        memcpy(tx_rx->tx_data, select_ppse_ans, sizeof(select_ppse_ans));
+        tx_rx->tx_bits = sizeof(select_ppse_ans) * 8;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        FURI_LOG_D(TAG, "Send select PPSE answer and read select App command");
+        if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
+
+        memcpy(tx_rx->tx_data, select_app_ans, sizeof(select_app_ans));
+        tx_rx->tx_bits = sizeof(select_app_ans) * 8;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        FURI_LOG_D(TAG, "Send select App answer and read get PDOL command");
+        if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
+
+        memcpy(tx_rx->tx_data, pdol_ans, sizeof(pdol_ans));
+        tx_rx->tx_bits = sizeof(pdol_ans) * 8;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        FURI_LOG_D(TAG, "Send get PDOL answer");
+        if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
+
+        emulation_complete = true;
+    } while(false);
+
+    return emulation_complete;
 }
 }

+ 87 - 0
lib/nfc_protocols/emv.h

@@ -0,0 +1,87 @@
+#pragma once
+
+#include <furi_hal_nfc.h>
+
+#define MAX_APDU_LEN 255
+
+#define EMV_TAG_APP_TEMPLATE 0x61
+#define EMV_TAG_AID 0x4F
+#define EMV_TAG_PRIORITY 0x87
+#define EMV_TAG_PDOL 0x9F38
+#define EMV_TAG_CARD_NAME 0x50
+#define EMV_TAG_FCI 0xBF0C
+#define EMV_TAG_LOG_CTRL 0x9F4D
+#define EMV_TAG_CARD_NUM 0x57
+#define EMV_TAG_PAN 0x5A
+#define EMV_TAG_AFL 0x94
+#define EMV_TAG_EXP_DATE 0x5F24
+#define EMV_TAG_COUNTRY_CODE 0x5F28
+#define EMV_TAG_CURRENCY_CODE 0x9F42
+#define EMV_TAG_CARDHOLDER_NAME 0x5F20
+
+typedef struct {
+    char name[32];
+    uint8_t aid[16];
+    uint16_t aid_len;
+    uint8_t number[10];
+    uint8_t number_len;
+    uint8_t exp_mon;
+    uint8_t exp_year;
+    uint16_t country_code;
+    uint16_t currency_code;
+} EmvData;
+
+typedef struct {
+    uint16_t tag;
+    uint8_t data[];
+} PDOLValue;
+
+typedef struct {
+    uint8_t size;
+    uint8_t data[MAX_APDU_LEN];
+} APDU;
+
+typedef struct {
+    uint8_t priority;
+    uint8_t aid[16];
+    uint8_t aid_len;
+    char name[32];
+    bool name_found;
+    uint8_t card_number[10];
+    uint8_t card_number_len;
+    uint8_t exp_month;
+    uint8_t exp_year;
+    uint16_t country_code;
+    uint16_t currency_code;
+    APDU pdol;
+    APDU afl;
+} EmvApplication;
+
+/** Read bank card data
+ * @note Search EMV Application, start it, try to read AID, PAN, card name,
+ * expiration date, currency and country codes
+ *
+ * @param tx_rx     FuriHalNfcTxRxContext instance
+ * @param emv_app   EmvApplication instance
+ * 
+ * @return true on success
+ */
+bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
+
+/** Search for EMV Application
+ *
+ * @param tx_rx     FuriHalNfcTxRxContext instance
+ * @param emv_app   EmvApplication instance
+ *
+ * @return true on success
+ */
+bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
+
+/** Emulate bank card
+ * @note Answer to application selection and PDOL
+ *
+ * @param tx_rx     FuriHalNfcTxRxContext instance
+ *
+ * @return true on success
+ */
+bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx);

+ 0 - 67
lib/nfc_protocols/emv_decoder.h

@@ -1,67 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-
-#define MAX_APDU_LEN 255
-
-#define EMV_TAG_APP_TEMPLATE 0x61
-#define EMV_TAG_AID 0x4F
-#define EMV_TAG_PRIORITY 0x87
-#define EMV_TAG_PDOL 0x9F38
-#define EMV_TAG_CARD_NAME 0x50
-#define EMV_TAG_FCI 0xBF0C
-#define EMV_TAG_LOG_CTRL 0x9F4D
-#define EMV_TAG_CARD_NUM 0x57
-#define EMV_TAG_PAN 0x5A
-#define EMV_TAG_AFL 0x94
-#define EMV_TAG_EXP_DATE 0x5F24
-#define EMV_TAG_COUNTRY_CODE 0x5F28
-#define EMV_TAG_CURRENCY_CODE 0x9F42
-#define EMV_TAG_CARDHOLDER_NAME 0x5F20
-
-typedef struct {
-    uint16_t tag;
-    uint8_t data[];
-} PDOLValue;
-
-extern const PDOLValue* const pdol_values[];
-
-typedef struct {
-    uint8_t size;
-    uint8_t data[MAX_APDU_LEN];
-} APDU;
-
-typedef struct {
-    uint8_t priority;
-    uint8_t aid[16];
-    uint8_t aid_len;
-    char name[32];
-    uint8_t card_number[10];
-    uint8_t card_number_len;
-    uint8_t exp_month;
-    uint8_t exp_year;
-    uint16_t country_code;
-    uint16_t currency_code;
-    APDU pdol;
-    APDU afl;
-} EmvApplication;
-
-/* Terminal emulation */
-uint16_t emv_prepare_select_ppse(uint8_t* dest);
-bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app);
-
-uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app);
-bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app);
-
-uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app);
-bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app);
-
-uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num);
-bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app);
-
-/* Card emulation */
-uint16_t emv_select_ppse_ans(uint8_t* buff);
-uint16_t emv_select_app_ans(uint8_t* buff);
-uint16_t emv_get_proc_opt_ans(uint8_t* buff);

+ 8 - 10
lib/nfc_protocols/mifare_classic.c

@@ -116,17 +116,15 @@ static bool mf_classic_auth(
             tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
             tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
         }
         }
         tx_rx->tx_data[1] = block;
         tx_rx->tx_data[1] = block;
-        tx_rx->tx_rx_type = FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc;
         tx_rx->tx_bits = 2 * 8;
         tx_rx->tx_bits = 2 * 8;
-        if(!furi_hal_nfc_tx_rx(tx_rx)) break;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
 
 
         uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
         uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
         crypto1_init(crypto, key);
         crypto1_init(crypto, key);
         crypto1_word(crypto, nt ^ cuid, 0);
         crypto1_word(crypto, nt ^ cuid, 0);
         uint8_t nr[4] = {};
         uint8_t nr[4] = {};
-        // uint8_t parity = 0;
         nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
         nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
-        // uint8_t nr_ar[8] = {};
         for(uint8_t i = 0; i < 4; i++) {
         for(uint8_t i = 0; i < 4; i++) {
             tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
             tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
             tx_rx->tx_parity[0] |=
             tx_rx->tx_parity[0] |=
@@ -140,9 +138,9 @@ static bool mf_classic_auth(
                 (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
                 (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
                  << (7 - i));
                  << (7 - i));
         }
         }
-        tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
         tx_rx->tx_bits = 8 * 8;
         tx_rx->tx_bits = 8 * 8;
-        if(!furi_hal_nfc_tx_rx(tx_rx)) break;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
         if(tx_rx->rx_bits == 32) {
         if(tx_rx->rx_bits == 32) {
             crypto1_word(crypto, 0, 0);
             crypto1_word(crypto, 0, 0);
             auth_success = true;
             auth_success = true;
@@ -178,7 +176,7 @@ bool mf_classic_auth_attempt(
     }
     }
 
 
     if(need_halt) {
     if(need_halt) {
-        furi_hal_nfc_deactivate();
+        furi_hal_nfc_sleep();
         furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
         furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
     }
     }
 
 
@@ -220,9 +218,9 @@ bool mf_classic_read_block(
             ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
             ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
     }
     }
     tx_rx->tx_bits = 4 * 9;
     tx_rx->tx_bits = 4 * 9;
-    tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
 
 
-    if(furi_hal_nfc_tx_rx(tx_rx)) {
+    if(furi_hal_nfc_tx_rx(tx_rx, 4)) {
         if(tx_rx->rx_bits == 8 * 18) {
         if(tx_rx->rx_bits == 8 * 18) {
             for(uint8_t i = 0; i < 18; i++) {
             for(uint8_t i = 0; i < 18; i++) {
                 block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
                 block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
@@ -248,7 +246,7 @@ bool mf_classic_read_sector(
     uint8_t first_block;
     uint8_t first_block;
     bool sector_read = false;
     bool sector_read = false;
 
 
-    furi_hal_nfc_deactivate();
+    furi_hal_nfc_sleep();
     do {
     do {
         // Activate card
         // Activate card
         if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
         if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;

+ 17 - 0
lib/nfc_protocols/mifare_common.c

@@ -0,0 +1,17 @@
+#include "mifare_common.h"
+
+MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
+    MifareType type = MifareTypeUnknown;
+
+    if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
+        type = MifareTypeUltralight;
+    } else if(
+        ((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08)) ||
+        ((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18))) {
+        type = MifareTypeClassic;
+    } else if(ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20) {
+        type = MifareTypeDesfire;
+    }
+
+    return type;
+}

+ 12 - 0
lib/nfc_protocols/mifare_common.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    MifareTypeUnknown,
+    MifareTypeUltralight,
+    MifareTypeClassic,
+    MifareTypeDesfire,
+} MifareType;
+
+MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);

+ 226 - 187
lib/nfc_protocols/mifare_ultralight.c

@@ -1,6 +1,7 @@
 #include "mifare_ultralight.h"
 #include "mifare_ultralight.h"
 #include <furi.h>
 #include <furi.h>
-#include <furi_hal_nfc.h>
+
+#define TAG "MfUltralight"
 
 
 bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
 bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
     if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
     if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
@@ -9,187 +10,204 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
     return false;
     return false;
 }
 }
 
 
-uint16_t mf_ul_prepare_get_version(uint8_t* dest) {
-    dest[0] = MF_UL_GET_VERSION_CMD;
-    return 1;
+static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) {
+    data->type = MfUltralightTypeUnknown;
+    reader->pages_to_read = 16;
+    reader->support_fast_read = false;
 }
 }
 
 
-void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
-    MfUltralightVersion* version = (MfUltralightVersion*)buff;
-    memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion));
-    if(version->storage_size == 0x0B || version->storage_size == 0x00) {
-        mf_ul_read->data.type = MfUltralightTypeUL11;
-        mf_ul_read->pages_to_read = 20;
-        mf_ul_read->support_fast_read = true;
-    } else if(version->storage_size == 0x0E) {
-        mf_ul_read->data.type = MfUltralightTypeUL21;
-        mf_ul_read->pages_to_read = 41;
-        mf_ul_read->support_fast_read = true;
-    } else if(version->storage_size == 0x0F) {
-        mf_ul_read->data.type = MfUltralightTypeNTAG213;
-        mf_ul_read->pages_to_read = 45;
-        mf_ul_read->support_fast_read = false;
-    } else if(version->storage_size == 0x11) {
-        mf_ul_read->data.type = MfUltralightTypeNTAG215;
-        mf_ul_read->pages_to_read = 135;
-        mf_ul_read->support_fast_read = false;
-    } else if(version->storage_size == 0x13) {
-        mf_ul_read->data.type = MfUltralightTypeNTAG216;
-        mf_ul_read->pages_to_read = 231;
-        mf_ul_read->support_fast_read = false;
-    } else {
-        mf_ul_set_default_version(mf_ul_read);
-    }
-}
+bool mf_ultralight_read_version(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data) {
+    bool version_read = false;
 
 
-void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) {
-    mf_ul_read->data.type = MfUltralightTypeUnknown;
-    mf_ul_read->pages_to_read = 16;
-    mf_ul_read->support_fast_read = false;
-}
+    do {
+        FURI_LOG_D(TAG, "Reading version");
+        tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD;
+        tx_rx->tx_bits = 8;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
+            FURI_LOG_D(TAG, "Failed reading version");
+            mf_ul_set_default_version(reader, data);
+            furi_hal_nfc_sleep();
+            furi_hal_nfc_activate_nfca(300, NULL);
+            break;
+        }
+        MfUltralightVersion* version = (MfUltralightVersion*)tx_rx->rx_data;
+        data->version = *version;
+        if(version->storage_size == 0x0B || version->storage_size == 0x00) {
+            data->type = MfUltralightTypeUL11;
+            reader->pages_to_read = 20;
+            reader->support_fast_read = true;
+        } else if(version->storage_size == 0x0E) {
+            data->type = MfUltralightTypeUL21;
+            reader->pages_to_read = 41;
+            reader->support_fast_read = true;
+        } else if(version->storage_size == 0x0F) {
+            data->type = MfUltralightTypeNTAG213;
+            reader->pages_to_read = 45;
+            reader->support_fast_read = false;
+        } else if(version->storage_size == 0x11) {
+            data->type = MfUltralightTypeNTAG215;
+            reader->pages_to_read = 135;
+            reader->support_fast_read = false;
+        } else if(version->storage_size == 0x13) {
+            data->type = MfUltralightTypeNTAG216;
+            reader->pages_to_read = 231;
+            reader->support_fast_read = false;
+        } else {
+            mf_ul_set_default_version(reader, data);
+            break;
+        }
+        version_read = true;
+    } while(false);
 
 
-uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) {
-    dest[0] = MF_UL_READ_CMD;
-    dest[1] = start_page;
-    return 2;
+    return version_read;
 }
 }
 
 
-void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) {
-    uint8_t pages_read = 4;
-    uint8_t page_read_count = mf_ul_read->pages_read + pages_read;
-    if(page_read_count > mf_ul_read->pages_to_read) {
-        pages_read -= page_read_count - mf_ul_read->pages_to_read;
+bool mf_ultralight_read_pages(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data) {
+    uint8_t pages_read_cnt = 0;
+
+    for(size_t i = 0; i < reader->pages_to_read; i += 4) {
+        FURI_LOG_D(TAG, "Reading pages %d - %d", i, i + 3);
+        tx_rx->tx_data[0] = MF_UL_READ_CMD;
+        tx_rx->tx_data[1] = i;
+        tx_rx->tx_bits = 16;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
+            FURI_LOG_D(TAG, "Failed to read pages %d - %d", i, i + 3);
+            break;
+        }
+        if(i + 4 <= reader->pages_to_read) {
+            pages_read_cnt = 4;
+        } else {
+            pages_read_cnt = reader->pages_to_read - reader->pages_read;
+        }
+        reader->pages_read += pages_read_cnt;
+        data->data_size = reader->pages_read * 4;
+        memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4);
     }
     }
-    mf_ul_read->pages_read += pages_read;
-    mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
-    memcpy(&mf_ul_read->data.data[page_addr * 4], buff, pages_read * 4);
-}
 
 
-uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) {
-    dest[0] = MF_UL_FAST_READ_CMD;
-    dest[1] = start_page;
-    dest[2] = end_page;
-    return 3;
+    return reader->pages_read == reader->pages_to_read;
 }
 }
 
 
-void mf_ul_parse_fast_read_response(
-    uint8_t* buff,
-    uint8_t start_page,
-    uint8_t end_page,
-    MifareUlDevice* mf_ul_read) {
-    mf_ul_read->pages_read = end_page - start_page + 1;
-    mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
-    memcpy(mf_ul_read->data.data, buff, mf_ul_read->data.data_size);
-}
+bool mf_ultralight_fast_read_pages(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data) {
+    FURI_LOG_D(TAG, "Reading pages 0 - %d", reader->pages_to_read);
+    tx_rx->tx_data[0] = MF_UL_FAST_READ_CMD;
+    tx_rx->tx_data[1] = 0;
+    tx_rx->tx_data[2] = reader->pages_to_read - 1;
+    tx_rx->tx_bits = 24;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+    if(furi_hal_nfc_tx_rx(tx_rx, 20)) {
+        reader->pages_read = reader->pages_to_read;
+        data->data_size = reader->pages_read * 4;
+        memcpy(data->data, tx_rx->rx_data, data->data_size);
+    } else {
+        FURI_LOG_D(TAG, "Failed to read pages 0 - %d", reader->pages_to_read);
+    }
 
 
-uint16_t mf_ul_prepare_read_signature(uint8_t* dest) {
-    dest[0] = MF_UL_READ_SIG;
-    dest[1] = 0;
-    return 2;
+    return reader->pages_read == reader->pages_to_read;
 }
 }
 
 
-void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
-    memcpy(mf_ul_read->data.signature, buff, sizeof(mf_ul_read->data.signature));
-}
+bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
+    bool signature_read = false;
 
 
-uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index) {
-    if(cnt_index > 2) {
-        return 0;
+    FURI_LOG_D(TAG, "Reading signature");
+    tx_rx->tx_data[0] = MF_UL_READ_SIG;
+    tx_rx->tx_data[1] = 0;
+    tx_rx->tx_bits = 16;
+    tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+    if(furi_hal_nfc_tx_rx(tx_rx, 7)) {
+        memcpy(data->signature, tx_rx->rx_data, sizeof(data->signature));
+        signature_read = true;
+    } else {
+        FURI_LOG_D(TAG, "Failed redaing signature");
     }
     }
-    dest[0] = MF_UL_READ_CNT;
-    dest[1] = cnt_index;
-    return 2;
-}
 
 
-void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) {
-    // Reverse LSB sequence
-    if(cnt_index < 3) {
-        mf_ul_read->data.counter[cnt_index] = (buff[2] << 16) | (buff[1] << 8) | (buff[0]);
-    }
+    return signature_read;
 }
 }
 
 
-uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value) {
-    if(cnt_index > 2) {
-        return 0;
-    }
-    dest[0] = MF_UL_INC_CNT;
-    dest[1] = cnt_index;
-    dest[2] = (uint8_t)value;
-    dest[3] = (uint8_t)(value >> 8);
-    dest[4] = (uint8_t)(value >> 16);
-    dest[5] = 0;
-    return 6;
-}
+bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
+    uint8_t counter_read = 0;
 
 
-uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index) {
-    if(cnt_index > 2) {
-        return 0;
+    FURI_LOG_D(TAG, "Reading counters");
+    for(size_t i = 0; i < 3; i++) {
+        tx_rx->tx_data[0] = MF_UL_READ_CNT;
+        tx_rx->rx_data[1] = i;
+        tx_rx->tx_bits = 16;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
+            FURI_LOG_D(TAG, "Failed to read %d counter", i);
+            break;
+        }
+        data->counter[i] = (tx_rx->rx_data[2] << 16) | (tx_rx->rx_data[1] << 8) |
+                           tx_rx->rx_data[0];
+        counter_read++;
     }
     }
-    dest[0] = MF_UL_CHECK_TEARING;
-    dest[1] = cnt_index;
-    return 2;
-}
 
 
-void mf_ul_parse_check_tearing_response(
-    uint8_t* buff,
-    uint8_t cnt_index,
-    MifareUlDevice* mf_ul_read) {
-    if(cnt_index < 2) {
-        mf_ul_read->data.tearing[cnt_index] = buff[0];
-    }
+    return counter_read == 2;
 }
 }
 
 
-uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) {
-    if(page_addr < 2) {
-        return 0;
+bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
+    uint8_t flag_read = 0;
+
+    FURI_LOG_D(TAG, "Reading tearing flags");
+    for(size_t i = 0; i < 3; i++) {
+        tx_rx->tx_data[0] = MF_UL_CHECK_TEARING;
+        tx_rx->rx_data[1] = i;
+        tx_rx->tx_bits = 16;
+        tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
+        if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
+            FURI_LOG_D(TAG, "Failed to read %d tearing flag", i);
+            break;
+        }
+        data->tearing[i] = tx_rx->rx_data[0];
+        flag_read++;
     }
     }
-    dest[0] = MF_UL_WRITE;
-    dest[1] = page_addr;
-    dest[2] = (uint8_t)(data >> 24);
-    dest[3] = (uint8_t)(data >> 16);
-    dest[4] = (uint8_t)(data >> 8);
-    dest[5] = (uint8_t)data;
-    return 6;
+
+    return flag_read == 2;
 }
 }
 
 
-void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) {
-    mf_ul_emulate->data = *data;
-    mf_ul_emulate->auth_data = NULL;
-    mf_ul_emulate->data_changed = false;
-    mf_ul_emulate->comp_write_cmd_started = false;
-    if(data->version.storage_size == 0) {
-        mf_ul_emulate->data.type = MfUltralightTypeUnknown;
-        mf_ul_emulate->support_fast_read = false;
-    } else if(data->version.storage_size == 0x0B) {
-        mf_ul_emulate->data.type = MfUltralightTypeUL11;
-        mf_ul_emulate->support_fast_read = true;
-    } else if(data->version.storage_size == 0x0E) {
-        mf_ul_emulate->data.type = MfUltralightTypeUL21;
-        mf_ul_emulate->support_fast_read = true;
-    } else if(data->version.storage_size == 0x0F) {
-        mf_ul_emulate->data.type = MfUltralightTypeNTAG213;
-        mf_ul_emulate->support_fast_read = true;
-    } else if(data->version.storage_size == 0x11) {
-        mf_ul_emulate->data.type = MfUltralightTypeNTAG215;
-        mf_ul_emulate->support_fast_read = true;
-    } else if(data->version.storage_size == 0x13) {
-        mf_ul_emulate->data.type = MfUltralightTypeNTAG216;
-        mf_ul_emulate->support_fast_read = true;
-    }
+bool mf_ul_read_card(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data) {
+    furi_assert(tx_rx);
+    furi_assert(reader);
+    furi_assert(data);
 
 
-    if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
-        uint16_t pwd_page = (data->data_size / 4) - 2;
-        mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4];
+    bool card_read = false;
+
+    // Read Mifare Ultralight version
+    if(mf_ultralight_read_version(tx_rx, reader, data)) {
+        // Read Signature
+        mf_ultralight_read_signature(tx_rx, data);
+    }
+    // Read data blocks
+    if(reader->support_fast_read) {
+        mf_ultralight_read_counters(tx_rx, data);
+        mf_ultralight_read_tearing_flags(tx_rx, data);
     }
     }
+    card_read = mf_ultralight_read_pages(tx_rx, reader, data);
+
+    return card_read;
 }
 }
 
 
-void mf_ul_protect_auth_data_on_read_command(
+// TODO rework
+static void mf_ul_protect_auth_data_on_read_command(
     uint8_t* tx_buff,
     uint8_t* tx_buff,
     uint8_t start_page,
     uint8_t start_page,
     uint8_t end_page,
     uint8_t end_page,
-    MifareUlDevice* mf_ul_emulate) {
-    if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
-        uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2;
+    MfUltralightEmulator* emulator) {
+    if(emulator->data.type >= MfUltralightTypeNTAG213) {
+        uint8_t pwd_page = (emulator->data.data_size / 4) - 2;
         uint8_t pack_page = pwd_page + 1;
         uint8_t pack_page = pwd_page + 1;
         if((start_page <= pwd_page) && (end_page >= pwd_page)) {
         if((start_page <= pwd_page) && (end_page >= pwd_page)) {
             memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4);
             memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4);
@@ -200,6 +218,31 @@ void mf_ul_protect_auth_data_on_read_command(
     }
     }
 }
 }
 
 
+void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) {
+    emulator->data = *data;
+    emulator->auth_data = NULL;
+    emulator->data_changed = false;
+    emulator->comp_write_cmd_started = false;
+    if(data->type == MfUltralightTypeUnknown) {
+        emulator->support_fast_read = false;
+    } else if(data->type == MfUltralightTypeUL11) {
+        emulator->support_fast_read = true;
+    } else if(data->type == MfUltralightTypeUL21) {
+        emulator->support_fast_read = true;
+    } else if(data->type == MfUltralightTypeNTAG213) {
+        emulator->support_fast_read = false;
+    } else if(data->type == MfUltralightTypeNTAG215) {
+        emulator->support_fast_read = false;
+    } else if(data->type == MfUltralightTypeNTAG216) {
+        emulator->support_fast_read = false;
+    }
+
+    if(data->type >= MfUltralightTypeNTAG213) {
+        uint16_t pwd_page = (data->data_size / 4) - 2;
+        emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4];
+    }
+}
+
 bool mf_ul_prepare_emulation_response(
 bool mf_ul_prepare_emulation_response(
     uint8_t* buff_rx,
     uint8_t* buff_rx,
     uint16_t buff_rx_len,
     uint16_t buff_rx_len,
@@ -208,30 +251,30 @@ bool mf_ul_prepare_emulation_response(
     uint32_t* data_type,
     uint32_t* data_type,
     void* context) {
     void* context) {
     furi_assert(context);
     furi_assert(context);
-    MifareUlDevice* mf_ul_emulate = context;
+    MfUltralightEmulator* emulator = context;
     uint8_t cmd = buff_rx[0];
     uint8_t cmd = buff_rx[0];
-    uint16_t page_num = mf_ul_emulate->data.data_size / 4;
+    uint16_t page_num = emulator->data.data_size / 4;
     uint16_t tx_bytes = 0;
     uint16_t tx_bytes = 0;
     uint16_t tx_bits = 0;
     uint16_t tx_bits = 0;
     bool command_parsed = false;
     bool command_parsed = false;
 
 
     // Check composite commands
     // Check composite commands
-    if(mf_ul_emulate->comp_write_cmd_started) {
+    if(emulator->comp_write_cmd_started) {
         // Compatibility write is the only one composit command
         // Compatibility write is the only one composit command
         if(buff_rx_len == 16) {
         if(buff_rx_len == 16) {
-            memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4);
-            mf_ul_emulate->data_changed = true;
+            memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4);
+            emulator->data_changed = true;
             // Send ACK message
             // Send ACK message
             buff_tx[0] = 0x0A;
             buff_tx[0] = 0x0A;
             tx_bits = 4;
             tx_bits = 4;
             *data_type = FURI_HAL_NFC_TXRX_RAW;
             *data_type = FURI_HAL_NFC_TXRX_RAW;
             command_parsed = true;
             command_parsed = true;
         }
         }
-        mf_ul_emulate->comp_write_cmd_started = false;
+        emulator->comp_write_cmd_started = false;
     } else if(cmd == MF_UL_GET_VERSION_CMD) {
     } else if(cmd == MF_UL_GET_VERSION_CMD) {
-        if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) {
-            tx_bytes = sizeof(mf_ul_emulate->data.version);
-            memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes);
+        if(emulator->data.type != MfUltralightTypeUnknown) {
+            tx_bytes = sizeof(emulator->data.version);
+            memcpy(buff_tx, &emulator->data.version, tx_bytes);
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             command_parsed = true;
             command_parsed = true;
         }
         }
@@ -242,28 +285,24 @@ bool mf_ul_prepare_emulation_response(
             if(start_page + 4 > page_num) {
             if(start_page + 4 > page_num) {
                 // Handle roll-over mechanism
                 // Handle roll-over mechanism
                 uint8_t end_pages_num = page_num - start_page;
                 uint8_t end_pages_num = page_num - start_page;
-                memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4);
-                memcpy(
-                    &buff_tx[end_pages_num * 4],
-                    mf_ul_emulate->data.data,
-                    (4 - end_pages_num) * 4);
+                memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4);
+                memcpy(&buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4);
             } else {
             } else {
-                memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
+                memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
             }
             }
             mf_ul_protect_auth_data_on_read_command(
             mf_ul_protect_auth_data_on_read_command(
-                buff_tx, start_page, (start_page + 4), mf_ul_emulate);
+                buff_tx, start_page, (start_page + 4), emulator);
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             command_parsed = true;
             command_parsed = true;
         }
         }
     } else if(cmd == MF_UL_FAST_READ_CMD) {
     } else if(cmd == MF_UL_FAST_READ_CMD) {
-        if(mf_ul_emulate->support_fast_read) {
+        if(emulator->support_fast_read) {
             uint8_t start_page = buff_rx[1];
             uint8_t start_page = buff_rx[1];
             uint8_t end_page = buff_rx[2];
             uint8_t end_page = buff_rx[2];
             if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) {
             if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) {
                 tx_bytes = ((end_page + 1) - start_page) * 4;
                 tx_bytes = ((end_page + 1) - start_page) * 4;
-                memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
-                mf_ul_protect_auth_data_on_read_command(
-                    buff_tx, start_page, end_page, mf_ul_emulate);
+                memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
+                mf_ul_protect_auth_data_on_read_command(buff_tx, start_page, end_page, emulator);
                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
                 command_parsed = true;
                 command_parsed = true;
             }
             }
@@ -271,8 +310,8 @@ bool mf_ul_prepare_emulation_response(
     } else if(cmd == MF_UL_WRITE) {
     } else if(cmd == MF_UL_WRITE) {
         uint8_t write_page = buff_rx[1];
         uint8_t write_page = buff_rx[1];
         if((write_page > 1) && (write_page < page_num - 2)) {
         if((write_page > 1) && (write_page < page_num - 2)) {
-            memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4);
-            mf_ul_emulate->data_changed = true;
+            memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4);
+            emulator->data_changed = true;
             // ACK
             // ACK
             buff_tx[0] = 0x0A;
             buff_tx[0] = 0x0A;
             tx_bits = 4;
             tx_bits = 4;
@@ -282,8 +321,8 @@ bool mf_ul_prepare_emulation_response(
     } else if(cmd == MF_UL_COMP_WRITE) {
     } else if(cmd == MF_UL_COMP_WRITE) {
         uint8_t write_page = buff_rx[1];
         uint8_t write_page = buff_rx[1];
         if((write_page > 1) && (write_page < page_num - 2)) {
         if((write_page > 1) && (write_page < page_num - 2)) {
-            mf_ul_emulate->comp_write_cmd_started = true;
-            mf_ul_emulate->comp_write_page_addr = write_page;
+            emulator->comp_write_cmd_started = true;
+            emulator->comp_write_page_addr = write_page;
             // ACK
             // ACK
             buff_tx[0] = 0x0A;
             buff_tx[0] = 0x0A;
             tx_bits = 4;
             tx_bits = 4;
@@ -293,9 +332,9 @@ bool mf_ul_prepare_emulation_response(
     } else if(cmd == MF_UL_READ_CNT) {
     } else if(cmd == MF_UL_READ_CNT) {
         uint8_t cnt_num = buff_rx[1];
         uint8_t cnt_num = buff_rx[1];
         if(cnt_num < 3) {
         if(cnt_num < 3) {
-            buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16;
-            buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
-            buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
+            buff_tx[0] = emulator->data.counter[cnt_num] >> 16;
+            buff_tx[1] = emulator->data.counter[cnt_num] >> 8;
+            buff_tx[2] = emulator->data.counter[cnt_num];
             tx_bytes = 3;
             tx_bytes = 3;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             command_parsed = true;
             command_parsed = true;
@@ -303,9 +342,9 @@ bool mf_ul_prepare_emulation_response(
     } else if(cmd == MF_UL_INC_CNT) {
     } else if(cmd == MF_UL_INC_CNT) {
         uint8_t cnt_num = buff_rx[1];
         uint8_t cnt_num = buff_rx[1];
         uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
         uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
-        if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
-            mf_ul_emulate->data.counter[cnt_num] += inc;
-            mf_ul_emulate->data_changed = true;
+        if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
+            emulator->data.counter[cnt_num] += inc;
+            emulator->data_changed = true;
             // ACK
             // ACK
             buff_tx[0] = 0x0A;
             buff_tx[0] = 0x0A;
             tx_bits = 4;
             tx_bits = 4;
@@ -313,14 +352,14 @@ bool mf_ul_prepare_emulation_response(
             command_parsed = true;
             command_parsed = true;
         }
         }
     } else if(cmd == MF_UL_AUTH) {
     } else if(cmd == MF_UL_AUTH) {
-        if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
-            if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) {
-                buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0];
-                buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1];
+        if(emulator->data.type >= MfUltralightTypeNTAG213) {
+            if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) {
+                buff_tx[0] = emulator->auth_data->pack.raw[0];
+                buff_tx[1] = emulator->auth_data->pack.raw[1];
                 tx_bytes = 2;
                 tx_bytes = 2;
                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
                 command_parsed = true;
                 command_parsed = true;
-            } else if(!mf_ul_emulate->auth_data->pack.value) {
+            } else if(!emulator->auth_data->pack.value) {
                 buff_tx[0] = 0x80;
                 buff_tx[0] = 0x80;
                 buff_tx[1] = 0x80;
                 buff_tx[1] = 0x80;
                 tx_bytes = 2;
                 tx_bytes = 2;
@@ -331,15 +370,15 @@ bool mf_ul_prepare_emulation_response(
     } else if(cmd == MF_UL_READ_SIG) {
     } else if(cmd == MF_UL_READ_SIG) {
         // Check 2nd byte = 0x00 - RFU
         // Check 2nd byte = 0x00 - RFU
         if(buff_rx[1] == 0x00) {
         if(buff_rx[1] == 0x00) {
-            tx_bytes = sizeof(mf_ul_emulate->data.signature);
-            memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes);
+            tx_bytes = sizeof(emulator->data.signature);
+            memcpy(buff_tx, emulator->data.signature, tx_bytes);
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             command_parsed = true;
             command_parsed = true;
         }
         }
     } else if(cmd == MF_UL_CHECK_TEARING) {
     } else if(cmd == MF_UL_CHECK_TEARING) {
         uint8_t cnt_num = buff_rx[1];
         uint8_t cnt_num = buff_rx[1];
         if(cnt_num < 3) {
         if(cnt_num < 3) {
-            buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
+            buff_tx[0] = emulator->data.tearing[cnt_num];
             tx_bytes = 1;
             tx_bytes = 1;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
             command_parsed = true;
             command_parsed = true;

+ 30 - 31
lib/nfc_protocols/mifare_ultralight.h

@@ -1,8 +1,6 @@
 #pragma once
 #pragma once
 
 
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
+#include <furi_hal_nfc.h>
 
 
 #define MF_UL_MAX_DUMP_SIZE 1024
 #define MF_UL_MAX_DUMP_SIZE 1024
 
 
@@ -62,7 +60,7 @@ typedef struct {
     uint8_t tearing[3];
     uint8_t tearing[3];
     uint16_t data_size;
     uint16_t data_size;
     uint8_t data[MF_UL_MAX_DUMP_SIZE];
     uint8_t data[MF_UL_MAX_DUMP_SIZE];
-} MifareUlData;
+} MfUltralightData;
 
 
 typedef struct {
 typedef struct {
     uint8_t pwd[4];
     uint8_t pwd[4];
@@ -70,52 +68,53 @@ typedef struct {
         uint8_t raw[2];
         uint8_t raw[2];
         uint16_t value;
         uint16_t value;
     } pack;
     } pack;
-} MifareUlAuthData;
+} MfUltralightAuth;
 
 
 typedef struct {
 typedef struct {
     uint8_t pages_to_read;
     uint8_t pages_to_read;
     uint8_t pages_read;
     uint8_t pages_read;
     bool support_fast_read;
     bool support_fast_read;
+} MfUltralightReader;
+
+typedef struct {
+    MfUltralightData data;
+    bool support_fast_read;
     bool data_changed;
     bool data_changed;
-    MifareUlData data;
-    MifareUlAuthData* auth_data;
     bool comp_write_cmd_started;
     bool comp_write_cmd_started;
     uint8_t comp_write_page_addr;
     uint8_t comp_write_page_addr;
-} MifareUlDevice;
+    MfUltralightAuth* auth_data;
+} MfUltralightEmulator;
 
 
 bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
 bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
 
 
-uint16_t mf_ul_prepare_get_version(uint8_t* dest);
-void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
-void mf_ul_set_default_version(MifareUlDevice* mf_ul_read);
+bool mf_ultralight_read_version(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_read_signature(uint8_t* dest);
-void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
+bool mf_ultralight_read_pages(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index);
-void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read);
+bool mf_ultralight_fast_read_pages(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value);
+bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index);
-void mf_ul_parse_check_tearing_response(
-    uint8_t* buff,
-    uint8_t cnt_index,
-    MifareUlDevice* mf_ul_read);
+bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page);
-void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read);
+bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page);
-void mf_ul_parse_fast_read_response(
-    uint8_t* buff,
-    uint8_t start_page,
-    uint8_t end_page,
-    MifareUlDevice* mf_ul_read);
+bool mf_ul_read_card(
+    FuriHalNfcTxRxContext* tx_rx,
+    MfUltralightReader* reader,
+    MfUltralightData* data);
 
 
-uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
+void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
 
 
-void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
 bool mf_ul_prepare_emulation_response(
 bool mf_ul_prepare_emulation_response(
     uint8_t* buff_rx,
     uint8_t* buff_rx,
     uint16_t buff_rx_len,
     uint16_t buff_rx_len,