فهرست منبع

free up some space in mifare nested too

MX 1 سال پیش
والد
کامیت
6da212763a

+ 1 - 1
application.fam

@@ -18,5 +18,5 @@ App(
     fap_author="AloneLiberty & xMasterX",
     fap_description="Recover Mifare Classic keys",
     fap_weburl="https://github.com/AloneLiberty/FlipperNested",
-    fap_version="1.6.5",
+    fap_version="1.6.6",
 )

+ 0 - 71
lib/nfclegacy/helpers/nfc_debug_log.c

@@ -1,71 +0,0 @@
-#include "nfc_debug_log.h"
-
-#include <storage/storage.h>
-#include <stream/buffered_file_stream.h>
-
-#define TAG "NfcDebugLog"
-
-#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.txt")
-
-struct NfcDebugLog {
-    Stream* file_stream;
-    FuriString* data_str;
-};
-
-NfcDebugLog* nfc_debug_log_alloc() {
-    NfcDebugLog* instance = malloc(sizeof(NfcDebugLog));
-
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    instance->file_stream = buffered_file_stream_alloc(storage);
-
-    if(!buffered_file_stream_open(
-           instance->file_stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
-        buffered_file_stream_close(instance->file_stream);
-        stream_free(instance->file_stream);
-        instance->file_stream = NULL;
-    }
-
-    if(!instance->file_stream) {
-        free(instance);
-        instance = NULL;
-    } else {
-        instance->data_str = furi_string_alloc();
-    }
-    furi_record_close(RECORD_STORAGE);
-
-    return instance;
-}
-
-void nfc_debug_log_free(NfcDebugLog* instance) {
-    furi_assert(instance);
-    furi_assert(instance->file_stream);
-    furi_assert(instance->data_str);
-
-    buffered_file_stream_close(instance->file_stream);
-    stream_free(instance->file_stream);
-    furi_string_free(instance->data_str);
-
-    free(instance);
-}
-
-void nfc_debug_log_process_data(
-    NfcDebugLog* instance,
-    uint8_t* data,
-    uint16_t len,
-    bool reader_to_tag,
-    bool crc_dropped) {
-    furi_assert(instance);
-    furi_assert(instance->file_stream);
-    furi_assert(instance->data_str);
-    furi_assert(data);
-    UNUSED(crc_dropped);
-
-    furi_string_printf(instance->data_str, "%lu %c:", furi_get_tick(), reader_to_tag ? 'R' : 'T');
-    uint16_t data_len = len;
-    for(size_t i = 0; i < data_len; i++) {
-        furi_string_cat_printf(instance->data_str, " %02x", data[i]);
-    }
-    furi_string_push_back(instance->data_str, '\n');
-
-    stream_write_string(instance->file_stream, instance->data_str);
-}

+ 0 - 17
lib/nfclegacy/helpers/nfc_debug_log.h

@@ -1,17 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef struct NfcDebugLog NfcDebugLog;
-
-NfcDebugLog* nfc_debug_log_alloc();
-
-void nfc_debug_log_free(NfcDebugLog* instance);
-
-void nfc_debug_log_process_data(
-    NfcDebugLog* instance,
-    uint8_t* data,
-    uint16_t len,
-    bool reader_to_tag,
-    bool crc_dropped);

+ 0 - 128
lib/nfclegacy/helpers/nfc_debug_pcap.c

@@ -1,128 +0,0 @@
-#include "nfc_debug_pcap.h"
-
-#include <storage/storage.h>
-#include <stream/buffered_file_stream.h>
-#include "../furi_hal_nfc.h"
-#include <furi_hal_rtc.h>
-
-#define TAG "NfcDebugPcap"
-
-#define PCAP_MAGIC 0xa1b2c3d4
-#define PCAP_MAJOR 2
-#define PCAP_MINOR 4
-#define DLT_ISO_14443 264
-
-#define DATA_PICC_TO_PCD 0xFF
-#define DATA_PCD_TO_PICC 0xFE
-#define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
-#define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
-
-#define NFC_DEBUG_PCAP_FILENAME EXT_PATH("nfc/debug.pcap")
-
-struct NfcDebugPcap {
-    Stream* file_stream;
-};
-
-static Stream* nfc_debug_pcap_open(Storage* storage) {
-    Stream* stream = NULL;
-    stream = buffered_file_stream_alloc(storage);
-    if(!buffered_file_stream_open(stream, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
-        buffered_file_stream_close(stream);
-        stream_free(stream);
-        stream = NULL;
-    } else {
-        if(!stream_tell(stream)) {
-            struct {
-                uint32_t magic;
-                uint16_t major, minor;
-                uint32_t reserved[2];
-                uint32_t snaplen;
-                uint32_t link_type;
-            } __attribute__((__packed__)) pcap_hdr = {
-                .magic = PCAP_MAGIC,
-                .major = PCAP_MAJOR,
-                .minor = PCAP_MINOR,
-                .snaplen = FURRY_HAL_NFC_DATA_BUFF_SIZE,
-                .link_type = DLT_ISO_14443,
-            };
-            if(stream_write(stream, (uint8_t*)&pcap_hdr, sizeof(pcap_hdr)) != sizeof(pcap_hdr)) {
-                FURI_LOG_E(TAG, "Failed to write pcap header");
-                buffered_file_stream_close(stream);
-                stream_free(stream);
-                stream = NULL;
-            }
-        }
-    }
-    return stream;
-}
-
-NfcDebugPcap* nfc_debug_pcap_alloc() {
-    NfcDebugPcap* instance = malloc(sizeof(NfcDebugPcap));
-
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    instance->file_stream = nfc_debug_pcap_open(storage);
-    if(!instance->file_stream) {
-        free(instance);
-        instance = NULL;
-    }
-    furi_record_close(RECORD_STORAGE);
-
-    return instance;
-}
-
-void nfc_debug_pcap_free(NfcDebugPcap* instance) {
-    furi_assert(instance);
-    furi_assert(instance->file_stream);
-
-    buffered_file_stream_close(instance->file_stream);
-    stream_free(instance->file_stream);
-
-    free(instance);
-}
-
-void nfc_debug_pcap_process_data(
-    NfcDebugPcap* instance,
-    uint8_t* data,
-    uint16_t len,
-    bool reader_to_tag,
-    bool crc_dropped) {
-    furi_assert(instance);
-    furi_assert(data);
-
-    uint8_t event = 0;
-    if(reader_to_tag) {
-        if(crc_dropped) {
-            event = DATA_PCD_TO_PICC_CRC_DROPPED;
-        } else {
-            event = DATA_PCD_TO_PICC;
-        }
-    } else {
-        if(crc_dropped) {
-            event = DATA_PICC_TO_PCD_CRC_DROPPED;
-        } else {
-            event = DATA_PICC_TO_PCD;
-        }
-    }
-
-    struct {
-        // https://wiki.wireshark.org/Development/LibpcapFileFormat#record-packet-header
-        uint32_t ts_sec;
-        uint32_t ts_usec;
-        uint32_t incl_len;
-        uint32_t orig_len;
-        // https://www.kaiser.cx/posts/pcap-iso14443/#_packet_data
-        uint8_t version;
-        uint8_t event;
-        uint16_t len;
-    } __attribute__((__packed__)) pkt_hdr = {
-        .ts_sec = furi_hal_rtc_get_timestamp(),
-        .ts_usec = 0,
-        .incl_len = len + 4,
-        .orig_len = len + 4,
-        .version = 0,
-        .event = event,
-        .len = len << 8 | len >> 8,
-    };
-    stream_write(instance->file_stream, (uint8_t*)&pkt_hdr, sizeof(pkt_hdr));
-    stream_write(instance->file_stream, data, len);
-}

+ 0 - 17
lib/nfclegacy/helpers/nfc_debug_pcap.h

@@ -1,17 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef struct NfcDebugPcap NfcDebugPcap;
-
-NfcDebugPcap* nfc_debug_pcap_alloc();
-
-void nfc_debug_pcap_free(NfcDebugPcap* instance);
-
-void nfc_debug_pcap_process_data(
-    NfcDebugPcap* instance,
-    uint8_t* data,
-    uint16_t len,
-    bool reader_to_tag,
-    bool crc_dropped);

+ 0 - 548
lib/nfclegacy/helpers/nfc_generators.c

@@ -1,548 +0,0 @@
-#include <furi_hal_random.h>
-#include "nfc_generators.h"
-
-#define NXP_MANUFACTURER_ID (0x04)
-
-static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03};
-static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03};
-static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03};
-static const uint8_t default_data_ntag203[] =
-    {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE};
-static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE};
-static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE};
-static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE};
-static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00};
-
-static void nfc_generate_common_start(NfcDeviceData* data) {
-    nfc_device_data_clear(data);
-}
-
-static void nfc_generate_mf_ul_uid(uint8_t* uid) {
-    uid[0] = NXP_MANUFACTURER_ID;
-    furi_hal_random_fill_buf(&uid[1], 6);
-    // I'm not sure how this is generated, but the upper nybble always seems to be 8
-    uid[6] &= 0x0F;
-    uid[6] |= 0x80;
-}
-
-static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) {
-    uid[0] = NXP_MANUFACTURER_ID;
-    furi_hal_random_fill_buf(&uid[1], length - 1);
-}
-
-static void nfc_generate_mf_classic_block_0(
-    uint8_t* block,
-    uint8_t uid_len,
-    uint8_t sak,
-    uint8_t atqa0,
-    uint8_t atqa1) {
-    // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes
-    furi_assert(uid_len == 4 || uid_len == 7);
-    furi_assert(block);
-
-    if(uid_len == 4) {
-        // Calculate BCC
-        block[uid_len] = 0;
-
-        for(int i = 0; i < uid_len; i++) {
-            block[uid_len] ^= block[i];
-        }
-    } else {
-        uid_len -= 1;
-    }
-
-    block[uid_len + 1] = sak;
-    block[uid_len + 2] = atqa0;
-    block[uid_len + 3] = atqa1;
-
-    for(int i = uid_len + 4; i < 16; i++) {
-        block[i] = 0xFF;
-    }
-}
-
-static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) {
-    // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h.
-    MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value;
-    sec_tr->access_bits[0] = 0xFF;
-    sec_tr->access_bits[1] = 0x07;
-    sec_tr->access_bits[2] = 0x80;
-    sec_tr->access_bits[3] = 0x69; // Nice
-
-    memset(sec_tr->key_a, 0xff, sizeof(sec_tr->key_a));
-    memset(sec_tr->key_b, 0xff, sizeof(sec_tr->key_b));
-
-    mf_classic_set_block_read(data, block, &data->block[block]);
-    mf_classic_set_key_found(
-        data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF);
-    mf_classic_set_key_found(
-        data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF);
-}
-
-static void nfc_generate_mf_ul_common(NfcDeviceData* data) {
-    data->nfc_data.type = FurryHalNfcTypeA;
-    data->nfc_data.interface = FurryHalNfcInterfaceRf;
-    data->nfc_data.uid_len = 7;
-    nfc_generate_mf_ul_uid(data->nfc_data.uid);
-    data->nfc_data.atqa[0] = 0x44;
-    data->nfc_data.atqa[1] = 0x00;
-    data->nfc_data.sak = 0x00;
-    data->protocol = NfcDeviceProtocolMifareUl;
-}
-
-static void
-    nfc_generate_mf_classic_common(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
-    data->nfc_data.type = FurryHalNfcTypeA;
-    data->nfc_data.interface = FurryHalNfcInterfaceRf;
-    data->nfc_data.uid_len = uid_len;
-    data->nfc_data.atqa[0] = 0x44;
-    data->nfc_data.atqa[1] = 0x00;
-    data->nfc_data.sak = 0x08;
-    data->protocol = NfcDeviceProtocolMifareClassic;
-    data->mf_classic_data.type = type;
-}
-
-static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) {
-    *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
-    *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
-}
-
-static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) {
-    MfUltralightData* mful = &data->mf_ul_data;
-    memcpy(mful->data, data->nfc_data.uid, 3);
-    memcpy(&mful->data[4], &data->nfc_data.uid[3], 4);
-    nfc_generate_calc_bcc(data->nfc_data.uid, &mful->data[3], &mful->data[8]);
-}
-
-static void nfc_generate_mf_ul_orig(NfcDeviceData* data) {
-    nfc_generate_common_start(data);
-    nfc_generate_mf_ul_common(data);
-
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeUnknown;
-    mful->data_size = 16 * 4;
-    mful->data_read = mful->data_size;
-    nfc_generate_mf_ul_copy_uid_with_bcc(data);
-    // TODO: what's internal byte on page 2?
-    memset(&mful->data[4 * 4], 0xFF, 4);
-}
-
-static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) {
-    nfc_generate_common_start(data);
-    nfc_generate_mf_ul_common(data);
-
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeNTAG203;
-    mful->data_size = 42 * 4;
-    mful->data_read = mful->data_size;
-    nfc_generate_mf_ul_copy_uid_with_bcc(data);
-    mful->data[9] = 0x48; // Internal byte
-    memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203));
-}
-
-static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) {
-    nfc_generate_common_start(data);
-    nfc_generate_mf_ul_common(data);
-
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->data_size = num_pages * 4;
-    mful->data_read = mful->data_size;
-    nfc_generate_mf_ul_copy_uid_with_bcc(data);
-    uint16_t config_index = (num_pages - 4) * 4;
-    mful->data[config_index] = 0x04; // STRG_MOD_EN
-    mful->data[config_index + 3] = 0xFF; // AUTH0
-    mful->data[config_index + 5] = 0x05; // VCTID
-    memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
-    if(num_pages > 20) mful->data[config_index - 1] = MF_UL_TEARING_FLAG_DEFAULT;
-}
-
-static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) {
-    nfc_generate_mf_ul_with_config_common(data, num_pages);
-    MfUltralightData* mful = &data->mf_ul_data;
-    memcpy(&mful->version, version_bytes_mf0ulx1, sizeof(version_bytes_mf0ulx1));
-    for(size_t i = 0; i < 3; ++i) {
-        mful->tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
-    }
-    // TODO: what's internal byte on page 2?
-}
-
-static void nfc_generate_mf_ul_11(NfcDeviceData* data) {
-    nfc_generate_mf_ul_ev1_common(data, 20);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeUL11;
-    mful->version.prod_subtype = 0x01;
-    mful->version.storage_size = 0x0B;
-    mful->data[16 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
-}
-
-static void nfc_generate_mf_ul_h11(NfcDeviceData* data) {
-    nfc_generate_mf_ul_ev1_common(data, 20);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeUL11;
-    mful->version.prod_subtype = 0x02;
-    mful->version.storage_size = 0x0B;
-}
-
-static void nfc_generate_mf_ul_21(NfcDeviceData* data) {
-    nfc_generate_mf_ul_ev1_common(data, 41);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeUL21;
-    mful->version.prod_subtype = 0x01;
-    mful->version.storage_size = 0x0E;
-    mful->data[37 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN
-}
-
-static void nfc_generate_mf_ul_h21(NfcDeviceData* data) {
-    nfc_generate_mf_ul_ev1_common(data, 41);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeUL21;
-    mful->version.prod_subtype = 0x02;
-    mful->version.storage_size = 0x0E;
-}
-
-static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) {
-    nfc_generate_mf_ul_with_config_common(data, num_pages);
-    MfUltralightData* mful = &data->mf_ul_data;
-    memcpy(&mful->version, version_bytes_ntag21x, sizeof(version_bytes_mf0ulx1));
-    mful->data[9] = 0x48; // Internal byte
-    // Capability container
-    mful->data[12] = 0xE1;
-    mful->data[13] = 0x10;
-}
-
-static void nfc_generate_ntag213(NfcDeviceData* data) {
-    nfc_generate_ntag21x_common(data, 45);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeNTAG213;
-    mful->version.storage_size = 0x0F;
-    mful->data[14] = 0x12;
-    // Default contents
-    memcpy(&mful->data[16], default_data_ntag213, sizeof(default_data_ntag213));
-}
-
-static void nfc_generate_ntag215(NfcDeviceData* data) {
-    nfc_generate_ntag21x_common(data, 135);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeNTAG215;
-    mful->version.storage_size = 0x11;
-    mful->data[14] = 0x3E;
-    // Default contents
-    memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
-}
-
-static void nfc_generate_ntag216(NfcDeviceData* data) {
-    nfc_generate_ntag21x_common(data, 231);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = MfUltralightTypeNTAG216;
-    mful->version.storage_size = 0x13;
-    mful->data[14] = 0x6D;
-    // Default contents
-    memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216));
-}
-
-static void
-    nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) {
-    nfc_generate_common_start(data);
-    nfc_generate_mf_ul_common(data);
-
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->type = type;
-    memcpy(&mful->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c));
-    mful->data_size = num_pages * 4;
-    mful->data_read = mful->data_size;
-    memcpy(mful->data, data->nfc_data.uid, data->nfc_data.uid_len);
-    mful->data[7] = data->nfc_data.sak;
-    mful->data[8] = data->nfc_data.atqa[0];
-    mful->data[9] = data->nfc_data.atqa[1];
-
-    uint16_t config_register_page;
-    uint16_t session_register_page;
-
-    // Sync with mifare_ultralight.c
-    switch(type) {
-    case MfUltralightTypeNTAGI2C1K:
-        config_register_page = 227;
-        session_register_page = 229;
-        break;
-    case MfUltralightTypeNTAGI2C2K:
-        config_register_page = 481;
-        session_register_page = 483;
-        break;
-    case MfUltralightTypeNTAGI2CPlus1K:
-    case MfUltralightTypeNTAGI2CPlus2K:
-        config_register_page = 232;
-        session_register_page = 234;
-        break;
-    default:
-        furi_crash("Unknown MFUL");
-        break;
-    }
-
-    memcpy(
-        &mful->data[config_register_page * 4],
-        default_config_ntag_i2c,
-        sizeof(default_config_ntag_i2c));
-    memcpy(
-        &mful->data[session_register_page * 4],
-        default_config_ntag_i2c,
-        sizeof(default_config_ntag_i2c));
-}
-
-static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) {
-    nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->version.prod_ver_minor = 0x01;
-    mful->version.storage_size = 0x13;
-
-    memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
-    mful->data[14] = 0x6D; // Size of tag in CC
-}
-
-static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) {
-    nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->version.prod_ver_minor = 0x01;
-    mful->version.storage_size = 0x15;
-
-    memcpy(&mful->data[12], default_data_ntag_i2c, sizeof(default_data_ntag_i2c));
-    mful->data[14] = 0xEA; // Size of tag in CC
-}
-
-static void nfc_generate_ntag_i2c_plus_common(
-    NfcDeviceData* data,
-    MfUltralightType type,
-    uint16_t num_pages) {
-    nfc_generate_ntag_i2c_common(data, type, num_pages);
-
-    MfUltralightData* mful = &data->mf_ul_data;
-    uint16_t config_index = 227 * 4;
-    mful->data[config_index + 3] = 0xFF; // AUTH0
-    memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD
-}
-
-static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) {
-    nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->version.prod_ver_minor = 0x02;
-    mful->version.storage_size = 0x13;
-}
-
-static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
-    nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492);
-    MfUltralightData* mful = &data->mf_ul_data;
-    mful->version.prod_ver_minor = 0x02;
-    mful->version.storage_size = 0x15;
-}
-
-void nfc_generate_mf_classic_ext(
-    NfcDeviceData* data,
-    uint8_t uid_len,
-    MfClassicType type,
-    bool random_uid,
-    uint8_t* uid) {
-    nfc_generate_common_start(data);
-    if(random_uid) {
-        nfc_generate_mf_classic_uid(data->mf_classic_data.block[0].value, uid_len);
-    } else {
-        memcpy(data->mf_classic_data.block[0].value, uid, uid_len);
-    }
-    nfc_generate_mf_classic_common(data, uid_len, type);
-
-    // Set the UID
-    if(random_uid) {
-        data->nfc_data.uid[0] = NXP_MANUFACTURER_ID;
-        for(int i = 1; i < uid_len; i++) {
-            data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i];
-        }
-    } else {
-        for(int i = 0; i < uid_len; i++) {
-            data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i];
-        }
-    }
-
-    MfClassicData* mfc = &data->mf_classic_data;
-    mf_classic_set_block_read(mfc, 0, &mfc->block[0]);
-
-    if(type == MfClassicType4k) {
-        // Set every block to 0xFF
-        for(uint16_t i = 1; i < 256; i += 1) {
-            if(mf_classic_is_sector_trailer(i)) {
-                nfc_generate_mf_classic_sector_trailer(mfc, i);
-            } else {
-                memset(&mfc->block[i].value, 0xFF, 16);
-            }
-            mf_classic_set_block_read(mfc, i, &mfc->block[i]);
-        }
-        // Set SAK to 18
-        data->nfc_data.sak = 0x18;
-    } else if(type == MfClassicType1k) {
-        // Set every block to 0xFF
-        for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
-            if(mf_classic_is_sector_trailer(i)) {
-                nfc_generate_mf_classic_sector_trailer(mfc, i);
-            } else {
-                memset(&mfc->block[i].value, 0xFF, 16);
-            }
-            mf_classic_set_block_read(mfc, i, &mfc->block[i]);
-        }
-        // Set SAK to 08
-        data->nfc_data.sak = 0x08;
-    } else if(type == MfClassicTypeMini) {
-        // Set every block to 0xFF
-        for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) {
-            if(mf_classic_is_sector_trailer(i)) {
-                nfc_generate_mf_classic_sector_trailer(mfc, i);
-            } else {
-                memset(&mfc->block[i].value, 0xFF, 16);
-            }
-            mf_classic_set_block_read(mfc, i, &mfc->block[i]);
-        }
-        // Set SAK to 09
-        data->nfc_data.sak = 0x09;
-    }
-
-    nfc_generate_mf_classic_block_0(
-        data->mf_classic_data.block[0].value,
-        uid_len,
-        data->nfc_data.sak,
-        data->nfc_data.atqa[0],
-        data->nfc_data.atqa[1]);
-
-    mfc->type = type;
-}
-
-void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
-    uint8_t uid = 0;
-    nfc_generate_mf_classic_ext(data, uid_len, type, true, &uid);
-}
-
-static void nfc_generate_mf_mini(NfcDeviceData* data) {
-    nfc_generate_mf_classic(data, 4, MfClassicTypeMini);
-}
-
-static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) {
-    nfc_generate_mf_classic(data, 4, MfClassicType1k);
-}
-
-static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) {
-    nfc_generate_mf_classic(data, 7, MfClassicType1k);
-}
-
-static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) {
-    nfc_generate_mf_classic(data, 4, MfClassicType4k);
-}
-
-static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) {
-    nfc_generate_mf_classic(data, 7, MfClassicType4k);
-}
-
-static const NfcGenerator mf_ul_generator = {
-    .name = "Mifare Ultralight",
-    .generator_func = nfc_generate_mf_ul_orig,
-};
-
-static const NfcGenerator mf_ul_11_generator = {
-    .name = "Mifare Ultralight EV1 11",
-    .generator_func = nfc_generate_mf_ul_11,
-};
-
-static const NfcGenerator mf_ul_h11_generator = {
-    .name = "Mifare Ultralight EV1 H11",
-    .generator_func = nfc_generate_mf_ul_h11,
-};
-
-static const NfcGenerator mf_ul_21_generator = {
-    .name = "Mifare Ultralight EV1 21",
-    .generator_func = nfc_generate_mf_ul_21,
-};
-
-static const NfcGenerator mf_ul_h21_generator = {
-    .name = "Mifare Ultralight EV1 H21",
-    .generator_func = nfc_generate_mf_ul_h21,
-};
-
-static const NfcGenerator ntag203_generator = {
-    .name = "NTAG203",
-    .generator_func = nfc_generate_mf_ul_ntag203,
-};
-
-static const NfcGenerator ntag213_generator = {
-    .name = "NTAG213",
-    .generator_func = nfc_generate_ntag213,
-};
-
-static const NfcGenerator ntag215_generator = {
-    .name = "NTAG215",
-    .generator_func = nfc_generate_ntag215,
-};
-
-static const NfcGenerator ntag216_generator = {
-    .name = "NTAG216",
-    .generator_func = nfc_generate_ntag216,
-};
-
-static const NfcGenerator ntag_i2c_1k_generator = {
-    .name = "NTAG I2C 1k",
-    .generator_func = nfc_generate_ntag_i2c_1k,
-};
-
-static const NfcGenerator ntag_i2c_2k_generator = {
-    .name = "NTAG I2C 2k",
-    .generator_func = nfc_generate_ntag_i2c_2k,
-};
-
-static const NfcGenerator ntag_i2c_plus_1k_generator = {
-    .name = "NTAG I2C Plus 1k",
-    .generator_func = nfc_generate_ntag_i2c_plus_1k,
-};
-
-static const NfcGenerator ntag_i2c_plus_2k_generator = {
-    .name = "NTAG I2C Plus 2k",
-    .generator_func = nfc_generate_ntag_i2c_plus_2k,
-};
-
-static const NfcGenerator mifare_mini_generator = {
-    .name = "Mifare Mini",
-    .generator_func = nfc_generate_mf_mini,
-};
-
-static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
-    .name = "Mifare Classic 1k 4byte UID",
-    .generator_func = nfc_generate_mf_classic_1k_4b_uid,
-};
-
-static const NfcGenerator mifare_classic_1k_7b_uid_generator = {
-    .name = "Mifare Classic 1k 7byte UID",
-    .generator_func = nfc_generate_mf_classic_1k_7b_uid,
-};
-
-static const NfcGenerator mifare_classic_4k_4b_uid_generator = {
-    .name = "Mifare Classic 4k 4byte UID",
-    .generator_func = nfc_generate_mf_classic_4k_4b_uid,
-};
-
-static const NfcGenerator mifare_classic_4k_7b_uid_generator = {
-    .name = "Mifare Classic 4k 7byte UID",
-    .generator_func = nfc_generate_mf_classic_4k_7b_uid,
-};
-
-const NfcGenerator* const nfc_generators[] = {
-    &mf_ul_generator,
-    &mf_ul_11_generator,
-    &mf_ul_h11_generator,
-    &mf_ul_21_generator,
-    &mf_ul_h21_generator,
-    &ntag203_generator,
-    &ntag213_generator,
-    &ntag215_generator,
-    &ntag216_generator,
-    &ntag_i2c_1k_generator,
-    &ntag_i2c_2k_generator,
-    &ntag_i2c_plus_1k_generator,
-    &ntag_i2c_plus_2k_generator,
-    &mifare_mini_generator,
-    &mifare_classic_1k_4b_uid_generator,
-    &mifare_classic_1k_7b_uid_generator,
-    &mifare_classic_4k_4b_uid_generator,
-    &mifare_classic_4k_7b_uid_generator,
-    NULL,
-};

