Просмотр исходного кода

Nfc: async pcap worker (#1315)

* Nfc: async pcap worker
* nfc: add pcap save to classic emulation

Co-authored-by: gornekich <n.gorbadey@gmail.com>
あく 3 лет назад
Родитель
Сommit
b2132b2ec7

+ 2 - 2
.github/workflows/build.yml

@@ -152,7 +152,7 @@ jobs:
         with:
         with:
           issue-number: ${{ github.event.pull_request.number }}
           issue-number: ${{ github.event.pull_request.number }}
           comment-author: 'github-actions[bot]'
           comment-author: 'github-actions[bot]'
-          body-includes: 'to flash the'
+          body-includes: 'Install with web updater'
 
 
       - name: 'Create or update comment'
       - name: 'Create or update comment'
         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}}
         if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request}}
@@ -161,7 +161,7 @@ jobs:
           comment-id: ${{ steps.fc.outputs.comment-id }}
           comment-id: ${{ steps.fc.outputs.comment-id }}
           issue-number: ${{ github.event.pull_request.number }}
           issue-number: ${{ github.event.pull_request.number }}
           body: |
           body: |
-            [Install with web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}})
+            [Install with web updater](https://my.flipp.dev/?url=https://update.flipperzero.one/builds/firmware/${{steps.names.outputs.artifacts-path}}/flipper-z-${{steps.names.outputs.default-target}}-update-${{steps.names.outputs.suffix}}.tgz&channel=${{steps.names.outputs.artifacts-path}}&version=${{steps.names.outputs.short-hash}}).
           edit-mode: replace
           edit-mode: replace
 
 
   compact:
   compact:

+ 92 - 25
applications/nfc/helpers/nfc_debug_pcap.c

@@ -1,6 +1,7 @@
 #include "nfc_debug_pcap.h"
 #include "nfc_debug_pcap.h"
 
 
 #include <furi_hal_rtc.h>
 #include <furi_hal_rtc.h>
+#include <stream_buffer.h>
 
 
 #define TAG "NfcDebugPcap"
 #define TAG "NfcDebugPcap"
 
 
@@ -14,9 +15,20 @@
 #define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
 #define DATA_PICC_TO_PCD_CRC_DROPPED 0xFB
 #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
 #define DATA_PCD_TO_PICC_CRC_DROPPED 0xFA
 
 
-File* nfc_debug_pcap_open(Storage* storage) {
+#define NFC_DEBUG_PCAP_FILENAME "/ext/nfc/debug.pcap"
+#define NFC_DEBUG_PCAP_BUFFER_SIZE 64
+
+struct NfcDebugPcapWorker {
+    bool alive;
+    Storage* storage;
+    File* file;
+    StreamBufferHandle_t stream;
+    FuriThread* thread;
+};
+
+static File* nfc_debug_pcap_open(Storage* storage) {
     File* file = storage_file_alloc(storage);
     File* file = storage_file_alloc(storage);
-    if(!storage_file_open(file, "/ext/nfc/debug.pcap", FSAM_WRITE, FSOM_OPEN_APPEND)) {
+    if(!storage_file_open(file, NFC_DEBUG_PCAP_FILENAME, FSAM_WRITE, FSOM_OPEN_APPEND)) {
         storage_file_free(file);
         storage_file_free(file);
         return NULL;
         return NULL;
     }
     }
@@ -41,10 +53,8 @@ File* nfc_debug_pcap_open(Storage* storage) {
     return file;
     return file;
 }
 }
 
 
-void nfc_debug_pcap_write(Storage* storage, uint8_t event, uint8_t* data, uint16_t len) {
-    File* file = nfc_debug_pcap_open(storage);
-    if(!file) return;
-
+static void
+    nfc_debug_pcap_write(NfcDebugPcapWorker* instance, uint8_t event, uint8_t* data, uint16_t len) {
     FuriHalRtcDateTime datetime;
     FuriHalRtcDateTime datetime;
     furi_hal_rtc_get_datetime(&datetime);
     furi_hal_rtc_get_datetime(&datetime);
 
 
@@ -67,33 +77,90 @@ void nfc_debug_pcap_write(Storage* storage, uint8_t event, uint8_t* data, uint16
         .event = event,
         .event = event,
         .len = len << 8 | len >> 8,
         .len = len << 8 | len >> 8,
     };
     };
-    if(storage_file_write(file, &pkt_hdr, sizeof(pkt_hdr)) != sizeof(pkt_hdr)) {
-        FURI_LOG_E(TAG, "Failed to write pcap packet header");
-    } else if(storage_file_write(file, data, len) != len) {
-        FURI_LOG_E(TAG, "Failed to write pcap packet data");
-    }
-    storage_file_free(file);
+    xStreamBufferSend(instance->stream, &pkt_hdr, sizeof(pkt_hdr), osWaitForever);
+    xStreamBufferSend(instance->stream, data, len, osWaitForever);
 }
 }
 
 
-void nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
+static void
+    nfc_debug_pcap_write_tx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
+    NfcDebugPcapWorker* instance = context;
     uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC;
     uint8_t event = crc_dropped ? DATA_PCD_TO_PICC_CRC_DROPPED : DATA_PCD_TO_PICC;
-    nfc_debug_pcap_write(context, event, data, bits / 8);
+    nfc_debug_pcap_write(instance, event, data, bits / 8);
 }
 }
 
 