+ 0 - 29
lib/nfclegacy/helpers/nfc_generators.h

@@ -1,29 +0,0 @@
-#pragma once
-
-#include "../nfc_device.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (*NfcGeneratorFunc)(NfcDeviceData* data);
-
-typedef struct {
-    const char* name;
-    NfcGeneratorFunc generator_func;
-} NfcGenerator;
-
-extern const NfcGenerator* const nfc_generators[];
-
-void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type);
-
-void nfc_generate_mf_classic_ext(
-    NfcDeviceData* data,
-    uint8_t uid_len,
-    MfClassicType type,
-    bool random_uid,
-    uint8_t* uid);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 265
lib/nfclegacy/helpers/reader_analyzer.c

@@ -1,265 +0,0 @@
-#include "reader_analyzer.h"
-#include "../protocols/nfc_util.h"
-#include "../protocols/mifare_classic.h"
-#include <m-array.h>
-
-#include "mfkey32.h"
-#include "nfc_debug_pcap.h"
-#include "nfc_debug_log.h"
-
-#define TAG "ReaderAnalyzer"
-
-#define READER_ANALYZER_MAX_BUFF_SIZE (1024)
-
-typedef struct {
-    bool reader_to_tag;
-    bool crc_dropped;
-    uint16_t len;
-} ReaderAnalyzerHeader;
-
-typedef enum {
-    ReaderAnalyzerNfcDataMfClassic,
-} ReaderAnalyzerNfcData;
-
-struct ReaderAnalyzer {
-    FurryHalNfcDevData nfc_data;
-
-    bool alive;
-    FuriStreamBuffer* stream;
-    FuriThread* thread;
-
-    ReaderAnalyzerParseDataCallback callback;
-    void* context;
-
-    ReaderAnalyzerMode mode;
-    Mfkey32* mfkey32;
-    NfcDebugLog* debug_log;
-    NfcDebugPcap* pcap;
-};
-
-const FurryHalNfcDevData reader_analyzer_nfc_data[] = {
-    [ReaderAnalyzerNfcDataMfClassic] =
-        {.sak = 0x08,
-         .atqa = {0x44, 0x00},
-         .interface = FurryHalNfcInterfaceRf,
-         .type = FurryHalNfcTypeA,
-         .uid_len = 7,
-         .uid = {0x04, 0x77, 0x70, 0x2A, 0x23, 0x4F, 0x80},
-         .cuid = 0x2A234F80},
-};
-
-void reader_analyzer_parse(ReaderAnalyzer* instance, uint8_t* buffer, size_t size) {
-    if(size < sizeof(ReaderAnalyzerHeader)) return;
-
-    size_t bytes_i = 0;
-    while(bytes_i < size) {
-        ReaderAnalyzerHeader* header = (ReaderAnalyzerHeader*)&buffer[bytes_i];
-        uint16_t len = header->len;
-        if(bytes_i + len > size) break;
-        bytes_i += sizeof(ReaderAnalyzerHeader);
-        if(instance->mfkey32) {
-            mfkey32_process_data(
-                instance->mfkey32,
-                &buffer[bytes_i],
-                len,
-                header->reader_to_tag,
-                header->crc_dropped);
-        }
-        if(instance->pcap) {
-            nfc_debug_pcap_process_data(
-                instance->pcap, &buffer[bytes_i], len, header->reader_to_tag, header->crc_dropped);
-        }
-        if(instance->debug_log) {
-            nfc_debug_log_process_data(
-                instance->debug_log,
-                &buffer[bytes_i],
-                len,
-                header->reader_to_tag,
-                header->crc_dropped);
-        }
-        bytes_i += len;
-    }
-}
-
-int32_t reader_analyzer_thread(void* context) {
-    ReaderAnalyzer* reader_analyzer = context;
-    uint8_t buffer[READER_ANALYZER_MAX_BUFF_SIZE] = {};
-
-    while(reader_analyzer->alive || !furi_stream_buffer_is_empty(reader_analyzer->stream)) {
-        size_t ret = furi_stream_buffer_receive(
-            reader_analyzer->stream, buffer, READER_ANALYZER_MAX_BUFF_SIZE, 50);
-        if(ret) {
-            reader_analyzer_parse(reader_analyzer, buffer, ret);
-        }
-    }
-
-    return 0;
-}
-
-ReaderAnalyzer* reader_analyzer_alloc() {
-    ReaderAnalyzer* instance = malloc(sizeof(ReaderAnalyzer));
-
-    instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic];
-    instance->alive = false;
-    instance->stream =
-        furi_stream_buffer_alloc(READER_ANALYZER_MAX_BUFF_SIZE, sizeof(ReaderAnalyzerHeader));
-
-    instance->thread =
-        furi_thread_alloc_ex("ReaderAnalyzerWorker", 2048, reader_analyzer_thread, instance);
-    furi_thread_set_priority(instance->thread, FuriThreadPriorityLow);
-
-    return instance;
-}
-
-static void reader_analyzer_mfkey_callback(Mfkey32Event event, void* context) {
-    furi_assert(context);
-    ReaderAnalyzer* instance = context;
-
-    if(event == Mfkey32EventParamCollected) {
-        if(instance->callback) {
-            instance->callback(ReaderAnalyzerEventMfkeyCollected, instance->context);
-        }
-    }
-}
-
-void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode) {
-    furi_assert(instance);
-
-    furi_stream_buffer_reset(instance->stream);
-    if(mode & ReaderAnalyzerModeDebugLog) {
-        instance->debug_log = nfc_debug_log_alloc();
-    }
-    if(mode & ReaderAnalyzerModeMfkey) {
-        instance->mfkey32 = mfkey32_alloc(instance->nfc_data.cuid);
-        if(instance->mfkey32) {
-            mfkey32_set_callback(instance->mfkey32, reader_analyzer_mfkey_callback, instance);
-        }
-    }
-    if(mode & ReaderAnalyzerModeDebugPcap) {
-        instance->pcap = nfc_debug_pcap_alloc();
-    }
-
-    instance->alive = true;
-    furi_thread_start(instance->thread);
-}
-
-void reader_analyzer_stop(ReaderAnalyzer* instance) {
-    furi_assert(instance);
-
-    instance->alive = false;
-    furi_thread_join(instance->thread);
-
-    if(instance->debug_log) {
-        nfc_debug_log_free(instance->debug_log);
-        instance->debug_log = NULL;
-    }
-    if(instance->mfkey32) {
-        mfkey32_free(instance->mfkey32);
-        instance->mfkey32 = NULL;
-    }
-    if(instance->pcap) {
-        nfc_debug_pcap_free(instance->pcap);
-        instance->pcap = NULL;
-    }
-}
-
-void reader_analyzer_free(ReaderAnalyzer* instance) {
-    furi_assert(instance);
-
-    reader_analyzer_stop(instance);
-    furi_thread_free(instance->thread);
-    furi_stream_buffer_free(instance->stream);
-    free(instance);
-}
-
-void reader_analyzer_set_callback(
-    ReaderAnalyzer* instance,
-    ReaderAnalyzerParseDataCallback callback,
-    void* context) {
-    furi_assert(instance);
-    furi_assert(callback);
-
-    instance->callback = callback;
-    instance->context = context;
-}
-
-NfcProtocol
-    reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len) {
-    furi_assert(instance);
-    furi_assert(buff_rx);
-    UNUSED(len);
-    NfcProtocol protocol = NfcDeviceProtocolUnknown;
-
-    if((buff_rx[0] == 0x60) || (buff_rx[0] == 0x61)) {
-        protocol = NfcDeviceProtocolMifareClassic;
-    }
-
-    return protocol;
-}
-
-FurryHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance) {
-    furi_assert(instance);
-    instance->nfc_data = reader_analyzer_nfc_data[ReaderAnalyzerNfcDataMfClassic];
-    return &instance->nfc_data;
-}
-
-void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FurryHalNfcDevData* nfc_data) {
-    furi_assert(instance);
-    furi_assert(nfc_data);
-
-    memcpy(&instance->nfc_data, nfc_data, sizeof(FurryHalNfcDevData));
-}
-
-static void reader_analyzer_write(
-    ReaderAnalyzer* instance,
-    uint8_t* data,
-    uint16_t len,
-    bool reader_to_tag,
-    bool crc_dropped) {
-    ReaderAnalyzerHeader header = {
-        .reader_to_tag = reader_to_tag, .crc_dropped = crc_dropped, .len = len};
-    size_t data_sent = 0;
-    data_sent = furi_stream_buffer_send(
-        instance->stream, &header, sizeof(ReaderAnalyzerHeader), FuriWaitForever);
-    if(data_sent != sizeof(ReaderAnalyzerHeader)) {
-        FURI_LOG_W(TAG, "Sent %zu out of %zu bytes", data_sent, sizeof(ReaderAnalyzerHeader));
-    }
-    data_sent = furi_stream_buffer_send(instance->stream, data, len, FuriWaitForever);
-    if(data_sent != len) {
-        FURI_LOG_W(TAG, "Sent %zu out of %u bytes", data_sent, len);
-    }
-}
-
-static void
-    reader_analyzer_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
-    UNUSED(crc_dropped);
-    ReaderAnalyzer* reader_analyzer = context;
-    uint16_t bytes = bits < 8 ? 1 : bits / 8;
-    reader_analyzer_write(reader_analyzer, data, bytes, false, crc_dropped);
-}
-
-static void
-    reader_analyzer_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
-    UNUSED(crc_dropped);
-    ReaderAnalyzer* reader_analyzer = context;
-    uint16_t bytes = bits < 8 ? 1 : bits / 8;
-    reader_analyzer_write(reader_analyzer, data, bytes, true, crc_dropped);
-}
-
-void reader_analyzer_prepare_tx_rx(
-    ReaderAnalyzer* instance,
-    FurryHalNfcTxRxContext* tx_rx,
-    bool is_picc) {
-    furi_assert(instance);
-    furi_assert(tx_rx);
-
-    if(is_picc) {
-        tx_rx->sniff_tx = reader_analyzer_write_rx;
-        tx_rx->sniff_rx = reader_analyzer_write_tx;
-    } else {
-        tx_rx->sniff_rx = reader_analyzer_write_rx;
-        tx_rx->sniff_tx = reader_analyzer_write_tx;
-    }
-
-    tx_rx->sniff_context = instance;
-}

+ 0 - 43
lib/nfclegacy/helpers/reader_analyzer.h

@@ -1,43 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include "../nfc_device.h"
-
-typedef enum {
-    ReaderAnalyzerModeDebugLog = 0x01,
-    ReaderAnalyzerModeMfkey = 0x02,
-    ReaderAnalyzerModeDebugPcap = 0x04,
-} ReaderAnalyzerMode;
-
-typedef enum {
-    ReaderAnalyzerEventMfkeyCollected,
-} ReaderAnalyzerEvent;
-
-typedef struct ReaderAnalyzer ReaderAnalyzer;
-
-typedef void (*ReaderAnalyzerParseDataCallback)(ReaderAnalyzerEvent event, void* context);
-
-ReaderAnalyzer* reader_analyzer_alloc();
-
-void reader_analyzer_free(ReaderAnalyzer* instance);
-
-void reader_analyzer_set_callback(
-    ReaderAnalyzer* instance,
-    ReaderAnalyzerParseDataCallback callback,
-    void* context);
-
-void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode);
-
-void reader_analyzer_stop(ReaderAnalyzer* instance);
-
-NfcProtocol
-    reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len);
-
-FurryHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance);
-
-void reader_analyzer_set_nfc_data(ReaderAnalyzer* instance, FurryHalNfcDevData* nfc_data);
-
-void reader_analyzer_prepare_tx_rx(
-    ReaderAnalyzer* instance,
-    FurryHalNfcTxRxContext* tx_rx,
-    bool is_picc);

+ 22 - 195
lib/nfclegacy/nfc_device.c

@@ -18,7 +18,6 @@ static const uint32_t nfc_keys_file_version = 1;
 
 // Protocols format versions
 static const uint32_t nfc_mifare_classic_data_format_version = 2;
-static const uint32_t nfc_mifare_ultralight_data_format_version = 1;
 
 NfcDevice* nfc_device_alloc() {
     NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
@@ -47,16 +46,8 @@ void nfc_device_free(NfcDevice* nfc_dev) {
 static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_string) {
     if(dev->format == NfcDeviceSaveFormatUid) {
         furi_string_set(format_string, "UID");
-    } else if(dev->format == NfcDeviceSaveFormatBankCard) {
-        furi_string_set(format_string, "Bank card");
-    } else if(dev->format == NfcDeviceSaveFormatMifareUl) {
-        furi_string_set(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true));
     } else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
         furi_string_set(format_string, "Mifare Classic");
-    } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
-        furi_string_set(format_string, "Mifare DESFire");
-    } else if(dev->format == NfcDeviceSaveFormatNfcV) {
-        furi_string_set(format_string, "ISO15693");
     } else {
         furi_string_set(format_string, "Unknown");
     }
@@ -68,172 +59,14 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st
         dev->dev_data.protocol = NfcDeviceProtocolUnknown;
         return true;
     }
-    if(furi_string_start_with_str(format_string, "Bank card")) {
-        dev->format = NfcDeviceSaveFormatBankCard;
-        dev->dev_data.protocol = NfcDeviceProtocolEMV;
-        return true;
-    }
-    // Check Mifare Ultralight types
-    for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
-        if(furi_string_equal(format_string, nfc_mf_ul_type(type, true))) {
-            dev->format = NfcDeviceSaveFormatMifareUl;
-            dev->dev_data.protocol = NfcDeviceProtocolMifareUl;
-            dev->dev_data.mf_ul_data.type = type;
-            return true;
-        }
-    }
+    // Check Mifare
     if(furi_string_start_with_str(format_string, "Mifare Classic")) {
         dev->format = NfcDeviceSaveFormatMifareClassic;
         dev->dev_data.protocol = NfcDeviceProtocolMifareClassic;
         return true;
     }
-    if(furi_string_start_with_str(format_string, "Mifare DESFire")) {
-        dev->format = NfcDeviceSaveFormatMifareDesfire;
-        dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
-        return true;
-    }
-    if(furi_string_start_with_str(format_string, "ISO15693")) {
-        dev->format = NfcDeviceSaveFormatNfcV;
-        dev->dev_data.protocol = NfcDeviceProtocolNfcV;
-        return true;
-    }
-    return false;
-}
-
-static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
-    bool saved = false;
-    MfUltralightData* data = &dev->dev_data.mf_ul_data;
-    FuriString* temp_str;
-    temp_str = furi_string_alloc();
-
-    // Save Mifare Ultralight specific data
-    do {
-        if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break;
-        if(!flipper_format_write_uint32(
-               file, "Data format version", &nfc_mifare_ultralight_data_format_version, 1))
-            break;
-        if(!flipper_format_write_hex(file, "Signature", data->signature, sizeof(data->signature)))
-            break;
-        if(!flipper_format_write_hex(
-               file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
-            break;
-        // Write conters and tearing flags data
-        bool counters_saved = true;
-        for(uint8_t i = 0; i < 3; i++) {
-            furi_string_printf(temp_str, "Counter %d", i);
-            if(!flipper_format_write_uint32(
-                   file, furi_string_get_cstr(temp_str), &data->counter[i], 1)) {
-                counters_saved = false;
-                break;
-            }
-            furi_string_printf(temp_str, "Tearing %d", i);
-            if(!flipper_format_write_hex(
-                   file, furi_string_get_cstr(temp_str), &data->tearing[i], 1)) {
-                counters_saved = false;
-                break;
-            }
-        }
-        if(!counters_saved) break;
-        // Write pages data
-        uint32_t pages_total = data->data_size / 4;
-        if(!flipper_format_write_uint32(file, "Pages total", &pages_total, 1)) break;
-        uint32_t pages_read = data->data_read / 4;
-        if(!flipper_format_write_uint32(file, "Pages read", &pages_read, 1)) break;
-        bool pages_saved = true;
-        for(uint16_t i = 0; i < data->data_size; i += 4) {
-            furi_string_printf(temp_str, "Page %d", i / 4);
-            if(!flipper_format_write_hex(file, furi_string_get_cstr(temp_str), &data->data[i], 4)) {
-                pages_saved = false;
-                break;
-            }
-        }
-        if(!pages_saved) break;
-
-        // Write authentication counter
-        uint32_t auth_counter = data->curr_authlim;
-        if(!flipper_format_write_uint32(file, "Failed authentication attempts", &auth_counter, 1))
-            break;
-
-        saved = true;
-    } while(false);
-
-    furi_string_free(temp_str);
-    return saved;
-}
-
-bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
-    bool parsed = false;
-    MfUltralightData* data = &dev->dev_data.mf_ul_data;
-    FuriString* temp_str;
-    temp_str = furi_string_alloc();
-    uint32_t data_format_version = 0;
-
-    do {
-        // Read Mifare Ultralight format version
-        if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) {
-            if(!flipper_format_rewind(file)) break;
-        }
-
-        // Read signature
-        if(!flipper_format_read_hex(file, "Signature", data->signature, sizeof(data->signature)))
-            break;
-        // Read Mifare version
-        if(!flipper_format_read_hex(
-               file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
-            break;
-        // Read counters and tearing flags
-        bool counters_parsed = true;
-        for(uint8_t i = 0; i < 3; i++) {
-            furi_string_printf(temp_str, "Counter %d", i);
-            if(!flipper_format_read_uint32(
-                   file, furi_string_get_cstr(temp_str), &data->counter[i], 1)) {
-                counters_parsed = false;
-                break;
-            }
-            furi_string_printf(temp_str, "Tearing %d", i);
-            if(!flipper_format_read_hex(
-                   file, furi_string_get_cstr(temp_str), &data->tearing[i], 1)) {
-                counters_parsed = false;
-                break;
-            }
-        }
-        if(!counters_parsed) break;
-        // Read pages
-        uint32_t pages_total = 0;
-        if(!flipper_format_read_uint32(file, "Pages total", &pages_total, 1)) break;
-        uint32_t pages_read = 0;
-        if(data_format_version < nfc_mifare_ultralight_data_format_version) {
-            pages_read = pages_total;
-        } else {
-            if(!flipper_format_read_uint32(file, "Pages read", &pages_read, 1)) break;
-        }
-        data->data_size = pages_total * 4;
-        data->data_read = pages_read * 4;
-        if(data->data_size > MF_UL_MAX_DUMP_SIZE || data->data_read > MF_UL_MAX_DUMP_SIZE) break;
-        bool pages_parsed = true;
-        for(uint16_t i = 0; i < pages_total; i++) {
-            furi_string_printf(temp_str, "Page %d", i);
-            if(!flipper_format_read_hex(
-                   file, furi_string_get_cstr(temp_str), &data->data[i * 4], 4)) {
-                pages_parsed = false;
-                break;
-            }
-        }
-        if(!pages_parsed) break;
-
-        // Read authentication counter
-        uint32_t auth_counter;
-        if(!flipper_format_read_uint32(file, "Failed authentication attempts", &auth_counter, 1))
-            auth_counter = 0;
-        data->curr_authlim = auth_counter;
-
-        data->auth_success = mf_ul_is_full_capture(data);
-
-        parsed = true;
-    } while(false);
 
-    furi_string_free(temp_str);
-    return parsed;
+    return false;
 }
 
 static void nfc_device_write_mifare_classic_block(
@@ -626,19 +459,17 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
         if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break;
         if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
 
-        if(dev->format != NfcDeviceSaveFormatNfcV) {
-            // Write ATQA, SAK
-            if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break;
-            // Save ATQA in MSB order for correct companion apps display
-            uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
-            if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
-            if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
-        }
+        //if(dev->format != NfcDeviceSaveFormatNfcV) {
+        // Write ATQA, SAK
+        if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break;
+        // Save ATQA in MSB order for correct companion apps display
+        uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
+        if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break;
+        if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
+        //}
 
         // Save more data if necessary
-        if(dev->format == NfcDeviceSaveFormatMifareUl) {
-            if(!nfc_device_save_mifare_ul_data(file, dev)) break;
-        } else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
+        if(dev->format == NfcDeviceSaveFormatMifareClassic) {
             // Save data
             if(!nfc_device_save_mifare_classic_data(file, dev)) break;
             // Save keys cache
@@ -716,17 +547,17 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
         if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) break;
         data->uid_len = data_cnt;
         if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
-        if(dev->format != NfcDeviceSaveFormatNfcV) {
-            if(version == version_with_lsb_atqa) {
-                if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
-            } else {
-                uint8_t atqa[2] = {};
-                if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break;
-                data->atqa[0] = atqa[1];
-                data->atqa[1] = atqa[0];
-            }
-            if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
+        //if(dev->format != NfcDeviceSaveFormatNfcV) {
+        if(version == version_with_lsb_atqa) {
+            if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
+        } else {
+            uint8_t atqa[2] = {};
+            if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break;
+            data->atqa[0] = atqa[1];
+            data->atqa[1] = atqa[0];
         }
+        if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
+        //}
         // Load CUID
         uint8_t* cuid_start = data->uid;
         if(data->uid_len == 7) {
@@ -735,9 +566,7 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia
         data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
                      (cuid_start[3]);
         // Parse other data
-        if(dev->format == NfcDeviceSaveFormatMifareUl) {
-            if(!nfc_device_load_mifare_ul_data(file, dev)) break;
-        } else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
+        if(dev->format == NfcDeviceSaveFormatMifareClassic) {
             if(!nfc_device_load_mifare_classic_data(file, dev)) break;
         }
         parsed = true;
@@ -782,8 +611,6 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog) {
 void nfc_device_data_clear(NfcDeviceData* dev_data) {
     if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
         memset(&dev_data->mf_classic_data, 0, sizeof(MfClassicData));
-    } else if(dev_data->protocol == NfcDeviceProtocolMifareUl) {
-        mf_ul_reset(&dev_data->mf_ul_data);
     }
 
     memset(&dev_data->nfc_data, 0, sizeof(FurryHalNfcDevData));

+ 0 - 14
lib/nfclegacy/nfc_device.h

@@ -7,7 +7,6 @@
 
 #include "./furi_hal_nfc.h"
 #include "helpers/mf_classic_dict.h"
-#include "protocols/mifare_ultralight.h"
 #include "protocols/mifare_classic.h"
 
 #ifdef __cplusplus
@@ -26,20 +25,12 @@ typedef void (*NfcLoadingCallback)(void* context, bool state);
 
 typedef enum {
     NfcDeviceProtocolUnknown,
-    NfcDeviceProtocolEMV,
-    NfcDeviceProtocolMifareUl,
     NfcDeviceProtocolMifareClassic,
-    NfcDeviceProtocolMifareDesfire,
-    NfcDeviceProtocolNfcV
 } NfcProtocol;
 
 typedef enum {
     NfcDeviceSaveFormatUid,
-    NfcDeviceSaveFormatBankCard,
-    NfcDeviceSaveFormatMifareUl,
     NfcDeviceSaveFormatMifareClassic,
-    NfcDeviceSaveFormatMifareDesfire,
-    NfcDeviceSaveFormatNfcV,
 } NfcDeviceSaveFormat;
 
 typedef struct {
@@ -55,9 +46,6 @@ typedef struct {
 typedef enum {
     NfcReadModeAuto,
     NfcReadModeMfClassic,
-    NfcReadModeMfUltralight,
-    NfcReadModeMfDesfire,
-    NfcReadModeEMV,
     NfcReadModeNFCA,
 } NfcReadMode;
 
@@ -68,10 +56,8 @@ typedef struct {
     union {
         NfcReaderRequestData reader_data;
         NfcMfClassicDictAttackData mf_classic_dict_attack_data;
-        MfUltralightAuth mf_ul_auth;
     };
     union {
-        MfUltralightData mf_ul_data;
         MfClassicData mf_classic_data;
     };
     FuriString* parsed_data;

+ 1 - 35
lib/nfclegacy/nfc_types.c

@@ -15,47 +15,13 @@ const char* nfc_get_dev_type(FurryHalNfcType type) {
 }
 
 const char* nfc_guess_protocol(NfcProtocol protocol) {
-    if(protocol == NfcDeviceProtocolEMV) {
-        return "EMV bank card";
-    } else if(protocol == NfcDeviceProtocolMifareUl) {
-        return "Mifare Ultral/NTAG";
-    } else if(protocol == NfcDeviceProtocolMifareClassic) {
+    if(protocol == NfcDeviceProtocolMifareClassic) {
         return "Mifare Classic";
-    } else if(protocol == NfcDeviceProtocolMifareDesfire) {
-        return "Mifare DESFire";
     } else {
         return "Unrecognized";
     }
 }
 
-const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) {
-    if(type == MfUltralightTypeNTAG213) {
-        return "NTAG213";
-    } else if(type == MfUltralightTypeNTAG215) {
-        return "NTAG215";
-    } else if(type == MfUltralightTypeNTAG216) {
-        return "NTAG216";
-    } else if(type == MfUltralightTypeNTAGI2C1K) {
-        return "NTAG I2C 1K";
-    } else if(type == MfUltralightTypeNTAGI2C2K) {
-        return "NTAG I2C 2K";
-    } else if(type == MfUltralightTypeNTAGI2CPlus1K) {
-        return "NTAG I2C Plus 1K";
-    } else if(type == MfUltralightTypeNTAGI2CPlus2K) {
-        return "NTAG I2C Plus 2K";
-    } else if(type == MfUltralightTypeNTAG203) {
-        return "NTAG203";
-    } else if(type == MfUltralightTypeULC) {
-        return "Mifare Ultralight C";
-    } else if(type == MfUltralightTypeUL11 && full_name) {
-        return "Mifare Ultralight 11";
-    } else if(type == MfUltralightTypeUL21 && full_name) {
-        return "Mifare Ultralight 21";
-    } else {
-        return "Mifare Ultralight";
-    }
-}
-
 const char* nfc_mf_classic_type(MfClassicType type) {
     if(type == MfClassicTypeMini) {
         return "Mifare Mini 0.3K";

+ 0 - 2
lib/nfclegacy/nfc_types.h

@@ -10,8 +10,6 @@ const char* nfc_get_dev_type(FurryHalNfcType type);
 
 const char* nfc_guess_protocol(NfcProtocol protocol);
 
-const char* nfc_mf_ul_type(MfUltralightType type, bool full_name);
-
 const char* nfc_mf_classic_type(MfClassicType type);
 
 #ifdef __cplusplus

+ 2 - 439
lib/nfclegacy/nfc_worker.c

@@ -23,8 +23,6 @@ NfcWorker* nfc_worker_alloc() {
     }
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
 
-    nfc_worker->reader_analyzer = reader_analyzer_alloc(nfc_worker->storage);
-
     return nfc_worker;
 }
 
@@ -35,8 +33,6 @@ void nfc_worker_free(NfcWorker* nfc_worker) {
 
     furi_record_close(RECORD_STORAGE);
 
-    reader_analyzer_free(nfc_worker->reader_analyzer);
-
     free(nfc_worker);
 }
 
@@ -94,20 +90,14 @@ int32_t nfc_worker_task(void* context) {
         }
     } else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
         nfc_worker_emulate_uid(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
-        nfc_worker_emulate_mf_ultralight(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
         nfc_worker_emulate_mf_classic(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateMfClassicWrite) {
         nfc_worker_write_mf_classic(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateMfClassicUpdate) {
         nfc_worker_update_mf_classic(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) {
-        nfc_worker_mf_ultralight_read_auth(nfc_worker);
     } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) {
         nfc_worker_mf_classic_dict_attack(nfc_worker);
-    } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) {
-        nfc_worker_analyze_reader(nfc_worker);
     }
     furry_hal_nfc_sleep();
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
@@ -115,43 +105,10 @@ int32_t nfc_worker_task(void* context) {
     return 0;
 }
 
-static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FurryHalNfcTxRxContext* tx_rx) {
-    bool read_success = false;
-    MfUltralightReader reader = {};
-    MfUltralightData data = {};
-
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false);
-        reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
-    }
-
-    do {
-        furry_hal_nfc_sleep();
-
-        // Otherwise, try to read as usual
-        if(!furry_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break;
-        if(!mf_ul_read_card(tx_rx, &reader, &data)) break;
-        // Copy data
-        nfc_worker->dev_data->mf_ul_data = data;
-        read_success = true;
-    } while(false);
-
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_stop(nfc_worker->reader_analyzer);
-    }
-
-    return read_success;
-}
-
 static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FurryHalNfcTxRxContext* tx_rx) {
     furi_assert(nfc_worker->callback);
     bool read_success = false;
 
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false);
-        reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
-    }
-
     do {
         // Try to read card with key cache
         FURI_LOG_I(TAG, "Search for key cache ...");
@@ -166,9 +123,6 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FurryHalNfcTxRxCon
         }
     } while(false);
 
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_stop(nfc_worker->reader_analyzer);
-    }
     return read_success;
 }
 
@@ -177,11 +131,7 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FurryHalNfcTxRxContext*
 
     bool card_read = false;
     furry_hal_nfc_sleep();
-    if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
-        FURI_LOG_I(TAG, "Mifare Ultralight / NTAG detected");
-        nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl;
-        card_read = nfc_worker_read_mf_ultralight(nfc_worker, tx_rx);
-    } else if(mf_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
+    if(mf_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
         FURI_LOG_I(TAG, "Mifare Classic detected");
         nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
         nfc_worker->dev_data->mf_classic_data.type =
@@ -219,18 +169,9 @@ void nfc_worker_read(NfcWorker* nfc_worker) {
             card_not_detected_notified = false;
             if(nfc_data->type == FurryHalNfcTypeA) {
                 if(nfc_worker_read_nfca(nfc_worker, &tx_rx)) {
-                    if(dev_data->protocol == NfcDeviceProtocolMifareUl) {
-                        event = NfcWorkerEventReadMfUltralight;
-                        break;
-                    } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
+                    if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
                         event = NfcWorkerEventReadMfClassicDone;
                         break;
-                    } else if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
-                        event = NfcWorkerEventReadMfDesfire;
-                        break;
-                    } else if(dev_data->protocol == NfcDeviceProtocolEMV) {
-                        event = NfcWorkerEventReadBankCard;
-                        break;
                     } else if(dev_data->protocol == NfcDeviceProtocolUnknown) {
                         event = NfcWorkerEventReadUidNfcA;
                         break;
@@ -298,13 +239,6 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) {
                         event = NfcWorkerEventReadMfClassicDictAttackRequired;
                         break;
                     }
-                } else if(read_mode == NfcReadModeMfUltralight) {
-                    FURI_LOG_I(TAG, "Mifare Ultralight / NTAG");
-                    nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl;
-                    if(nfc_worker_read_mf_ultralight(nfc_worker, &tx_rx)) {
-                        event = NfcWorkerEventReadMfUltralight;
-                        break;
-                    }
                 } else if(read_mode == NfcReadModeNFCA) {
                     nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
                     event = NfcWorkerEventReadUidNfcA;
@@ -351,50 +285,6 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) {
     }
 }
 
-void nfc_worker_mf_ultralight_auth_received_callback(MfUltralightAuth auth, void* context) {
-    furi_assert(context);
-
-    NfcWorker* nfc_worker = context;
-    nfc_worker->dev_data->mf_ul_auth = auth;
-    if(nfc_worker->callback) {
-        nfc_worker->callback(NfcWorkerEventMfUltralightPwdAuth, nfc_worker->context);
-    }
-}
-
-void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) {
-    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
-    MfUltralightEmulator emulator = {};
-    mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
-
-    // TODO rework with reader analyzer
-    emulator.auth_received_callback = nfc_worker_mf_ultralight_auth_received_callback;
-    emulator.context = nfc_worker;
-
-    rfal_platform_spi_acquire();
-
-    while(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
-        mf_ul_reset_emulation(&emulator, true);
-        furry_hal_nfc_emulate_nfca(
-            nfc_data->uid,
-            nfc_data->uid_len,
-            nfc_data->atqa,
-            nfc_data->sak,
-            mf_ul_prepare_emulation_response,
-            &emulator,
-            5000);
-        // Check if data was modified
-        if(emulator.data_changed) {
-            nfc_worker->dev_data->mf_ul_data = emulator.data;
-            if(nfc_worker->callback) {
-                nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-            }
-            emulator.data_changed = false;
-        }
-    }
-
-    rfal_platform_spi_release();
-}
-
 static bool nfc_worker_mf_get_b_key_from_sector_trailer(
     FurryHalNfcTxRxContext* tx_rx,
     uint16_t sector,
@@ -642,330 +532,3 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
         nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
     }
 }