-void nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
+static void
+    nfc_debug_pcap_write_rx(uint8_t* data, uint16_t bits, bool crc_dropped, void* context) {
+    NfcDebugPcapWorker* instance = context;
     uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD;
     uint8_t event = crc_dropped ? DATA_PICC_TO_PCD_CRC_DROPPED : DATA_PICC_TO_PCD;
-    nfc_debug_pcap_write(context, event, data, bits / 8);
+    nfc_debug_pcap_write(instance, event, data, bits / 8);
 }
 }
 
 
-void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc) {
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        if(is_picc) {
-            tx_rx->sniff_tx = nfc_debug_pcap_write_rx;
-            tx_rx->sniff_rx = nfc_debug_pcap_write_tx;
-        } else {
-            tx_rx->sniff_tx = nfc_debug_pcap_write_tx;
-            tx_rx->sniff_rx = nfc_debug_pcap_write_rx;
+int32_t nfc_debug_pcap_thread(void* context) {
+    NfcDebugPcapWorker* instance = context;
+    uint8_t buffer[NFC_DEBUG_PCAP_BUFFER_SIZE];
+
+    while(instance->alive) {
+        size_t ret =
+            xStreamBufferReceive(instance->stream, buffer, NFC_DEBUG_PCAP_BUFFER_SIZE, 50);
+        if(storage_file_write(instance->file, buffer, ret) != ret) {
+            FURI_LOG_E(TAG, "Failed to write pcap data");
         }
         }
-        tx_rx->sniff_context = storage;
     }
     }
+
+    return 0;
+}
+
+NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage) {
+    NfcDebugPcapWorker* instance = malloc(sizeof(NfcDebugPcapWorker));
+
+    instance->alive = true;
+
+    instance->storage = storage;
+
+    instance->file = nfc_debug_pcap_open(storage);
+
+    instance->stream = xStreamBufferCreate(4096, 1);
+
+    instance->thread = furi_thread_alloc();
+    furi_thread_set_name(instance->thread, "PcapWorker");
+    furi_thread_set_stack_size(instance->thread, 1024);
+    furi_thread_set_callback(instance->thread, nfc_debug_pcap_thread);
+    furi_thread_set_context(instance->thread, instance);
+    furi_thread_start(instance->thread);
+
+    return instance;
+}
+
+void nfc_debug_pcap_free(NfcDebugPcapWorker* instance) {
+    furi_assert(instance);
+
+    instance->alive = false;
+
+    furi_thread_join(instance->thread);
+    furi_thread_free(instance->thread);
+
+    vStreamBufferDelete(instance->stream);
+
+    if(instance->file) storage_file_free(instance->file);
+
+    instance->storage = NULL;
+
+    free(instance);
+}
+
+void nfc_debug_pcap_prepare_tx_rx(
+    NfcDebugPcapWorker* instance,
+    FuriHalNfcTxRxContext* tx_rx,
+    bool is_picc) {
+    if(!instance || !instance->file) return;
+
+    if(is_picc) {
+        tx_rx->sniff_tx = nfc_debug_pcap_write_rx;
+        tx_rx->sniff_rx = nfc_debug_pcap_write_tx;
+    } else {
+        tx_rx->sniff_tx = nfc_debug_pcap_write_tx;
+        tx_rx->sniff_rx = nfc_debug_pcap_write_rx;
+    }
+
+    tx_rx->sniff_context = instance;
 }
 }