-
-void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
-    FurryHalNfcTxRxContext tx_rx = {};
-    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
-    MfClassicEmulator emulator = {
-        .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
-        .data = nfc_worker->dev_data->mf_classic_data,
-        .data_changed = false,
-    };
-    NfcaSignal* nfca_signal = nfca_signal_alloc();
-    tx_rx.nfca_signal = nfca_signal;
-
-    rfal_platform_spi_acquire();
-
-    furry_hal_nfc_listen_start(nfc_data);
-    while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044
-        if(furry_hal_nfc_listen_rx(&tx_rx, 300)) {
-            if(!mf_classic_emulator(&emulator, &tx_rx, false)) {
-                furry_hal_nfc_listen_start(nfc_data);
-            }
-        }
-    }
-    if(emulator.data_changed) {
-        nfc_worker->dev_data->mf_classic_data = emulator.data;
-        if(nfc_worker->callback) {
-            nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-        }
-        emulator.data_changed = false;
-    }
-
-    nfca_signal_free(nfca_signal);
-
-    rfal_platform_spi_release();
-}
-
-void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) {
-    FurryHalNfcTxRxContext tx_rx = {};
-    bool card_found_notified = false;
-    FurryHalNfcDevData nfc_data = {};
-    MfClassicData* src_data = &nfc_worker->dev_data->mf_classic_data;
-    MfClassicData dest_data = *src_data;
-
-    while(nfc_worker->state == NfcWorkerStateMfClassicWrite) {
-        if(furry_hal_nfc_detect(&nfc_data, 200)) {
-            if(!card_found_notified) {
-                nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
-                card_found_notified = true;
-            }
-            furry_hal_nfc_sleep();
-
-            FURI_LOG_I(TAG, "Check low level nfc data");
-            if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FurryHalNfcDevData)) !=
-               0) {
-                FURI_LOG_E(TAG, "Wrong card");
-                nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
-                break;
-            }
-
-            FURI_LOG_I(TAG, "Check mf classic type");
-            MfClassicType type =
-                mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak);
-            if(type != nfc_worker->dev_data->mf_classic_data.type) {
-                FURI_LOG_E(TAG, "Wrong mf classic type");
-                nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
-                break;
-            }
-
-            // Set blocks not read
-            mf_classic_set_sector_data_not_read(&dest_data);
-            FURI_LOG_I(TAG, "Updating card sectors");
-            uint8_t total_sectors = mf_classic_get_total_sectors_num(type);
-            bool write_success = true;
-            for(uint8_t i = 0; i < total_sectors; i++) {
-                FURI_LOG_I(TAG, "Reading sector %d", i);
-                mf_classic_read_sector(&tx_rx, &dest_data, i);
-                bool old_data_read = mf_classic_is_sector_data_read(src_data, i);
-                bool new_data_read = mf_classic_is_sector_data_read(&dest_data, i);
-                if(old_data_read != new_data_read) {
-                    FURI_LOG_E(TAG, "Failed to update sector %d", i);
-                    write_success = false;
-                    break;
-                }
-                if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break;
-                if(!mf_classic_write_sector(&tx_rx, &dest_data, src_data, i)) {
-                    FURI_LOG_E(TAG, "Failed to write %d sector", i);
-                    write_success = false;
-                    break;
-                }
-            }
-            if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break;
-            if(write_success) {
-                nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-                break;
-            } else {
-                nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context);
-                break;
-            }
-
-        } else {
-            if(card_found_notified) {
-                nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
-                card_found_notified = false;
-            }
-        }
-        furi_delay_ms(300);
-    }
-}
-
-void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) {
-    FurryHalNfcTxRxContext tx_rx = {};
-    bool card_found_notified = false;
-    FurryHalNfcDevData nfc_data = {};
-    MfClassicData* old_data = &nfc_worker->dev_data->mf_classic_data;
-    MfClassicData new_data = *old_data;
-
-    while(nfc_worker->state == NfcWorkerStateMfClassicUpdate) {
-        if(furry_hal_nfc_detect(&nfc_data, 200)) {
-            if(!card_found_notified) {
-                nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
-                card_found_notified = true;
-            }
-            furry_hal_nfc_sleep();
-
-            FURI_LOG_I(TAG, "Check low level nfc data");
-            if(memcmp(&nfc_data, &nfc_worker->dev_data->nfc_data, sizeof(FurryHalNfcDevData)) !=
-               0) {
-                FURI_LOG_E(TAG, "Low level nfc data mismatch");
-                nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
-                break;
-            }
-
-            FURI_LOG_I(TAG, "Check MF classic type");
-            MfClassicType type =
-                mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak);
-            if(type != nfc_worker->dev_data->mf_classic_data.type) {
-                FURI_LOG_E(TAG, "MF classic type mismatch");
-                nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context);
-                break;
-            }
-
-            // Set blocks not read
-            mf_classic_set_sector_data_not_read(&new_data);
-            FURI_LOG_I(TAG, "Updating card sectors");
-            uint8_t total_sectors = mf_classic_get_total_sectors_num(type);
-            bool update_success = true;
-            for(uint8_t i = 0; i < total_sectors; i++) {
-                FURI_LOG_I(TAG, "Reading sector %d", i);
-                mf_classic_read_sector(&tx_rx, &new_data, i);
-                bool old_data_read = mf_classic_is_sector_data_read(old_data, i);
-                bool new_data_read = mf_classic_is_sector_data_read(&new_data, i);
-                if(old_data_read != new_data_read) {
-                    FURI_LOG_E(TAG, "Failed to update sector %d", i);
-                    update_success = false;
-                    break;
-                }
-                if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break;
-            }
-            if(nfc_worker->state != NfcWorkerStateMfClassicUpdate) break;
-
-            // Check updated data
-            if(update_success) {
-                *old_data = new_data;
-                nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-                break;
-            }
-        } else {
-            if(card_found_notified) {
-                nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
-                card_found_notified = false;
-            }
-        }
-        furi_delay_ms(300);
-    }
-}
-
-void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker) {
-    furi_assert(nfc_worker);
-    furi_assert(nfc_worker->callback);
-
-    MfUltralightData* data = &nfc_worker->dev_data->mf_ul_data;
-    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
-    FurryHalNfcTxRxContext tx_rx = {};
-    MfUltralightReader reader = {};
-    mf_ul_reset(data);
-
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true);
-        reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
-    }
-
-    uint32_t key = 0;
-    uint16_t pack = 0;
-    while(nfc_worker->state == NfcWorkerStateReadMfUltralightReadAuth) {
-        furry_hal_nfc_sleep();
-        if(furry_hal_nfc_detect(nfc_data, 300) && nfc_data->type == FurryHalNfcTypeA) {
-            if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
-                nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
-                if(data->auth_method == MfUltralightAuthMethodManual ||
-                   data->auth_method == MfUltralightAuthMethodAuto) {
-                    nfc_worker->callback(NfcWorkerEventMfUltralightPassKey, nfc_worker->context);
-                    key = nfc_util_bytes2num(data->auth_key, 4);
-                } else if(data->auth_method == MfUltralightAuthMethodAmeebo) {
-                    key = mf_ul_pwdgen_amiibo(nfc_data);
-                } else if(data->auth_method == MfUltralightAuthMethodXiaomi) {
-                    key = mf_ul_pwdgen_xiaomi(nfc_data);
-                } else {
-                    FURI_LOG_E(TAG, "Incorrect auth method");
-                    break;
-                }
-
-                data->auth_success = mf_ultralight_authenticate(&tx_rx, key, &pack);
-
-                if(!data->auth_success) {
-                    // Reset card
-                    furry_hal_nfc_sleep();
-                    if(!furry_hal_nfc_activate_nfca(300, NULL)) {
-                        nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context);
-                        break;
-                    }
-                }
-
-                mf_ul_read_card(&tx_rx, &reader, data);
-                if(data->auth_success) {
-                    MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data);
-                    if(config_pages != NULL) {
-                        config_pages->auth_data.pwd.value = REVERSE_BYTES_U32(key);
-                        config_pages->auth_data.pack.value = pack;
-                    }
-                    nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
-                    break;
-                } else {
-                    nfc_worker->callback(NfcWorkerEventFail, nfc_worker->context);
-                    break;
-                }
-            } else {
-                nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context);
-                furi_delay_ms(10);
-            }
-        } else {
-            nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
-            furi_delay_ms(10);
-        }
-    }
-
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        reader_analyzer_stop(nfc_worker->reader_analyzer);
-    }
-}
-
-static void nfc_worker_reader_analyzer_callback(ReaderAnalyzerEvent event, void* context) {
-    furi_assert(context);
-    NfcWorker* nfc_worker = context;
-
-    if((nfc_worker->state == NfcWorkerStateAnalyzeReader) &&
-       (event == ReaderAnalyzerEventMfkeyCollected)) {
-        if(nfc_worker->callback) {
-            nfc_worker->callback(NfcWorkerEventDetectReaderMfkeyCollected, nfc_worker->context);
-        }
-    }
-}
-
-void nfc_worker_analyze_reader(NfcWorker* nfc_worker) {
-    furi_assert(nfc_worker);
-    furi_assert(nfc_worker->callback);
-
-    FurryHalNfcTxRxContext tx_rx = {};
-
-    ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer;
-    FurryHalNfcDevData* nfc_data = NULL;
-    if(nfc_worker->dev_data->protocol == NfcDeviceProtocolMifareClassic) {
-        nfc_data = &nfc_worker->dev_data->nfc_data;
-        reader_analyzer_set_nfc_data(reader_analyzer, nfc_data);
-    } else {
-        nfc_data = reader_analyzer_get_nfc_data(reader_analyzer);
-    }
-    MfClassicEmulator emulator = {
-        .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
-        .data = nfc_worker->dev_data->mf_classic_data,
-        .data_changed = false,
-    };
-    NfcaSignal* nfca_signal = nfca_signal_alloc();
-    tx_rx.nfca_signal = nfca_signal;
-    reader_analyzer_prepare_tx_rx(reader_analyzer, &tx_rx, true);
-    reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeMfkey);
-    reader_analyzer_set_callback(reader_analyzer, nfc_worker_reader_analyzer_callback, nfc_worker);
-
-    rfal_platform_spi_acquire();
-
-    FURI_LOG_D(TAG, "Start reader analyzer");
-
-    uint8_t reader_no_data_received_cnt = 0;
-    bool reader_no_data_notified = true;
-
-    while(nfc_worker->state == NfcWorkerStateAnalyzeReader) {
-        furry_hal_nfc_listen_start(nfc_data);
-        if(furry_hal_nfc_listen_rx(&tx_rx, 300)) {
-            if(reader_no_data_notified) {
-                nfc_worker->callback(NfcWorkerEventDetectReaderDetected, nfc_worker->context);
-            }
-            reader_no_data_received_cnt = 0;
-            reader_no_data_notified = false;
-            NfcProtocol protocol =
-                reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8);
-            if(protocol == NfcDeviceProtocolMifareClassic) {
-                if(!mf_classic_emulator(&emulator, &tx_rx, true)) {
-                    furry_hal_nfc_listen_start(nfc_data);
-                }
-            }
-        } else {
-            reader_no_data_received_cnt++;
-            if(!reader_no_data_notified && (reader_no_data_received_cnt > 5)) {
-                nfc_worker->callback(NfcWorkerEventDetectReaderLost, nfc_worker->context);
-                reader_no_data_received_cnt = 0;
-                reader_no_data_notified = true;
-            }
-            FURI_LOG_D(TAG, "No data from reader");
-            continue;
-        }
-        furi_delay_ms(1);
-    }
-
-    rfal_platform_spi_release();
-
-    reader_analyzer_stop(nfc_worker->reader_analyzer);
-
-    nfca_signal_free(nfca_signal);
-}

+ 0 - 25
lib/nfclegacy/nfc_worker.h

@@ -15,17 +15,10 @@ typedef enum {
     // Main worker states
     NfcWorkerStateRead,
     NfcWorkerStateUidEmulate,
-    NfcWorkerStateMfUltralightEmulate,
     NfcWorkerStateMfClassicEmulate,
     NfcWorkerStateMfClassicWrite,
     NfcWorkerStateMfClassicUpdate,
-    NfcWorkerStateReadMfUltralightReadAuth,
     NfcWorkerStateMfClassicDictAttack,
-    NfcWorkerStateAnalyzeReader,
-    NfcWorkerStateNfcVEmulate,
-    NfcWorkerStateNfcVUnlock,
-    NfcWorkerStateNfcVUnlockAndSave,
-    NfcWorkerStateNfcVSniff,
     // Debug
     NfcWorkerStateEmulateApdu,
     NfcWorkerStateField,
@@ -42,13 +35,9 @@ typedef enum {
     NfcWorkerEventReadUidNfcV,
     NfcWorkerEventReadUidNfcF,
     NfcWorkerEventReadUidNfcA,
-    NfcWorkerEventReadMfUltralight,
-    NfcWorkerEventReadMfDesfire,
     NfcWorkerEventReadMfClassicDone,
     NfcWorkerEventReadMfClassicLoadKeyCache,
     NfcWorkerEventReadMfClassicDictAttackRequired,
-    NfcWorkerEventReadBankCard,
-    NfcWorkerEventReadNfcV,
 
     // Nfc worker common events
     NfcWorkerEventSuccess,
@@ -71,17 +60,6 @@ typedef enum {
     // Write Mifare Classic events
     NfcWorkerEventWrongCard,
 
-    // Detect Reader events
-    NfcWorkerEventDetectReaderDetected,
-    NfcWorkerEventDetectReaderLost,
-    NfcWorkerEventDetectReaderMfkeyCollected,
-
-    // Mifare Ultralight events
-    NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key
-    NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command
-    NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key
-    NfcWorkerEventNfcVCommandExecuted,
-    NfcWorkerEventNfcVContentChanged,
 } NfcWorkerEvent;
 
 typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
@@ -100,9 +78,6 @@ void nfc_worker_start(
     void* context);
 
 void nfc_worker_stop(NfcWorker* nfc_worker);
-void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker);
-void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker);
-void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker);
 
 #ifdef __cplusplus
 }

+ 1 - 13
lib/nfclegacy/nfc_worker_i.h

@@ -7,10 +7,8 @@
 
 #include "protocols/nfc_util.h"
 #include "protocols/mifare_common.h"
-#include "protocols/mifare_ultralight.h"
 #include "protocols/mifare_classic.h"
 #include "protocols/nfca.h"
-#include "helpers/reader_analyzer.h"
 
 struct NfcWorker {
     FuriThread* thread;
@@ -23,8 +21,6 @@ struct NfcWorker {
     void* context;
 
     NfcWorkerState state;
-
-    ReaderAnalyzer* reader_analyzer;
 };
 
 void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
@@ -37,8 +33,6 @@ void nfc_worker_read_type(NfcWorker* nfc_worker);
 
 void nfc_worker_emulate_uid(NfcWorker* nfc_worker);
 
-void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker);
-
 void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker);
 
 void nfc_worker_write_mf_classic(NfcWorker* nfc_worker);
@@ -47,10 +41,4 @@ void nfc_worker_update_mf_classic(NfcWorker* nfc_worker);
 
 void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker);
 
-void nfc_worker_mf_ultralight_read_auth(NfcWorker* nfc_worker);
-
-void nfc_worker_mf_ul_auth_attack(NfcWorker* nfc_worker);
-
-void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);
-
-void nfc_worker_analyze_reader(NfcWorker* nfc_worker);
+void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);

+ 0 - 1946
lib/nfclegacy/protocols/mifare_ultralight.c

@@ -1,1946 +0,0 @@
-#include <limits.h>
-#include <mbedtls/sha1.h>
-#include "mifare_ultralight.h"
-#include "nfc_util.h"
-#include <furi.h>
-#include "../furi_hal_nfc.h"
-
-#define TAG "MfUltralight"
-
-// Algorithms from: https://github.com/RfidResearchGroup/proxmark3/blob/0f6061c16f072372b7d4d381911f1542afbc3a69/common/generator.c#L110
-uint32_t mf_ul_pwdgen_xiaomi(FurryHalNfcDevData* data) {
-    uint8_t hash[20];
-    mbedtls_sha1(data->uid, data->uid_len, hash);
-
-    uint32_t pwd = 0;
-    pwd |= (hash[hash[0] % 20]) << 24;
-    pwd |= (hash[(hash[0] + 5) % 20]) << 16;
-    pwd |= (hash[(hash[0] + 13) % 20]) << 8;
-    pwd |= (hash[(hash[0] + 17) % 20]);
-
-    return pwd;
-}
-
-uint32_t mf_ul_pwdgen_amiibo(FurryHalNfcDevData* data) {
-    uint8_t* uid = data->uid;
-
-    uint32_t pwd = 0;
-    pwd |= (uid[1] ^ uid[3] ^ 0xAA) << 24;
-    pwd |= (uid[2] ^ uid[4] ^ 0x55) << 16;
-    pwd |= (uid[3] ^ uid[5] ^ 0xAA) << 8;
-    pwd |= uid[4] ^ uid[6] ^ 0x55;
-
-    return pwd;
-}
-
-bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
-    if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
-        return true;
-    }
-    return false;
-}
-
-void mf_ul_reset(MfUltralightData* data) {
-    furi_assert(data);
-    data->type = MfUltralightTypeUnknown;
-    memset(&data->version, 0, sizeof(MfUltralightVersion));
-    memset(data->signature, 0, sizeof(data->signature));
-    memset(data->counter, 0, sizeof(data->counter));
-    memset(data->tearing, 0, sizeof(data->tearing));
-    memset(data->data, 0, sizeof(data->data));
-    data->data_size = 0;
-    data->data_read = 0;
-    data->curr_authlim = 0;
-    data->auth_success = false;
-}
-
-static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) {
-    switch(type) {
-    case MfUltralightTypeUL11:
-    case MfUltralightTypeUL21:
-        return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite |
-               MfUltralightSupportReadCounter | MfUltralightSupportIncrCounter |
-               MfUltralightSupportAuth | MfUltralightSupportSignature |
-               MfUltralightSupportTearingFlags | MfUltralightSupportVcsl;
-    case MfUltralightTypeNTAG213:
-    case MfUltralightTypeNTAG215:
-    case MfUltralightTypeNTAG216:
-        return MfUltralightSupportFastRead | MfUltralightSupportCompatWrite |
-               MfUltralightSupportReadCounter | MfUltralightSupportAuth |
-               MfUltralightSupportSignature | MfUltralightSupportSingleCounter |
-               MfUltralightSupportAsciiMirror;
-    case MfUltralightTypeNTAGI2C1K:
-    case MfUltralightTypeNTAGI2C2K:
-        return MfUltralightSupportFastRead | MfUltralightSupportSectorSelect;
-    case MfUltralightTypeNTAGI2CPlus1K:
-    case MfUltralightTypeNTAGI2CPlus2K:
-        return MfUltralightSupportFastRead | MfUltralightSupportAuth |
-               MfUltralightSupportFastWrite | MfUltralightSupportSignature |
-               MfUltralightSupportSectorSelect;
-    case MfUltralightTypeNTAG203:
-        return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory;
-    case MfUltralightTypeULC:
-        return MfUltralightSupportCompatWrite | MfUltralightSupport3DesAuth;
-    default:
-        // Assumed original MFUL 512-bit
-        return MfUltralightSupportCompatWrite;
-    }
-}
-
-static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) {
-    data->type = MfUltralightTypeUnknown;
-    reader->pages_to_read = 16;
-}
-
-static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightData* data) {
-    data->type = MfUltralightTypeNTAG203;
-    reader->pages_to_read = 42;
-}
-
-static void mf_ul_set_version_ulc(MfUltralightReader* reader, MfUltralightData* data) {
-    data->type = MfUltralightTypeULC;
-    reader->pages_to_read = 48;
-}
-
-bool mf_ultralight_read_version(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data) {
-    bool version_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 = FurryHalNfcTxRxTypeDefault;
-        if(!furry_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits != 64) {
-            FURI_LOG_D(TAG, "Failed reading version");
-            mf_ul_set_default_version(reader, data);
-            furry_hal_nfc_sleep();
-            furry_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;
-        } else if(version->storage_size == 0x0E) {
-            data->type = MfUltralightTypeUL21;
-            reader->pages_to_read = 41;
-        } else if(version->storage_size == 0x0F) {
-            data->type = MfUltralightTypeNTAG213;
-            reader->pages_to_read = 45;
-        } else if(version->storage_size == 0x11) {
-            data->type = MfUltralightTypeNTAG215;
-            reader->pages_to_read = 135;
-        } else if(version->prod_subtype == 5 && version->prod_ver_major == 2) {
-            // NTAG I2C
-            bool known = false;
-            if(version->prod_ver_minor == 1) {
-                if(version->storage_size == 0x13) {
-                    data->type = MfUltralightTypeNTAGI2C1K;
-                    reader->pages_to_read = 231;
-                    known = true;
-                } else if(version->storage_size == 0x15) {
-                    data->type = MfUltralightTypeNTAGI2C2K;
-                    reader->pages_to_read = 485;
-                    known = true;
-                }
-            } else if(version->prod_ver_minor == 2) {
-                if(version->storage_size == 0x13) {
-                    data->type = MfUltralightTypeNTAGI2CPlus1K;
-                    reader->pages_to_read = 236;
-                    known = true;
-                } else if(version->storage_size == 0x15) {
-                    data->type = MfUltralightTypeNTAGI2CPlus2K;
-                    reader->pages_to_read = 492;
-                    known = true;
-                }
-            }
-
-            if(!known) {
-                mf_ul_set_default_version(reader, data);
-            }
-        } else if(version->storage_size == 0x13) {
-            data->type = MfUltralightTypeNTAG216;
-            reader->pages_to_read = 231;
-        } else {
-            mf_ul_set_default_version(reader, data);
-            break;
-        }
-        version_read = true;
-    } while(false);
-
-    reader->supported_features = mf_ul_get_features(data->type);
-    return version_read;
-}
-
-bool mf_ultralight_authenticate(FurryHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack) {
-    furi_assert(pack);
-    bool authenticated = false;
-
-    do {
-        FURI_LOG_D(TAG, "Authenticating");
-        tx_rx->tx_data[0] = MF_UL_PWD_AUTH;
-        nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]);
-        tx_rx->tx_bits = 40;
-        tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-        if(!furry_hal_nfc_tx_rx(tx_rx, 50)) {
-            FURI_LOG_D(TAG, "Tag did not respond to authentication");
-            break;
-        }
-
-        // PACK
-        if(tx_rx->rx_bits < 2 * 8) {
-            FURI_LOG_D(TAG, "Authentication failed");
-            break;
-        }
-
-        *pack = (tx_rx->rx_data[1] << 8) | tx_rx->rx_data[0];
-
-        FURI_LOG_I(TAG, "Auth success. Password: %08lX. PACK: %04X", key, *pack);
-        authenticated = true;
-    } while(false);
-
-    return authenticated;
-}
-
-static int16_t mf_ultralight_page_addr_to_tag_addr(uint8_t sector, uint8_t page) {
-    return sector * 256 + page;
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_1k(
-    int16_t linear_address,
-    uint8_t* sector,
-    int16_t* valid_pages) {
-    // 0 - 226: sector 0
-    // 227 - 228: config registers
-    // 229 - 230: session registers
-
-    if(linear_address > 230) {
-        *valid_pages = 0;
-        return -1;
-    } else if(linear_address >= 229) {
-        *sector = 3;
-        *valid_pages = 2 - (linear_address - 229);
-        return linear_address - 229 + 248;
-    } else if(linear_address >= 227) {
-        *sector = 0;
-        *valid_pages = 2 - (linear_address - 227);
-        return linear_address - 227 + 232;
-    } else {
-        *sector = 0;
-        *valid_pages = 227 - linear_address;
-        return linear_address;
-    }
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_2k(
-    int16_t linear_address,
-    uint8_t* sector,
-    int16_t* valid_pages) {
-    // 0 - 255: sector 0
-    // 256 - 480: sector 1
-    // 481 - 482: config registers
-    // 483 - 484: session registers
-
-    if(linear_address > 484) {
-        *valid_pages = 0;
-        return -1;
-    } else if(linear_address >= 483) {
-        *sector = 3;
-        *valid_pages = 2 - (linear_address - 483);
-        return linear_address - 483 + 248;
-    } else if(linear_address >= 481) {
-        *sector = 1;
-        *valid_pages = 2 - (linear_address - 481);
-        return linear_address - 481 + 232;
-    } else if(linear_address >= 256) {
-        *sector = 1;
-        *valid_pages = 225 - (linear_address - 256);
-        return linear_address - 256;
-    } else {
-        *sector = 0;
-        *valid_pages = 256 - linear_address;
-        return linear_address;
-    }
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_plus_1k(
-    int16_t linear_address,
-    uint8_t* sector,
-    int16_t* valid_pages) {
-    // 0 - 233: sector 0 + registers
-    // 234 - 235: session registers
-
-    if(linear_address > 235) {
-        *valid_pages = 0;
-        return -1;
-    } else if(linear_address >= 234) {
-        *sector = 0;
-        *valid_pages = 2 - (linear_address - 234);
-        return linear_address - 234 + 236;
-    } else {
-        *sector = 0;
-        *valid_pages = 234 - linear_address;
-        return linear_address;
-    }
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag_plus_2k(
-    int16_t linear_address,
-    uint8_t* sector,
-    int16_t* valid_pages) {
-    // 0 - 233: sector 0 + registers
-    // 234 - 235: session registers
-    // 236 - 491: sector 1
-
-    if(linear_address > 491) {
-        *valid_pages = 0;
-        return -1;
-    } else if(linear_address >= 236) {
-        *sector = 1;
-        *valid_pages = 256 - (linear_address - 236);
-        return linear_address - 236;
-    } else if(linear_address >= 234) {
-        *sector = 0;
-        *valid_pages = 2 - (linear_address - 234);
-        return linear_address - 234 + 236;
-    } else {
-        *sector = 0;
-        *valid_pages = 234 - linear_address;
-        return linear_address;
-    }
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_lin_to_tag(
-    MfUltralightData* data,
-    MfUltralightReader* reader,
-    int16_t linear_address,
-    uint8_t* sector,
-    int16_t* valid_pages) {
-    switch(data->type) {
-    case MfUltralightTypeNTAGI2C1K:
-        return mf_ultralight_ntag_i2c_addr_lin_to_tag_1k(linear_address, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2C2K:
-        return mf_ultralight_ntag_i2c_addr_lin_to_tag_2k(linear_address, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2CPlus1K:
-        return mf_ultralight_ntag_i2c_addr_lin_to_tag_plus_1k(linear_address, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2CPlus2K:
-        return mf_ultralight_ntag_i2c_addr_lin_to_tag_plus_2k(linear_address, sector, valid_pages);
-
-    default:
-        *sector = 0xff;
-        *valid_pages = reader->pages_to_read - linear_address;
-        return linear_address;
-    }
-}
-
-static int16_t
-    mf_ultralight_ntag_i2c_addr_tag_to_lin_1k(uint8_t page, uint8_t sector, uint16_t* valid_pages) {
-    bool valid = false;
-    int16_t translated_page;
-    if(sector == 0) {
-        if(page <= 226) {
-            *valid_pages = 227 - page;
-            translated_page = page;
-            valid = true;
-        } else if(page >= 232 && page <= 233) {
-            *valid_pages = 2 - (page - 232);
-            translated_page = page - 232 + 227;
-            valid = true;
-        }
-    } else if(sector == 3) {
-        if(page >= 248 && page <= 249) {
-            *valid_pages = 2 - (page - 248);
-            translated_page = page - 248 + 229;
-            valid = true;
-        }
-    }
-
-    if(!valid) {
-        *valid_pages = 0;
-        translated_page = -1;
-    }
-    return translated_page;
-}
-
-static int16_t
-    mf_ultralight_ntag_i2c_addr_tag_to_lin_2k(uint8_t page, uint8_t sector, uint16_t* valid_pages) {
-    bool valid = false;
-    int16_t translated_page;
-    if(sector == 0) {
-        *valid_pages = 256 - page;
-        translated_page = page;
-        valid = true;
-    } else if(sector == 1) {
-        if(page <= 224) {
-            *valid_pages = 225 - page;
-            translated_page = 256 + page;
-            valid = true;
-        } else if(page >= 232 && page <= 233) {
-            *valid_pages = 2 - (page - 232);
-            translated_page = page - 232 + 481;
-            valid = true;
-        }
-    } else if(sector == 3) {
-        if(page >= 248 && page <= 249) {
-            *valid_pages = 2 - (page - 248);
-            translated_page = page - 248 + 483;
-            valid = true;
-        }
-    }
-
-    if(!valid) {
-        *valid_pages = 0;
-        translated_page = -1;
-    }
-    return translated_page;
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin_plus_1k(
-    uint8_t page,
-    uint8_t sector,
-    uint16_t* valid_pages) {
-    bool valid = false;
-    int16_t translated_page;
-    if(sector == 0) {
-        if(page <= 233) {
-            *valid_pages = 234 - page;
-            translated_page = page;
-            valid = true;
-        } else if(page >= 236 && page <= 237) {
-            *valid_pages = 2 - (page - 236);
-            translated_page = page - 236 + 234;
-            valid = true;
-        }
-    } else if(sector == 3) {
-        if(page >= 248 && page <= 249) {
-            *valid_pages = 2 - (page - 248);
-            translated_page = page - 248 + 234;
-            valid = true;
-        }
-    }
-
-    if(!valid) {
-        *valid_pages = 0;
-        translated_page = -1;
-    }
-    return translated_page;
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin_plus_2k(
-    uint8_t page,
-    uint8_t sector,
-    uint16_t* valid_pages) {
-    bool valid = false;
-    int16_t translated_page;
-    if(sector == 0) {
-        if(page <= 233) {
-            *valid_pages = 234 - page;
-            translated_page = page;
-            valid = true;
-        } else if(page >= 236 && page <= 237) {
-            *valid_pages = 2 - (page - 236);
-            translated_page = page - 236 + 234;
-            valid = true;
-        }
-    } else if(sector == 1) {
-        *valid_pages = 256 - page;
-        translated_page = page + 236;
-        valid = true;
-    } else if(sector == 3) {
-        if(page >= 248 && page <= 249) {
-            *valid_pages = 2 - (page - 248);
-            translated_page = page - 248 + 234;
-            valid = true;
-        }
-    }
-
-    if(!valid) {
-        *valid_pages = 0;
-        translated_page = -1;
-    }
-    return translated_page;
-}
-
-static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin(
-    MfUltralightData* data,
-    uint8_t page,
-    uint8_t sector,
-    uint16_t* valid_pages) {
-    switch(data->type) {
-    case MfUltralightTypeNTAGI2C1K:
-        return mf_ultralight_ntag_i2c_addr_tag_to_lin_1k(page, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2C2K:
-        return mf_ultralight_ntag_i2c_addr_tag_to_lin_2k(page, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2CPlus1K:
-        return mf_ultralight_ntag_i2c_addr_tag_to_lin_plus_1k(page, sector, valid_pages);
-
-    case MfUltralightTypeNTAGI2CPlus2K:
-        return mf_ultralight_ntag_i2c_addr_tag_to_lin_plus_2k(page, sector, valid_pages);
-
-    default:
-        *valid_pages = data->data_size / 4 - page;
-        return page;
-    }
-}
-
-MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) {
-    if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) {
-        return (MfUltralightConfigPages*)&data->data[data->data_size - 4 * 4];
-    } else if(
-        data->type >= MfUltralightTypeNTAGI2CPlus1K &&
-        data->type <= MfUltralightTypeNTAGI2CPlus2K) {
-        return (MfUltralightConfigPages*)&data->data[0xe3 * 4]; //-V641
-    } else {
-        return NULL;
-    }
-}
-
-static uint16_t mf_ultralight_calc_auth_count(MfUltralightData* data) {
-    if(mf_ul_get_features(data->type) & MfUltralightSupportAuth) {
-        MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data);
-        uint16_t scaled_authlim = config->access.authlim;
-        // NTAG I2C Plus uses 2^AUTHLIM attempts rather than the direct number
-        if(scaled_authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K &&
-           data->type <= MfUltralightTypeNTAGI2CPlus2K) {
-            scaled_authlim = 1 << scaled_authlim;
-        }
-        return scaled_authlim;
-    }
-
-    return 0;
-}
-
-// NTAG21x will NAK if NFC_CNT_EN unset, so preempt
-static bool mf_ultralight_should_read_counters(MfUltralightData* data) {
-    if(data->type < MfUltralightTypeNTAG213 || data->type > MfUltralightTypeNTAG216) return true;
-
-    MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data);
-    return config->access.nfc_cnt_en;
-}
-
-static bool mf_ultralight_sector_select(FurryHalNfcTxRxContext* tx_rx, uint8_t sector) {
-    FURI_LOG_D(TAG, "Selecting sector %u", sector);
-    tx_rx->tx_data[0] = MF_UL_SECTOR_SELECT;
-    tx_rx->tx_data[1] = 0xff;
-    tx_rx->tx_bits = 16;
-    tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-    if(!furry_hal_nfc_tx_rx(tx_rx, 50)) {
-        FURI_LOG_D(TAG, "Failed to issue sector select command");
-        return false;
-    }
-
-    tx_rx->tx_data[0] = sector;
-    tx_rx->tx_data[1] = 0x00;
-    tx_rx->tx_data[2] = 0x00;
-    tx_rx->tx_data[3] = 0x00;
-    tx_rx->tx_bits = 32;
-    tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-    // This is NOT a typo! The tag ACKs by not sending a response within 1ms.
-    if(furry_hal_nfc_tx_rx(tx_rx, 20)) {
-        // TODO: what gets returned when an actual NAK is received?
-        FURI_LOG_D(TAG, "Sector %u select NAK'd", sector);
-        return false;
-    }
-
-    return true;
-}
-
-bool mf_ultralight_read_pages_direct(
-    FurryHalNfcTxRxContext* tx_rx,
-    uint8_t start_index,
-    uint8_t* data) {
-    FURI_LOG_D(TAG, "Reading pages %d - %d", start_index, start_index + 3);
-    tx_rx->tx_data[0] = MF_UL_READ_CMD;
-    tx_rx->tx_data[1] = start_index;
-    tx_rx->tx_bits = 16;
-    tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-    if(!furry_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) {
-        FURI_LOG_D(TAG, "Failed to read pages %d - %d", start_index, start_index + 3);
-        return false;
-    }
-    memcpy(data, tx_rx->rx_data, 16); //-V1086
-    return true;
-}
-
-bool mf_ultralight_read_pages(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data) {
-    uint8_t pages_read_cnt = 0;
-    uint8_t curr_sector_index = 0xff;
-    reader->pages_read = 0;
-    for(size_t i = 0; i < reader->pages_to_read; i += pages_read_cnt) {
-        uint8_t tag_sector;
-        int16_t valid_pages;
-        int16_t tag_page = mf_ultralight_ntag_i2c_addr_lin_to_tag(
-            data, reader, (int16_t)i, &tag_sector, &valid_pages);
-
-        furi_assert(tag_page != -1);
-        if(curr_sector_index != tag_sector) {
-            if(!mf_ultralight_sector_select(tx_rx, tag_sector)) return false;
-            curr_sector_index = tag_sector;
-        }
-
-        FURI_LOG_D(
-            TAG, "Reading pages %zu - %zu", i, i + (valid_pages > 4 ? 4 : valid_pages) - 1U);
-        tx_rx->tx_data[0] = MF_UL_READ_CMD;
-        tx_rx->tx_data[1] = tag_page;
-        tx_rx->tx_bits = 16;
-        tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-
-        if(!furry_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) {
-            FURI_LOG_D(
-                TAG,
-                "Failed to read pages %zu - %zu",
-                i,
-                i + (valid_pages > 4 ? 4 : valid_pages) - 1U);
-            break;
-        }
-
-        if(valid_pages > 4) {
-            pages_read_cnt = 4;
-        } else {
-            pages_read_cnt = valid_pages;
-        }
-        reader->pages_read += pages_read_cnt;
-        memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4);
-    }
-    data->data_size = reader->pages_to_read * 4;
-    data->data_read = reader->pages_read * 4;
-
-    return reader->pages_read > 0;
-}
-
-bool mf_ultralight_fast_read_pages(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data) {
-    uint8_t curr_sector_index = 0xff;
-    reader->pages_read = 0;
-    while(reader->pages_read < reader->pages_to_read) {
-        uint8_t tag_sector;
-        int16_t valid_pages;
-        int16_t tag_page = mf_ultralight_ntag_i2c_addr_lin_to_tag(
-            data, reader, reader->pages_read, &tag_sector, &valid_pages);
-
-        furi_assert(tag_page != -1);
-        if(curr_sector_index != tag_sector) {
-            if(!mf_ultralight_sector_select(tx_rx, tag_sector)) return false;
-            curr_sector_index = tag_sector;
-        }
-
-        FURI_LOG_D(
-            TAG, "Reading pages %d - %d", reader->pages_read, reader->pages_read + valid_pages - 1);
-        tx_rx->tx_data[0] = MF_UL_FAST_READ_CMD;
-        tx_rx->tx_data[1] = tag_page;
-        tx_rx->tx_data[2] = valid_pages - 1;
-        tx_rx->tx_bits = 24;
-        tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-        if(furry_hal_nfc_tx_rx(tx_rx, 50)) {
-            memcpy(&data->data[reader->pages_read * 4], tx_rx->rx_data, valid_pages * 4);
-            reader->pages_read += valid_pages;
-            data->data_size = reader->pages_read * 4;
-        } else {
-            FURI_LOG_D(
-                TAG,
-                "Failed to read pages %d - %d",
-                reader->pages_read,
-                reader->pages_read + valid_pages - 1);
-            break;
-        }
-    }
-
-    return reader->pages_read == reader->pages_to_read;
-}
-
-bool mf_ultralight_read_signature(FurryHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
-    bool signature_read = false;
-
-    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 = FurryHalNfcTxRxTypeDefault;
-    if(furry_hal_nfc_tx_rx(tx_rx, 50)) {
-        memcpy(data->signature, tx_rx->rx_data, sizeof(data->signature));
-        signature_read = true;
-    } else {
-        FURI_LOG_D(TAG, "Failed redaing signature");
-    }
-
-    return signature_read;
-}
-
-bool mf_ultralight_read_counters(FurryHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
-    uint8_t counter_read = 0;
-
-    FURI_LOG_D(TAG, "Reading counters");
-    bool is_single_counter = (mf_ul_get_features(data->type) & MfUltralightSupportSingleCounter) !=
-                             0;
-    for(size_t i = is_single_counter ? 2 : 0; i < 3; i++) {
-        tx_rx->tx_data[0] = MF_UL_READ_CNT;
-        tx_rx->tx_data[1] = i;
-        tx_rx->tx_bits = 16;
-        tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-        if(!furry_hal_nfc_tx_rx(tx_rx, 50)) {
-            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++;
-    }
-
-    return counter_read == (is_single_counter ? 1 : 3);
-}
-
-bool mf_ultralight_read_tearing_flags(FurryHalNfcTxRxContext* 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->tx_data[1] = i;
-        tx_rx->tx_bits = 16;
-        tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-        if(!furry_hal_nfc_tx_rx(tx_rx, 50)) {
-            FURI_LOG_D(TAG, "Failed to read %d tearing flag", i);
-            break;
-        }
-        data->tearing[i] = tx_rx->rx_data[0];
-        flag_read++;
-    }
-
-    return flag_read == 2;
-}
-
-static bool mf_ul_probe_3des_auth(FurryHalNfcTxRxContext* tx_rx) {
-    tx_rx->tx_data[0] = MF_UL_AUTHENTICATE_1;
-    tx_rx->tx_data[1] = 0;
-    tx_rx->tx_bits = 16;
-    tx_rx->tx_rx_type = FurryHalNfcTxRxTypeDefault;
-    bool rc = furry_hal_nfc_tx_rx(tx_rx, 50) && tx_rx->rx_bits == 9 * 8 &&
-              tx_rx->rx_data[0] == 0xAF;
-
-    // Reset just in case, we're not going to finish authenticating and need to if tag doesn't support auth
-    furry_hal_nfc_sleep();
-    furry_hal_nfc_activate_nfca(300, NULL);
-
-    return rc;
-}
-
-bool mf_ul_read_card(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data) {
-    furi_assert(tx_rx);
-    furi_assert(reader);
-    furi_assert(data);
-
-    bool card_read = false;
-
-    // Read Mifare Ultralight version
-    if(mf_ultralight_read_version(tx_rx, reader, data)) {
-        if(reader->supported_features & MfUltralightSupportSignature) {
-            // Read Signature
-            mf_ultralight_read_signature(tx_rx, data);
-        }
-    } else {
-        uint8_t dummy[16];
-        // No GET_VERSION command, check if AUTHENTICATE command available (detect UL C).
-        if(mf_ul_probe_3des_auth(tx_rx)) {
-            mf_ul_set_version_ulc(reader, data);
-        } else if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) {
-            // No AUTHENTICATE, check for NTAG203 by reading last page (41)
-            mf_ul_set_version_ntag203(reader, data);
-        } else {
-            // We're really an original Mifare Ultralight, reset tag for safety
-            furry_hal_nfc_sleep();
-            furry_hal_nfc_activate_nfca(300, NULL);
-        }
-
-        reader->supported_features = mf_ul_get_features(data->type);
-    }
-
-    card_read = mf_ultralight_read_pages(tx_rx, reader, data);
-
-    if(card_read) {
-        if(reader->supported_features & MfUltralightSupportReadCounter &&
-           mf_ultralight_should_read_counters(data)) {
-            mf_ultralight_read_counters(tx_rx, data);
-        }
-        if(reader->supported_features & MfUltralightSupportTearingFlags) {
-            mf_ultralight_read_tearing_flags(tx_rx, data);
-        }
-        data->curr_authlim = 0;
-
-        if(reader->pages_read == reader->pages_to_read &&
-           reader->supported_features & MfUltralightSupportAuth && !data->auth_success) {
-            MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data);
-            if(config->access.authlim == 0) {
-                // Attempt to auth with default PWD
-                uint16_t pack;
-                data->auth_success = mf_ultralight_authenticate(tx_rx, MF_UL_DEFAULT_PWD, &pack);
-                if(data->auth_success) {
-                    config->auth_data.pwd.value = MF_UL_DEFAULT_PWD;
-                    config->auth_data.pack.value = pack;
-                } else {
-                    furry_hal_nfc_sleep();
-                    furry_hal_nfc_activate_nfca(300, NULL);
-                }
-            }
-        }
-    }
-
-    if(reader->pages_read != reader->pages_to_read) {
-        if(reader->supported_features & MfUltralightSupportAuth) {
-            // Probably password protected, fix AUTH0 and PROT so before AUTH0
-            // can be written and since AUTH0 won't be readable, like on the
-            // original card
-            MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data);
-            config->auth0 = reader->pages_read;
-            config->access.prot = true;
-        }
-    }
-
-    return card_read;
-}
-
-static void mf_ul_protect_auth_data_on_read_command_i2c(
-    uint8_t* tx_buff,
-    uint8_t start_page,
-    uint8_t end_page,
-    MfUltralightEmulator* emulator) {
-    if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) {
-        // Blank out PWD and PACK
-        if(start_page <= 229 && end_page >= 229) {
-            uint16_t offset = (229 - start_page) * 4;
-            uint8_t count = 4;
-            if(end_page >= 230) count += 2;
-            memset(&tx_buff[offset], 0, count);
-        }
-
-        // Handle AUTH0 for sector 0
-        if(!emulator->auth_success) {
-            if(emulator->config_cache.access.prot) {
-                uint8_t auth0 = emulator->config_cache.auth0;
-                if(auth0 < end_page) {
-                    // start_page is always < auth0; otherwise is NAK'd already
-                    uint8_t page_offset = auth0 - start_page;
-                    uint8_t page_count = end_page - auth0;
-                    memset(&tx_buff[page_offset * 4], 0, page_count * 4);
-                }
-            }
-        }
-    }
-}
-
-static void mf_ul_ntag_i2c_fill_cross_area_read(
-    uint8_t* tx_buff,
-    uint8_t start_page,
-    uint8_t end_page,
-    MfUltralightEmulator* emulator) {
-    // For copying config or session registers in fast read
-    int16_t tx_page_offset;
-    int16_t data_page_offset;
-    uint8_t page_length;
-    bool apply = false;
-    MfUltralightType type = emulator->data.type;
-    if(emulator->curr_sector == 0) {
-        if(type == MfUltralightTypeNTAGI2C1K) {
-            if(start_page <= 233 && end_page >= 232) {
-                tx_page_offset = start_page - 232;
-                data_page_offset = 227;
-                page_length = 2;
-                apply = true;
-            }
-        } else if(type == MfUltralightTypeNTAGI2CPlus1K || type == MfUltralightTypeNTAGI2CPlus2K) {
-            if(start_page <= 237 && end_page >= 236) {
-                tx_page_offset = start_page - 236;
-                data_page_offset = 234;
-                page_length = 2;
-                apply = true;
-            }
-        }
-    } else if(emulator->curr_sector == 1) {
-        if(type == MfUltralightTypeNTAGI2C2K) {
-            if(start_page <= 233 && end_page >= 232) {
-                tx_page_offset = start_page - 232;
-                data_page_offset = 483;
-                page_length = 2;
-                apply = true;
-            }
-        }
-    }
-
-    if(apply) {
-        while(tx_page_offset < 0 && page_length > 0) { //-V614
-            ++tx_page_offset;
-            ++data_page_offset;
-            --page_length;
-        }
-        memcpy(
-            &tx_buff[tx_page_offset * 4],
-            &emulator->data.data[data_page_offset * 4],
-            page_length * 4);
-    }
-}
-
-static bool mf_ul_check_auth(MfUltralightEmulator* emulator, uint8_t start_page, bool is_write) {
-    if(!emulator->auth_success) {
-        if(start_page >= emulator->config_cache.auth0 &&
-           (emulator->config_cache.access.prot || is_write))
-            return false;
-    }
-
-    if(is_write && emulator->config_cache.access.cfglck) {
-        uint16_t config_start_page = emulator->page_num - 4;
-        if(start_page == config_start_page || start_page == config_start_page + 1) return false;
-    }
-
-    return true;
-}
-
-static bool mf_ul_ntag_i2c_plus_check_auth(
-    MfUltralightEmulator* emulator,
-    uint8_t start_page,
-    bool is_write) {
-    if(!emulator->auth_success) {
-        // Check NFC_PROT
-        if(emulator->curr_sector == 0 && (emulator->config_cache.access.prot || is_write)) {
-            if(start_page >= emulator->config_cache.auth0) return false;
-        } else if(emulator->curr_sector == 1) {
-            // We don't have to specifically check for type because this is done
-            // by address translator
-            uint8_t pt_i2c = emulator->data.data[231 * 4];
-            // Check 2K_PROT
-            if(pt_i2c & 0x08) return false;
-        }
-    }
-
-    if(emulator->curr_sector == 1) {
-        // Check NFC_DIS_SEC1
-        if(emulator->config_cache.access.nfc_dis_sec1) return false;
-    }
-
-    return true;
-}
-
-static int16_t mf_ul_get_dynamic_lock_page_addr(MfUltralightData* data) {
-    switch(data->type) {
-    case MfUltralightTypeNTAG203:
-        return 0x28;
-    case MfUltralightTypeUL21:
-    case MfUltralightTypeNTAG213:
-    case MfUltralightTypeNTAG215:
-    case MfUltralightTypeNTAG216:
-        return data->data_size / 4 - 5;
-    case MfUltralightTypeNTAGI2C1K:
-    case MfUltralightTypeNTAGI2CPlus1K:
-    case MfUltralightTypeNTAGI2CPlus2K:
-        return 0xe2;
-    case MfUltralightTypeNTAGI2C2K:
-        return 0x1e0;
-    default:
-        return -1; // No dynamic lock bytes
-    }
-}
-
-// Returns true if page not locked
-// write_page is tag address
-static bool mf_ul_check_lock(MfUltralightEmulator* emulator, int16_t write_page) {
-    if(write_page < 2) return false; // Page 0-1 is always locked
-    if(write_page == 2) return true; // Page 2 does not have a lock flag
-
-    // Check static lock bytes
-    if(write_page <= 15) {
-        uint16_t static_lock_bytes = emulator->data.data[10] | (emulator->data.data[11] << 8);
-        return (static_lock_bytes & (1 << write_page)) == 0;
-    }
-
-    // Check dynamic lock bytes
-
-    // Check max page
-    switch(emulator->data.type) {
-    case MfUltralightTypeNTAG203:
-        // Counter page can be locked and is after dynamic locks
-        if(write_page == 40) return true;
-        break;
-    case MfUltralightTypeUL21:
-    case MfUltralightTypeNTAG213:
-    case MfUltralightTypeNTAG215:
-    case MfUltralightTypeNTAG216:
-        if(write_page >= emulator->page_num - 5) return true;
-        break;
-    case MfUltralightTypeNTAGI2C1K:
-    case MfUltralightTypeNTAGI2CPlus1K:
-        if(write_page > 225) return true;
-        break;
-    case MfUltralightTypeNTAGI2C2K:
-        if(write_page > 479) return true;
-        break;
-    case MfUltralightTypeNTAGI2CPlus2K:
-        if(write_page >= 226 && write_page <= 255) return true;
-        if(write_page >= 512) return true;
-        break;
-    default:
-        furi_crash("Unknown MFUL");
-        return true;
-    }
-
-    int16_t dynamic_lock_index = mf_ul_get_dynamic_lock_page_addr(&emulator->data);
-    if(dynamic_lock_index == -1) return true;
-    // Run address through converter because NTAG I2C 2K is special
-    uint16_t valid_pages; // unused
-    dynamic_lock_index =
-        mf_ultralight_ntag_i2c_addr_tag_to_lin(
-            &emulator->data, dynamic_lock_index & 0xff, dynamic_lock_index >> 8, &valid_pages) *
-        4;
-
-    uint16_t dynamic_lock_bytes = emulator->data.data[dynamic_lock_index] |
-                                  (emulator->data.data[dynamic_lock_index + 1] << 8);
-    uint8_t shift;
-
-    switch(emulator->data.type) {
-    // low byte LSB range, MSB range
-    case MfUltralightTypeNTAG203:
-        if(write_page >= 16 && write_page <= 27) //-V560
-            shift = (write_page - 16) / 4 + 1;
-        else if(write_page >= 28 && write_page <= 39) //-V560
-            shift = (write_page - 28) / 4 + 5;
-        else if(write_page == 41)
-            shift = 12;
-        else {
-            furi_crash("Unknown MFUL");
-        }
-
-        break;
-    case MfUltralightTypeUL21:
-    case MfUltralightTypeNTAG213:
-        // 16-17, 30-31
-        shift = (write_page - 16) / 2;
-        break;
-    case MfUltralightTypeNTAG215:
-    case MfUltralightTypeNTAG216:
-    case MfUltralightTypeNTAGI2C1K:
-    case MfUltralightTypeNTAGI2CPlus1K:
-        // 16-31, 128-129
-        // 16-31, 128-143
-        shift = (write_page - 16) / 16;
-        break;
-    case MfUltralightTypeNTAGI2C2K:
-        // 16-47, 240-271
-        shift = (write_page - 16) / 32;
-        break;
-    case MfUltralightTypeNTAGI2CPlus2K:
-        // 16-47, 256-271
-        if(write_page >= 208 && write_page <= 225)
-            shift = 6;
-        else if(write_page >= 256 && write_page <= 271)
-            shift = 7;
-        else
-            shift = (write_page - 16) / 32;
-        break;
-    default:
-        furi_crash("Unknown MFUL");
-        break;
-    }
-
-    return (dynamic_lock_bytes & (1 << shift)) == 0;
-}
-
-static void mf_ul_make_ascii_mirror(MfUltralightEmulator* emulator, FuriString* str) {
-    // Locals to improve readability
-    uint8_t mirror_page = emulator->config->mirror_page;
-    uint8_t mirror_byte = emulator->config->mirror.mirror_byte;
-    MfUltralightMirrorConf mirror_conf = emulator->config_cache.mirror.mirror_conf;
-    uint16_t last_user_page_index = emulator->page_num - 6;
-    bool uid_printed = false;
-
-    if(mirror_conf == MfUltralightMirrorUid || mirror_conf == MfUltralightMirrorUidCounter) {
-        // UID range check
-        if(mirror_page < 4 || mirror_page > last_user_page_index - 3 ||
-           (mirror_page == last_user_page_index - 3 && mirror_byte > 2)) {
-            if(mirror_conf == MfUltralightMirrorUid) return;
-            // NTAG21x has the peculiar behavior when UID+counter selected, if UID does not fit but
-            // counter will fit, it will actually mirror the counter
-            furi_string_cat(str, "              ");
-        } else {
-            for(int i = 0; i < 3; ++i) {
-                furi_string_cat_printf(str, "%02X", emulator->data.data[i]);
-            }
-            // Skip BCC0
-            for(int i = 4; i < 8; ++i) {
-                furi_string_cat_printf(str, "%02X", emulator->data.data[i]);
-            }
-            uid_printed = true;
-        }
-
-        uint16_t next_byte_offset = mirror_page * 4 + mirror_byte + 14;
-        if(mirror_conf == MfUltralightMirrorUidCounter) ++next_byte_offset;
-        mirror_page = next_byte_offset / 4;
-        mirror_byte = next_byte_offset % 4;
-    }
-
-    if(mirror_conf == MfUltralightMirrorCounter || mirror_conf == MfUltralightMirrorUidCounter) {
-        // Counter is only printed if counter enabled
-        if(emulator->config_cache.access.nfc_cnt_en) {
-            // Counter protection check
-            if(emulator->config_cache.access.nfc_cnt_pwd_prot && !emulator->auth_success) return;
-            // Counter range check
-            if(mirror_page < 4) return;
-            if(mirror_page > last_user_page_index - 1) return;
-            if(mirror_page == last_user_page_index - 1 && mirror_byte > 2) return;
-
-            if(mirror_conf == MfUltralightMirrorUidCounter)
-                furi_string_cat(str, uid_printed ? "x" : " ");
-
-            furi_string_cat_printf(str, "%06lX", emulator->data.counter[2]);
-        }
-    }
-}
-
-static void mf_ul_increment_single_counter(MfUltralightEmulator* emulator) {
-    if(!emulator->read_counter_incremented && emulator->config_cache.access.nfc_cnt_en) {
-        if(emulator->data.counter[2] < 0xFFFFFF) {
-            ++emulator->data.counter[2];
-            emulator->data_changed = true;
-        }
-        emulator->read_counter_incremented = true;
-    }
-}
-
-static bool
-    mf_ul_emulate_ntag203_counter_write(MfUltralightEmulator* emulator, uint8_t* page_buff) {
-    // We'll reuse the existing counters for other NTAGs as staging
-    // Counter 0 stores original value, data is new value
-    uint32_t counter_value;
-    if(emulator->data.tearing[0] == MF_UL_TEARING_FLAG_DEFAULT) {
-        counter_value = emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] |
-                        (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8);
-    } else {
-        // We've had a reset here, so load from original value
-        counter_value = emulator->data.counter[0];
-    }
-    // Although the datasheet says increment by 0 is always possible, this is not the case on
-    // an actual tag. If the counter is at 0xFFFF, any writes are locked out.
-    if(counter_value == 0xFFFF) return false;
-    uint32_t increment = page_buff[0] | (page_buff[1] << 8);
-    if(counter_value == 0) {
-        counter_value = increment;
-    } else {
-        // Per datasheet specifying > 0x000F is supposed to NAK, but actual tag doesn't
-        increment &= 0x000F;
-        if(counter_value + increment > 0xFFFF) return false;
-        counter_value += increment;
-    }
-    // Commit to new value counter
-    emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = (uint8_t)counter_value;
-    emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = (uint8_t)(counter_value >> 8);
-    emulator->data.tearing[0] = MF_UL_TEARING_FLAG_DEFAULT;
-    if(counter_value == 0xFFFF) {
-        // Tag will lock out counter if final number is 0xFFFF, even if you try to roll it back
-        emulator->data.counter[1] = 0xFFFF;
-    }
-    emulator->data_changed = true;
-    return true;
-}
-
-static void mf_ul_emulate_write(
-    MfUltralightEmulator* emulator,
-    int16_t tag_addr,
-    int16_t write_page,
-    uint8_t* page_buff) {
-    // Assumption: all access checks have been completed
-
-    if(tag_addr == 2) {
-        // Handle static locks
-        uint16_t orig_static_locks = emulator->data.data[write_page * 4 + 2] |
-                                     (emulator->data.data[write_page * 4 + 3] << 8);
-        uint16_t new_static_locks = page_buff[2] | (page_buff[3] << 8);
-        if(orig_static_locks & 1) new_static_locks &= ~0x08;
-        if(orig_static_locks & 2) new_static_locks &= ~0xF0;
-        if(orig_static_locks & 4) new_static_locks &= 0xFF;
-        new_static_locks |= orig_static_locks;
-        page_buff[0] = emulator->data.data[write_page * 4];
-        page_buff[1] = emulator->data.data[write_page * 4 + 1];
-        page_buff[2] = new_static_locks & 0xff;
-        page_buff[3] = new_static_locks >> 8;
-    } else if(tag_addr == 3) {
-        // Handle OTP/capability container
-        *(uint32_t*)page_buff |= *(uint32_t*)&emulator->data.data[write_page * 4];
-    } else if(tag_addr == mf_ul_get_dynamic_lock_page_addr(&emulator->data)) {
-        // Handle dynamic locks
-        if(emulator->data.type == MfUltralightTypeNTAG203) {
-            // NTAG203 lock bytes are a bit different from the others
-            uint8_t orig_page_lock_byte = emulator->data.data[write_page * 4];
-            uint8_t orig_cnt_lock_byte = emulator->data.data[write_page * 4 + 1];
-            uint8_t new_page_lock_byte = page_buff[0];
-            uint8_t new_cnt_lock_byte = page_buff[1];
-
-            if(orig_page_lock_byte & 0x01) // Block lock bits 1-3
-                new_page_lock_byte &= ~0x0E;
-            if(orig_page_lock_byte & 0x10) // Block lock bits 5-7
-                new_page_lock_byte &= ~0xE0;
-            for(uint8_t i = 0; i < 4; ++i) {
-                if(orig_cnt_lock_byte & (1 << i)) // Block lock counter bit
-                    new_cnt_lock_byte &= ~(1 << (4 + i));
-            }
-
-            new_page_lock_byte |= orig_page_lock_byte;
-            new_cnt_lock_byte |= orig_cnt_lock_byte;
-            page_buff[0] = new_page_lock_byte;
-            page_buff[1] = new_cnt_lock_byte;
-        } else {
-            uint16_t orig_locks = emulator->data.data[write_page * 4] |
-                                  (emulator->data.data[write_page * 4 + 1] << 8);
-            uint8_t orig_block_locks = emulator->data.data[write_page * 4 + 2];
-            uint16_t new_locks = page_buff[0] | (page_buff[1] << 8);
-            uint8_t new_block_locks = page_buff[2];
-
-            int block_lock_count;
-            switch(emulator->data.type) {
-            case MfUltralightTypeUL21:
-                block_lock_count = 5;
-                break;
-            case MfUltralightTypeNTAG213:
-                block_lock_count = 6;
-                break;
-            case MfUltralightTypeNTAG215:
-                block_lock_count = 4;
-                break;
-            case MfUltralightTypeNTAG216:
-            case MfUltralightTypeNTAGI2C1K:
-            case MfUltralightTypeNTAGI2CPlus1K:
-                block_lock_count = 7;
-                break;
-            case MfUltralightTypeNTAGI2C2K:
-            case MfUltralightTypeNTAGI2CPlus2K:
-                block_lock_count = 8;
-                break;
-            default:
-                furi_crash("Unknown MFUL");
-                break;
-            }
-
-            for(int i = 0; i < block_lock_count; ++i) {
-                if(orig_block_locks & (1 << i)) new_locks &= ~(3 << (2 * i));
-            }
-
-            new_locks |= orig_locks;
-            new_block_locks |= orig_block_locks;
-
-            page_buff[0] = new_locks & 0xff;
-            page_buff[1] = new_locks >> 8;
-            page_buff[2] = new_block_locks;
-            if(emulator->data.type >= MfUltralightTypeUL21 && //-V1016
-               emulator->data.type <= MfUltralightTypeNTAG216)
-                page_buff[3] = MF_UL_TEARING_FLAG_DEFAULT;
-            else
-                page_buff[3] = 0;
-        }
-    }
-
-    memcpy(&emulator->data.data[write_page * 4], page_buff, 4);
-    emulator->data_changed = true;
-}
-
-bool mf_ul_emulation_supported(MfUltralightData* data) {
-    return data->type != MfUltralightTypeULC;
-}
-
-void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) {
-    emulator->comp_write_cmd_started = false;
-    emulator->sector_select_cmd_started = false;
-    emulator->curr_sector = 0;
-    emulator->ntag_i2c_plus_sector3_lockout = false;
-    emulator->auth_success = false;
-    if(is_power_cycle) {
-        if(emulator->config != NULL) emulator->config_cache = *emulator->config;
-
-        if(emulator->supported_features & MfUltralightSupportSingleCounter) {
-            emulator->read_counter_incremented = false;
-        }
-
-        if(emulator->data.type == MfUltralightTypeNTAG203) {
-            // Apply lockout if counter ever reached 0xFFFF
-            if(emulator->data.counter[1] == 0xFFFF) {
-                emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] = 0xFF;
-                emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] = 0xFF;
-            }
-            // Copy original counter value from data
-            emulator->data.counter[0] =
-                emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4] |
-                (emulator->data.data[MF_UL_NTAG203_COUNTER_PAGE * 4 + 1] << 8);
-        }
-    } else {
-        if(emulator->config != NULL) {
-            // ACCESS (less CFGLCK) and AUTH0 are updated when reactivated
-            // MIRROR_CONF is not; don't know about STRG_MOD_EN, but we're not using that anyway
-            emulator->config_cache.access.value = (emulator->config->access.value & 0xBF) |
-                                                  (emulator->config_cache.access.value & 0x40);
-            emulator->config_cache.auth0 = emulator->config->auth0;
-        }
-    }
-    if(emulator->data.type == MfUltralightTypeNTAG203) {
-        // Mark counter as dirty
-        emulator->data.tearing[0] = 0;
-    }
-}
-
-void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) {
-    FURI_LOG_D(TAG, "Prepare emulation");
-    emulator->data = *data;
-    emulator->supported_features = mf_ul_get_features(data->type);
-    emulator->config = mf_ultralight_get_config_pages(&emulator->data);
-    emulator->page_num = emulator->data.data_size / 4;
-    emulator->data_changed = false;
-    memset(&emulator->auth_attempt, 0, sizeof(MfUltralightAuth));
-    mf_ul_reset_emulation(emulator, true);
-}
-
-bool mf_ul_prepare_emulation_response(
-    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);
-    MfUltralightEmulator* emulator = context;
-    uint16_t tx_bytes = 0;
-    uint16_t tx_bits = 0;
-    bool command_parsed = false;
-    bool send_ack = false;
-    bool respond_nothing = false;
-    bool reset_idle = false;
-
-#ifdef FURI_DEBUG
-    FuriString* debug_buf;
-    debug_buf = furi_string_alloc();
-    for(int i = 0; i < (buff_rx_len + 7) / 8; ++i) {
-        furi_string_cat_printf(debug_buf, "%02x ", buff_rx[i]);
-    }
-    furi_string_trim(debug_buf);
-    FURI_LOG_T(TAG, "Emu RX (%d): %s", buff_rx_len, furi_string_get_cstr(debug_buf));
-    furi_string_reset(debug_buf);
-#endif
-
-    // Check composite commands
-    if(emulator->comp_write_cmd_started) {
-        if(buff_rx_len == 16 * 8) {
-            if(emulator->data.type == MfUltralightTypeNTAG203 &&
-               emulator->comp_write_page_addr == MF_UL_NTAG203_COUNTER_PAGE) {
-                send_ack = mf_ul_emulate_ntag203_counter_write(emulator, buff_rx);
-                command_parsed = send_ack;
-            } else {
-                mf_ul_emulate_write(
-                    emulator,
-                    emulator->comp_write_page_addr,
-                    emulator->comp_write_page_addr,
-                    buff_rx);
-                send_ack = true;
-                command_parsed = true;
-            }
-        }
-        emulator->comp_write_cmd_started = false;
-    } else if(emulator->sector_select_cmd_started) {
-        if(buff_rx_len == 4 * 8) {
-            if(buff_rx[0] <= 0xFE) {
-                emulator->curr_sector = buff_rx[0] > 3 ? 0 : buff_rx[0];
-                emulator->ntag_i2c_plus_sector3_lockout = false;
-                command_parsed = true;
-                respond_nothing = true;
-                FURI_LOG_D(TAG, "Changing sector to %d", emulator->curr_sector);
-            }
-        }
-        emulator->sector_select_cmd_started = false;
-    } else if(buff_rx_len >= 8) {
-        uint8_t cmd = buff_rx[0];
-        if(cmd == MF_UL_GET_VERSION_CMD) {
-            if(emulator->data.type >= MfUltralightTypeUL11) {
-                if(buff_rx_len == 1 * 8) {
-                    tx_bytes = sizeof(emulator->data.version);
-                    memcpy(buff_tx, &emulator->data.version, tx_bytes);
-                    *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                    command_parsed = true;
-                }
-            }
-        } else if(cmd == MF_UL_READ_CMD) {
-            if(buff_rx_len == (1 + 1) * 8) {
-                int16_t start_page = buff_rx[1];
-                tx_bytes = 16;
-                if(emulator->data.type < MfUltralightTypeNTAGI2C1K) {
-                    if(start_page < emulator->page_num) {
-                        do {
-                            uint8_t copied_pages = 0;
-                            uint8_t src_page = start_page;
-                            uint8_t last_page_plus_one = start_page + 4;
-                            uint8_t pwd_page = emulator->page_num - 2;
-                            FuriString* ascii_mirror = NULL;
-                            size_t ascii_mirror_len = 0;
-                            const char* ascii_mirror_cptr = NULL;
-                            uint8_t ascii_mirror_curr_page = 0;
-                            uint8_t ascii_mirror_curr_byte = 0;
-                            if(last_page_plus_one > emulator->page_num)
-                                last_page_plus_one = emulator->page_num;
-                            if(emulator->supported_features & MfUltralightSupportAuth) {
-                                if(!mf_ul_check_auth(emulator, start_page, false)) break;
-                                if(!emulator->auth_success && emulator->config_cache.access.prot &&
-                                   emulator->config_cache.auth0 < last_page_plus_one)
-                                    last_page_plus_one = emulator->config_cache.auth0;
-                            }
-                            if(emulator->supported_features & MfUltralightSupportSingleCounter)
-                                mf_ul_increment_single_counter(emulator);
-                            if(emulator->supported_features & MfUltralightSupportAsciiMirror &&
-                               emulator->config_cache.mirror.mirror_conf !=
-                                   MfUltralightMirrorNone) {
-                                ascii_mirror_curr_byte = emulator->config->mirror.mirror_byte;
-                                ascii_mirror_curr_page = emulator->config->mirror_page;
-                                // Try to avoid wasting time making mirror if we won't copy it
-                                // Conservatively check with UID+counter mirror size
-                                if(last_page_plus_one > ascii_mirror_curr_page &&
-                                   start_page + 3 >= ascii_mirror_curr_page &&
-                                   start_page <= ascii_mirror_curr_page + 6) {
-                                    ascii_mirror = furi_string_alloc();
-                                    mf_ul_make_ascii_mirror(emulator, ascii_mirror);
-                                    ascii_mirror_len = furi_string_utf8_length(ascii_mirror);
-                                    ascii_mirror_cptr = furi_string_get_cstr(ascii_mirror);
-                                    // Move pointer to where it should be to start copying
-                                    if(ascii_mirror_len > 0 &&
-                                       ascii_mirror_curr_page < start_page &&
-                                       ascii_mirror_curr_byte != 0) {
-                                        uint8_t diff = 4 - ascii_mirror_curr_byte;
-                                        ascii_mirror_len -= diff;
-                                        ascii_mirror_cptr += diff;
-                                        ascii_mirror_curr_byte = 0;
-                                        ++ascii_mirror_curr_page;
-                                    }
-                                    while(ascii_mirror_len > 0 &&
-                                          ascii_mirror_curr_page < start_page) {
-                                        uint8_t diff = ascii_mirror_len > 4 ? 4 : ascii_mirror_len;
-                                        ascii_mirror_len -= diff;
-                                        ascii_mirror_cptr += diff;
-                                        ++ascii_mirror_curr_page;
-                                    }
-                                }
-                            }
-
-                            uint8_t* dest_ptr = buff_tx;
-                            while(copied_pages < 4) {
-                                // Copy page
-                                memcpy(dest_ptr, &emulator->data.data[src_page * 4], 4);
-
-                                // Note: don't have to worry about roll-over with ASCII mirror because
-                                // lowest valid page for it is 4, while roll-over will at best read
-                                // pages 0-2
-                                if(ascii_mirror_len > 0 && src_page == ascii_mirror_curr_page) {
-                                    // Copy ASCII mirror
-                                    size_t copy_len = 4 - ascii_mirror_curr_byte;
-                                    if(copy_len > ascii_mirror_len) copy_len = ascii_mirror_len;
-                                    for(size_t i = 0; i < copy_len; ++i) {
-                                        if(*ascii_mirror_cptr != ' ')
-                                            dest_ptr[ascii_mirror_curr_byte] =
-                                                (uint8_t)*ascii_mirror_cptr;
-                                        ++ascii_mirror_curr_byte;
-                                        ++ascii_mirror_cptr;
-                                    }
-                                    ascii_mirror_len -= copy_len;
-                                    // Don't care if this is inaccurate after ascii_mirror_len = 0
-                                    ascii_mirror_curr_byte = 0;
-                                    ++ascii_mirror_curr_page;
-                                }
-
-                                if(emulator->supported_features & MfUltralightSupportAuth) {
-                                    if(src_page == pwd_page || src_page == pwd_page + 1) {
-                                        // Blank out PWD and PACK pages
-                                        memset(dest_ptr, 0, 4);
-                                    }
-                                }
-
-                                dest_ptr += 4;
-                                ++copied_pages;
-                                ++src_page;
-                                if(src_page >= last_page_plus_one) src_page = 0;
-                            }
-                            if(ascii_mirror != NULL) {
-                                furi_string_free(ascii_mirror);
-                            }
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            command_parsed = true;
-                        } while(false);
-                    }
-                } else {
-                    uint16_t valid_pages;
-                    start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin(
-                        &emulator->data, start_page, emulator->curr_sector, &valid_pages);
-                    if(start_page != -1) {
-                        if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K ||
-                           mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) {
-                            if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K &&
-                               emulator->curr_sector == 3 && valid_pages == 1) {
-                                // Rewind back a sector to match behavior on a real tag
-                                --start_page;
-                                ++valid_pages;
-                            }
-
-                            uint16_t copy_count = (valid_pages > 4 ? 4 : valid_pages) * 4;
-                            FURI_LOG_D(
-                                TAG,
-                                "NTAG I2C Emu: page valid, %02x:%02x -> %d, %d",
-                                emulator->curr_sector,
-                                buff_rx[1],
-                                start_page,
-                                valid_pages);
-                            memcpy(buff_tx, &emulator->data.data[start_page * 4], copy_count);
-                            // For NTAG I2C, there's no roll-over; remainder is filled by null bytes
-                            if(copy_count < tx_bytes)
-                                memset(&buff_tx[copy_count], 0, tx_bytes - copy_count);
-                            // Special case: NTAG I2C Plus sector 0 page 233 read crosses into page 236
-                            if(start_page == 233)
-                                memcpy(
-                                    &buff_tx[12], &emulator->data.data[(start_page + 1) * 4], 4);
-                            mf_ul_protect_auth_data_on_read_command_i2c(
-                                buff_tx, start_page, start_page + copy_count / 4 - 1, emulator);
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            command_parsed = true;
-                        }
-                    } else {
-                        FURI_LOG_D(
-                            TAG,
-                            "NTAG I2C Emu: page invalid, %02x:%02x",
-                            emulator->curr_sector,
-                            buff_rx[1]);
-                        if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K &&
-                           emulator->curr_sector == 3 &&
-                           !emulator->ntag_i2c_plus_sector3_lockout) {
-                            // NTAG I2C Plus has a weird behavior where if you read sector 3
-                            // at an invalid address, it responds with zeroes then locks
-                            // the read out, while if you read the mirrored session registers,
-                            // it returns both session registers on either pages
-                            memset(buff_tx, 0, tx_bytes);
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            command_parsed = true;
-                            emulator->ntag_i2c_plus_sector3_lockout = true;
-                        }
-                    }
-                }
-                if(!command_parsed) tx_bytes = 0;
-            }
-        } else if(cmd == MF_UL_FAST_READ_CMD) {
-            if(emulator->supported_features & MfUltralightSupportFastRead) {
-                if(buff_rx_len == (1 + 2) * 8) {
-                    int16_t start_page = buff_rx[1];
-                    uint8_t end_page = buff_rx[2];
-                    if(start_page <= end_page) {
-                        tx_bytes = ((end_page + 1) - start_page) * 4;
-                        if(emulator->data.type < MfUltralightTypeNTAGI2C1K) {
-                            if((start_page < emulator->page_num) &&
-                               (end_page < emulator->page_num)) {
-                                do {
-                                    if(emulator->supported_features & MfUltralightSupportAuth) {
-                                        // NAK if not authenticated and requested pages cross over AUTH0
-                                        if(!emulator->auth_success &&
-                                           emulator->config_cache.access.prot &&
-                                           (start_page >= emulator->config_cache.auth0 ||
-                                            end_page >= emulator->config_cache.auth0))
-                                            break;
-                                    }
-                                    if(emulator->supported_features &
-                                       MfUltralightSupportSingleCounter)
-                                        mf_ul_increment_single_counter(emulator);
-
-                                    // Copy requested pages
-                                    memcpy(
-                                        buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
-
-                                    if(emulator->supported_features &
-                                           MfUltralightSupportAsciiMirror &&
-                                       emulator->config_cache.mirror.mirror_conf !=
-                                           MfUltralightMirrorNone) {
-                                        // Copy ASCII mirror
-                                        // Less stringent check here, because expecting FAST_READ to
-                                        // only be issued once rather than repeatedly
-                                        FuriString* ascii_mirror;
-                                        ascii_mirror = furi_string_alloc();
-                                        mf_ul_make_ascii_mirror(emulator, ascii_mirror);
-                                        size_t ascii_mirror_len =
-                                            furi_string_utf8_length(ascii_mirror);
-                                        const char* ascii_mirror_cptr =
-                                            furi_string_get_cstr(ascii_mirror);
-                                        int16_t mirror_start_offset =
-                                            (emulator->config->mirror_page - start_page) * 4 +
-                                            emulator->config->mirror.mirror_byte;
-                                        if(mirror_start_offset < 0) {
-                                            if(mirror_start_offset < -(int16_t)ascii_mirror_len) {
-                                                // Past ASCII mirror, don't copy
-                                                ascii_mirror_len = 0;
-                                            } else {
-                                                ascii_mirror_cptr += -mirror_start_offset;
-                                                ascii_mirror_len -= -mirror_start_offset;
-                                                mirror_start_offset = 0;
-                                            }
-                                        }
-                                        if(ascii_mirror_len > 0) {
-                                            int16_t mirror_end_offset =
-                                                mirror_start_offset + ascii_mirror_len;
-                                            if(mirror_end_offset > (end_page + 1) * 4) {
-                                                mirror_end_offset = (end_page + 1) * 4;
-                                                ascii_mirror_len =
-                                                    mirror_end_offset - mirror_start_offset;
-                                            }
-                                            for(size_t i = 0; i < ascii_mirror_len; ++i) {
-                                                if(*ascii_mirror_cptr != ' ')
-                                                    buff_tx[mirror_start_offset] =
-                                                        (uint8_t)*ascii_mirror_cptr;
-                                                ++mirror_start_offset;
-                                                ++ascii_mirror_cptr;
-                                            }
-                                        }
-                                        furi_string_free(ascii_mirror);
-                                    }
-
-                                    if(emulator->supported_features & MfUltralightSupportAuth) {
-                                        // Clear PWD and PACK pages
-                                        uint8_t pwd_page = emulator->page_num - 2;
-                                        int16_t pwd_page_offset = pwd_page - start_page;
-                                        // PWD page
-                                        if(pwd_page_offset >= 0 && pwd_page <= end_page) {
-                                            memset(&buff_tx[pwd_page_offset * 4], 0, 4);
-                                            // PACK page
-                                            if(pwd_page + 1 <= end_page)
-                                                memset(&buff_tx[(pwd_page_offset + 1) * 4], 0, 4);
-                                        }
-                                    }
-                                    *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                                    command_parsed = true;
-                                } while(false);
-                            }
-                        } else {
-                            uint16_t valid_pages;
-                            start_page = mf_ultralight_ntag_i2c_addr_tag_to_lin(
-                                &emulator->data, start_page, emulator->curr_sector, &valid_pages);
-                            if(start_page != -1) {
-                                if(emulator->data.type < MfUltralightTypeNTAGI2CPlus1K ||
-                                   mf_ul_ntag_i2c_plus_check_auth(emulator, buff_rx[1], false)) {
-                                    uint16_t copy_count = tx_bytes;
-                                    if(copy_count > valid_pages * 4) copy_count = valid_pages * 4;
-                                    memcpy(
-                                        buff_tx, &emulator->data.data[start_page * 4], copy_count);
-                                    if(copy_count < tx_bytes)
-                                        memset(&buff_tx[copy_count], 0, tx_bytes - copy_count);
-                                    mf_ul_ntag_i2c_fill_cross_area_read(
-                                        buff_tx, buff_rx[1], buff_rx[2], emulator);
-                                    mf_ul_protect_auth_data_on_read_command_i2c(
-                                        buff_tx,
-                                        start_page,
-                                        start_page + copy_count / 4 - 1,
-                                        emulator);
-                                    *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                                    command_parsed = true;
-                                }
-                            }
-                        }
-                        if(!command_parsed) tx_bytes = 0;
-                    }
-                }
-            }
-        } else if(cmd == MF_UL_WRITE) {
-            if(buff_rx_len == (1 + 5) * 8) {
-                do {
-                    uint8_t orig_write_page = buff_rx[1];
-                    int16_t write_page = orig_write_page;
-                    uint16_t valid_pages; // unused
-                    write_page = mf_ultralight_ntag_i2c_addr_tag_to_lin(
-                        &emulator->data, write_page, emulator->curr_sector, &valid_pages);
-                    if(write_page == -1) // NTAG I2C range check
-                        break;
-                    else if(write_page < 2 || write_page >= emulator->page_num) // Other MFUL/NTAG range check
-                        break;
-
-                    if(emulator->supported_features & MfUltralightSupportAuth) {
-                        if(emulator->data.type >= MfUltralightTypeNTAGI2CPlus1K) {
-                            if(!mf_ul_ntag_i2c_plus_check_auth(emulator, orig_write_page, true))
-                                break;
-                        } else {
-                            if(!mf_ul_check_auth(emulator, orig_write_page, true)) break;
-                        }
-                    }
-                    int16_t tag_addr = mf_ultralight_page_addr_to_tag_addr(
-                        emulator->curr_sector, orig_write_page);
-                    if(!mf_ul_check_lock(emulator, tag_addr)) break;
-                    if(emulator->data.type == MfUltralightTypeNTAG203 &&
-                       orig_write_page == MF_UL_NTAG203_COUNTER_PAGE) {
-                        send_ack = mf_ul_emulate_ntag203_counter_write(emulator, &buff_rx[2]);
-                        command_parsed = send_ack;
-                    } else {
-                        mf_ul_emulate_write(emulator, tag_addr, write_page, &buff_rx[2]);
-                        send_ack = true;
-                        command_parsed = true;
-                    }
-                } while(false);
-            }
-        } else if(cmd == MF_UL_FAST_WRITE) {
-            if(emulator->supported_features & MfUltralightSupportFastWrite) {
-                if(buff_rx_len == (1 + 66) * 8) {
-                    if(buff_rx[1] == 0xF0 && buff_rx[2] == 0xFF) {
-                        // TODO: update when SRAM emulation implemented
-                        send_ack = true;
-                        command_parsed = true;
-                    }
-                }
-            }
-        } else if(cmd == MF_UL_COMP_WRITE) {
-            if(emulator->supported_features & MfUltralightSupportCompatWrite) {
-                if(buff_rx_len == (1 + 1) * 8) {
-                    uint8_t write_page = buff_rx[1];
-                    do {
-                        if(write_page < 2 || write_page >= emulator->page_num) break;
-                        if(emulator->supported_features & MfUltralightSupportAuth &&
-                           !mf_ul_check_auth(emulator, write_page, true))
-                            break;
-                        // Note we don't convert to tag addr here because there's only one sector
-                        if(!mf_ul_check_lock(emulator, write_page)) break;
-
-                        emulator->comp_write_cmd_started = true;
-                        emulator->comp_write_page_addr = write_page;
-                        send_ack = true;
-                        command_parsed = true;
-                    } while(false);
-                }
-            }
-        } else if(cmd == MF_UL_READ_CNT) {
-            if(emulator->supported_features & MfUltralightSupportReadCounter) {
-                if(buff_rx_len == (1 + 1) * 8) {
-                    do {
-                        uint8_t cnt_num = buff_rx[1];
-
-                        // NTAG21x checks
-                        if(emulator->supported_features & MfUltralightSupportSingleCounter) {
-                            if(cnt_num != 2) break; // Only counter 2 is available
-                            if(!emulator->config_cache.access.nfc_cnt_en)
-                                break; // NAK if counter not enabled
-                            if(emulator->config_cache.access.nfc_cnt_pwd_prot &&
-                               !emulator->auth_success)
-                                break;
-                        }
-
-                        if(cnt_num < 3) {
-                            buff_tx[0] = emulator->data.counter[cnt_num] & 0xFF;
-                            buff_tx[1] = (emulator->data.counter[cnt_num] >> 8) & 0xFF;
-                            buff_tx[2] = (emulator->data.counter[cnt_num] >> 16) & 0xFF;
-                            tx_bytes = 3;
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            command_parsed = true;
-                        }
-                    } while(false);
-                }
-            }
-        } else if(cmd == MF_UL_INC_CNT) {
-            if(emulator->supported_features & MfUltralightSupportIncrCounter) {
-                if(buff_rx_len == (1 + 5) * 8) {
-                    uint8_t cnt_num = buff_rx[1];
-                    uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
-                    // TODO: can you increment by 0 when counter is at 0xffffff?
-                    if((cnt_num < 3) && (emulator->data.counter[cnt_num] != 0x00FFFFFF) &&
-                       (emulator->data.counter[cnt_num] + inc <= 0x00FFFFFF)) {
-                        emulator->data.counter[cnt_num] += inc;
-                        // We're RAM-backed, so tearing never happens
-                        emulator->data.tearing[cnt_num] = MF_UL_TEARING_FLAG_DEFAULT;
-                        emulator->data_changed = true;
-                        send_ack = true;
-                        command_parsed = true;
-                    }
-                }
-            }
-        } else if(cmd == MF_UL_PWD_AUTH) {
-            if(emulator->supported_features & MfUltralightSupportAuth) {
-                if(buff_rx_len == (1 + 4) * 8) {
-                    // Record password sent by PCD
-                    memcpy(
-                        emulator->auth_attempt.pwd.raw,
-                        &buff_rx[1],
-                        sizeof(emulator->auth_attempt.pwd.raw));
-                    emulator->auth_attempted = true;
-                    if(emulator->auth_received_callback) {
-                        emulator->auth_received_callback(
-                            emulator->auth_attempt, emulator->context);
-                    }
-
-                    uint16_t scaled_authlim = mf_ultralight_calc_auth_count(&emulator->data);
-                    if(scaled_authlim != 0 && emulator->data.curr_authlim >= scaled_authlim) {
-                        if(emulator->data.curr_authlim != UINT16_MAX) {
-                            // Handle case where AUTHLIM has been lowered or changed from 0
-                            emulator->data.curr_authlim = UINT16_MAX;
-                            emulator->data_changed = true;
-                        }
-                        // AUTHLIM reached, always fail
-                        buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED;
-                        tx_bits = 4;
-                        *data_type = FURRY_HAL_NFC_TX_RAW_RX_DEFAULT;
-                        mf_ul_reset_emulation(emulator, false);
-                        command_parsed = true;
-                    } else {
-                        if(memcmp(&buff_rx[1], emulator->config->auth_data.pwd.raw, 4) == 0) {
-                            // Correct password
-                            buff_tx[0] = emulator->config->auth_data.pack.raw[0];
-                            buff_tx[1] = emulator->config->auth_data.pack.raw[1];
-                            tx_bytes = 2;
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            emulator->auth_success = true;
-                            command_parsed = true;
-                            if(emulator->data.curr_authlim != 0) {
-                                // Reset current AUTHLIM
-                                emulator->data.curr_authlim = 0;
-                                emulator->data_changed = true;
-                            }
-                        } else if(!emulator->config->auth_data.pwd.value) {
-                            // Unknown password, pretend to be an Amiibo
-                            buff_tx[0] = 0x80;
-                            buff_tx[1] = 0x80;
-                            tx_bytes = 2;
-                            *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                            emulator->auth_success = true;
-                            command_parsed = true;
-                        } else {
-                            // Wrong password, increase negative verification count
-                            if(emulator->data.curr_authlim < UINT16_MAX) {
-                                ++emulator->data.curr_authlim;
-                                emulator->data_changed = true;
-                            }
-                            if(scaled_authlim != 0 &&
-                               emulator->data.curr_authlim >= scaled_authlim) {
-                                emulator->data.curr_authlim = UINT16_MAX;
-                                buff_tx[0] = MF_UL_NAK_AUTHLIM_REACHED;
-                                tx_bits = 4;
-                                *data_type = FURRY_HAL_NFC_TX_RAW_RX_DEFAULT;
-                                mf_ul_reset_emulation(emulator, false);
-                                command_parsed = true;
-                            } else {
-                                // Should delay here to slow brute forcing
-                            }
-                        }
-                    }
-                }
-            }
-        } else if(cmd == MF_UL_READ_SIG) {
-            if(emulator->supported_features & MfUltralightSupportSignature) {
-                // Check 2nd byte = 0x00 - RFU
-                if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0x00) {
-                    tx_bytes = sizeof(emulator->data.signature);
-                    memcpy(buff_tx, emulator->data.signature, tx_bytes);
-                    *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                    command_parsed = true;
-                }
-            }
-        } else if(cmd == MF_UL_CHECK_TEARING) {
-            if(emulator->supported_features & MfUltralightSupportTearingFlags) {
-                if(buff_rx_len == (1 + 1) * 8) {
-                    uint8_t cnt_num = buff_rx[1];
-                    if(cnt_num < 3) {
-                        buff_tx[0] = emulator->data.tearing[cnt_num];
-                        tx_bytes = 1;
-                        *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                        command_parsed = true;
-                    }
-                }
-            }
-        } else if(cmd == MF_UL_HALT_START) {
-            reset_idle = true;
-            FURI_LOG_D(TAG, "Received HLTA");
-        } else if(cmd == MF_UL_SECTOR_SELECT) {
-            if(emulator->supported_features & MfUltralightSupportSectorSelect) {
-                if(buff_rx_len == (1 + 1) * 8 && buff_rx[1] == 0xFF) {
-                    // Send ACK
-                    emulator->sector_select_cmd_started = true;
-                    send_ack = true;
-                    command_parsed = true;
-                }
-            }
-        } else if(cmd == MF_UL_READ_VCSL) {
-            if(emulator->supported_features & MfUltralightSupportVcsl) {
-                if(buff_rx_len == (1 + 20) * 8) {
-                    buff_tx[0] = emulator->config_cache.vctid;
-                    tx_bytes = 1;
-                    *data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
-                    command_parsed = true;
-                }
-            }
-        } else {
-            // NTAG203 appears to NAK instead of just falling off on invalid commands
-            if(emulator->data.type != MfUltralightTypeNTAG203) reset_idle = true;
-            FURI_LOG_D(TAG, "Received invalid command");
-        }
-    } else {
-        reset_idle = true;
-        FURI_LOG_D(TAG, "Received invalid buffer less than 8 bits in length");
-    }
-
-    if(reset_idle) {
-        mf_ul_reset_emulation(emulator, false);
-        tx_bits = 0;
-        command_parsed = true;
-    }
-
-    if(!command_parsed) {
-        // Send NACK
-        buff_tx[0] = MF_UL_NAK_INVALID_ARGUMENT;
-        tx_bits = 4;
-        *data_type = FURRY_HAL_NFC_TX_RAW_RX_DEFAULT;
-        // Every NAK should cause reset to IDLE
-        mf_ul_reset_emulation(emulator, false);
-    } else if(send_ack) {
-        buff_tx[0] = MF_UL_ACK;
-        tx_bits = 4;
-        *data_type = FURRY_HAL_NFC_TX_RAW_RX_DEFAULT;
-    }
-
-    if(respond_nothing) {
-        *buff_tx_len = UINT16_MAX;
-        *data_type = FURRY_HAL_NFC_TX_RAW_RX_DEFAULT;
-    } else {
-        // Return tx buffer size in bits
-        if(tx_bytes) {
-            tx_bits = tx_bytes * 8;
-        }
-        *buff_tx_len = tx_bits;
-    }
-
-#ifdef FURI_DEBUG
-    if(*buff_tx_len == UINT16_MAX) {
-        FURI_LOG_T(TAG, "Emu TX: no reply");
-    } else if(*buff_tx_len > 0) {
-        int count = (*buff_tx_len + 7) / 8;
-        for(int i = 0; i < count; ++i) {
-            furi_string_cat_printf(debug_buf, "%02x ", buff_tx[i]);
-        }
-        furi_string_trim(debug_buf);
-        FURI_LOG_T(TAG, "Emu TX (%d): %s", *buff_tx_len, furi_string_get_cstr(debug_buf));
-        furi_string_free(debug_buf);
-    } else {
-        FURI_LOG_T(TAG, "Emu TX: HALT");
-    }
-#endif
-
-    return tx_bits > 0;
-}
-
-bool mf_ul_is_full_capture(MfUltralightData* data) {
-    if(data->data_read != data->data_size) return false;
-
-    // Having read all the pages doesn't mean that we've got everything.
-    // By default PWD is 0xFFFFFFFF, but if read back it is always 0x00000000,
-    // so a default read on an auth-supported NTAG is never complete.
-    if(!(mf_ul_get_features(data->type) & MfUltralightSupportAuth)) return true;
-    MfUltralightConfigPages* config = mf_ultralight_get_config_pages(data);
-    return config->auth_data.pwd.value != 0 || config->auth_data.pack.value != 0;
-}