+ 11 - 2
applications/nfc/helpers/nfc_debug_pcap.h

@@ -3,10 +3,19 @@
 #include <furi_hal_nfc.h>
 #include <furi_hal_nfc.h>
 #include <storage/storage.h>
 #include <storage/storage.h>
 
 
+typedef struct NfcDebugPcapWorker NfcDebugPcapWorker;
+
+NfcDebugPcapWorker* nfc_debug_pcap_alloc(Storage* storage);
+
+void nfc_debug_pcap_free(NfcDebugPcapWorker* instance);
+
 /** Prepare tx/rx context for debug pcap logging, if enabled.
 /** Prepare tx/rx context for debug pcap logging, if enabled.
  *
  *
+ * @param      instance NfcDebugPcapWorker* instance, can be NULL
  * @param      tx_rx   TX/RX context to log
  * @param      tx_rx   TX/RX context to log
- * @param      storage Storage to log to
  * @param      is_picc if true, record Flipper as PICC, else PCD.
  * @param      is_picc if true, record Flipper as PICC, else PCD.
  */
  */
-void nfc_debug_pcap_prepare_tx_rx(FuriHalNfcTxRxContext* tx_rx, Storage* storage, bool is_picc);
+void nfc_debug_pcap_prepare_tx_rx(
+    NfcDebugPcapWorker* instance,
+    FuriHalNfcTxRxContext* tx_rx,
+    bool is_picc);

+ 17 - 18
applications/nfc/nfc_worker.c

@@ -1,17 +1,6 @@
 #include "nfc_worker_i.h"
 #include "nfc_worker_i.h"
 #include <furi_hal.h>
 #include <furi_hal.h>
 
 
-#include <lib/nfc_protocols/nfc_util.h>
-#include <lib/nfc_protocols/emv.h>
-#include <lib/nfc_protocols/mifare_common.h>
-#include <lib/nfc_protocols/mifare_ultralight.h>
-#include <lib/nfc_protocols/mifare_classic.h>
-#include <lib/nfc_protocols/mifare_desfire.h>
-#include <lib/nfc_protocols/nfca.h>
-
-#include "helpers/nfc_mf_classic_dict.h"
-#include "helpers/nfc_debug_pcap.h"
-
 #define TAG "NfcWorker"
 #define TAG "NfcWorker"
 
 
 /***************************** NFC Worker API *******************************/
 /***************************** NFC Worker API *******************************/
@@ -36,13 +25,22 @@ NfcWorker* nfc_worker_alloc() {
     }
     }
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
 
 
+    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
+        nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage);
+    }
+
     return nfc_worker;
     return nfc_worker;
 }
 }
 
 
 void nfc_worker_free(NfcWorker* nfc_worker) {
 void nfc_worker_free(NfcWorker* nfc_worker) {
     furi_assert(nfc_worker);
     furi_assert(nfc_worker);
+
     furi_thread_free(nfc_worker->thread);
     furi_thread_free(nfc_worker->thread);
+
     furi_record_close("storage");
     furi_record_close("storage");
+
+    if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker);
+
     free(nfc_worker);
     free(nfc_worker);
 }
 }
 
 