+ 0 - 269
lib/nfclegacy/protocols/mifare_ultralight.h

@@ -1,269 +0,0 @@
-#pragma once
-
-#include "../furi_hal_nfc.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Largest tag is NTAG I2C Plus 2K, both data sectors plus SRAM
-#define MF_UL_MAX_DUMP_SIZE ((238 + 256 + 16) * 4)
-
-#define MF_UL_TEARING_FLAG_DEFAULT (0xBD)
-
-#define MF_UL_HALT_START (0x50)
-#define MF_UL_GET_VERSION_CMD (0x60)
-#define MF_UL_READ_CMD (0x30)
-#define MF_UL_FAST_READ_CMD (0x3A)
-#define MF_UL_WRITE (0xA2)
-#define MF_UL_FAST_WRITE (0xA6)
-#define MF_UL_COMP_WRITE (0xA0)
-#define MF_UL_READ_CNT (0x39)
-#define MF_UL_INC_CNT (0xA5)
-#define MF_UL_AUTHENTICATE_1 (0x1A)
-#define MF_UL_PWD_AUTH (0x1B)
-#define MF_UL_READ_SIG (0x3C)
-#define MF_UL_CHECK_TEARING (0x3E)
-#define MF_UL_READ_VCSL (0x4B)
-#define MF_UL_SECTOR_SELECT (0xC2)
-
-#define MF_UL_ACK (0xa)
-#define MF_UL_NAK_INVALID_ARGUMENT (0x0)
-#define MF_UL_NAK_AUTHLIM_REACHED (0x4)
-
-#define MF_UL_NTAG203_COUNTER_PAGE (41)
-
-#define MF_UL_DEFAULT_PWD (0xFFFFFFFF)
-
-typedef enum {
-    MfUltralightAuthMethodManual,
-    MfUltralightAuthMethodAmeebo,
-    MfUltralightAuthMethodXiaomi,
-    MfUltralightAuthMethodAuto,
-} MfUltralightAuthMethod;
-
-// Important: order matters; some features are based on positioning in this enum
-typedef enum {
-    MfUltralightTypeUnknown,
-    MfUltralightTypeNTAG203,
-    MfUltralightTypeULC,
-    // Below have config pages and GET_VERSION support
-    MfUltralightTypeUL11,
-    MfUltralightTypeUL21,
-    MfUltralightTypeNTAG213,
-    MfUltralightTypeNTAG215,
-    MfUltralightTypeNTAG216,
-    // Below also have sector select
-    // NTAG I2C's *does not* have regular config pages, so it's a bit of an odd duck
-    MfUltralightTypeNTAGI2C1K,
-    MfUltralightTypeNTAGI2C2K,
-    // NTAG I2C Plus has stucture expected from NTAG21x
-    MfUltralightTypeNTAGI2CPlus1K,
-    MfUltralightTypeNTAGI2CPlus2K,
-
-    // Keep last for number of types calculation
-    MfUltralightTypeNum,
-} MfUltralightType;
-
-typedef enum {
-    MfUltralightSupportNone = 0,
-    MfUltralightSupportFastRead = 1 << 0,
-    MfUltralightSupportTearingFlags = 1 << 1,
-    MfUltralightSupportReadCounter = 1 << 2,
-    MfUltralightSupportIncrCounter = 1 << 3,
-    MfUltralightSupportSignature = 1 << 4,
-    MfUltralightSupportFastWrite = 1 << 5,
-    MfUltralightSupportCompatWrite = 1 << 6,
-    MfUltralightSupportAuth = 1 << 7,
-    MfUltralightSupportVcsl = 1 << 8,
-    MfUltralightSupportSectorSelect = 1 << 9,
-    // NTAG21x only has counter 2
-    MfUltralightSupportSingleCounter = 1 << 10,
-    // ASCII mirror is not a command, but handy to have as a flag
-    MfUltralightSupportAsciiMirror = 1 << 11,
-    // NTAG203 counter that's in memory rather than through a command
-    MfUltralightSupportCounterInMemory = 1 << 12,
-    MfUltralightSupport3DesAuth = 1 << 13,
-} MfUltralightFeatures;
-
-typedef enum {
-    MfUltralightMirrorNone,
-    MfUltralightMirrorUid,
-    MfUltralightMirrorCounter,
-    MfUltralightMirrorUidCounter,
-} MfUltralightMirrorConf;
-
-typedef struct {
-    uint8_t header;
-    uint8_t vendor_id;
-    uint8_t prod_type;
-    uint8_t prod_subtype;
-    uint8_t prod_ver_major;
-    uint8_t prod_ver_minor;
-    uint8_t storage_size;
-    uint8_t protocol_type;
-} MfUltralightVersion;
-
-typedef struct {
-    uint8_t sn0[3];
-    uint8_t btBCC0;
-    uint8_t sn1[4];
-    uint8_t btBCC1;
-    uint8_t internal;
-    uint8_t lock[2];
-    uint8_t otp[4];
-} MfUltralightManufacturerBlock;
-
-typedef struct {
-    MfUltralightType type;
-    MfUltralightVersion version;
-    uint8_t signature[32];
-    uint32_t counter[3];
-    uint8_t tearing[3];
-    MfUltralightAuthMethod auth_method;
-    uint8_t auth_key[4];
-    bool auth_success;
-    uint16_t curr_authlim;
-    uint16_t data_size;
-    uint8_t data[MF_UL_MAX_DUMP_SIZE];
-    uint16_t data_read;
-} MfUltralightData;
-
-typedef struct __attribute__((packed)) {
-    union {
-        uint8_t raw[4];
-        uint32_t value;
-    } pwd;
-    union {
-        uint8_t raw[2];
-        uint16_t value;
-    } pack;
-} MfUltralightAuth;
-
-// Common configuration pages for MFUL EV1, NTAG21x, and NTAG I2C Plus
-typedef struct __attribute__((packed)) {
-    union {
-        uint8_t value;
-        struct {
-            uint8_t rfui1 : 2;
-            bool strg_mod_en : 1;
-            bool rfui2 : 1;
-            uint8_t mirror_byte : 2;
-            MfUltralightMirrorConf mirror_conf : 2;
-        };
-    } mirror;
-    uint8_t rfui1;
-    uint8_t mirror_page;
-    uint8_t auth0;
-    union {
-        uint8_t value;
-        struct {
-            uint8_t authlim : 3;
-            bool nfc_cnt_pwd_prot : 1;
-            bool nfc_cnt_en : 1;
-            bool nfc_dis_sec1 : 1; // NTAG I2C Plus only
-            bool cfglck : 1;
-            bool prot : 1;
-        };
-    } access;
-    uint8_t vctid;
-    uint8_t rfui2[2];
-    MfUltralightAuth auth_data;
-    uint8_t rfui3[2];
-} MfUltralightConfigPages;
-
-typedef struct {
-    uint16_t pages_to_read;
-    int16_t pages_read;
-    MfUltralightFeatures supported_features;
-} MfUltralightReader;
-
-// TODO rework with reader analyzer
-typedef void (*MfUltralightAuthReceivedCallback)(MfUltralightAuth auth, void* context);
-
-typedef struct {
-    MfUltralightData data;
-    MfUltralightConfigPages* config;
-    // Most config values don't apply until power cycle, so cache config pages
-    // for correct behavior
-    MfUltralightConfigPages config_cache;
-    MfUltralightFeatures supported_features;
-    uint16_t page_num;
-    bool data_changed;
-    bool comp_write_cmd_started;
-    uint8_t comp_write_page_addr;
-    bool auth_success;
-    uint8_t curr_sector;
-    bool sector_select_cmd_started;
-    bool ntag_i2c_plus_sector3_lockout;
-    bool read_counter_incremented;
-    bool auth_attempted;
-    MfUltralightAuth auth_attempt;
-
-    // TODO rework with reader analyzer
-    MfUltralightAuthReceivedCallback auth_received_callback;
-    void* context;
-} MfUltralightEmulator;
-
-void mf_ul_reset(MfUltralightData* data);
-
-bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
-
-bool mf_ultralight_read_version(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data);
-
-bool mf_ultralight_read_pages_direct(
-    FurryHalNfcTxRxContext* tx_rx,
-    uint8_t start_index,
-    uint8_t* data);
-
-bool mf_ultralight_read_pages(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data);
-
-bool mf_ultralight_fast_read_pages(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data);
-
-bool mf_ultralight_read_signature(FurryHalNfcTxRxContext* tx_rx, MfUltralightData* data);
-
-bool mf_ultralight_read_counters(FurryHalNfcTxRxContext* tx_rx, MfUltralightData* data);
-
-bool mf_ultralight_read_tearing_flags(FurryHalNfcTxRxContext* tx_rx, MfUltralightData* data);
-
-bool mf_ultralight_authenticate(FurryHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack);
-
-MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data);
-
-bool mf_ul_read_card(
-    FurryHalNfcTxRxContext* tx_rx,
-    MfUltralightReader* reader,
-    MfUltralightData* data);
-
-bool mf_ul_emulation_supported(MfUltralightData* data);
-
-void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle);
-
-void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
-
-bool mf_ul_prepare_emulation_response(
-    uint8_t* buff_rx,
-    uint16_t buff_rx_len,
-    uint8_t* buff_tx,
-    uint16_t* buff_tx_len,
-    uint32_t* data_type,
-    void* context);
-
-uint32_t mf_ul_pwdgen_amiibo(FurryHalNfcDevData* data);
-
-uint32_t mf_ul_pwdgen_xiaomi(FurryHalNfcDevData* data);
-
-bool mf_ul_is_full_capture(MfUltralightData* data);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 236
lib/nfclegacy/pulse_reader/pulse_reader.c

@@ -1,236 +0,0 @@
-#include "pulse_reader.h"
-
-#include <limits.h>
-#include <furi.h>
-#include <furi_hal.h>
-#include <furi_hal_gpio.h>
-
-#include <stm32wbxx_ll_dma.h>
-#include <stm32wbxx_ll_dmamux.h>
-#include <stm32wbxx_ll_tim.h>
-#include <stm32wbxx_ll_exti.h>
-
-struct PulseReader {
-    uint32_t* timer_buffer;
-    uint32_t* gpio_buffer;
-    uint32_t size;
-    uint32_t pos;
-    uint32_t timer_value;
-    uint32_t gpio_value;
-    uint32_t gpio_mask;
-    uint32_t unit_multiplier;
-    uint32_t unit_divider;
-    uint32_t bit_time;
-    uint32_t dma_channel;
-    const GpioPin* gpio;
-    GpioPull pull;
-    LL_DMA_InitTypeDef dma_config_timer;
-    LL_DMA_InitTypeDef dma_config_gpio;
-};
-
-#define GPIO_PIN_MAP(pin, prefix)               \
-    (((pin) == (LL_GPIO_PIN_0))  ? prefix##0 :  \
-     ((pin) == (LL_GPIO_PIN_1))  ? prefix##1 :  \
-     ((pin) == (LL_GPIO_PIN_2))  ? prefix##2 :  \
-     ((pin) == (LL_GPIO_PIN_3))  ? prefix##3 :  \
-     ((pin) == (LL_GPIO_PIN_4))  ? prefix##4 :  \
-     ((pin) == (LL_GPIO_PIN_5))  ? prefix##5 :  \
-     ((pin) == (LL_GPIO_PIN_6))  ? prefix##6 :  \
-     ((pin) == (LL_GPIO_PIN_7))  ? prefix##7 :  \
-     ((pin) == (LL_GPIO_PIN_8))  ? prefix##8 :  \
-     ((pin) == (LL_GPIO_PIN_9))  ? prefix##9 :  \
-     ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \
-     ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \
-     ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
-     ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
-     ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
-                                   prefix##15)
-
-#define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE)
-
-PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) {
-    PulseReader* signal = malloc(sizeof(PulseReader));
-    signal->timer_buffer = malloc(size * sizeof(uint32_t));
-    signal->gpio_buffer = malloc(size * sizeof(uint32_t));
-    signal->dma_channel = LL_DMA_CHANNEL_4;
-    signal->gpio = gpio;
-    signal->pull = GpioPullNo;
-    signal->size = size;
-    signal->timer_value = 0;
-    signal->pos = 0;
-
-    pulse_reader_set_timebase(signal, PulseReaderUnit64MHz);
-    pulse_reader_set_bittime(signal, 1);
-
-    signal->dma_config_timer.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
-    signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->CNT);
-    signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
-    signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
-    signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->timer_buffer;
-    signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
-    signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
-    signal->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR;
-    signal->dma_config_timer.PeriphRequest =
-        LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */
-    signal->dma_config_timer.Priority = LL_DMA_PRIORITY_VERYHIGH;
-
-    signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
-    signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
-    signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
-    signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
-    signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
-    signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
-    signal->dma_config_gpio.PeriphRequest =
-        LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */
-    signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
-
-    return signal;
-}
-
-void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit) {
-    switch(unit) {
-    case PulseReaderUnit64MHz:
-        signal->unit_multiplier = 1;
-        signal->unit_divider = 1;
-        break;
-    case PulseReaderUnitPicosecond:
-        signal->unit_multiplier = 15625;
-        signal->unit_divider = 1;
-        break;
-    case PulseReaderUnitNanosecond:
-        signal->unit_multiplier = 15625;
-        signal->unit_divider = 1000;
-        break;
-    case PulseReaderUnitMicrosecond:
-        signal->unit_multiplier = 15625;
-        signal->unit_divider = 1000000;
-        break;
-    }
-}
-
-void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) {
-    signal->bit_time = bit_time;
-}
-
-void pulse_reader_set_pull(PulseReader* signal, GpioPull pull) {
-    signal->pull = pull;
-}
-
-void pulse_reader_free(PulseReader* signal) {
-    furi_assert(signal);
-
-    free(signal->timer_buffer);
-    free(signal->gpio_buffer);
-    free(signal);
-}
-
-uint32_t pulse_reader_samples(PulseReader* signal) {
-    uint32_t dma_pos = signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel);
-
-    return ((signal->pos + signal->size) - dma_pos) % signal->size;
-}
-
-void pulse_reader_stop(PulseReader* signal) {
-    LL_DMA_DisableChannel(DMA1, signal->dma_channel);
-    LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1);
-    LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0);
-    LL_TIM_DisableCounter(TIM2);
-    furi_hal_bus_disable(FuriHalBusTIM2);
-    furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog);
-}
-
-void pulse_reader_start(PulseReader* signal) {
-    /* configure DMA to read from a timer peripheral */
-    signal->dma_config_timer.NbData = signal->size;
-
-    signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (signal->gpio->port->IDR);
-    signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer;
-    signal->dma_config_gpio.NbData = signal->size;
-
-    furi_hal_bus_enable(FuriHalBusTIM2);
-
-    /* start counter */
-    LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
-    LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
-    LL_TIM_SetPrescaler(TIM2, 0);
-    LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF);
-    LL_TIM_SetCounter(TIM2, 0);
-    LL_TIM_EnableCounter(TIM2);
-
-    /* generator 0 gets fed by EXTI_LINEn */
-    LL_DMAMUX_SetRequestSignalID(
-        NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin));
-    /* trigger on rising edge of the interrupt */
-    LL_DMAMUX_SetRequestGenPolarity(NULL, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING);
-    /* now enable request generation again */
-    LL_DMAMUX_EnableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0);
-
-    /* we need the EXTI to be configured as interrupt generating line, but no ISR registered */
-    furi_hal_gpio_init_ex(
-        signal->gpio, GpioModeInterruptRiseFall, signal->pull, GpioSpeedVeryHigh, GpioAltFnUnused);
-
-    /* capture current timer */
-    signal->pos = 0;
-    signal->timer_value = TIM2->CNT;
-    signal->gpio_mask = signal->gpio->pin;
-    signal->gpio_value = signal->gpio->port->IDR & signal->gpio_mask;
-
-    /* now set up DMA with these settings */
-    LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer);
-    LL_DMA_Init(DMA1, signal->dma_channel + 1, &signal->dma_config_gpio);
-    LL_DMA_EnableChannel(DMA1, signal->dma_channel);
-    LL_DMA_EnableChannel(DMA1, signal->dma_channel + 1);
-}
-
-uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) {
-    uint32_t start_time = DWT->CYCCNT;
-    uint32_t timeout_ticks = timeout_us * (F_TIM2 / 1000000);
-
-    do {
-        /* get the DMA's next write position by reading "remaining length" register */
-        uint32_t dma_pos =
-            signal->size - (uint32_t)LL_DMA_GetDataLength(DMA1, signal->dma_channel);
-
-        /* the DMA has advanced in the ringbuffer */
-        if(dma_pos != signal->pos) {
-            uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value;
-            uint32_t last_gpio_value = signal->gpio_value;
-
-            signal->gpio_value = signal->gpio_buffer[signal->pos];
-
-            /* check if the GPIO really toggled. if not, we lost an edge :( */
-            if(((last_gpio_value ^ signal->gpio_value) & signal->gpio_mask) != signal->gpio_mask) {
-                signal->gpio_value ^= signal->gpio_mask;
-                return PULSE_READER_LOST_EDGE;
-            }
-            signal->timer_value = signal->timer_buffer[signal->pos];
-
-            signal->pos++;
-            signal->pos %= signal->size;
-
-            uint32_t delta_unit = 0;
-
-            /* probably larger values, so choose a wider data type */
-            if(signal->unit_divider > 1) {
-                delta_unit =
-                    (uint32_t)((uint64_t)delta * (uint64_t)signal->unit_multiplier / signal->unit_divider);
-            } else {
-                delta_unit = delta * signal->unit_multiplier;
-            }
-
-            /* if to be scaled to bit times, save a few instructions. should be faster */
-            if(signal->bit_time > 1) {
-                return (delta_unit + signal->bit_time / 2) / signal->bit_time;
-            }
-
-            return delta_unit;
-        }
-
-        /* check for timeout */
-        uint32_t elapsed = DWT->CYCCNT - start_time;
-
-        if(elapsed > timeout_ticks) {
-            return PULSE_READER_NO_EDGE;
-        }
-    } while(true);
-}