@@ -154,7 +152,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_emulate(NfcWorker* nfc_worker) {
 void nfc_worker_emulate(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
     FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
     FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
 
 
@@ -177,7 +175,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
 void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
     EmvApplication emv_app = {};
     EmvApplication emv_app = {};
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
@@ -209,7 +207,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_read_emv(NfcWorker* nfc_worker) {
 void nfc_worker_read_emv(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
     EmvApplication emv_app = {};
     EmvApplication emv_app = {};
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
@@ -258,7 +256,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
 void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, true);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
     FuriHalNfcDevData params = {
     FuriHalNfcDevData params = {
         .uid = {0xCF, 0x72, 0xd4, 0x40},
         .uid = {0xCF, 0x72, 0xd4, 0x40},
         .uid_len = 4,
         .uid_len = 4,
@@ -283,7 +281,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
 void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
     MfUltralightReader reader = {};
     MfUltralightReader reader = {};
     MfUltralightData data = {};
     MfUltralightData data = {};
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
@@ -348,7 +346,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
 void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
     furi_assert(nfc_worker->callback);
     furi_assert(nfc_worker->callback);
     FuriHalNfcTxRxContext tx_rx_ctx = {};
     FuriHalNfcTxRxContext tx_rx_ctx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx_ctx, nfc_worker->storage, false);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx_ctx, false);
     MfClassicAuthContext auth_ctx = {};
     MfClassicAuthContext auth_ctx = {};
     MfClassicReader reader = {};
     MfClassicReader reader = {};
     uint64_t curr_key = 0;
     uint64_t curr_key = 0;
@@ -491,6 +489,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
 void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
     MfClassicEmulator emulator = {
     MfClassicEmulator emulator = {
         .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
         .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
@@ -519,7 +518,7 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
 
 
 void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
 void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
     FuriHalNfcTxRxContext tx_rx = {};
     FuriHalNfcTxRxContext tx_rx = {};
-    nfc_debug_pcap_prepare_tx_rx(&tx_rx, nfc_worker->storage, false);
+    nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
     NfcDeviceData* result = nfc_worker->dev_data;
     NfcDeviceData* result = nfc_worker->dev_data;
     nfc_device_data_clear(result);
     nfc_device_data_clear(result);
     MifareDesfireData* data = &result->mf_df_data;
     MifareDesfireData* data = &result->mf_df_data;

+ 14 - 1
applications/nfc/nfc_worker_i.h

@@ -1,11 +1,22 @@
 #pragma once
 #pragma once
 
 
-#include "nfc_i.h"
 #include "nfc_worker.h"
 #include "nfc_worker.h"
+#include "nfc_i.h"
 
 
 #include <furi.h>
 #include <furi.h>
 #include <lib/toolbox/stream/file_stream.h>
 #include <lib/toolbox/stream/file_stream.h>
 
 
+#include <lib/nfc_protocols/nfc_util.h>
+#include <lib/nfc_protocols/emv.h>
+#include <lib/nfc_protocols/mifare_common.h>
+#include <lib/nfc_protocols/mifare_ultralight.h>
+#include <lib/nfc_protocols/mifare_classic.h>
+#include <lib/nfc_protocols/mifare_desfire.h>
+#include <lib/nfc_protocols/nfca.h>
+
+#include "helpers/nfc_mf_classic_dict.h"
+#include "helpers/nfc_debug_pcap.h"
+
 struct NfcWorker {
 struct NfcWorker {
     FuriThread* thread;
     FuriThread* thread;
     Storage* storage;
     Storage* storage;
@@ -17,6 +28,8 @@ struct NfcWorker {
     void* context;
     void* context;
 
 
     NfcWorkerState state;
     NfcWorkerState state;
+
+    NfcDebugPcapWorker* debug_pcap_worker;
 };
 };
 
 
 void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
 void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);

+ 8 - 0
applications/storage/storage_external_api.c

@@ -134,6 +134,10 @@ bool storage_file_close(File* file) {
 }
 }
 
 
 uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) {
 uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) {
+    if(bytes_to_read == 0) {
+        return 0;
+    }
+
     S_FILE_API_PROLOGUE;
     S_FILE_API_PROLOGUE;
     S_API_PROLOGUE;
     S_API_PROLOGUE;
 
 
@@ -150,6 +154,10 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) {
 }
 }
 
 
 uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write) {
 uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write) {
+    if(bytes_to_write == 0) {
+        return 0;
+    }
+
     S_FILE_API_PROLOGUE;
     S_FILE_API_PROLOGUE;
     S_API_PROLOGUE;
     S_API_PROLOGUE;
 
 

+ 8 - 0
firmware/targets/f7/furi_hal/furi_hal_nfc.c

@@ -392,6 +392,10 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
     st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
     st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
 
 
+    if(tx_rx->sniff_tx) {
+        tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context);
+    }
+
     // Manually wait for interrupt
     // Manually wait for interrupt
     furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
     furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
     st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE);
     st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE);
@@ -428,6 +432,10 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
         tx_rx->rx_bits = len * 8;
         tx_rx->rx_bits = len * 8;
         memcpy(tx_rx->rx_data, rx, len);
         memcpy(tx_rx->rx_data, rx, len);
 
 
+        if(tx_rx->sniff_rx) {
+            tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context);
+        }
+
         ret = true;
         ret = true;
     } else {
     } else {
         FURI_LOG_E(TAG, "Timeout error");
         FURI_LOG_E(TAG, "Timeout error");