+ 0 - 122
lib/nfclegacy/pulse_reader/pulse_reader.h

@@ -1,122 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include <furi_hal_gpio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PULSE_READER_NO_EDGE (0xFFFFFFFFUL)
-#define PULSE_READER_LOST_EDGE (0xFFFFFFFEUL)
-#define F_TIM2 (64000000UL)
-
-/**
- * unit of the edge durations to return
- */
-typedef enum {
-    PulseReaderUnit64MHz,
-    PulseReaderUnitPicosecond,
-    PulseReaderUnitNanosecond,
-    PulseReaderUnitMicrosecond,
-} PulseReaderUnit;
-
-/* using an anonymous type */
-typedef struct PulseReader PulseReader;
-
-/** Allocate a PulseReader object
- *
- * Allocates memory for a ringbuffer and initalizes the object
- *
- * @param[in]  gpio        the GPIO to use. will get configured as input.
- * @param[in]  size        number of edges to buffer
- */
-PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size);
-
-/** Free a PulseReader object
- *
- * Frees all memory of the given object
- *
- * @param[in]  signal      previously allocated PulseReader object.
- */
-void pulse_reader_free(PulseReader* signal);
-
-/** Start signal capturing
- *
- * Initializes DMA1, TIM2 and DMAMUX_REQ_GEN_0 to automatically capture timer values.
- * Ensure that interrupts are always enabled, as the used EXTI line is handled as one.
- *
- * @param[in]  signal      previously allocated PulseReader object.
- */
-void pulse_reader_start(PulseReader* signal);
-
-/** Stop signal capturing
- *
- * Frees DMA1, TIM2 and DMAMUX_REQ_GEN_0
- *
- * @param[in]  signal      previously allocated PulseReader object.
- */
-void pulse_reader_stop(PulseReader* signal);
-
-/** Recevie a sample from ringbuffer
- *
- * Waits for the specified time until a new edge gets detected.
- * If not configured otherwise, the pulse duration will be in picosecond resolution.
- * If a bittime was configured, the return value will contain the properly rounded
- * number of bit times measured.
- *
- * @param[in]  signal      previously allocated PulseReader object.
- * @param[in]  timeout_us  time to wait for a signal [µs]
- *
- * @returns the scaled value of the pulse duration
- */
-uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us);
-
-/** Get available samples
- *
- * Get the number of available samples in the ringbuffer
- *
- * @param[in]  signal  previously allocated PulseReader object.
- *
- * @returns the number of samples in buffer
- */
-uint32_t pulse_reader_samples(PulseReader* signal);
-
-/** Set timebase
- *
- * Set the timebase to be used when returning pulse duration.
- *
- * @param[in]  signal  previously allocated PulseReader object.
- * @param[in]  unit  PulseReaderUnit64MHz or PulseReaderUnitPicosecond
- */
-void pulse_reader_set_timebase(PulseReader* signal, PulseReaderUnit unit);
-
-/** Set bit time
- *
- * Set the number of timebase units per bit.
- * When set, the pulse_reader_receive() will return an already rounded
- * bit count value instead of the raw duration.
- *
- * Set to 1 to return duration again.
- *
- * @param[in]  signal    previously allocated PulseReader object.
- * @param[in]  bit_time
- */
-void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time);
-
-/** Set GPIO pull direction
- *
- * Some GPIOs need pulldown, others don't. By default the
- * pull direction is GpioPullNo.
- *
- * @param[in]  signal    previously allocated PulseReader object.
- * @param[in]  pull      GPIO pull direction
- */
-void pulse_reader_set_pull(PulseReader* signal, GpioPull pull);
-
-#ifdef __cplusplus
-}
-#endif