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

ESubGHz Chat: Merge nfclegacy port by xMasterX

Willy-JL 1 год назад
Родитель
Сommit
c664278101
89 измененных файлов с 43347 добавлено и 412 удалено
  1. 2 1
      esubghz_chat/application.fam
  2. BIN
      esubghz_chat/assets/NFC_manual_60x50.png
  3. BIN
      esubghz_chat/assets/Pin_back_arrow_10x8.png
  4. BIN
      esubghz_chat/assets/WarningDolphin_45x42.png
  5. 42 18
      esubghz_chat/esubghz_chat.c
  6. 4 4
      esubghz_chat/esubghz_chat_i.h
  7. 435 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_analogConfig.h
  8. 287 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_chip.h
  9. 74 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_crc.h
  10. 207 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_dpo.h
  11. 206 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_iso15693_2.h
  12. 1092 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_isoDep.h
  13. 425 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfc.h
  14. 831 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcDep.h
  15. 497 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfca.h
  16. 425 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcb.h
  17. 403 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcf.h
  18. 923 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcv.h
  19. 1724 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_rf.h
  20. 340 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_st25tb.h
  21. 844 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_st25xv.h
  22. 178 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t1t.h
  23. 150 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t2t.h
  24. 395 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t4t.h
  25. 104 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/platform.c
  26. 188 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/platform.h
  27. 777 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/custom_analog_config.c
  28. 480 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_analogConfig.c
  29. 82 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_crc.c
  30. 232 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_dpo.c
  31. 516 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_iso15693_2.c
  32. 3045 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_isoDep.c
  33. 2126 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfc.c
  34. 2741 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcDep.c
  35. 891 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfca.c
  36. 519 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcb.c
  37. 587 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcf.c
  38. 1059 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcv.c
  39. 563 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_st25tb.c
  40. 818 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_st25xv.c
  41. 233 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t1t.c
  42. 253 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t2t.c
  43. 397 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t4t.c
  44. 1487 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_analogConfigTbl.h
  45. 68 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_dpoTbl.h
  46. 109 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_features.h
  47. 4857 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c
  48. 801 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916.c
  49. 669 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916.h
  50. 366 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_aat.c
  51. 109 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_aat.h
  52. 618 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_com.c
  53. 1384 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_com.h
  54. 231 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_irq.c
  55. 296 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_irq.h
  56. 148 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_led.c
  57. 151 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_led.h
  58. 158 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/st_errno.h
  59. 105 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/timer.c
  60. 125 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/timer.h
  61. 100 0
      esubghz_chat/lib/nfclegacy/ST25RFAL002/utils.h
  62. 666 0
      esubghz_chat/lib/nfclegacy/digital_signal/digital_signal.c
  63. 75 0
      esubghz_chat/lib/nfclegacy/digital_signal/digital_signal.h
  64. 839 0
      esubghz_chat/lib/nfclegacy/furi_hal_nfc.c
  65. 438 0
      esubghz_chat/lib/nfclegacy/furi_hal_nfc.h
  66. 558 0
      esubghz_chat/lib/nfclegacy/nfc_device.c
  67. 111 0
      esubghz_chat/lib/nfclegacy/nfc_device.h
  68. 57 0
      esubghz_chat/lib/nfclegacy/nfc_types.c
  69. 17 0
      esubghz_chat/lib/nfclegacy/nfc_types.h
  70. 390 0
      esubghz_chat/lib/nfclegacy/nfc_worker.c
  71. 109 0
      esubghz_chat/lib/nfclegacy/nfc_worker.h
  72. 52 0
      esubghz_chat/lib/nfclegacy/nfc_worker_i.h
  73. 128 0
      esubghz_chat/lib/nfclegacy/protocols/crypto1.c
  74. 45 0
      esubghz_chat/lib/nfclegacy/protocols/crypto1.h
  75. 19 0
      esubghz_chat/lib/nfclegacy/protocols/mifare_common.c
  76. 12 0
      esubghz_chat/lib/nfclegacy/protocols/mifare_common.h
  77. 1946 0
      esubghz_chat/lib/nfclegacy/protocols/mifare_ultralight.c
  78. 269 0
      esubghz_chat/lib/nfclegacy/protocols/mifare_ultralight.h
  79. 70 0
      esubghz_chat/lib/nfclegacy/protocols/nfc_util.c
  80. 21 0
      esubghz_chat/lib/nfclegacy/protocols/nfc_util.h
  81. 140 0
      esubghz_chat/lib/nfclegacy/protocols/nfca.c
  82. 31 0
      esubghz_chat/lib/nfclegacy/protocols/nfca.h
  83. 71 0
      esubghz_chat/lib/parity/parity.c
  84. 10 0
      esubghz_chat/lib/parity/parity.h
  85. 6 6
      esubghz_chat/scenes/esubghz_chat_key_display.c
  86. 17 17
      esubghz_chat/scenes/esubghz_chat_key_menu.c
  87. 268 273
      esubghz_chat/scenes/esubghz_chat_key_read_popup.c
  88. 103 91
      esubghz_chat/scenes/esubghz_chat_key_share_popup.c
  89. 2 2
      esubghz_chat/scenes/esubghz_chat_scene_config.h

+ 2 - 1
esubghz_chat/application.fam

@@ -7,9 +7,10 @@ App(
         "gui",
         "subghz",
     ],
-    stack_size=8 * 1024,
+    stack_size=7 * 1024,
     fap_category="Sub-GHz",
     fap_libs=["mbedtls"],
+    fap_private_libs=[Lib(name="nfclegacy"), Lib(name="parity")],
     fap_icon="assets/chat_10px.png",
     fap_icon_assets="assets",
     fap_icon_assets_symbol="esubghz_chat",

BIN
esubghz_chat/assets/NFC_manual_60x50.png


BIN
esubghz_chat/assets/Pin_back_arrow_10x8.png


BIN
esubghz_chat/assets/WarningDolphin_45x42.png


+ 42 - 18
esubghz_chat/esubghz_chat.c

@@ -547,6 +547,15 @@ static void chat_box_free(ESubGhzChatState* state) {
 }
 
 int32_t esubghz_chat(const char* args) {
+    if(furi_hal_nfc_is_hal_ready() != FuriHalNfcErrorNone) {
+        printf("NFC chip failed to start\r\n");
+        return -1;
+    }
+
+    furi_hal_nfc_acquire();
+    furi_hal_nfc_low_power_mode_start();
+    furi_hal_nfc_release();
+    furry_hal_nfc_init();
     /* init the crypto system */
     crypto_init();
 
@@ -610,16 +619,20 @@ int32_t esubghz_chat(const char* args) {
         goto err_alloc_worker;
     }
 
-    // state->nfc_worker = nfc_worker_alloc();
-    // if(state->nfc_worker == NULL) {
-    //     goto err_alloc_nworker;
-    // }
+    NfcDevice* nfcdevic = nfc_device_alloc();
+    state->nfc_dev_data = &nfcdevic->dev_data;
+
+    state->nfc_worker = nfc_worker_alloc();
+    if(state->nfc_worker == NULL) {
+        goto err_alloc_nworker;
+    }
+
+    /*state->nfc_dev_data = malloc(sizeof(NfcDeviceData));
+    if(state->nfc_dev_data == NULL) {
+        goto err_alloc_ndevdata;
+    }*/
 
-    // state->nfc_dev_data = malloc(sizeof(NfcDeviceData));
-    // if(state->nfc_dev_data == NULL) {
-    //     goto err_alloc_ndevdata;
-    // }
-    // memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
+    //memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
 
     state->crypto_ctx = crypto_ctx_alloc();
     if(state->crypto_ctx == NULL) {
@@ -715,7 +728,7 @@ int32_t esubghz_chat(const char* args) {
     }
 
     /* if it is running, stop the NFC worker */
-    // nfc_worker_stop(state->nfc_worker);
+    nfc_worker_stop(state->nfc_worker);
 
     err = 0;
 
@@ -740,10 +753,12 @@ int32_t esubghz_chat(const char* args) {
     crypto_ctx_clear(state->crypto_ctx);
 
     /* clear nfc data */
-    // if(state->nfc_dev_data->parsed_data != NULL) {
-    //     furi_string_free(state->nfc_dev_data->parsed_data);
-    // }
-    // crypto_explicit_bzero(state->nfc_dev_data, sizeof(NfcDeviceData));
+    if(state->nfc_dev_data->parsed_data != NULL) {
+        furi_string_free(state->nfc_dev_data->parsed_data);
+    }
+
+    //nfc_device_data_clear(state->nfc_dev_data);
+    crypto_explicit_bzero(state->nfc_dev_data, sizeof(NfcDeviceData));
 
     /* deinit devices */
     radio_device_loader_end(state->subghz_device);
@@ -758,12 +773,14 @@ int32_t esubghz_chat(const char* args) {
     crypto_ctx_free(state->crypto_ctx);
 
 err_alloc_crypto:
-    //     free(state->nfc_dev_data);
+    //free(state->nfc_dev_data);
+
+    //err_alloc_ndevdata:
+    nfc_worker_free(state->nfc_worker);
 
-    // err_alloc_ndevdata:
-    //     nfc_worker_free(state->nfc_worker);
+    nfc_device_free(nfcdevic);
 
-    // err_alloc_nworker:
+err_alloc_nworker:
     subghz_tx_rx_worker_free(state->subghz_worker);
 
 err_alloc_worker:
@@ -803,5 +820,12 @@ err_alloc:
         FURI_LOG_I(APPLICATION_NAME, "Clean exit.");
     }
 
+    furry_hal_nfc_deinit();
+
+    //
+    furi_hal_nfc_acquire();
+    furi_hal_nfc_low_power_mode_start();
+    furi_hal_nfc_release();
+
     return err;
 }

+ 4 - 4
esubghz_chat/esubghz_chat_i.h

@@ -19,7 +19,7 @@
 
 #include "esubghz_chat_icons.h"
 
-#include <assets_icons.h>
+#include <lib/nfclegacy/nfc_worker.h>
 
 #define APPLICATION_NAME "ESubGhzChat"
 
@@ -58,8 +58,8 @@ typedef struct {
     const SubGhzDevice* subghz_device;
 
     // for NFC
-    // NfcWorker* nfc_worker;
-    // NfcDeviceData* nfc_dev_data;
+    NfcWorker* nfc_worker;
+    NfcDeviceData* nfc_dev_data;
 
     // message assembly before TX
     FuriString* name_prefix;
@@ -100,7 +100,7 @@ typedef enum {
     ESubGhzChatEvent_KeyMenuPassword,
     ESubGhzChatEvent_KeyMenuHexKey,
     ESubGhzChatEvent_KeyMenuGenKey,
-    // ESubGhzChatEvent_KeyMenuReadKeyFromNfc,
+    ESubGhzChatEvent_KeyMenuReadKeyFromNfc,
     ESubGhzChatEvent_KeyReadPopupFailed,
     ESubGhzChatEvent_KeyReadPopupSucceeded,
     ESubGhzChatEvent_PassEntered,

+ 435 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_analogConfig.h

@@ -0,0 +1,435 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_AnalogConfig.h
+ *
+ *  \author bkam
+ *
+ *  \brief RF Chip Analog Configuration Settings
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup AnalogConfig
+ * \brief RFAL Analog Config Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_ANALOG_CONFIG_H
+#define RFAL_ANALOG_CONFIG_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_ANALOG_CONFIG_LUT_SIZE \
+    (87U) /*!< Maximum number of Configuration IDs in the Loop Up Table     */
+#define RFAL_ANALOG_CONFIG_LUT_NOT_FOUND \
+    (0xFFU) /*!< Index value indicating no Configuration IDs found            */
+
+#define RFAL_ANALOG_CONFIG_TBL_SIZE \
+    (1024U) /*!< Maximum number of Register-Mask-Value in the Setting List    */
+
+#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK \
+    (0x8000U) /*!< Mask bit of Poll Mode in Analog Configuration ID             */
+#define RFAL_ANALOG_CONFIG_TECH_MASK \
+    (0x7F00U) /*!< Mask bits for Technology in Analog Configuration ID          */
+#define RFAL_ANALOG_CONFIG_BITRATE_MASK \
+    (0x00F0U) /*!< Mask bits for Bit rate in Analog Configuration ID            */
+#define RFAL_ANALOG_CONFIG_DIRECTION_MASK \
+    (0x000FU) /*!< Mask bits for Direction in Analog Configuration ID           */
+#define RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK \
+    (0x00FFU) /*!< Mask bits for Chip Specific Technology                       */
+
+#define RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_SHIFT \
+    (15U) /*!< Shift value of Poll Mode in Analog Configuration ID          */
+#define RFAL_ANALOG_CONFIG_TECH_SHIFT \
+    (8U) /*!< Shift value for Technology in Analog Configuration ID        */
+#define RFAL_ANALOG_CONFIG_BITRATE_SHIFT \
+    (4U) /*!< Shift value for Technology in Analog Configuration ID        */
+#define RFAL_ANALOG_CONFIG_DIRECTION_SHIFT \
+    (0U) /*!< Shift value for Direction in Analog Configuration ID         */
+
+#define RFAL_ANALOG_CONFIG_POLL \
+    (0x0000U) /*!< Poll Mode bit setting in Analog Configuration ID             */
+#define RFAL_ANALOG_CONFIG_LISTEN \
+    (0x8000U) /*!< Listen Mode bit setting in Analog Configuration ID           */
+
+#define RFAL_ANALOG_CONFIG_TECH_CHIP \
+    (0x0000U) /*!< Chip-Specific bit setting in Analog Configuration ID         */
+#define RFAL_ANALOG_CONFIG_TECH_NFCA \
+    (0x0100U) /*!< NFC-A Technology bits setting in Analog Configuration ID     */
+#define RFAL_ANALOG_CONFIG_TECH_NFCB \
+    (0x0200U) /*!< NFC-B Technology bits setting in Analog Configuration ID     */
+#define RFAL_ANALOG_CONFIG_TECH_NFCF \
+    (0x0400U) /*!< NFC-F Technology bits setting in Analog Configuration ID     */
+#define RFAL_ANALOG_CONFIG_TECH_AP2P \
+    (0x0800U) /*!< AP2P Technology bits setting in Analog Configuration ID      */
+#define RFAL_ANALOG_CONFIG_TECH_NFCV \
+    (0x1000U) /*!< NFC-V Technology bits setting in Analog Configuration ID     */
+#define RFAL_ANALOG_CONFIG_TECH_RFU (0x2000U) /*!< RFU for Technology bits */
+
+#define RFAL_ANALOG_CONFIG_BITRATE_COMMON \
+    (0x0000U) /*!< Common settings for all bit rates in Analog Configuration ID */
+#define RFAL_ANALOG_CONFIG_BITRATE_106 \
+    (0x0010U) /*!< 106kbits/s settings in Analog Configuration ID               */
+#define RFAL_ANALOG_CONFIG_BITRATE_212 \
+    (0x0020U) /*!< 212kbits/s settings in Analog Configuration ID               */
+#define RFAL_ANALOG_CONFIG_BITRATE_424 \
+    (0x0030U) /*!< 424kbits/s settings in Analog Configuration ID               */
+#define RFAL_ANALOG_CONFIG_BITRATE_848 \
+    (0x0040U) /*!< 848kbits/s settings in Analog Configuration ID               */
+#define RFAL_ANALOG_CONFIG_BITRATE_1695 \
+    (0x0050U) /*!< 1695kbits/s settings in Analog Configuration ID              */
+#define RFAL_ANALOG_CONFIG_BITRATE_3390 \
+    (0x0060U) /*!< 3390kbits/s settings in Analog Configuration ID              */
+#define RFAL_ANALOG_CONFIG_BITRATE_6780 \
+    (0x0070U) /*!< 6780kbits/s settings in Analog Configuration ID              */
+#define RFAL_ANALOG_CONFIG_BITRATE_1OF4 \
+    (0x00C0U) /*!< 1 out of 4 for NFC-V setting in Analog Configuration ID      */
+#define RFAL_ANALOG_CONFIG_BITRATE_1OF256 \
+    (0x00D0U) /*!< 1 out of 256 for NFC-V setting in Analog Configuration ID    */
+
+#define RFAL_ANALOG_CONFIG_NO_DIRECTION \
+    (0x0000U) /*!< No direction setting in Analog Conf ID (Chip Specific only)  */
+#define RFAL_ANALOG_CONFIG_TX \
+    (0x0001U) /*!< Transmission bit setting in Analog Configuration ID          */
+#define RFAL_ANALOG_CONFIG_RX \
+    (0x0002U) /*!< Reception bit setting in Analog Configuration ID             */
+#define RFAL_ANALOG_CONFIG_ANTICOL \
+    (0x0003U) /*!< Anticollision setting in Analog Configuration ID             */
+#define RFAL_ANALOG_CONFIG_DPO \
+    (0x0004U) /*!< DPO setting in Analog Configuration ID                       */
+
+#define RFAL_ANALOG_CONFIG_CHIP_INIT \
+    (0x0000U) /*!< Chip-Specific event: Startup;Reset;Initialize                */
+#define RFAL_ANALOG_CONFIG_CHIP_DEINIT \
+    (0x0001U) /*!< Chip-Specific event: Deinitialize                            */
+#define RFAL_ANALOG_CONFIG_CHIP_FIELD_ON \
+    (0x0002U) /*!< Chip-Specific event: Field On                                */
+#define RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF \
+    (0x0003U) /*!< Chip-Specific event: Field Off                               */
+#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON \
+    (0x0004U) /*!< Chip-Specific event: Wake-up On                              */
+#define RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF \
+    (0x0005U) /*!< Chip-Specific event: Wake-up Off                             */
+#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON \
+    (0x0006U) /*!< Chip-Specific event: Listen On                               */
+#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF \
+    (0x0007U) /*!< Chip-Specific event: Listen Off                              */
+#define RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON \
+    (0x0008U) /*!< Chip-Specific event: Poll common                             */
+#define RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON \
+    (0x0009U) /*!< Chip-Specific event: Listen common                           */
+#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON \
+    (0x000AU) /*!< Chip-Specific event: Low Power On                            */
+#define RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF \
+    (0x000BU) /*!< Chip-Specific event: Low Power Off                           */
+
+#define RFAL_ANALOG_CONFIG_UPDATE_LAST \
+    (0x00U) /*!< Value indicating Last configuration set during update        */
+#define RFAL_ANALOG_CONFIG_UPDATE_MORE \
+    (0x01U) /*!< Value indicating More configuration set coming during update */
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+#define RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(id) \
+    (RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK & (id)) /*!< Check if id indicates Listen mode   */
+
+#define RFAL_ANALOG_CONFIG_ID_GET_TECH(id) \
+    (RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Get the technology of Configuration ID     */
+#define RFAL_ANALOG_CONFIG_ID_IS_CHIP(id) \
+    (RFAL_ANALOG_CONFIG_TECH_MASK & (id)) /*!< Check if ID indicates Chip-specific        */
+#define RFAL_ANALOG_CONFIG_ID_IS_NFCA(id) \
+    (RFAL_ANALOG_CONFIG_TECH_NFCA & (id)) /*!< Check if ID indicates NFC-A                */
+#define RFAL_ANALOG_CONFIG_ID_IS_NFCB(id) \
+    (RFAL_ANALOG_CONFIG_TECH_NFCB & (id)) /*!< Check if ID indicates NFC-B                */
+#define RFAL_ANALOG_CONFIG_ID_IS_NFCF(id) \
+    (RFAL_ANALOG_CONFIG_TECH_NFCF & (id)) /*!< Check if ID indicates NFC-F                */
+#define RFAL_ANALOG_CONFIG_ID_IS_AP2P(id) \
+    (RFAL_ANALOG_CONFIG_TECH_AP2P & (id)) /*!< Check if ID indicates AP2P                 */
+#define RFAL_ANALOG_CONFIG_ID_IS_NFCV(id) \
+    (RFAL_ANALOG_CONFIG_TECH_NFCV & (id)) /*!< Check if ID indicates NFC-V                */
+
+#define RFAL_ANALOG_CONFIG_ID_GET_BITRATE(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Get Bitrate of Configuration ID            */
+#define RFAL_ANALOG_CONFIG_ID_IS_COMMON(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_MASK & (id)) /*!< Check if ID indicates common bitrate       */
+#define RFAL_ANALOG_CONFIG_ID_IS_106(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_106 & (id)) /*!< Check if ID indicates 106kbits/s           */
+#define RFAL_ANALOG_CONFIG_ID_IS_212(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_212 & (id)) /*!< Check if ID indicates 212kbits/s           */
+#define RFAL_ANALOG_CONFIG_ID_IS_424(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_424 & (id)) /*!< Check if ID indicates 424kbits/s           */
+#define RFAL_ANALOG_CONFIG_ID_IS_848(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_848 & (id)) /*!< Check if ID indicates 848kbits/s           */
+#define RFAL_ANALOG_CONFIG_ID_IS_1695(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_1695 & (id)) /*!< Check if ID indicates 1695kbits/s          */
+#define RFAL_ANALOG_CONFIG_ID_IS_3390(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_3390 & (id)) /*!< Check if ID indicates 3390kbits/s          */
+#define RFAL_ANALOG_CONFIG_ID_IS_6780(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_6780 & (id)) /*!< Check if ID indicates 6780kbits/s          */
+#define RFAL_ANALOG_CONFIG_ID_IS_1OF4(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_1OF4 & (id)) /*!< Check if ID indicates 1 out of 4 bitrate   */
+#define RFAL_ANALOG_CONFIG_ID_IS_1OF256(id) \
+    (RFAL_ANALOG_CONFIG_BITRATE_1OF256 & (id)) /*!< Check if ID indicates 1 out of 256 bitrate */
+
+#define RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(id) \
+    (RFAL_ANALOG_CONFIG_DIRECTION_MASK & (id)) /*!< Get Direction of Configuration ID          */
+#define RFAL_ANALOG_CONFIG_ID_IS_TX(id) \
+    (RFAL_ANALOG_CONFIG_TX & (id)) /*!< Check if id indicates TX                   */
+#define RFAL_ANALOG_CONFIG_ID_IS_RX(id) \
+    (RFAL_ANALOG_CONFIG_RX & (id)) /*!< Check if id indicates RX                   */
+
+#define RFAL_ANALOG_CONFIG_CONFIG_NUM(x) \
+    (sizeof(x) / sizeof((x)[0])) /*!< Get Analog Config number                   */
+
+/*! Set Analog Config ID value by: Mode, Technology, Bitrate and Direction      */
+#define RFAL_ANALOG_CONFIG_ID_SET(mode, tech, br, direction)                              \
+    (RFAL_ANALOG_CONFIG_ID_GET_POLL_LISTEN(mode) | RFAL_ANALOG_CONFIG_ID_GET_TECH(tech) | \
+     RFAL_ANALOG_CONFIG_ID_GET_BITRATE(br) | RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(direction))
+
+/*
+ ******************************************************************************
+ * GLOBAL DATA TYPES
+ ******************************************************************************
+ */
+
+typedef uint8_t
+    rfalAnalogConfigMode; /*!< Polling or Listening Mode of Configuration                    */
+typedef uint8_t
+    rfalAnalogConfigTech; /*!< Technology of Configuration                                   */
+typedef uint8_t
+    rfalAnalogConfigBitrate; /*!< Bitrate of Configuration                                      */
+typedef uint8_t
+    rfalAnalogConfigDirection; /*!< Transmit/Receive direction of Configuration                   */
+
+typedef uint8_t
+    rfalAnalogConfigRegAddr[2]; /*!< Register Address to ST Chip                                   */
+typedef uint8_t
+    rfalAnalogConfigRegMask; /*!< Register Mask Value                                           */
+typedef uint8_t
+    rfalAnalogConfigRegVal; /*!< Register Value                                                */
+
+typedef uint16_t
+    rfalAnalogConfigId; /*!< Analog Configuration ID                                       */
+typedef uint16_t
+    rfalAnalogConfigOffset; /*!< Analog Configuration offset address in the table              */
+typedef uint8_t
+    rfalAnalogConfigNum; /*!< Number of Analog settings for the respective Configuration ID */
+
+/*! Struct that contain the Register-Mask-Value set. Make sure that the whole structure size is even and unaligned! */
+typedef struct {
+    rfalAnalogConfigRegAddr addr; /*!< Register Address    */
+    rfalAnalogConfigRegMask mask; /*!< Register Mask Value */
+    rfalAnalogConfigRegVal val; /*!< Register Value      */
+} rfalAnalogConfigRegAddrMaskVal;
+
+/*! Struct that represents the Analog Configs */
+typedef struct {
+    uint8_t id[sizeof(rfalAnalogConfigId)]; /*!< Configuration ID                   */
+    rfalAnalogConfigNum num; /*!< Number of Config Sets to follow    */
+    rfalAnalogConfigRegAddrMaskVal regSet[];
+    /*!< Register-Mask-Value sets           */ /*  PRQA S 1060 # MISRA 18.7 - Flexible Array Members are the only meaningful way of denoting a variable length input buffer which follows a fixed header structure. */
+} rfalAnalogConfig;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*!
+ *****************************************************************************
+ * \brief Initialize the Analog Configuration
+ * 
+ * Reset the Analog Configuration LUT pointer to reference to default settings.
+ * 
+ *****************************************************************************
+ */
+void rfalAnalogConfigInitialize(void);
+
+/*!
+ *****************************************************************************
+ * \brief Indicate if the current Analog Configuration Table is complete and ready to be used.
+ * 
+ * \return true if current Analog Configuration Table is complete and ready to be used.
+ * \return false if current Analog Configuration Table is incomplete
+ * 
+ *****************************************************************************
+ */
+bool rfalAnalogConfigIsReady(void);
+
+/*!
+ *****************************************************************************
+ * \brief  Write the whole Analog Configuration table in raw format 
+ *  
+ * Writes the Analog Configuration and Look Up Table with the given raw table
+ * 
+ * NOTE: Function does not check the validity of the given Table contents
+ * 
+ * \param[in]  configTbl:     location of config Table to be loaded
+ * \param[in]  configTblSize: size of the config Table to be loaded
+ * 
+ * \return ERR_NONE    : if setting is updated
+ * \return ERR_PARAM   : if configTbl is invalid
+ * \return ERR_NOMEM   : if the given Table is bigger exceeds the max size
+ * \return ERR_REQUEST : if the update Configuration Id is disabled
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalAnalogConfigListWriteRaw(const uint8_t* configTbl, uint16_t configTblSize);
+
+/*!
+ *****************************************************************************
+ * \brief  Write the Analog Configuration table with new analog settings.
+ *  
+ * Writes the Analog Configuration and Look Up Table with the new list of register-mask-value 
+ * and Configuration ID respectively.
+ * 
+ * NOTE: Function does not check for the validity of the Register Address.
+ * 
+ * \param[in]  more: 0x00 indicates it is last Configuration ID settings; 
+ *                   0x01 indicates more Configuration ID setting(s) are coming.
+ * \param[in]  *config: reference to the configuration list of current Configuration ID.
+ *                          
+ * \return ERR_PARAM   : if Configuration ID or parameter is invalid
+ * \return ERR_NOMEM   : if LUT is full      
+ * \return ERR_REQUEST : if the update Configuration Id is disabled               
+ * \return ERR_NONE    : if setting is updated
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalAnalogConfigListWrite(uint8_t more, const rfalAnalogConfig* config);
+
+/*!
+ *****************************************************************************
+ * \brief  Read the whole Analog Configuration table in raw format
+ *  
+ * Reads the whole Analog Configuration Table in raw format
+ * 
+ * \param[out]   tblBuf: location to the buffer to place the Config Table 
+ * \param[in]    tblBufLen: length of the buffer to place the Config Table
+ * \param[out]   configTblSize: Config Table size 
+ *                          
+ * \return ERR_PARAM : if configTbl or configTblSize is invalid
+ * \return ERR_NOMEM : if configTblSize is not enough for the whole table           
+ * \return ERR_NONE  : if read is successful
+ * 
+ *****************************************************************************
+ */
+ReturnCode
+    rfalAnalogConfigListReadRaw(uint8_t* tblBuf, uint16_t tblBufLen, uint16_t* configTblSize);
+
+/*!
+ *****************************************************************************
+ * \brief  Read the Analog Configuration table.
+ *  
+ * Read the Analog Configuration Table
+ * 
+ * \param[in]     configOffset: offset to the next Configuration ID in the List Table to be read.   
+ * \param[out]    more: 0x00 indicates it is last Configuration ID settings; 
+ *                      0x01 indicates more Configuration ID setting(s) are coming.
+ * \param[out]    config: configuration id, number of configuration sets and register-mask-value sets
+ * \param[in]     numConfig: the remaining configuration settings space available;
+ *                          
+ * \return ERR_NOMEM : if number of Configuration for respective Configuration ID is greater the the remaining configuration setting space available                
+ * \return ERR_NONE  : if read is successful
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalAnalogConfigListRead(
+    rfalAnalogConfigOffset* configOffset,
+    uint8_t* more,
+    rfalAnalogConfig* config,
+    rfalAnalogConfigNum numConfig);
+
+/*!
+ *****************************************************************************
+ * \brief  Set the Analog settings of indicated Configuration ID.
+ *  
+ * Update the chip with indicated analog settings of indicated Configuration ID.
+ *
+ * \param[in]  configId: configuration ID
+ *                            
+ * \return ERR_PARAM if Configuration ID is invalid
+ * \return ERR_INTERNAL if error updating setting to chip                   
+ * \return ERR_NONE if new settings is applied to chip
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalSetAnalogConfig(rfalAnalogConfigId configId);
+
+/*!
+ *****************************************************************************
+ * \brief  Generates Analog Config mode ID 
+ *
+ * Converts RFAL mode and bitrate into Analog Config Mode ID.
+ *  
+ * Update the chip with indicated analog settings of indicated Configuration ID.
+ *
+ * \param[in]  md:  RFAL mode format
+ * \param[in]  br:  RFAL bit rate format
+ * \param[in]  dir: Analog Config communication direction
+ *                            
+ * \return  Analog Config Mode ID
+ *
+ *****************************************************************************
+ */
+uint16_t rfalAnalogConfigGenModeID(rfalMode md, rfalBitRate br, uint16_t dir);
+
+#endif /* RFAL_ANALOG_CONFIG_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 287 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_chip.h

@@ -0,0 +1,287 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_chip.h
+ *
+ *  \author Gustavo Patricio 
+ *
+ *  \brief RF Chip specific Layer
+ *  
+ *  \warning This layer, which provides direct access to RF chip, should 
+ *           only be used for debug purposes and/or advanced features
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup Chip
+ * \brief RFAL RF Chip Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_CHIP_H
+#define RFAL_CHIP_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*****************************************************************************
+ *  RF Chip                                                                  *  
+ *****************************************************************************/
+
+/*!
+ *****************************************************************************
+ * \brief Writes a register on the RF Chip
+ *
+ * Checks if the given register is valid and if so, writes the value(s)
+ * on the RF Chip register
+ * 
+ * \param[in] reg: register address to be written, or the first if len > 1
+ * \param[in] values: pointer with content to be written on the register(s)
+ * \param[in] len: number of consecutive registers to be written
+ *  
+ * 
+ * \return ERR_PARAM    : Invalid register or bad request
+ * \return ERR_NOTSUPP  : Feature not supported
+ * \return ERR_NONE     : Write done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipWriteReg(uint16_t reg, const uint8_t* values, uint8_t len);
+
+/*!
+ *****************************************************************************
+ * \brief Reads a register on the RF Chip
+ *
+ * Checks if the given register is valid and if so, reads the value(s)
+ * of the RF Chip register(s)
+ * 
+ * \param[in]  reg: register address to be read, or the first if len > 1
+ * \param[out] values: pointer where the register(s) read content will be placed 
+ * \param[in]  len: number of consecutive registers to be read  
+ * 
+ * \return ERR_PARAM    : Invalid register or bad request
+ * \return ERR_NOTSUPP  : Feature not supported
+ * \return ERR_NONE     : Read done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipReadReg(uint16_t reg, uint8_t* values, uint8_t len);
+
+/*!
+ *****************************************************************************
+ * \brief Change a register on the RF Chip
+ *
+ * Change the value of the register bits on the RF Chip Test set in the valueMask. 
+ * 
+ * \param[in] reg: register address to be modified
+ * \param[in] valueMask: mask value of the register bits to be changed
+ * \param[in] value: register value to be set
+ * 
+ * \return ERR_PARAM    : Invalid register or bad request
+ * \return ERR_NOTSUPP  : Feature not supported
+ * \return ERR_OK       : Change done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipChangeRegBits(uint16_t reg, uint8_t valueMask, uint8_t value);
+
+/*!
+ *****************************************************************************
+ * \brief Writes a Test register on the RF Chip
+ *
+ * Writes the value on the RF Chip Test register
+ * 
+ * \param[in] reg: register address to be written
+ * \param[in] value: value to be written on the register
+ *  
+ * 
+ * \return ERR_PARAM    : Invalid register or bad request
+ * \return ERR_NOTSUPP  : Feature not supported
+ * \return ERR_NONE     : Write done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipWriteTestReg(uint16_t reg, uint8_t value);
+
+/*!
+ *****************************************************************************
+ * \brief Reads a Test register on the RF Chip
+ *
+ * Reads the value of the RF Chip Test register
+ * 
+ * \param[in]  reg: register address to be read
+ * \param[out] value: pointer where the register content will be placed  
+ * 
+ * \return ERR_PARAM    :Invalid register or bad request
+ * \return ERR_NOTSUPP  : Feature not supported
+ * \return ERR_NONE     : Read done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipReadTestReg(uint16_t reg, uint8_t* value);
+
+/*!
+ *****************************************************************************
+ * \brief Change a Test register on the RF Chip
+ *
+ * Change the value of the register bits on the RF Chip Test set in the valueMask. 
+ * 
+ * \param[in] reg: test register address to be modified
+ * \param[in] valueMask: mask value of the register bits to be changed
+ * \param[in] value: register value to be set
+ * 
+ * \return ERR_PARAM     : Invalid register or bad request
+ * \return ERR_NOTSUPP   : Feature not supported
+ * \return ERR_OK        : Change done with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipChangeTestRegBits(uint16_t reg, uint8_t valueMask, uint8_t value);
+
+/*!
+ *****************************************************************************
+ * \brief Execute command on the RF Chip
+ *
+ * Checks if the given command is valid and if so, executes it on 
+ * the RF Chip
+ * 
+ * \param[in] cmd: direct command to be executed
+ * 
+ * \return ERR_PARAM     : Invalid command or bad request
+ * \return  ERR_NOTSUPP  : Feature not supported
+ * \return ERR_NONE      : Direct command executed with no error
+ *****************************************************************************
+ */
+ReturnCode rfalChipExecCmd(uint16_t cmd);
+
+/*! 
+ *****************************************************************************
+ * \brief  Set RFO
+ *
+ * Sets the RFO value to be used when the field is on (unmodulated/active)
+ * 
+ * \param[in] rfo : the RFO value to be used
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipSetRFO(uint8_t rfo);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get RFO
+ *
+ * Gets the RFO value used used when the field is on (unmodulated/active)
+ *
+ * \param[out] result : the current RFO value 
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipGetRFO(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ * \brief  Measure Amplitude
+ *
+ * Measures the RF Amplitude
+ *
+ * \param[out] result : result of RF measurement
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipMeasureAmplitude(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ * \brief  Measure Phase
+ *
+ * Measures the Phase
+ *
+ * \param[out] result : result of Phase measurement
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipMeasurePhase(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ * \brief  Measure Capacitance
+ *
+ * Measures the Capacitance
+ *
+ * \param[out] result : result of Capacitance measurement
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipMeasureCapacitance(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ * \brief  Measure Power Supply
+ *
+ * Measures the Power Supply
+ *
+ * \param[in]   param : measurement parameter (chip specific)
+ * \param[out] result : result of the measurement
+ *
+ * \return  ERR_IO           : Internal error
+ * \return  ERR_NOTSUPP      : Feature not supported
+ * \return  ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalChipMeasurePowerSupply(uint8_t param, uint8_t* result);
+
+#endif /* RFAL_CHIP_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 74 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_crc.h

@@ -0,0 +1,74 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_crc.h
+ *
+ *  \author Ulrich Herrmann
+ *
+ *  \brief CRC calculation module
+ *
+ */
+/*!
+ * 
+ */
+
+#ifndef RFAL_CRC_H_
+#define RFAL_CRC_H_
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../platform.h"
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+/*! 
+ *****************************************************************************
+ *  \brief  Calculate CRC according to CCITT standard.
+ *
+ *  This function takes \a length bytes from \a buf and calculates the CRC
+ *  for this data. The result is returned.
+ *  \note This implementation calculates the CRC with LSB first, i.e. all
+ *  bytes are "read" from right to left.
+ *
+ *  \param[in] preloadValue : Initial value of CRC calculation.
+ *  \param[in] buf : buffer to calculate the CRC for.
+ *  \param[in] length : size of the buffer.
+ *
+ *  \return 16 bit long crc value.
+ *
+ *****************************************************************************
+ */
+extern uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length);
+
+#endif /* RFAL_CRC_H_ */

+ 207 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_dpo.h

@@ -0,0 +1,207 @@
+
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      $Revision: $
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_dpo.h
+ *
+ *  \author Martin Zechleitner
+ *
+ *  \brief Dynamic Power adjustment
+ *  
+ *  This module provides an interface to perform the power adjustment dynamically 
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup DPO
+ * \brief RFAL Dynamic Power Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_DPO_H
+#define RFAL_DPO_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_DPO_TABLE_SIZE_MAX 15U /*!< Max DPO table size */
+#define RFAL_DPO_TABLE_PARAMETER 3U /*!< DPO table Parameter length */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! DPO table entry struct */
+typedef struct {
+    uint8_t rfoRes; /*!< Setting for the resistance level of the RFO */
+    uint8_t inc; /*!< Threshold for incrementing the output power */
+    uint8_t dec; /*!< Threshold for decrementing the output power */
+} rfalDpoEntry;
+
+/*! Function pointer to method doing the reference measurement */
+typedef ReturnCode (*rfalDpoMeasureFunc)(uint8_t*);
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize dynamic power table
+ *  
+ *  This function sets the internal dynamic power table to the default 
+ *  values stored in rfal_DpoTbl.h
+ *  
+ *****************************************************************************
+ */
+void rfalDpoInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Set the measurement method
+ *  
+ * This function sets the measurement method used for reference measurement.
+ * Based on the measurement the power will then be adjusted
+ *  
+ * \param[in]  dpoMeasureFunc: callback of measurement function
+ *
+ *****************************************************************************
+ */
+void rfalDpoSetMeasureCallback(rfalDpoMeasureFunc dpoMeasureFunc);
+
+/*! 
+ *****************************************************************************
+ * \brief  Write dynamic power table
+ *  
+ * Load the dynamic power table  
+ *
+ * \param[in]  powerTbl:     location of power Table to be loaded
+ * \param[in]  powerTblEntries: number of entries of the power Table to be loaded
+ * 
+ * \return ERR_NONE    : No error
+ * \return ERR_PARAM   : if configTbl is invalid
+ * \return ERR_NOMEM   : if the given Table is bigger exceeds the max size
+ *****************************************************************************
+ */
+ReturnCode rfalDpoTableWrite(rfalDpoEntry* powerTbl, uint8_t powerTblEntries);
+
+/*! 
+ *****************************************************************************
+ * \brief  Dynamic power table Read
+ *  
+ * Read the dynamic power table  
+ *
+ * \param[out]   tblBuf: location to the rfalDpoEntry[] to place the Table 
+ * \param[in]    tblBufEntries: number of entries available in tblBuf to place the power Table
+ * \param[out]   tableEntries: returned number of entries actually written into tblBuf
+ * 
+ * \return ERR_NONE    : No error
+ * \return ERR_PARAM   : if configTbl is invalid or parameters are invalid
+ *****************************************************************************
+ */
+ReturnCode rfalDpoTableRead(rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries);
+
+/*! 
+ *****************************************************************************
+ * \brief  Dynamic power adjust
+ *  
+ * It measures the current output and adjusts the power accordingly to 
+ * the dynamic power table  
+ * 
+ * \return ERR_NONE        : No error
+ * \return ERR_PARAM       : if configTbl is invalid or parameters are invalid
+ * \return ERR_WRONG_STATE : if the current state is valid for DPO Adjustment
+ *****************************************************************************
+ */
+ReturnCode rfalDpoAdjust(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get Current Dynamic power table entry
+ *  
+ * Return current used DPO power table entry settings
+ *
+ * \return ERR_NONE    : Current DpoEntry. This includes d_res, inc and dec
+ * 
+ *****************************************************************************
+ */
+rfalDpoEntry* rfalDpoGetCurrentTableEntry(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Dynamic power set enabled state
+ *  
+ * \param[in]     enable: new active state
+ *
+ * Set state to enable or disable the Dynamic power adjustment 
+ * 
+ *****************************************************************************
+ */
+void rfalDpoSetEnabled(bool enable);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get the Dynamic power enabled state
+ *  
+ * Get state of the Dynamic power adjustment 
+ * 
+ * \return true   : enabled
+ * \return false  : disabled
+ *****************************************************************************
+ */
+bool rfalDpoIsEnabled(void);
+
+#endif /* RFAL_DPO_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 206 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_iso15693_2.h

@@ -0,0 +1,206 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_iso15693_2.h
+ *
+ *  \author Ulrich Herrmann
+ *
+ *  \brief Implementation of ISO-15693-2
+ *
+ */
+/*!
+ * 
+ */
+
+#ifndef RFAL_ISO_15693_2_H
+#define RFAL_ISO_15693_2_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../platform.h"
+#include "../st_errno.h"
+
+/*
+******************************************************************************
+* GLOBAL DATATYPES
+******************************************************************************
+*/
+/*! Enum holding possible VCD codings  */
+typedef enum { ISO15693_VCD_CODING_1_4, ISO15693_VCD_CODING_1_256 } iso15693VcdCoding_t;
+
+/*! Enum holding possible VICC datarates */
+
+/*! Configuration parameter used by #iso15693PhyConfigure  */
+typedef struct {
+    iso15693VcdCoding_t coding; /*!< desired VCD coding                                       */
+    uint32_t
+        speedMode; /*!< 0: normal mode, 1: 2^1 = x2 Fast mode, 2 : 2^2 = x4 mode, 3 : 2^3 = x8 mode - all rx pulse numbers and times are divided by 1,2,4,8 */
+} iso15693PhyConfig_t;
+
+/*! Parameters how the stream mode should work */
+struct iso15693StreamConfig {
+    uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK */
+    uint8_t din; /*!< the divider for the in subcarrier frequency: fc/2^din  */
+    uint8_t dout; /*!< the divider for the in subcarrier frequency fc/2^dout */
+    uint8_t report_period_length; /*!< the length of the reporting period 2^report_period_length*/
+};
+/*
+******************************************************************************
+* GLOBAL CONSTANTS
+******************************************************************************
+*/
+
+#define ISO15693_REQ_FLAG_TWO_SUBCARRIERS \
+    0x01U /*!< Flag indication that communication uses two subcarriers */
+#define ISO15693_REQ_FLAG_HIGH_DATARATE \
+    0x02U /*!< Flag indication that communication uses high bitrate    */
+#define ISO15693_MASK_FDT_LISTEN \
+    (65) /*!< t1min = 308,2us = 4192/fc = 65.5 * 64/fc                */
+
+/*! t1max = 323,3us = 4384/fc = 68.5 * 64/fc
+ *         12 = 768/fc unmodulated time of single subcarrior SoF */
+#define ISO15693_FWT (69 + 12)
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+/*! 
+ *****************************************************************************
+ *  \brief  Initialize the ISO15693 phy
+ *
+ *  \param[in] config : ISO15693 phy related configuration (See #iso15693PhyConfig_t)
+ *  \param[out] needed_stream_config : return a pointer to the stream config 
+ *              needed for this iso15693 config. To be used for configure RF chip.
+ *
+ *  \return ERR_IO : Error during communication.
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+extern ReturnCode iso15693PhyConfigure(
+    const iso15693PhyConfig_t* config,
+    const struct iso15693StreamConfig** needed_stream_config);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Return current phy configuration
+ *
+ *  This function returns current Phy configuration previously
+ *  set by #iso15693PhyConfigure
+ *
+ *  \param[out] config : ISO15693 phy configuration.
+ *
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+extern ReturnCode iso15693PhyGetConfiguration(iso15693PhyConfig_t* config);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Code an ISO15693 compatible frame
+ *
+ *  This function takes \a length bytes from \a buffer, perform proper
+ *  encoding and sends out the frame to the ST25R391x.
+ *
+ *  \param[in] buffer : data to send, modified to adapt flags.
+ *  \param[in] length : number of bytes to send.
+ *  \param[in] sendCrc : If set to true, CRC is appended to the frame
+ *  \param[in] sendFlags: If set to true, flag field is sent according to
+ *                        ISO15693.
+ *  \param[in] picopassMode :  If set to true, the coding will be according to Picopass
+ *  \param[out] subbit_total_length : Return the complete bytes which need to 
+ *                                   be send for the current coding
+ *  \param[in,out] offset : Set to 0 for first transfer, function will update it to
+                            point to next byte to be coded
+ *  \param[out] outbuf : buffer where the function will store the coded subbit stream
+ *  \param[out] outBufSize : the size of the output buffer
+ *  \param[out] actOutBufSize : the amount of data stored into the buffer at this call
+ *
+ *  \return ERR_IO : Error during communication.
+ *  \return ERR_AGAIN : Data was not coded all the way. Call function again with a new/emptied buffer
+ *  \return ERR_NO_MEM : In case outBuf is not big enough. Needs to have at 
+                         least 5 bytes for 1of4 coding and 65 bytes for 1of256 coding
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+extern ReturnCode iso15693VCDCode(
+    uint8_t* buffer,
+    uint16_t length,
+    bool sendCrc,
+    bool sendFlags,
+    bool picopassMode,
+    uint16_t* subbit_total_length,
+    uint16_t* offset,
+    uint8_t* outbuf,
+    uint16_t outBufSize,
+    uint16_t* actOutBufSize);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Receive an ISO15693 compatible frame
+ *
+ *  This function receives an ISO15693 frame from the ST25R391x, decodes the frame
+ *  and writes the raw data to \a buffer.
+ *  \note Buffer needs to be big enough to hold CRC also (+2 bytes)
+ *
+ *  \param[in] inBuf : buffer with the hamming coded stream to be decoded
+ *  \param[in] inBufLen : number of bytes to decode (=length of buffer).
+ *  \param[out] outBuf : buffer where received data shall be written to.
+ *  \param[in] outBufLen : Length of output buffer, should be approx twice the size of inBuf
+ *  \param[out] outBufPos : The number of decoded bytes. Could be used in 
+ *                          extended implementation to allow multiple calls
+ *  \param[out] bitsBeforeCol : in case of ERR_COLLISION this value holds the
+ *   number of bits in the current byte where the collision happened.
+ *  \param[in] ignoreBits : number of bits in the beginning where collisions will be ignored
+ *  \param[in] picopassMode :  if set to true, the decoding will be according to Picopass
+ *
+ *  \return ERR_COLLISION : collision occurred, data incorrect
+ *  \return ERR_CRC : CRC error, data incorrect
+ *  \return ERR_TIMEOUT : timeout waiting for data.
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+extern ReturnCode iso15693VICCDecode(
+    const uint8_t* inBuf,
+    uint16_t inBufLen,
+    uint8_t* outBuf,
+    uint16_t outBufLen,
+    uint16_t* outBufPos,
+    uint16_t* bitsBeforeCol,
+    uint16_t ignoreBits,
+    bool picopassMode);
+
+#endif /* RFAL_ISO_15693_2_H */

+ 1092 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_isoDep.h

@@ -0,0 +1,1092 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_isoDep.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of ISO-DEP protocol
+ *  
+ *  This implementation was based on the following specs:
+ *    - ISO/IEC 14443-4  2nd Edition 2008-07-15
+ *    - NFC Forum Digital Protocol  1.1 2014-01-14
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup ISO-DEP
+ * \brief RFAL ISO-DEP Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_ISODEP_H_
+#define RFAL_ISODEP_H_
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "rfal_nfcb.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_ISO_DEP
+#define RFAL_FEATURE_ISO_DEP \
+    false /*!< ISO-DEP module configuration missing. Disabled by default */
+#endif
+
+/* If module is disabled remove the need for the user to set lengths */
+#if !RFAL_FEATURE_ISO_DEP
+#undef RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN
+#undef RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN
+
+#define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN (1U) /*!< ISO-DEP I-Block max length, set to "none" */
+#define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN (1U) /*!< ISO-DEP APDU max length, set to "none"    */
+#endif /* !RFAL_FEATURE_NFC_DEP  */
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_ISODEP_PROLOGUE_SIZE \
+    (3U) /*!< Length of Prologue Field for I-Block Format                       */
+
+#define RFAL_ISODEP_PCB_LEN \
+    (1U) /*!< PCB length                                                        */
+#define RFAL_ISODEP_DID_LEN \
+    (1U) /*!< DID length                                                        */
+#define RFAL_ISODEP_NAD_LEN \
+    (1U) /*!< NAD length                                                        */
+#define RFAL_ISODEP_NO_DID \
+    (0x00U) /*!< DID value indicating the ISO-DEP layer not to use DID             */
+#define RFAL_ISODEP_NO_NAD \
+    (0xFFU) /*!< NAD value indicating the ISO-DEP layer not to use NAD             */
+
+#define RFAL_ISODEP_FWI_MASK \
+    (0xF0U) /*!< Mask bits of FWI                                                  */
+#define RFAL_ISODEP_FWI_SHIFT \
+    (4U) /*!< Shift val of FWI                                                  */
+#define RFAL_ISODEP_FWI_DEFAULT \
+    (4U) /*!< Default value for FWI Digital 1.0 11.6.2.17                       */
+#define RFAL_ISODEP_ADV_FEATURE \
+    (0x0FU) /*!< Indicate 256 Bytes FSD and Advanc Proto Feature support:NAD & DID */
+
+#define RFAL_ISODEP_DID_MAX \
+    (14U) /*!< Maximum DID value                                                 */
+
+#define RFAL_ISODEP_BRI_MASK \
+    (0x07U) /*!< Mask bits for Poll to Listen Send bitrate                         */
+#define RFAL_ISODEP_BSI_MASK \
+    (0x70U) /*!< Mask bits for Listen to Poll Send bitrate                         */
+#define RFAL_ISODEP_SAME_BITRATE_MASK \
+    (0x80U) /*!< Mask bit indicate only same bit rate D for both direction support */
+#define RFAL_ISODEP_BITRATE_RFU_MASK \
+    (0x08U) /*!< Mask bit for RFU                                                  */
+
+/*! Maximum Frame Waiting Time = ((256 * 16/fc) * 2^FWImax) = ((256*16/fc)*2^14) = (67108864)/fc = 2^26 (1/fc)                  */
+#define RFAL_ISODEP_MAX_FWT ((uint32_t)1U << 26)
+
+#define RFAL_ISODEP_FSDI_DEFAULT \
+    RFAL_ISODEP_FSXI_256 /*!< Default Frame Size Integer in Poll mode              */
+#define RFAL_ISODEP_FSX_KEEP (0xFFU) /*!< Flag to keep FSX from activation                     */
+#define RFAL_ISODEP_DEFAULT_FSCI \
+    RFAL_ISODEP_FSXI_256 /*!< FSCI default value to be used  in Listen Mode        */
+#define RFAL_ISODEP_DEFAULT_FSC \
+    RFAL_ISODEP_FSX_256 /*!< FSC default value (aligned RFAL_ISODEP_DEFAULT_FSCI) */
+#define RFAL_ISODEP_DEFAULT_SFGI (0U) /*!< SFGI Default value to be used  in Listen Mode        */
+#define RFAL_ISODEP_DEFAULT_FWI (8U) /*!< Default Listener FWI (Max)      Digital 2.0  B7 & B3 */
+
+#define RFAL_ISODEP_APDU_MAX_LEN \
+    RFAL_ISODEP_FSX_1024 /*!< Max APDU length                                      */
+
+#define RFAL_ISODEP_ATTRIB_RES_MBLI_NO_INFO \
+    (0x00U) /*!< MBLI indicating no information on its internal input buffer size  */
+#define RFAL_ISODEP_ATTRIB_REQ_PARAM1_DEFAULT \
+    (0x00U) /*!< Default values of Param 1 of ATTRIB_REQ Digital 1.0  12.6.1.3-5   */
+#define RFAL_ISODEP_ATTRIB_HLINFO_LEN \
+    (32U) /*!< Maximum Size of Higher Layer Information                          */
+#define RFAL_ISODEP_ATS_HB_MAX_LEN \
+    (15U) /*!< Maximum length of Historical Bytes  Digital 1.1  13.6.2.23        */
+#define RFAL_ISODEP_ATTRIB_REQ_MIN_LEN \
+    (9U) /*!< Minimum Length of ATTRIB_REQ command                              */
+#define RFAL_ISODEP_ATTRIB_RES_MIN_LEN \
+    (1U) /*!< Minimum Length of ATTRIB_RES response                             */
+
+#define RFAL_ISODEP_SPARAM_VALUES_MAX_LEN \
+    (16U) /*!< Maximum Length of the value field on S(PARAMETERS)                */
+#define RFAL_ISODEP_SPARAM_TAG_BLOCKINFO \
+    (0xA0U) /*!< S(PARAMETERS) tag Block information                               */
+#define RFAL_ISODEP_SPARAM_TAG_BRREQ \
+    (0xA1U) /*!< S(PARAMETERS) tag Bit rates Request                               */
+#define RFAL_ISODEP_SPARAM_TAG_BRIND \
+    (0xA2U) /*!< S(PARAMETERS) tag Bit rates Indication                            */
+#define RFAL_ISODEP_SPARAM_TAG_BRACT \
+    (0xA3U) /*!< S(PARAMETERS) tag Bit rates Activation                            */
+#define RFAL_ISODEP_SPARAM_TAG_BRACK \
+    (0xA4U) /*!< S(PARAMETERS) tag Bit rates Acknowledgement                       */
+
+#define RFAL_ISODEP_SPARAM_TAG_SUP_PCD2PICC \
+    (0x80U) /*!< S(PARAMETERS) tag Supported bit rates from PCD to PICC            */
+#define RFAL_ISODEP_SPARAM_TAG_SUP_PICC2PCD \
+    (0x81U) /*!< S(PARAMETERS) tag Supported bit rates from PICC to PCD            */
+#define RFAL_ISODEP_SPARAM_TAG_SUP_FRAME \
+    (0x82U) /*!< S(PARAMETERS) tag Supported framing options PICC to PCD           */
+#define RFAL_ISODEP_SPARAM_TAG_SEL_PCD2PICC \
+    (0x83U) /*!< S(PARAMETERS) tag Selected bit rate from PCD to PICC              */
+#define RFAL_ISODEP_SPARAM_TAG_SEL_PICC2PCD \
+    (0x84U) /*!< S(PARAMETERS) tag Selected bit rate from PICC to PCD              */
+#define RFAL_ISODEP_SPARAM_TAG_SEL_FRAME \
+    (0x85U) /*!< S(PARAMETERS) tag Selected framing options PICC to PCD            */
+
+#define RFAL_ISODEP_SPARAM_TAG_LEN \
+    (1) /*!< S(PARAMETERS) Tag Length                                          */
+#define RFAL_ISODEP_SPARAM_TAG_BRREQ_LEN \
+    (0U) /*!< S(PARAMETERS) tag Bit rates Request Length                        */
+#define RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN \
+    (2U) /*!< S(PARAMETERS) bit rates from PCD to PICC Length                   */
+#define RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN \
+    (2U) /*!< S(PARAMETERS) bit rates from PICC to PCD Length                   */
+#define RFAL_ISODEP_SPARAM_TAG_BRACK_LEN \
+    (0U) /*!< S(PARAMETERS) tag Bit rates Acknowledgement Length                */
+
+#define RFAL_ISODEP_ATS_TA_DPL_212 \
+    (0x01U) /*!< ATS TA DSI 212 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_DPL_424 \
+    (0x02U) /*!< ATS TA DSI 424 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_DPL_848 \
+    (0x04U) /*!< ATS TA DSI 848 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_DLP_212 \
+    (0x10U) /*!< ATS TA DSI 212 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_DLP_424 \
+    (0x20U) /*!< ATS TA DRI 424 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_DLP_848 \
+    (0x40U) /*!< ATS TA DRI 848 kbps support bit mask                              */
+#define RFAL_ISODEP_ATS_TA_SAME_D \
+    (0x80U) /*!< ATS TA same bit both directions bit mask                          */
+#define RFAL_ISODEP_ATS_TB_FWI_MASK \
+    (0xF0U) /*!< Mask bits for FWI (Frame Waiting Integer) in TB byte              */
+#define RFAL_ISODEP_ATS_TB_SFGI_MASK \
+    (0x0FU) /*!< Mask bits for SFGI (Start-Up Frame Guard Integer) in TB byte      */
+
+#define RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK \
+    (0x10U) /*!< Mask bit for TA presence                                          */
+#define RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK \
+    (0x20U) /*!< Mask bit for TB presence                                          */
+#define RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK \
+    (0x40U) /*!< Mask bit for TC presence                                          */
+#define RFAL_ISODEP_ATS_T0_FSCI_MASK \
+    (0x0FU) /*!< Mask bit for FSCI presence                                        */
+#define RFAL_ISODEP_ATS_T0_OFFSET \
+    (0x01U) /*!< Offset of T0 in ATS Response                                      */
+
+#define RFAL_ISODEP_MAX_I_RETRYS \
+    (2U) /*!< Number of retries for a I-Block     Digital 2.0   16.2.5.4                  */
+#define RFAL_ISODEP_MAX_R_RETRYS \
+    (3U) /*!< Number of retries for a R-Block     Digital 2.0 B9 - nRETRY ACK/NAK: [2,5]  */
+#define RFAL_ISODEP_MAX_WTX_NACK_RETRYS \
+    (3U) /*!< Number of S(WTX) replied with NACK  Digital 2.0 B9 - nRETRY WTX[2,5]        */
+#define RFAL_ISODEP_MAX_WTX_RETRYS \
+    (20U) /*!< Number of overall S(WTX) retries    Digital 2.0  16.2.5.2                   */
+#define RFAL_ISODEP_MAX_WTX_RETRYS_ULTD \
+    (255U) /*!< Use unlimited number of overall S(WTX)                                      */
+#define RFAL_ISODEP_MAX_DSL_RETRYS \
+    (0U) /*!< Number of retries for a S(DESELECT) Digital 2.0 B9 - nRETRY DESELECT: [0,5] */
+#define RFAL_ISODEP_RATS_RETRIES \
+    (1U) /*!< RATS retries upon fail              Digital 2.0 B7 - nRETRY RATS [0,1]      */
+
+/*! Frame Size for Proximity Card Integer definitions                                                               */
+typedef enum {
+    RFAL_ISODEP_FSXI_16 =
+        0, /*!< Frame Size for Proximity Card Integer with 16 bytes                         */
+    RFAL_ISODEP_FSXI_24 =
+        1, /*!< Frame Size for Proximity Card Integer with 24 bytes                         */
+    RFAL_ISODEP_FSXI_32 =
+        2, /*!< Frame Size for Proximity Card Integer with 32 bytes                         */
+    RFAL_ISODEP_FSXI_40 =
+        3, /*!< Frame Size for Proximity Card Integer with 40 bytes                         */
+    RFAL_ISODEP_FSXI_48 =
+        4, /*!< Frame Size for Proximity Card Integer with 48 bytes                         */
+    RFAL_ISODEP_FSXI_64 =
+        5, /*!< Frame Size for Proximity Card Integer with 64 bytes                         */
+    RFAL_ISODEP_FSXI_96 =
+        6, /*!< Frame Size for Proximity Card Integer with 96 bytes                         */
+    RFAL_ISODEP_FSXI_128 =
+        7, /*!< Frame Size for Proximity Card Integer with 128 bytes                        */
+    RFAL_ISODEP_FSXI_256 =
+        8, /*!< Frame Size for Proximity Card Integer with 256 bytes                        */
+    RFAL_ISODEP_FSXI_512 =
+        9, /*!< Frame Size for Proximity Card Integer with 512 bytes   ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSXI_1024 =
+        10, /*!< Frame Size for Proximity Card Integer with 1024 bytes  ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSXI_2048 =
+        11, /*!< Frame Size for Proximity Card Integer with 2048 bytes  ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSXI_4096 =
+        12 /*!< Frame Size for Proximity Card Integer with 4096 bytes  ISO14443-3 Amd2 2012 */
+} rfalIsoDepFSxI;
+
+/*! Frame Size for Proximity Card  definitions                                                             */
+typedef enum {
+    RFAL_ISODEP_FSX_16 =
+        16, /*!< Frame Size for Proximity Card with 16 bytes                         */
+    RFAL_ISODEP_FSX_24 =
+        24, /*!< Frame Size for Proximity Card with 24 bytes                         */
+    RFAL_ISODEP_FSX_32 =
+        32, /*!< Frame Size for Proximity Card with 32 bytes                         */
+    RFAL_ISODEP_FSX_40 =
+        40, /*!< Frame Size for Proximity Card with 40 bytes                         */
+    RFAL_ISODEP_FSX_48 =
+        48, /*!< Frame Size for Proximity Card with 48 bytes                         */
+    RFAL_ISODEP_FSX_64 =
+        64, /*!< Frame Size for Proximity Card with 64 bytes                         */
+    RFAL_ISODEP_FSX_96 =
+        96, /*!< Frame Size for Proximity Card with 96 bytes                         */
+    RFAL_ISODEP_FSX_128 =
+        128, /*!< Frame Size for Proximity Card with 128 bytes                        */
+    RFAL_ISODEP_FSX_256 =
+        256, /*!< Frame Size for Proximity Card with 256 bytes                        */
+    RFAL_ISODEP_FSX_512 =
+        512, /*!< Frame Size for Proximity Card with 512 bytes   ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSX_1024 =
+        1024, /*!< Frame Size for Proximity Card with 1024 bytes  ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSX_2048 =
+        2048, /*!< Frame Size for Proximity Card with 2048 bytes  ISO14443-3 Amd2 2012 */
+    RFAL_ISODEP_FSX_4096 =
+        4096, /*!< Frame Size for Proximity Card with 4096 bytes  ISO14443-3 Amd2 2012 */
+} rfalIsoDepFSx;
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * GLOBAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! RATS format  Digital 1.1 13.6.1                                                               */
+typedef struct {
+    uint8_t CMD; /*!< RATS command byte: 0xE0                  */
+    uint8_t PARAM; /*!< Param indicating FSDI and DID            */
+} rfalIsoDepRats;
+
+/*! ATS response format  Digital 1.1 13.6.2                                                       */
+typedef struct {
+    uint8_t TL; /*!< Length Byte, including TL byte itself    */
+    uint8_t T0; /*!< Format Byte T0 indicating if TA, TB, TC  */
+    uint8_t TA; /*!< Interface Byte TA(1)                     */
+    uint8_t TB; /*!< Interface Byte TB(1)                     */
+    uint8_t TC; /*!< Interface Byte TC(1)                     */
+    uint8_t HB[RFAL_ISODEP_ATS_HB_MAX_LEN]; /*!< Historical Bytes                         */
+} rfalIsoDepAts;
+
+/*! PPS Request format (Protocol and Parameter Selection) ISO14443-4  5.3                         */
+typedef struct {
+    uint8_t PPSS; /*!< Start Byte: [ 1101b | CID[4b] ]          */
+    uint8_t PPS0; /*!< Parameter 0:[ 000b | PPS1[1n] | 0001b ]  */
+    uint8_t PPS1; /*!< Parameter 1:[ 0000b | DSI[2b] | DRI[2b] ]*/
+} rfalIsoDepPpsReq;
+
+/*! PPS Response format (Protocol and Parameter Selection) ISO14443-4  5.4                        */
+typedef struct {
+    uint8_t PPSS; /*!< Start Byte:  [ 1101b | CID[4b] ]         */
+} rfalIsoDepPpsRes;
+
+/*! ATTRIB Command Format  Digital 1.1  15.6.1 */
+typedef struct {
+    uint8_t cmd; /*!< ATTRIB_REQ command byte           */
+    uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFCID0 of the card to be selected */
+    struct {
+        uint8_t PARAM1; /*!< PARAM1 of ATTRIB command          */
+        uint8_t PARAM2; /*!< PARAM2 of ATTRIB command          */
+        uint8_t PARAM3; /*!< PARAM3 of ATTRIB command          */
+        uint8_t PARAM4; /*!< PARAM4 of ATTRIB command          */
+    } Param; /*!< Parameter of ATTRIB command       */
+    uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Higher Layer Information          */
+} rfalIsoDepAttribCmd;
+
+/*! ATTRIB Response Format  Digital 1.1  15.6.2 */
+typedef struct {
+    uint8_t mbliDid; /*!< Contains MBLI and DID             */
+    uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Higher Layer Information          */
+} rfalIsoDepAttribRes;
+
+/*! S(Parameters) Command Format  ISO14443-4 (2016) Table 4 */
+typedef struct {
+    uint8_t tag; /*!< S(PARAMETERS) Tag field        */
+    uint8_t length; /*!< S(PARAMETERS) Length field     */
+    uint8_t value[RFAL_ISODEP_SPARAM_VALUES_MAX_LEN]; /*!< S(PARAMETERS) Value field      */
+} rfalIsoDepSParameter;
+
+/*! Activation info as Poller and Listener for NFC-A and NFC-B                                    */
+typedef union { /*  PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently, device is only of type A or B at a time. Thus no problem can occur. */
+
+    /*! NFC-A information                                                                         */
+    union { /*  PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently, device is only PCD or PICC at a time. Thus no problem can occur. */
+        struct {
+            rfalIsoDepAts ATS; /*!< ATS response            (Poller mode)    */
+            uint8_t ATSLen; /*!< ATS response length     (Poller mode)    */
+        } Listener;
+        struct {
+            rfalIsoDepRats RATS; /*!< RATS request          (Listener mode)    */
+        } Poller;
+    } A;
+
+    /*! NFC-B information                                                                         */
+    union { /*  PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently, device is only PCD or PICC at a time. Thus no problem can occur. */
+        struct {
+            rfalIsoDepAttribRes ATTRIB_RES; /*!< ATTRIB_RES              (Poller mode)    */
+            uint8_t ATTRIB_RESLen; /*!< ATTRIB_RES length       (Poller mode)    */
+        } Listener;
+        struct {
+            rfalIsoDepAttribCmd ATTRIB; /*!< ATTRIB request        (Listener mode)    */
+            uint8_t ATTRIBLen; /*!< ATTRIB request length (Listener mode)    */
+        } Poller;
+    } B;
+} rfalIsoDepActivation;
+
+/*! ISO-DEP device Info */
+typedef struct {
+    uint8_t FWI; /*!< Frame Waiting Integer                                */
+    uint32_t FWT; /*!< Frame Waiting Time (1/fc)                            */
+    uint32_t dFWT; /*!< Delta Frame Waiting Time (1/fc)                      */
+    uint32_t SFGI; /*!< Start-up Frame Guard time Integer                    */
+    uint32_t SFGT; /*!< Start-up Frame Guard Time (ms)                       */
+    uint8_t FSxI; /*!< Frame Size Device/Card Integer (FSDI or FSCI)        */
+    uint16_t FSx; /*!< Frame Size Device/Card (FSD or FSC)                  */
+    uint32_t MBL; /*!< Maximum Buffer Length (optional for NFC-B)           */
+    rfalBitRate DSI; /*!< Bit Rate coding from Listener (PICC) to Poller (PCD) */
+    rfalBitRate DRI; /*!< Bit Rate coding from Poller (PCD) to Listener (PICC) */
+    uint8_t DID; /*!< Device ID                                            */
+    uint8_t NAD; /*!< Node ADdress                                         */
+    bool supDID; /*!< DID supported flag                                   */
+    bool supNAD; /*!< NAD supported flag                                   */
+    bool supAdFt; /*!< Advanced Features supported flag                     */
+} rfalIsoDepInfo;
+
+/*! ISO-DEP Device structure */
+typedef struct {
+    rfalIsoDepActivation activation; /*!< Activation Info                                      */
+    rfalIsoDepInfo info; /*!< ISO-DEP (ISO14443-4) device Info                     */
+} rfalIsoDepDevice;
+
+/*! ATTRIB Response parameters */
+typedef struct {
+    uint8_t mbli; /*!< MBLI                                     */
+    uint8_t HLInfo[RFAL_ISODEP_ATTRIB_HLINFO_LEN]; /*!< Hi Layer Information                     */
+    uint8_t HLInfoLen; /*!< Hi Layer Information Length              */
+} rfalIsoDepAttribResParam;
+
+/*! ATS Response parameter */
+typedef struct {
+    uint8_t fsci; /*!< Frame Size of Proximity Card Integer     */
+    uint8_t fwi; /*!< Frame Waiting Time Integer               */
+    uint8_t sfgi; /*!< Start-Up Frame Guard Time Integer        */
+    bool didSupport; /*!< DID Supported                            */
+    uint8_t ta; /*!< Max supported bitrate both direction     */
+    uint8_t* hb; /*!< Historical Bytes data                    */
+    uint8_t hbLen; /*!< Historical Bytes Length                  */
+} rfalIsoDepAtsParam;
+
+/*! Structure of I-Block Buffer format from caller */
+typedef struct {
+    uint8_t prologue[RFAL_ISODEP_PROLOGUE_SIZE]; /*!< Prologue/SoD buffer                      */
+    uint8_t
+        inf[RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN]; /*!< INF/Payload buffer                       */
+} rfalIsoDepBufFormat;
+
+/*! Structure of APDU Buffer format from caller */
+typedef struct {
+    uint8_t prologue[RFAL_ISODEP_PROLOGUE_SIZE]; /*!< Prologue/SoD buffer                      */
+    uint8_t apdu[RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN]; /*!< APDU/Payload buffer                      */
+} rfalIsoDepApduBufFormat;
+
+/*! Listen Activation Parameters Structure */
+typedef struct {
+    rfalIsoDepBufFormat* rxBuf; /*!< Receive Buffer struct reference          */
+    uint16_t* rxLen; /*!< Received INF data length in Bytes        */
+    bool* isRxChaining; /*!< Received data is not complete            */
+    rfalIsoDepDevice* isoDepDev; /*!< ISO-DEP device info                      */
+} rfalIsoDepListenActvParam;
+
+/*! Structure of parameters used on ISO DEP Transceive */
+typedef struct {
+    rfalIsoDepBufFormat* txBuf; /*!< Transmit Buffer struct reference         */
+    uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/
+    bool isTxChaining; /*!< Transmit data is not complete            */
+    rfalIsoDepBufFormat* rxBuf; /*!< Receive Buffer struct reference in Bytes */
+    uint16_t* rxLen; /*!< Received INF data length in Bytes        */
+    bool* isRxChaining; /*!< Received data is not complete            */
+    uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode)  */
+    uint32_t dFWT; /*!< Delta FWT to be used                     */
+    uint16_t ourFSx; /*!< Our device Frame Size (FSD or FSC)       */
+    uint16_t FSx; /*!< Other device Frame Size (FSD or FSC)     */
+    uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */
+} rfalIsoDepTxRxParam;
+
+/*! Structure of parameters used on ISO DEP APDU Transceive */
+typedef struct {
+    rfalIsoDepApduBufFormat* txBuf; /*!< Transmit Buffer struct reference         */
+    uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/
+    rfalIsoDepApduBufFormat* rxBuf; /*!< Receive Buffer struct reference in Bytes */
+    uint16_t* rxLen; /*!< Received INF data length in Bytes        */
+    rfalIsoDepBufFormat* tmpBuf; /*!< Temp buffer for Rx I-Blocks (internal)   */
+    uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode)  */
+    uint32_t dFWT; /*!< Delta FWT to be used                     */
+    uint16_t FSx; /*!< Other device Frame Size (FSD or FSC)     */
+    uint16_t ourFSx; /*!< Our device Frame Size (FSD or FSC)       */
+    uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */
+} rfalIsoDepApduTxRxParam;
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+
+/*!
+ ******************************************************************************
+ * \brief Initialize the ISO-DEP protocol 
+ * 
+ * Initialize the ISO-DEP protocol layer with default config
+ ******************************************************************************
+ */
+void rfalIsoDepInitialize(void);
+
+/*!
+ ******************************************************************************
+ * \brief Initialize the ISO-DEP protocol 
+ * 
+ * Initialize the ISO-DEP protocol layer with additional parameters allowing
+ * to customise the protocol layer for specific behaviours
+ * 
+
+ *  \param[in] compMode        : Compliance mode to be performed
+ *  \param[in] maxRetriesR     : Number of retries for a R-Block
+ *                                Digital 2.0 B9 - nRETRY ACK/NAK: [2,5]
+ *  \param[in] maxRetriesSnWTX : Number of retries for a S(WTX) (only in case
+ *                               of NAKs)   Digital 2.0 B9 - nRETRY WTX[2,5]    
+ *  \param[in] maxRetriesSWTX  : Number of overall S(WTX) retries. 
+ *                                Use RFAL_ISODEP_MAX_WTX_RETRYS_ULTD for disabling 
+ *                                this limit check   Digital 2.0  16.2.5.2
+ *  \param[in] maxRetriesSDSL  : Number of retries for a S(DESELECT)
+ *                                Digital 2.0 B9 - nRETRY DESELECT: [0,5]
+ *  \param[in] maxRetriesI     : Number of retries for a I-Block 
+ *                                Digital 2.0  16.2.5.4
+ *  \param[in] maxRetriesRATS  : Number of retries for RATS 
+ *                                Digital 2.0 B7 - nRETRY RATS [0,1]
+ *    
+ ******************************************************************************
+ */
+void rfalIsoDepInitializeWithParams(
+    rfalComplianceMode compMode,
+    uint8_t maxRetriesR,
+    uint8_t maxRetriesSnWTX,
+    uint8_t maxRetriesSWTX,
+    uint8_t maxRetriesSDSL,
+    uint8_t maxRetriesI,
+    uint8_t maxRetriesRATS);
+
+/*!
+ *****************************************************************************
+ *  \brief  FSxI to FSx
+ *
+ *  Convert Frame Size for proximity coupling Device Integer (FSxI) to 
+ *  Frame Size for proximity coupling Device (FSx)
+ *  
+ *  FSD - maximum frame size for NFC Forum Device in Poll Mode
+ *  FSC - maximum frame size for NFC Forum Device in Listen Mode
+ *  
+ *  FSxI = FSDI or FSCI
+ *  FSx  = FSD or FSC
+ *  
+ *  The FSD/FSC value includes the header and CRC
+ *
+ *  \param[in] FSxI :  Frame Size for proximity coupling Device Integer
+ *  
+ *  \return fsx : Frame Size for proximity coupling Device (FSD or FSC)
+ *
+ *****************************************************************************
+ */
+uint16_t rfalIsoDepFSxI2FSx(uint8_t FSxI);
+
+/*! 
+ *****************************************************************************
+ *  \brief  FWI to FWT
+ *
+ *  Convert Frame Waiting time Integer (FWI) to Frame Waiting Time (FWT) in
+ *  1/fc units
+ *
+ *  \param[in] fwi : Frame Waiting time Integer
+ *  
+ *  \return fwt : Frame Waiting Time in 1/fc units
+ *
+ *****************************************************************************
+ */
+uint32_t rfalIsoDepFWI2FWT(uint8_t fwi);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Check if the buffer data contains a valid RATS command
+ *
+ *  Check if it is a  well formed RATS command with 2 bytes
+ *  This function does not check the validity of FSDI and DID
+ *
+ *  \param[in] buf    : reference to buffer containing the data to be checked
+ *  \param[in] bufLen : length of data in the buffer in bytes
+ *
+ *  \return true if the data indicates a RATS command; false otherwise
+ *****************************************************************************
+ */
+bool rfalIsoDepIsRats(const uint8_t* buf, uint8_t bufLen);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Check if the buffer data contains a valid ATTRIB command
+ *
+ *  Check if it is a well formed ATTRIB command, but does not check the 
+ *  validity of the information inside
+ *
+ *  \param[in] buf    : reference to buffer containing the data to be checked
+ *  \param[in] bufLen : length of data in the buffer in bytes
+ *
+ *  \return true if the data indicates a ATTRIB command; false otherwise
+ *****************************************************************************
+ */
+bool rfalIsoDepIsAttrib(const uint8_t* buf, uint8_t bufLen);
+
+/*!
+ *****************************************************************************
+ * \brief Start Listen Activation Handling
+ * 
+ * Start Listen Activation Handling and setup to receive first I-block which may
+ * contain complete or partial APDU after activation is completed 
+ * 
+ *  Pass in RATS for T4AT, or ATTRIB for T4BT, to handle ATS or ATTRIB Response respectively
+ *  The Activation Handling handles ATS and ATTRIB Response; and additionally PPS Response 
+ *  if a PPS is received for T4AT.
+ *  The method uses the current RFAL state machine to determine if it is expecting RATS or ATTRIB
+ * 
+ *  Activation is completed if PPS Response is sent or if first PDU is received in T4T-A
+ *  Activation is completed if ATTRIB Response is sent in T4T-B
+ *  
+ *  \ref rfalIsoDepListenGetActivationStatus provide status if activation is completed. 
+ *  \ref rfalIsoDepStartTransceive shall be called right after activation is completed
+ * 
+ *  \param[in] atsParam       : reference to ATS parameters
+ *  \param[in] attribResParam : reference to ATTRIB_RES parameters
+ *  \param[in] buf            : reference to buffer containing RATS or ATTRIB
+ *  \param[in] bufLen         : length in bytes of the given buffer
+ *  \param[in] actParam       : reference to incoming reception information will be placed
+ *  
+ *  
+ *  \warning Once the Activation has been completed the method 
+ *  rfalIsoDepGetTransceiveStatus() must be called.
+ *  If activation has completed due to reception of a data block (not PPS) the 
+ *  buffer owned by the caller and passed on actParam must still contain this data.
+ *  The first data will be processed (I-Block or S-DSL) by rfalIsoDepGetTransceiveStatus()
+ *  inform the caller and then for the next transaction use rfalIsoDepStartTransceive()
+ * 
+ *  \return ERR_NONE    : RATS/ATTRIB is valid and activation has started
+ *  \return ERR_PARAM   : Invalid parameters
+ *  \return ERR_PROTO   : Invalid request
+ *  \return ERR_NOTSUPP : Feature not supported
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepListenStartActivation(
+    rfalIsoDepAtsParam* atsParam,
+    const rfalIsoDepAttribResParam* attribResParam,
+    const uint8_t* buf,
+    uint16_t bufLen,
+    rfalIsoDepListenActvParam actParam);
+
+/*!
+ *****************************************************************************
+ *  \brief Get the current Activation Status
+ * 
+ *  \return ERR_NONE if Activation is already completed
+ *  \return ERR_BUSY if Activation is ongoing
+ *  \return ERR_LINK_LOSS if Remote Field is turned off
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepListenGetActivationStatus(void);
+
+/*!
+ *****************************************************************************
+ *  \brief Get the ISO-DEP Communication Information
+ *  
+ *  Gets the maximum INF length in bytes based on current Frame Size 
+ *  for proximity coupling Device (FSD or FSC) excluding the header and CRC
+ *
+ *  \return maximum INF length in bytes
+ *****************************************************************************
+ */
+uint16_t rfalIsoDepGetMaxInfLen(void);
+
+/*!
+ *****************************************************************************
+ *  \brief ISO-DEP Start Transceive 
+ *  
+ *  This method triggers a ISO-DEP Transceive containing a complete or 
+ *  partial APDU
+ *  It transmits the given message and handles all protocol retransmitions,
+ *  error handling and control messages
+ *  
+ *  The txBuf  contains a complete or partial APDU (INF) to be transmitted 
+ *  The Prologue field will be manipulated by the Transceive
+ *  
+ *  If the buffer contains a partial APDU and is not the last block, 
+ *  then isTxChaining must be set to true
+ *  
+ *  \param[in] param: reference parameters to be used for the Transceive
+ *                     
+ *  \return ERR_PARAM       : Bad request
+ *  \return ERR_WRONG_STATE : The module is not in a proper state
+ *  \return ERR_NONE        : The Transceive request has been started
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepStartTransceive(rfalIsoDepTxRxParam param);
+
+/*!
+ *****************************************************************************
+ *  \brief Get the Transceive status
+ *  
+ *  Returns the status of the ISO-DEP Transceive
+ *  
+ *  \warning  When the other device is performing chaining once a chained 
+ *            block is received the error ERR_AGAIN is sent. At this point 
+ *            caller must handle the received data immediately. 
+ *            When ERR_AGAIN is returned an ACK has already been sent to 
+ *            the other device and the next block might be incoming. 
+ *            If rfalWorker() is called frequently it will place the next 
+ *            block on the given buffer  
+ *              
+ *  
+ *  \return ERR_NONE      : Transceive has been completed successfully
+ *  \return ERR_BUSY      : Transceive is ongoing
+ *  \return ERR_PROTO     : Protocol error occurred
+ *  \return ERR_TIMEOUT   : Timeout error occurred
+ *  \return ERR_SLEEP_REQ : Deselect has been received and responded
+ *  \return ERR_NOMEM     : The received INF does not fit into the
+ *                            receive buffer
+ *  \return ERR_LINK_LOSS : Communication is lost because Reader/Writer 
+ *                            has turned off its field
+ *  \return ERR_AGAIN     : received one chaining block, continue to call
+ *                            this method to retrieve the remaining blocks
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepGetTransceiveStatus(void);
+
+/*!
+ *****************************************************************************
+ *  \brief ISO-DEP Start APDU Transceive 
+ *  
+ *  This method triggers a ISO-DEP Transceive containing a complete APDU
+ *  It transmits the given message and handles all protocol retransmitions,
+ *  error handling and control messages
+ *  
+ *  The txBuf  contains a complete APDU to be transmitted 
+ *  The Prologue field will be manipulated by the Transceive
+ *  
+ *  \warning the txBuf will be modified during the transmission
+ *  \warning the maximum RF frame which can be received is limited by param.tmpBuf
+ *  
+ *  \param[in] param: reference parameters to be used for the Transceive
+ *                     
+ *  \return ERR_PARAM       : Bad request
+ *  \return ERR_WRONG_STATE : The module is not in a proper state
+ *  \return ERR_NONE        : The Transceive request has been started
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepStartApduTransceive(rfalIsoDepApduTxRxParam param);
+
+/*!
+ *****************************************************************************
+ *  \brief Get the APDU Transceive status
+ *  
+ *  \return ERR_NONE      : if Transceive has been completed successfully
+ *  \return ERR_BUSY      : if Transceive is ongoing
+ *  \return ERR_PROTO     : if a protocol error occurred
+ *  \return ERR_TIMEOUT   : if a timeout error occurred
+ *  \return ERR_SLEEP_REQ : if Deselect is received and responded
+ *  \return ERR_NOMEM     : if the received INF does not fit into the 
+ *                            receive buffer
+ *  \return ERR_LINK_LOSS : if communication is lost because Reader/Writer 
+ *                            has turned off its field
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepGetApduTransceiveStatus(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Send RATS
+ *   
+ *  This sends a RATS to make a NFC-A Listen Device to enter 
+ *  ISO-DEP layer (ISO14443-4) and checks if the received ATS is valid
+ *   
+ *  \param[in]  FSDI   : Frame Size Device Integer to be used
+ *  \param[in]  DID    : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID  
+ *  \param[out] ats    : pointer to place the ATS Response
+ *  \param[out] atsLen : pointer to place the ATS length
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, ATS received
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepRATS(rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts* ats, uint8_t* atsLen);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Send PPS
+ *   
+ *  This sends a PPS to make a NFC-A Listen Device change the communications
+ *  bit rate from 106kbps to one of the supported bit rates
+ *  Additionally checks if the received PPS response is valid
+ *   
+ *  \param[in]  DID    : Device ID
+ *  \param[in]  DSI    : DSI code the divisor from Listener (PICC) to Poller (PCD)
+ *  \param[in]  DRI    : DRI code the divisor from Poller (PCD) to Listener (PICC)
+ *  \param[out] ppsRes : pointer to place the PPS Response
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, PPS Response received
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPPS(uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes* ppsRes);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Send ATTRIB
+ *   
+ *  This sends a ATTRIB to make a NFC-B Listen Device to enter 
+ *  ISO-DEP layer (ISO14443-4) and checks if the received ATTRIB Response is valid
+ *   
+ *  \param[in]  nfcid0    : NFCID0 to be used for the ATTRIB 
+ *  \param[in]  PARAM1    : ATTRIB PARAM1 byte (communication parameters) 
+ *  \param[in]  DSI       : DSI code the divisor from Listener (PICC) to Poller (PCD)
+ *  \param[in]  DRI       : DRI code the divisor from Poller (PCD) to Listener (PICC)
+ *  \param[in]  FSDI      : PCD's Frame Size to be announced on the ATTRIB
+ *  \param[in]  PARAM3    : ATTRIB PARAM1 byte (protocol type)
+ *  \param[in]  DID       : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID
+ *  \param[in]  HLInfo    : pointer to Higher layer INF (NULL if none)
+ *  \param[in]  HLInfoLen : Length HLInfo
+ *  \param[in]  fwt       : Frame Waiting Time to be used (from SENSB_RES)
+ *  \param[out] attribRes    : pointer to place the ATTRIB Response
+ *  \param[out] attribResLen : pointer to place the ATTRIB Response length
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, ATTRIB Response received
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepATTRIB(
+    const uint8_t* nfcid0,
+    uint8_t PARAM1,
+    rfalBitRate DSI,
+    rfalBitRate DRI,
+    rfalIsoDepFSxI FSDI,
+    uint8_t PARAM3,
+    uint8_t DID,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    uint32_t fwt,
+    rfalIsoDepAttribRes* attribRes,
+    uint8_t* attribResLen);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Deselects PICC
+ *
+ *  This function sends a deselect command to PICC and waits for it`s
+ *  response in a blocking way
+ *
+ *  \return ERR_NONE   : Deselect successfully sent and acknowledged by PICC 
+ *  \return ERR_TIMEOUT: No response rcvd from PICC 
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepDeselect(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Handle NFC-A Activation
+ *   
+ *  This performs a NFC-A Activation into ISO-DEP layer (ISO14443-4) with the given
+ *  parameters. It sends RATS and if the higher bit rates are supported by 
+ *  both devices it additionally sends PPS
+ *  Once Activated all details of the device are provided on isoDepDev
+ *   
+ *  \param[in]  FSDI      : Frame Size Device Integer to be used
+ *  \param[in]  DID       : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID
+ *  \param[in]  maxBR     : Max bit rate supported by the Poller
+ *  \param[out] isoDepDev : ISO-DEP information of the activated Listen device
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollAHandleActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    rfalIsoDepDevice* isoDepDev);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Handle NFC-B Activation
+ *   
+ *  This performs a NFC-B Activation into ISO-DEP layer (ISO14443-4) with the given
+ *  parameters. It sends ATTRIB and calculates supported higher bit rates of both 
+ *  devices and performs activation.
+ *  Once Activated all details of the device are provided on isoDepDev
+ *   
+ *  \param[in]  FSDI         : Frame Size Device Integer to be used
+ *  \param[in]  DID          : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID
+ *  \param[in]  maxBR        : Max bit rate supported by the Poller
+ *  \param[in]  PARAM1       : ATTRIB PARAM1 byte (communication parameters)
+ *  \param[in]  nfcbDev      : pointer to the NFC-B Device containing the SENSB_RES
+ *  \param[in]  HLInfo       : pointer to Higher layer INF (NULL if none)
+ *  \param[in]  HLInfoLen    : Length HLInfo
+ *  \param[out] isoDepDev    : ISO-DEP information of the activated Listen device
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollBHandleActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    uint8_t PARAM1,
+    const rfalNfcbListenDevice* nfcbDev,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    rfalIsoDepDevice* isoDepDev);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Handle S(Parameters)
+ *   
+ *  This checks if PICC supports S(PARAMETERS), retrieves PICC's
+ *  capabilities and sets the Bit Rate at the highest supported by both
+ *  devices
+ *   
+ *  \param[out] isoDepDev    : ISO-DEP information of the activated Listen device
+ *  \param[in]  maxTxBR      : Maximum Tx bit rate supported by PCD
+ *  \param[in]  maxRxBR      : Maximum Rx bit rate supported by PCD
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, S(PARAMETERS) selection successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollHandleSParameters(
+    rfalIsoDepDevice* isoDepDev,
+    rfalBitRate maxTxBR,
+    rfalBitRate maxRxBR);
+
+/*!
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Start NFC-A Activation 
+ *
+ *  This starts a NFC-A Activation into ISO-DEP layer (ISO14443-4) with the given
+ *  parameters. It sends RATS and if the higher bit rates are supported by
+ *  both devices it additionally sends PPS
+ *  Once Activated all details of the device are provided on isoDepDev
+ *
+ *
+ *  \see rfalIsoDepPollAGetActivationStatus
+ *
+ *  \param[in]  FSDI      : Frame Size Device Integer to be used
+ *  \param[in]  DID       : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID
+ *  \param[in]  maxBR     : Max bit rate supported by the Poller
+ *  \param[out] isoDepDev : ISO-DEP information of the activated Listen device
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, start of asynchronous operation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollAStartActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    rfalIsoDepDevice* isoDepDev);
+
+/*!
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Get NFC-A Activation Status
+ *
+ *  Returns the activation status started by rfalIsoDepPollAStartActivation
+ *
+ *  \see rfalIsoDepPollAStartActivation
+ *
+ *  \return ERR_BUSY         : Operation is ongoing
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollAGetActivationStatus(void);
+
+/*!
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Start NFC-B Activation 
+ *
+ *  This starts a NFC-B Activation into ISO-DEP layer (ISO14443-4) with the given
+ *  parameters. It will send ATTRIB and calculate supported higher bit rates of both 
+ *  devices and perform activation.
+ *  Once Activated all details of the device are provided on isoDepDev
+ *
+ *  \see rfalIsoDepPollBGetActivationStatus
+ *
+ *  \param[in]  FSDI         : Frame Size Device Integer to be used
+ *  \param[in]  DID          : Device ID to be used or RFAL_ISODEP_NO_DID for not use DID
+ *  \param[in]  maxBR        : Max bit rate supported by the Poller
+ *  \param[in]  PARAM1       : ATTRIB PARAM1 byte (communication parameters)
+ *  \param[in]  nfcbDev      : pointer to the NFC-B Device containing the SENSB_RES
+ *  \param[in]  HLInfo       : pointer to Higher layer INF (NULL if none)
+ *  \param[in]  HLInfoLen    : Length HLInfo
+ *  \param[out] isoDepDev    : ISO-DEP information of the activated Listen device
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, start of asynchronous operation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollBStartActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    uint8_t PARAM1,
+    const rfalNfcbListenDevice* nfcbDev,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    rfalIsoDepDevice* isoDepDev);
+
+/*!
+ *****************************************************************************
+ *  \brief  ISO-DEP Poller Get NFC-B Activation Status
+ *
+ *  Returns the activation status started by rfalIsoDepPollBStartActivation
+ *
+ *  \see rfalIsoDepPollBStartActivation
+ *
+ *  \return ERR_BUSY         : Operation is ongoing
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalIsoDepPollBGetActivationStatus(void);
+
+#endif /* RFAL_ISODEP_H_ */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 425 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfc.h

@@ -0,0 +1,425 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfc.h
+ *
+ *  \brief RFAL NFC device
+ *  
+ *  This module provides the required features to behave as an NFC Poller 
+ *  or Listener device. It grants an easy to use interface for the following
+ *  activities: Technology Detection, Collision Resolution, Activation,
+ *  Data Exchange, and Deactivation
+ *  
+ *  This layer is influenced by (but not fully aligned with) the NFC Forum 
+ *  specifications, in particular: Activity 2.0 and NCI 2.0
+ *
+ *  
+ *    
+ * \addtogroup RFAL
+ * @{
+ * 
+ * \addtogroup RFAL-HL
+ * \brief RFAL Higher Layer
+ * @{
+ * 
+ * \addtogroup NFC
+ * \brief RFAL NFC Device
+ * @{
+ *  
+ */
+
+#ifndef RFAL_NFC_H
+#define RFAL_NFC_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+#include "rfal_nfca.h"
+#include "rfal_nfcb.h"
+#include "rfal_nfcf.h"
+#include "rfal_nfcv.h"
+#include "rfal_st25tb.h"
+#include "rfal_nfcDep.h"
+#include "rfal_isoDep.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+#define RFAL_NFC_TECH_NONE 0x0000U /*!< No technology             */
+#define RFAL_NFC_POLL_TECH_A 0x0001U /*!< NFC-A technology Flag     */
+#define RFAL_NFC_POLL_TECH_B 0x0002U /*!< NFC-B technology Flag     */
+#define RFAL_NFC_POLL_TECH_F 0x0004U /*!< NFC-F technology Flag     */
+#define RFAL_NFC_POLL_TECH_V 0x0008U /*!< NFC-V technology Flag     */
+#define RFAL_NFC_POLL_TECH_AP2P 0x0010U /*!< AP2P technology Flag      */
+#define RFAL_NFC_POLL_TECH_ST25TB 0x0020U /*!< ST25TB technology Flag    */
+#define RFAL_NFC_LISTEN_TECH_A 0x1000U /*!< NFC-V technology Flag     */
+#define RFAL_NFC_LISTEN_TECH_B 0x2000U /*!< NFC-V technology Flag     */
+#define RFAL_NFC_LISTEN_TECH_F 0x4000U /*!< NFC-V technology Flag     */
+#define RFAL_NFC_LISTEN_TECH_AP2P 0x8000U /*!< NFC-V technology Flag     */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*! Checks if a device is currently activated */
+#define rfalNfcIsDevActivated(st) \
+    (((st) >= RFAL_NFC_STATE_ACTIVATED) && ((st) < RFAL_NFC_STATE_DEACTIVATION))
+
+/*! Checks if a device is in discovery */
+#define rfalNfcIsInDiscovery(st) \
+    (((st) >= RFAL_NFC_STATE_START_DISCOVERY) && ((st) < RFAL_NFC_STATE_ACTIVATED))
+
+/*! Checks if remote device is in Poll mode */
+#define rfalNfcIsRemDevPoller(tp) \
+    (((tp) >= RFAL_NFC_POLL_TYPE_NFCA) && ((tp) <= RFAL_NFC_POLL_TYPE_AP2P))
+
+/*! Checks if remote device is in Listen mode */
+#define rfalNfcIsRemDevListener(tp) \
+    (((int16_t)(tp) >= (int16_t)RFAL_NFC_LISTEN_TYPE_NFCA) && ((tp) <= RFAL_NFC_LISTEN_TYPE_AP2P))
+
+/*
+******************************************************************************
+* GLOBAL ENUMS
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Main state                                                                       */
+typedef enum {
+    RFAL_NFC_STATE_NOTINIT = 0, /*!< Not Initialized state       */
+    RFAL_NFC_STATE_IDLE = 1, /*!< Initialize state            */
+    RFAL_NFC_STATE_START_DISCOVERY = 2, /*!< Start Discovery loop state  */
+    RFAL_NFC_STATE_WAKEUP_MODE = 3, /*!< Wake-Up state               */
+    RFAL_NFC_STATE_POLL_TECHDETECT = 10, /*!< Technology Detection state  */
+    RFAL_NFC_STATE_POLL_COLAVOIDANCE = 11, /*!< Collision Avoidance state   */
+    RFAL_NFC_STATE_POLL_SELECT = 12, /*!< Wait for Selection state    */
+    RFAL_NFC_STATE_POLL_ACTIVATION = 13, /*!< Activation state            */
+    RFAL_NFC_STATE_LISTEN_TECHDETECT = 20, /*!< Listen Tech Detect          */
+    RFAL_NFC_STATE_LISTEN_COLAVOIDANCE = 21, /*!< Listen Collision Avoidance  */
+    RFAL_NFC_STATE_LISTEN_ACTIVATION = 22, /*!< Listen Activation state     */
+    RFAL_NFC_STATE_LISTEN_SLEEP = 23, /*!< Listen Sleep state          */
+    RFAL_NFC_STATE_ACTIVATED = 30, /*!< Activated state             */
+    RFAL_NFC_STATE_DATAEXCHANGE = 31, /*!< Data Exchange Start state   */
+    RFAL_NFC_STATE_DATAEXCHANGE_DONE = 33, /*!< Data Exchange terminated    */
+    RFAL_NFC_STATE_DEACTIVATION = 34 /*!< Deactivation state          */
+} rfalNfcState;
+
+/*! Device type                                                                       */
+typedef enum {
+    RFAL_NFC_LISTEN_TYPE_NFCA = 0, /*!< NFC-A Listener device type  */
+    RFAL_NFC_LISTEN_TYPE_NFCB = 1, /*!< NFC-B Listener device type  */
+    RFAL_NFC_LISTEN_TYPE_NFCF = 2, /*!< NFC-F Listener device type  */
+    RFAL_NFC_LISTEN_TYPE_NFCV = 3, /*!< NFC-V Listener device type  */
+    RFAL_NFC_LISTEN_TYPE_ST25TB = 4, /*!< ST25TB Listener device type */
+    RFAL_NFC_LISTEN_TYPE_AP2P = 5, /*!< AP2P Listener device type   */
+    RFAL_NFC_POLL_TYPE_NFCA = 10, /*!< NFC-A Poller device type    */
+    RFAL_NFC_POLL_TYPE_NFCB = 11, /*!< NFC-B Poller device type    */
+    RFAL_NFC_POLL_TYPE_NFCF = 12, /*!< NFC-F Poller device type    */
+    RFAL_NFC_POLL_TYPE_NFCV = 13, /*!< NFC-V Poller device type    */
+    RFAL_NFC_POLL_TYPE_AP2P = 15 /*!< AP2P Poller device type     */
+} rfalNfcDevType;
+
+/*! Device interface                                                                 */
+typedef enum {
+    RFAL_NFC_INTERFACE_RF = 0, /*!< RF Frame interface          */
+    RFAL_NFC_INTERFACE_ISODEP = 1, /*!< ISO-DEP interface           */
+    RFAL_NFC_INTERFACE_NFCDEP = 2 /*!< NFC-DEP interface           */
+} rfalNfcRfInterface;
+
+/*! Device struct containing all its details                                          */
+typedef struct {
+    rfalNfcDevType type; /*!< Device's type                */
+    union { /*  PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one technology at a time */
+        rfalNfcaListenDevice nfca; /*!< NFC-A Listen Device instance */
+        rfalNfcbListenDevice nfcb; /*!< NFC-B Listen Device instance */
+        rfalNfcfListenDevice nfcf; /*!< NFC-F Listen Device instance */
+        rfalNfcvListenDevice nfcv; /*!< NFC-V Listen Device instance */
+        rfalSt25tbListenDevice st25tb; /*!< ST25TB Listen Device instance*/
+    } dev; /*!< Device's instance            */
+
+    uint8_t* nfcid; /*!< Device's NFCID               */
+    uint8_t nfcidLen; /*!< Device's NFCID length        */
+    rfalNfcRfInterface rfInterface; /*!< Device's interface           */
+
+    union { /*  PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one protocol at a time */
+        rfalIsoDepDevice isoDep; /*!< ISO-DEP instance             */
+        rfalNfcDepDevice nfcDep; /*!< NFC-DEP instance             */
+    } proto; /*!< Device's protocol            */
+} rfalNfcDevice;
+
+/*! Discovery parameters                                                                                           */
+typedef struct {
+    rfalComplianceMode compMode; /*!< Compliance mode to be used                            */
+    uint16_t techs2Find; /*!< Technologies to search for                            */
+    uint16_t totalDuration; /*!< Duration of a whole Poll + Listen cycle               */
+    uint8_t devLimit; /*!< Max number of devices                                 */
+    rfalBitRate maxBR; /*!< Max Bit rate to be used for communications            */
+
+    rfalBitRate nfcfBR; /*!< Bit rate to poll for NFC-F                            */
+    uint8_t
+        nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 to be used on the ATR_REQ/ATR_RES              */
+    uint8_t GB[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General bytes to be used on the ATR-REQ               */
+    uint8_t GBLen; /*!< Length of the General Bytes                           */
+    rfalBitRate ap2pBR; /*!< Bit rate to poll for AP2P                             */
+
+    rfalLmConfPA lmConfigPA; /*!< Configuration for Passive Listen mode NFC-A           */
+    rfalLmConfPF lmConfigPF; /*!< Configuration for Passive Listen mode NFC-A           */
+
+    void (*notifyCb)(rfalNfcState st); /*!< Callback to Notify upper layer                        */
+
+    bool wakeupEnabled; /*!< Enable Wake-Up mode before polling                    */
+    bool wakeupConfigDefault; /*!< Wake-Up mode default configuration                    */
+    rfalWakeUpConfig wakeupConfig; /*!< Wake-Up mode configuration                            */
+
+    bool activate_after_sak; // Set device to Active mode after SAK response
+} rfalNfcDiscoverParam;
+
+/*! Buffer union, only one interface is used at a time                                                             */
+typedef union { /*  PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one interface at a time */
+    uint8_t rfBuf[RFAL_FEATURE_NFC_RF_BUF_LEN]; /*!< RF buffer                                    */
+    rfalIsoDepApduBufFormat isoDepBuf; /*!< ISO-DEP buffer format (with header/prologue) */
+    rfalNfcDepPduBufFormat nfcDepBuf; /*!< NFC-DEP buffer format (with header/prologue) */
+} rfalNfcBuffer;
+
+/*******************************************************************************/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL NFC Worker
+ *  
+ * It runs the internal state machine and runs the RFAL RF worker.
+ *****************************************************************************
+ */
+void rfalNfcWorker(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL NFC Initialize
+ *  
+ * It initializes this module and its dependencies
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcInitialize(void);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Discovery
+ *  
+ * It set the device in Discovery state.
+ * In discovery it will Poll and/or Listen for the technologies configured, 
+ * and perform Wake-up mode if configured to do so.
+ *
+ * The device list passed on disParams must not be empty.
+ * The number of devices on the list is indicated by the devLimit and shall
+ * be at >= 1.
+ *
+ * \param[in]  disParams    : discovery configuration parameters
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDiscover(const rfalNfcDiscoverParam* disParams);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Get State
+ *  
+ * It returns the current state
+ *
+ * \return rfalNfcState : the current state
+ *****************************************************************************
+ */
+rfalNfcState rfalNfcGetState(void);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Get Devices Found
+ *  
+ * It returns the location of the device list and the number of 
+ * devices found.
+ *
+ * \param[out]  devList     : device list location
+ * \param[out]  devCnt      : number of devices found
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ *                            Discovery still ongoing
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcGetDevicesFound(rfalNfcDevice** devList, uint8_t* devCnt);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Get Active Device
+ *  
+ * It returns the location of the device current Active device
+ *
+ * \param[out]  dev           : device info location
+ *
+ * \return ERR_WRONG_STATE    : Incorrect state for this operation
+ *                              No device activated
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcGetActiveDevice(rfalNfcDevice** dev);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Select Device
+ *  
+ * It selects the device to be activated.
+ * It shall be called when more than one device has been identified to 
+ * indiacte which device shall be active
+ * 
+ * \param[in]  devIdx       : device index to be activated
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ *                            Not in select state
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcSelect(uint8_t devIdx);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL NFC Start Data Exchange
+ *  
+ * After a device has been activated, it starts a data exchange.
+ * It handles automatically which interface/protocol to be used and acts accordingly.
+ *
+ * In Listen mode the first frame/data shall be sent by the Reader/Initiator
+ * therefore this method must be called first with txDataLen set to zero 
+ * to retrieve the rxData and rcvLen locations.
+ *
+ *
+ * \param[in]  txData       : data to be transmitted
+ * \param[in]  txDataLen    : size of the data to be transmitted
+ * \param[out] rxData       : location of the received data after operation is completed
+ * \param[out] rvdLen       : location of thelength of the received data
+ * \param[in]  fwt          : FWT to be used in case of RF interface.
+ *                            If ISO-DEP or NFC-DEP interface is used, this will be ignored
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDataExchangeStart(
+    uint8_t* txData,
+    uint16_t txDataLen,
+    uint8_t** rxData,
+    uint16_t** rvdLen,
+    uint32_t fwt,
+    uint32_t tx_flag);
+
+ReturnCode rfalNfcDataExchangeCustomStart(
+    uint8_t* txData,
+    uint16_t txDataLen,
+    uint8_t** rxData,
+    uint16_t** rvdLen,
+    uint32_t fwt,
+    uint32_t flags);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL NFC Get Data Exchange Status
+ *  
+ * Gets current Data Exchange status
+ *
+ * \return  ERR_NONE         : Transceive done with no error
+ * \return  ERR_BUSY         : Transceive ongoing
+ *  \return ERR_AGAIN        : received one chaining block, copy received data 
+ *                             and continue to call this method to retrieve the 
+ *                             remaining blocks
+ * \return  ERR_XXXX         : Error occurred
+ * \return  ERR_TIMEOUT      : No response
+ * \return  ERR_FRAMING      : Framing error detected
+ * \return  ERR_PAR          : Parity error detected
+ * \return  ERR_CRC          : CRC error detected
+ * \return  ERR_LINK_LOSS    : Link Loss - External Field is Off
+ * \return  ERR_RF_COLLISION : Collision detected
+ * \return  ERR_IO           : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDataExchangeGetStatus(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL NFC Deactivate
+ *  
+ * It triggers the deactivation procedure to terminate communications with 
+ * remote device. At the end the field will be turned off.
+ *
+ * \param[in]  discovery    : TRUE if after deactivation go back into discovery
+ *                          : FALSE if after deactivation remain in idle
+ *
+ * \return ERR_WRONG_STATE  : Incorrect state for this operation
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDeactivate(bool discovery);
+
+#endif /* RFAL_NFC_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 831 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcDep.h

@@ -0,0 +1,831 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcDep.h
+ *
+ *  \author  Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-DEP protocol
+ *  
+ *  NFC-DEP is also known as NFCIP - Near Field Communication 
+ *  Interface and Protocol
+ *  
+ *  This implementation was based on the following specs:
+ *    - NFC Forum Digital 1.1
+ *    - ECMA 340 3rd Edition 2013
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup NFC-DEP
+ * \brief RFAL NFC-DEP Module
+ * @{
+ */
+
+#ifndef RFAL_NFCDEP_H_
+#define RFAL_NFCDEP_H_
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFC_DEP
+#define RFAL_FEATURE_NFC_DEP \
+    false /*!< NFC-DEP module configuration missing. Disabled by default */
+#endif
+
+/* If module is disabled remove the need for the user to set lengths */
+#if !RFAL_FEATURE_NFC_DEP
+#undef RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN
+#undef RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN
+
+#define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN 1U /*!< NFC-DEP Block/Payload length, set to "none" */
+#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN 1U /*!< NFC-DEP PDU length, set to "none"           */
+#endif /* !RFAL_FEATURE_NFC_DEP  */
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+#define RFAL_NFCDEP_FRAME_SIZE_MAX_LEN \
+    254U /*!< Maximum Frame Size   Digital 2.0 Table 90                      */
+#define RFAL_NFCDEP_DEPREQ_HEADER_LEN \
+    5U /*!< DEP_REQ header length: CMD_TYPE + CMD_CMD + PBF + DID + NAD    */
+
+/*! Length NFCIP DEP REQ or RES header (incl LEN)                                                                           */
+#define RFAL_NFCDEP_DEP_HEADER \
+    (RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN + RFAL_NFCDEP_DEP_PFB_LEN)
+#define RFAL_NFCDEP_HEADER \
+    (RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) /*!< NFCIP header length           */
+#define RFAL_NFCDEP_SB_LEN \
+    1U /*!< SB length on NFCIP fram for NFC-A                              */
+#define RFAL_NFCDEP_LEN_LEN \
+    1U /*!< LEN length on NFCIP frame                                      */
+#define RFAL_NFCDEP_CMDTYPE_LEN \
+    1U /*!< Length of the cmd type (REQ | RES) on NFCIP frame              */
+#define RFAL_NFCDEP_CMD_LEN \
+    1U /*!< Length of the cmd on NFCIP frame                               */
+#define RFAL_NFCDEP_DID_LEN \
+    1U /*!< Length of did on NFCIP frame                                   */
+#define RFAL_NFCDEP_DEP_PFB_LEN \
+    1U /*!< Length of the PFB field on NFCIP frame                         */
+
+#define RFAL_NFCDEP_DSL_RLS_LEN_NO_DID               \
+    (RFAL_NFCDEP_LEN_LEN + RFAL_NFCDEP_CMDTYPE_LEN + \
+     RFAL_NFCDEP_CMD_LEN) /*!< Length of DSL_REQ and RLS_REQ with no DID */
+#define RFAL_NFCDEP_DSL_RLS_LEN_DID   \
+    (RFAL_NFCDEP_DSL_RLS_LEN_NO_DID + \
+     RFAL_NFCDEP_DID_LEN) /*!< Length of DSL_REQ and RLS_REQ with DID    */
+
+#define RFAL_NFCDEP_FS_VAL_MIN \
+    64U /*!< Minimum LR value                                               */
+#define RFAL_NFCDEP_LR_VAL_MASK \
+    0x03U /*!< Bit mask for a LR value                                        */
+#define RFAL_NFCDEP_PP_LR_MASK \
+    0x30U /*!< Bit mask for LR value in PP byte on a ATR REQ/RES              */
+#define RFAL_NFCDEP_PP_LR_SHIFT \
+    4U /*!< Position of LR value in PP byte on a ATR REQ/RES               */
+
+#define RFAL_NFCDEP_DID_MAX \
+    14U /*!< Max DID value Digital 14.6.2.3                                 */
+#define RFAL_NFCDEP_DID_KEEP \
+    0xFFU /*!< Keep DID value already configured                              */
+#define RFAL_NFCDEP_DID_NO \
+    0x00U /*!< No DID shall be used                                           */
+#define RFAL_NFCDEP_NAD_NO \
+    0x00U /*!< No NAD shall be used                                           */
+
+#define RFAL_NFCDEP_OPER_RTOX_REQ_DIS \
+    0x01U /*!< Operation config: RTOX REQ disable                             */
+#define RFAL_NFCDEP_OPER_RTOX_REQ_EN \
+    0x00U /*!< Operation config: RTOX REQ enable                              */
+
+#define RFAL_NFCDEP_OPER_ATN_DIS \
+    0x00U /*!< Operation config: ATN disable                                  */
+#define RFAL_NFCDEP_OPER_ATN_EN \
+    0x02U /*!< Operation config: ATN enable                                   */
+
+#define RFAL_NFCDEP_OPER_EMPTY_DEP_DIS \
+    0x04U /*!< Operation config: empty DEPs disable                           */
+#define RFAL_NFCDEP_OPER_EMPTY_DEP_EN \
+    0x00U /*!< Operation config: empty DEPs enable                            */
+
+#define RFAL_NFCDEP_OPER_FULL_MI_DIS \
+    0x00U /*!< Operation config: full chaining DEPs disable                   */
+#define RFAL_NFCDEP_OPER_FULL_MI_EN \
+    0x08U /*!< Operation config: full chaining DEPs enable                    */
+
+#define RFAL_NFCDEP_BRS_MAINTAIN \
+    0xC0U /*!< Value signalling that BR is to be maintained (no PSL)          */
+#define RFAL_NFCDEP_BRS_Dx_MASK \
+    0x07U /*!< Value signalling that BR is to be maintained (no PSL)          */
+#define RFAL_NFCDEP_BRS_DSI_POS \
+    3U /*!< Value signalling that BR is to be maintained (no PSL)          */
+
+#define RFAL_NFCDEP_WT_DELTA \
+    (16U - RFAL_NFCDEP_WT_DELTA_ADJUST) /*!< NFC-DEP dWRT (adjusted)  Digital 2.0 B.10  */
+#define RFAL_NFCDEP_WT_DELTA_ADJUST \
+    4U /*!< dWRT value adjustment                                          */
+
+#define RFAL_NFCDEP_ATR_REQ_NFCID3_POS \
+    2U /*!< NFCID3 offset in ATR_REQ frame                                 */
+#define RFAL_NFCDEP_NFCID3_LEN \
+    10U /*!< NFCID3 Length                                                  */
+
+#define RFAL_NFCDEP_LEN_MIN \
+    3U /*!< Minimum length byte LEN value                                  */
+#define RFAL_NFCDEP_LEN_MAX \
+    255U /*!< Maximum length byte LEN value                                  */
+
+#define RFAL_NFCDEP_ATRRES_HEADER_LEN \
+    2U /*!< ATR RES Header Len:  CmdType: 0xD5 + Cod: 0x01                 */
+#define RFAL_NFCDEP_ATRRES_MIN_LEN \
+    17U /*!< Minimum length for an ATR RES                                  */
+#define RFAL_NFCDEP_ATRRES_MAX_LEN \
+    64U /*!< Maximum length for an ATR RES  Digital 1.0 14.6.1              */
+#define RFAL_NFCDEP_ATRREQ_MIN_LEN \
+    16U /*!< Minimum length for an ATR REQ                                  */
+#define RFAL_NFCDEP_ATRREQ_MAX_LEN \
+    RFAL_NFCDEP_ATRRES_MAX_LEN /*!< Maximum length for an ATR REQ  Digital 1.0 14.6.1   */
+
+#define RFAL_NFCDEP_GB_MAX_LEN    \
+    (RFAL_NFCDEP_ATRREQ_MAX_LEN - \
+     RFAL_NFCDEP_ATRREQ_MIN_LEN) /*!< Maximum length the General Bytes on ATR  Digital 1.1  16.6.3 */
+
+#define RFAL_NFCDEP_WT_INI_DEFAULT \
+    RFAL_NFCDEP_WT_INI_MAX /*!< WT Initiator default value Digital 1.0 14.6.3.8        */
+#define RFAL_NFCDEP_WT_INI_MIN 0U /*!< WT Initiator minimum value Digital 1.0 14.6.3.8        */
+#define RFAL_NFCDEP_WT_INI_MAX 14U /*!< WT Initiator maximum value Digital 1.0 14.6.3.8 A.10   */
+#define RFAL_NFCDEP_RWT_INI_MAX \
+    rfalNfcDepWT2RWT(RFAL_NFCDEP_WT_INI_MAX) /*!< RWT Initiator maximum value   */
+
+#define RFAL_NFCDEP_WT_TRG_MAX_D10 8U /*!< WT target max Digital 1.0 14.6.3.8 A.10 */
+#define RFAL_NFCDEP_WT_TRG_MAX_D11 14U /*!< WT target max Digital 1.1 16.6.3.9 A.9  */
+#define RFAL_NFCDEP_WT_TRG_MAX_L13 10U /*!< WT target max [LLCP] 1.3 6.2.1          */
+#define RFAL_NFCDEP_WT_TRG_MAX \
+    RFAL_NFCDEP_WT_TRG_MAX_D11 /*!< WT target max Digital x.x | LLCP x.x    */
+#define RFAL_NFCDEP_RWT_TRG_MAX \
+    rfalNfcDepWT2RWT(RFAL_NFCDEP_WT_TRG_MAX) /*!< RWT Initiator maximum value         */
+
+/*! Maximum Frame Waiting Time = ((256 * 16/fc)*2^FWImax) = ((256*16/fc)*2^14) = (1048576 / 64)/fc = (100000h*64)/fc         */
+#define RFAL_NFCDEP_MAX_FWT ((uint32_t)1U << 20)
+
+#define RFAL_NFCDEP_WT_MASK \
+    0x0FU /*!< Bit mask for the Wait Time value                               */
+
+#define RFAL_NFCDEP_BR_MASK_106 \
+    0x01U /*!< Enable mask bit rate 106                                    */
+#define RFAL_NFCDEP_BR_MASK_212 \
+    0x02U /*!< Enable mask bit rate 242                                    */
+#define RFAL_NFCDEP_BR_MASK_424 \
+    0x04U /*!< Enable mask bit rate 424                                    */
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+#define rfalNfcDepWT2RWT(wt)                      \
+    ((uint32_t)1U                                 \
+     << (((uint32_t)(wt) & RFAL_NFCDEP_WT_MASK) + \
+         12U)) /*!< Converts WT value to RWT (1/fc)               */
+
+/*! Returns the BRS value from the given bit rate */
+#define rfalNfcDepDx2BRS(br)                                                  \
+    ((((uint8_t)(br) & RFAL_NFCDEP_BRS_Dx_MASK) << RFAL_NFCDEP_BRS_DSI_POS) | \
+     ((uint8_t)(br) & RFAL_NFCDEP_BRS_Dx_MASK))
+
+#define rfalNfcDepBRS2DRI(brs) \
+    (uint8_t)(                 \
+        (uint8_t)(brs) &       \
+        RFAL_NFCDEP_BRS_Dx_MASK) /*!< Returns the DRI value from the given BRS byte */
+#define rfalNfcDepBRS2DSI(brs)                        \
+    (uint8_t)(                                        \
+        ((uint8_t)(brs) >> RFAL_NFCDEP_BRS_DSI_POS) & \
+        RFAL_NFCDEP_BRS_Dx_MASK) /*!< Returns the DSI value from the given BRS byte */
+
+#define rfalNfcDepPP2LR(PPx)                      \
+    (((uint8_t)(PPx) & RFAL_NFCDEP_PP_LR_MASK) >> \
+     RFAL_NFCDEP_PP_LR_SHIFT) /*!< Returns the LR value from the given PPx byte  */
+#define rfalNfcDepLR2PP(LRx)                       \
+    (((uint8_t)(LRx) << RFAL_NFCDEP_PP_LR_SHIFT) & \
+     RFAL_NFCDEP_PP_LR_MASK) /*!< Returns the PP byte with the given LRx value  */
+
+/*! Returns the Frame size value from the given LRx value  */
+#define rfalNfcDepLR2FS(LRx) \
+    (uint16_t)(              \
+        MIN((RFAL_NFCDEP_FS_VAL_MIN * ((uint16_t)(LRx) + 1U)), RFAL_NFCDEP_FRAME_SIZE_MAX_LEN))
+
+/*! 
+ *  Despite DIGITAL 1.0 14.6.2.1 stating that the last two bytes may filled with 
+ *  any value, some devices (Samsung Google Nexus) only accept when these are 0 */
+#define rfalNfcDepSetNFCID(dst, src, len)           \
+    ST_MEMSET((dst), 0x00, RFAL_NFCDEP_NFCID3_LEN); \
+    if((len) > 0U) {                                \
+        ST_MEMCPY((dst), (src), (len));             \
+    }
+
+/*
+ ******************************************************************************
+ * GLOBAL ENUMERATIONS
+ ******************************************************************************
+ */
+
+/*! Enumeration of NFC-DEP bit rate in ATR    Digital 1.0 Table 93 and 94   */
+enum {
+    RFAL_NFCDEP_Bx_NO_HIGH_BR = 0x00, /*!< Peer supports no high bit rates      */
+    RFAL_NFCDEP_Bx_08_848 = 0x01, /*!< Peer also supports 848               */
+    RFAL_NFCDEP_Bx_16_1695 = 0x02, /*!< Peer also supports 1695              */
+    RFAL_NFCDEP_Bx_32_3390 = 0x04, /*!< Peer also supports 3390              */
+    RFAL_NFCDEP_Bx_64_6780 = 0x08 /*!< Peer also supports 6780              */
+};
+
+/*! Enumeration of NFC-DEP bit rate Divider in PSL   Digital 1.0 Table 100  */
+enum {
+    RFAL_NFCDEP_Dx_01_106 = RFAL_BR_106, /*!< Divisor D =  1 : bit rate = 106      */
+    RFAL_NFCDEP_Dx_02_212 = RFAL_BR_212, /*!< Divisor D =  2 : bit rate = 212      */
+    RFAL_NFCDEP_Dx_04_424 = RFAL_BR_424, /*!< Divisor D =  4 : bit rate = 424      */
+    RFAL_NFCDEP_Dx_08_848 = RFAL_BR_848, /*!< Divisor D =  8 : bit rate = 848      */
+    RFAL_NFCDEP_Dx_16_1695 = RFAL_BR_1695, /*!< Divisor D = 16 : bit rate = 1695     */
+    RFAL_NFCDEP_Dx_32_3390 = RFAL_BR_3390, /*!< Divisor D = 32 : bit rate = 3390     */
+    RFAL_NFCDEP_Dx_64_6780 = RFAL_BR_6780 /*!< Divisor D = 64 : bit rate = 6780     */
+};
+
+/*! Enumeration of  NFC-DEP Length Reduction (LR)   Digital 1.0 Table 91    */
+enum {
+    RFAL_NFCDEP_LR_64 = 0x00, /*!< Maximum payload size is  64 bytes    */
+    RFAL_NFCDEP_LR_128 = 0x01, /*!< Maximum payload size is 128 bytes    */
+    RFAL_NFCDEP_LR_192 = 0x02, /*!< Maximum payload size is 192 bytes    */
+    RFAL_NFCDEP_LR_254 = 0x03 /*!< Maximum payload size is 254 bytes    */
+};
+
+/*
+ ******************************************************************************
+ * GLOBAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! NFC-DEP callback to check if upper layer has deactivation pending   */
+typedef bool (*rfalNfcDepDeactCallback)(void);
+
+/*! Enumeration of the nfcip communication modes */
+typedef enum {
+    RFAL_NFCDEP_COMM_PASSIVE, /*!< Passive communication mode    */
+    RFAL_NFCDEP_COMM_ACTIVE /*!< Active communication mode     */
+} rfalNfcDepCommMode;
+
+/*! Enumeration of the nfcip roles */
+typedef enum {
+    RFAL_NFCDEP_ROLE_INITIATOR, /*!< Perform as Initiator          */
+    RFAL_NFCDEP_ROLE_TARGET /*!< Perform as Target             */
+} rfalNfcDepRole;
+
+/*! Struct that holds all NFCIP configs                                                      */
+typedef struct {
+    rfalNfcDepRole role; /*!< Current NFCIP role                                      */
+    rfalNfcDepCommMode commMode; /*!< Current NFCIP communication mode                        */
+    uint8_t oper; /*!< Operation config similar to NCI 1.0 Table 81            */
+
+    uint8_t did; /*!< Current Device ID (DID)                                 */
+    uint8_t nad; /*!< Current Node Addressing (NAD)                           */
+    uint8_t bs; /*!< Bit rate in Sending Direction                           */
+    uint8_t br; /*!< Bit rate in Receiving Direction                         */
+    uint8_t nfcid[RFAL_NFCDEP_NFCID3_LEN]; /*!< Pointer to the NFCID to be used    */
+    uint8_t nfcidLen; /*!< Length of the given NFCID in nfcid                      */
+    uint8_t gb[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Pointer General Bytes (GB) to be used */
+    uint8_t gbLen; /*!< Length of the given GB in gb                            */
+    uint8_t lr; /*!< Length Reduction (LR) to be used                        */
+    uint8_t to; /*!< Timeout (TO)  to be used                                */
+    uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used                     */
+    uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used              */
+} rfalNfcDepConfigs;
+
+/*! ATR_REQ command    Digital 1.1 16.6.2   */
+typedef struct {
+    uint8_t CMD1; /*!< Command format 0xD4                    */
+    uint8_t CMD2; /*!< Command Value                          */
+    uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value                           */
+    uint8_t DID; /*!< DID                                    */
+    uint8_t BSi; /*!< Sending Bitrate for Initiator          */
+    uint8_t BRi; /*!< Receiving Bitrate for Initiator        */
+    uint8_t PPi; /*!< Optional Parameters presence indicator */
+    uint8_t GBi[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes                          */
+} rfalNfcDepAtrReq;
+
+/*! ATR_RES response    Digital 1.1 16.6.3  */
+typedef struct {
+    uint8_t CMD1; /*!< Response Byte 0xD5                     */
+    uint8_t CMD2; /*!< Command Value                          */
+    uint8_t NFCID3[RFAL_NFCDEP_NFCID3_LEN]; /*!< NFCID3 value                           */
+    uint8_t DID; /*!< DID                                    */
+    uint8_t BSt; /*!< Sending Bitrate for Initiator          */
+    uint8_t BRt; /*!< Receiving Bitrate for Initiator        */
+    uint8_t TO; /*!< Timeout                                */
+    uint8_t PPt; /*!< Optional Parameters presence indicator */
+    uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< General Bytes                          */
+} rfalNfcDepAtrRes;
+
+/*! Structure of transmit I-PDU Buffer format from caller                                    */
+typedef struct {
+    uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue space for NFC-DEP header*/
+    uint8_t inf[RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN]; /*!< INF | Data area of the buffer    */
+} rfalNfcDepBufFormat;
+
+/*! Structure of APDU Buffer format from caller */
+typedef struct {
+    uint8_t prologue[RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /*!< Prologue/SoD buffer                     */
+    uint8_t pdu[RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN]; /*!< Complete PDU/Payload buffer             */
+} rfalNfcDepPduBufFormat;
+
+/*! Activation info as Initiator and Target                                       */
+typedef union { /*  PRQA S 0750 # MISRA 19.2 - Both members of the union will not be used concurrently , device is only initiatior or target a time. No problem can occur. */
+    struct {
+        rfalNfcDepAtrRes ATR_RES; /*!< ATR RES            (Initiator mode)  */
+        uint8_t ATR_RESLen; /*!< ATR RES length     (Initiator mode)  */
+    } Target; /*!< Target                               */
+    struct {
+        rfalNfcDepAtrReq ATR_REQ; /*!< ATR REQ            (Target mode)     */
+        uint8_t ATR_REQLen; /*!< ATR REQ length     (Target mode)     */
+    } Initiator; /*!< Initiator                            */
+} rfalNfcDepActivation;
+
+/*! NFC-DEP device Info */
+typedef struct {
+    uint8_t GBLen; /*!< General Bytes length                       */
+    uint8_t WT; /*!< WT to be used (ignored in Listen Mode)     */
+    uint32_t FWT; /*!< FWT to be used (1/fc)(ignored Listen Mode) */
+    uint32_t dFWT; /*!< Delta FWT to be used (1/fc)                */
+    uint8_t LR; /*!< Length Reduction coding the max payload    */
+    uint16_t FS; /*!< Frame Size                                 */
+    rfalBitRate DSI; /*!< Bit Rate coding from Initiator  to Target  */
+    rfalBitRate DRI; /*!< Bit Rate coding from Target to Initiator   */
+    uint8_t DID; /*!< Device ID (RFAL_NFCDEP_DID_NO if no DID)   */
+    uint8_t NAD; /*!< Node ADdress (RFAL_NFCDEP_NAD_NO if no NAD)*/
+} rfalNfcDepInfo;
+
+/*! NFC-DEP Device structure */
+typedef struct {
+    rfalNfcDepActivation activation; /*!< Activation Info               */
+    rfalNfcDepInfo info; /*!< NFC-DEP device Info           */
+} rfalNfcDepDevice;
+
+/*! NFCIP Protocol structure for P2P Target
+ *
+ *   operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter
+ *               NCI 1.1 Table 86: NFC-DEP Operation Parameter
+ *               and it's a bit mask composed as:
+ *                  [ 0000b 
+ *                    | Chain SHALL use max. Transport Data Byte[1b] 
+ *                    | I-PDU with no Transport Data SHALL NOT be sent [1b]
+ *                    | NFC-DEP Target SHALL NOT send RTOX request [1b]
+ *                  ]
+ * 
+ */
+typedef struct {
+    rfalNfcDepCommMode commMode; /*!< Initiator in Active P2P or Passive P2P*/
+    uint8_t operParam; /*!< NFC-DEP Operation Parameter           */
+    uint8_t* nfcid; /*!< Initiator's NFCID2 or NFCID3          */
+    uint8_t nfcidLen; /*!< Initiator's NFCID length (NFCID2/3)   */
+    uint8_t DID; /*!< Initiator's Device ID DID             */
+    uint8_t NAD; /*!< Initiator's Node ID NAD               */
+    uint8_t BS; /*!< Initiator's Bit Rates supported in Tx */
+    uint8_t BR; /*!< Initiator's Bit Rates supported in Rx */
+    uint8_t LR; /*!< Initiator's Length reduction          */
+    uint8_t* GB; /*!< Initiator's General Bytes (Gi)        */
+    uint8_t GBLen; /*!< Initiator's General Bytes length      */
+} rfalNfcDepAtrParam;
+
+/*! Structure of parameters to be passed in for nfcDepListenStartActivation       */
+typedef struct {
+    rfalNfcDepBufFormat* rxBuf; /*!< Receive Buffer struct reference      */
+    uint16_t* rxLen; /*!< Receive INF data length in bytes     */
+    bool* isRxChaining; /*!< Received data is not complete        */
+    rfalNfcDepDevice* nfcDepDev; /*!< NFC-DEP device info                  */
+} rfalNfcDepListenActvParam;
+
+/*! NFCIP Protocol structure for P2P Target
+ *
+ *   operParam : derives from NFC-Forum NCI NFC-DEP Operation Parameter
+ *               NCI 1.1 Table 86: NFC-DEP Operation Parameter
+ *               and it's a bit mask composed as:
+ *                  [ 0000b 
+ *                    | Chain SHALL use max. Transport Data Byte[1b] 
+ *                    | I-PDU with no Transport Data SHALL NOT be sent [1b]
+ *                    | NFC-DEP Target SHALL NOT send RTOX request [1b]
+ *                  ]
+ * 
+ */
+typedef struct {
+    rfalNfcDepCommMode commMode; /*!< Target in Active P2P or Passive P2P   */
+    uint8_t nfcid3[RFAL_NFCDEP_NFCID3_LEN]; /*!< Target's NFCID3                       */
+    uint8_t bst; /*!< Target's Bit Rates supported in Tx    */
+    uint8_t brt; /*!< Target's Bit Rates supported in Rx    */
+    uint8_t to; /*!< Target's timeout (TO) value           */
+    uint8_t ppt; /*!< Target's Presence optional Params(PPt)*/
+    uint8_t GBt[RFAL_NFCDEP_GB_MAX_LEN]; /*!< Target's General Bytes (Gt)           */
+    uint8_t GBtLen; /*!< Target's General Bytes length         */
+    uint8_t operParam; /*!< NFC-DEP Operation Parameter           */
+} rfalNfcDepTargetParam;
+
+/*! Structure of parameters to be passed in for nfcDepStartIpduTransceive              */
+typedef struct {
+    rfalNfcDepBufFormat* txBuf; /*!< Transmit Buffer struct reference          */
+    uint16_t txBufLen; /*!< Transmit Buffer INF field length in bytes */
+    bool isTxChaining; /*!< Transmit data is not complete             */
+    rfalNfcDepBufFormat* rxBuf; /*!< Receive Buffer struct reference           */
+    uint16_t* rxLen; /*!< Receive INF data length                   */
+    bool* isRxChaining; /*!< Received data is not complete             */
+    uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode)   */
+    uint32_t dFWT; /*!< Delta FWT to be used                      */
+    uint16_t FSx; /*!< Other device Frame Size (FSD or FSC)      */
+    uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID)  */
+} rfalNfcDepTxRxParam;
+
+/*! Structure of parameters used on NFC DEP PDU Transceive */
+typedef struct {
+    rfalNfcDepPduBufFormat* txBuf; /*!< Transmit Buffer struct reference         */
+    uint16_t txBufLen; /*!< Transmit Buffer INF field length in Bytes*/
+    rfalNfcDepPduBufFormat* rxBuf; /*!< Receive Buffer struct reference in Bytes */
+    uint16_t* rxLen; /*!< Received INF data length in Bytes        */
+    rfalNfcDepBufFormat* tmpBuf; /*!< Temp buffer for single PDUs (internal)   */
+    uint32_t FWT; /*!< FWT to be used (ignored in Listen Mode)  */
+    uint32_t dFWT; /*!< Delta FWT to be used                     */
+    uint16_t FSx; /*!< Other device Frame Size (FSD or FSC)     */
+    uint8_t DID; /*!< Device ID (RFAL_ISODEP_NO_DID if no DID) */
+} rfalNfcDepPduTxRxParam;
+
+/*
+ * *****************************************************************************
+ * GLOBAL VARIABLE DECLARATIONS
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+
+/*!
+ ******************************************************************************
+ * \brief NFCIP Initialize
+ * 
+ * This method resets all NFC-DEP inner states, counters and context and sets
+ * default values
+ * 
+ ******************************************************************************
+ */
+void rfalNfcDepInitialize(void);
+
+/*!
+ ******************************************************************************
+ * \brief Set deactivating callback
+ * 
+ * Sets the deactivating callback so that nfcip layer can check if upper layer
+ * has a deactivation pending, and not perform error recovery upon specific
+ * errors
+ * 
+ * \param[in] pFunc : method pointer to deactivation flag check 
+ ******************************************************************************
+ */
+void rfalNfcDepSetDeactivatingCallback(rfalNfcDepDeactCallback pFunc);
+
+/*!
+ ******************************************************************************
+ * \brief Calculate Response Waiting Time
+ * 
+ * Calculates the Response Waiting Time (RWT) from the given Waiting Time (WT)
+ * 
+ * \param[in]  wt : the WT value to calculate RWT
+ * 
+ * \return RWT value in 1/fc
+ ******************************************************************************
+ */
+uint32_t rfalNfcDepCalculateRWT(uint8_t wt);
+
+/*!
+ ******************************************************************************
+ * \brief NFC-DEP Initiator ATR (Attribute Request)
+ * 
+ * This method configures the NFC-DEP layer with given parameters and then
+ * sends an ATR to the Target with and checks for a valid response response
+ *
+ * \param[in]   param     : parameters to initialize and compose the ATR
+ * \param[out]  atrRes    : location to store the ATR_RES
+ * \param[out]  atrResLen : length of the ATR_RES received
+ * 
+ * \return ERR_NONE    : No error
+ * \return ERR_TIMEOUT : Timeout occurred
+ * \return ERR_PROTO   : Protocol error occurred
+ ******************************************************************************
+ */
+ReturnCode
+    rfalNfcDepATR(const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes* atrRes, uint8_t* atrResLen);
+
+/*!
+ ******************************************************************************
+ * \brief NFC-DEP Initiator PSL (Parameter Selection)
+ * 
+ * This method sends a PSL to the Target with the given parameters and checks
+ * for a valid response response
+ * 
+ * The parameters must be coded according to  Digital 1.1  16.7.1
+ * 
+ * \param[in] BRS : the selected Bit Rates for Initiator and Target
+ * \param[in] FSL : the maximum length of Commands and Responses
+ * 
+ * \return ERR_NONE    : No error
+ * \return ERR_TIMEOUT : Timeout occurred
+ * \return ERR_PROTO   : Protocol error occurred
+ ******************************************************************************
+ */
+ReturnCode rfalNfcDepPSL(uint8_t BRS, uint8_t FSL);
+
+/*!
+ ******************************************************************************
+ * \brief NFC-DEP Initiator DSL (Deselect)
+ * 
+ * This method checks if the NFCIP module is configured as initiator and if 
+ * so sends a DSL REQ, waits  the target's response and checks it 
+ * 
+ * In case of performing as target no action is taken 
+ * 
+ * \return ERR_NONE       : No error
+ * \return ERR_TIMEOUT    : Timeout occurred
+ * \return ERR_MAX_RERUNS : Timeout occurred
+ * \return ERR_PROTO      : Protocol error occurred
+ ******************************************************************************
+ */
+ReturnCode rfalNfcDepDSL(void);
+
+/*!
+ ******************************************************************************
+ * \brief NFC-DEP Initiator RLS (Release)
+ * 
+ * This method checks if the NFCIP module is configured as initiator and if 
+ * so sends a RLS REQ, waits target's response and checks it 
+ * 
+ * In case of performing as target no action is taken 
+ * 
+ * \return ERR_NONE       : No error
+ * \return ERR_TIMEOUT    : Timeout occurred
+ * \return ERR_MAX_RERUNS : Timeout occurred
+ * \return ERR_PROTO      : Protocol error occurred
+ ******************************************************************************
+ */
+ReturnCode rfalNfcDepRLS(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  NFC-DEP Initiator Handle  Activation
+ *   
+ *  This performs a Activation into NFC-DEP layer with the given
+ *  parameters. It sends ATR_REQ and if the higher bit rates are supported by 
+ *  both devices it additionally sends PSL
+ *  Once Activated all details of the device are provided on nfcDepDev
+ *   
+ *  \param[in]  param     : required parameters to initialize and send ATR_REQ
+ *  \param[in]  desiredBR : Desired bit rate supported by the Poller
+ *  \param[out] nfcDepDev : NFC-DEP information of the activated Listen device
+ *
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepInitiatorHandleActivation(
+    rfalNfcDepAtrParam* param,
+    rfalBitRate desiredBR,
+    rfalNfcDepDevice* nfcDepDev);
+
+/*!
+ ******************************************************************************
+ * \brief Check if buffer contains valid ATR_REQ 
+ * 
+ * This method checks if the given ATR_REQ is valid
+ * 
+ * 
+ * \param[in]  buf    : buffer holding Initiator's received request
+ * \param[in]  bufLen : size of the msg contained on the buf in Bytes
+ * \param[out] nfcid3 : pointer to where the NFCID3 may be outputted, 
+ *                       nfcid3 has NFCF_SENSF_NFCID3_LEN as length
+ *                       Pass NULL if output parameter not desired 
+ *                       
+ * \return true  : Valid ATR_REQ received, the ATR_RES has been computed in txBuf
+ * \return false : Invalid protocol request
+ * 
+ ******************************************************************************
+ */
+bool rfalNfcDepIsAtrReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3);
+
+/*!
+ ******************************************************************************
+ * \brief Check is Target has received ATR 
+ * 
+ * This method checks if the NFCIP module is configured as target and if a
+ * ATR REQ has been received ( whether is in activation or in data exchange)
+ * 
+ * \return true  : a ATR has already been received
+ * \return false : no ATR has been received 
+ ******************************************************************************
+ */
+bool rfalNfcDepTargetRcvdATR(void);
+
+/*!
+ *****************************************************************************
+ * \brief NFCDEP Start Listen Activation Handling
+ * 
+ * Start Activation Handling and setup to receive first frame which may
+ * contain complete or partial DEP-REQ after activation is completed 
+ * 
+ * Pass in ATR_REQ for NFC-DEP to handle ATR_RES. The Activation Handling 
+ * handles ATR_RES and PSL_RES if a PSL_REQ is received
+ * 
+ * Activation is completed if PSL_RES is sent or if first I-PDU is received
+ *  
+ * \ref rfalNfcDepListenGetActivationStatus() provide status of the 
+ *       ongoing activation
+ * 
+ * \warning nfcDepGetTransceiveStatus() shall be called right after activation 
+ * is completed (i.e. rfalNfcDepListenGetActivationStatus() return ERR_NONE) 
+ * to check for first received frame.
+ * 
+ * \param[in]  param       : Target parameters to be used
+ * \param[in]  atrReq      : reference to buffer containing ATR_REQ 
+ * \param[in]  atrReqLength: Length of ATR_REQ
+ * \param[out] rxParam     : references to buffer, length and chaining indication 
+ *                           for first complete LLCP to be received
+ * 
+ * \return ERR_NONE      : ATR_REQ is valid and activation ongoing
+ * \return ERR_PARAM     : ATR_REQ or other params are invalid
+ * \return ERR_LINK_LOSS : Remote Field is turned off
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepListenStartActivation(
+    const rfalNfcDepTargetParam* param,
+    const uint8_t* atrReq,
+    uint16_t atrReqLength,
+    rfalNfcDepListenActvParam rxParam);
+
+/*!
+ *****************************************************************************
+ * \brief Get the current NFC-DEP Activation Status
+ * 
+ * \return ERR_NONE      : Activation has completed successfully
+ * \return ERR_BUSY      : Activation is ongoing
+ * \return ERR_LINK_LOSS : Remote Field was turned off
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepListenGetActivationStatus(void);
+
+/*!
+ *****************************************************************************
+ * \brief Start Transceive 
+ * 
+ * Transceives a complete or partial DEP block
+ * 
+ * The txBuf contains complete or partial of DEP to be transmitted. 
+ * The Prologue field of the I-PDU is handled internally
+ * 
+ * If the buffer contains partial LLCP and is not the last block, then 
+ * isTxChaining must be set to true
+ * 
+ * \param[in] param: reference parameters to be used for the Transceive
+ *                    
+ * \return ERR_PARAM       : Bad request
+ * \return ERR_WRONG_STATE : The module is not in a proper state
+ * \return ERR_NONE        : The Transceive request has been started
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepStartTransceive(const rfalNfcDepTxRxParam* param);
+
+/*!
+ *****************************************************************************
+ * \brief Return the Transceive status
+ *
+ * Returns the status of the NFC-DEP Transceive
+ * 
+ * \warning  When the other device is performing chaining once a chained 
+ *            block is received the error ERR_AGAIN is sent. At this point 
+ *            caller must handle the received data immediately. 
+ *            When ERR_AGAIN is returned an ACK has already been sent to 
+ *            the other device and the next block might be incoming. 
+ *            If rfalWorker() is called frequently it will place the next 
+ *            block on the given buffer  
+ * 
+ * \return ERR_NONE      : Transceive has been completed successfully
+ * \return ERR_BUSY      : Transceive is ongoing
+ * \return ERR_PROTO     : Protocol error occurred
+ * \return ERR_TIMEOUT   : Timeout error occurred
+ * \return ERR_SLEEP_REQ : Deselect has been received and responded
+ * \return ERR_NOMEM     : The received I-PDU does not fit into the
+ *                            receive buffer
+ * \return ERR_LINK_LOSS : Communication is lost because Reader/Writer 
+ *                            has turned off its field
+ * \return ERR_AGAIN     : received one chaining block, continue to call
+ *                            this method to retrieve the remaining blocks
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepGetTransceiveStatus(void);
+
+/*!
+ *****************************************************************************
+ * \brief Start PDU Transceive 
+ * 
+ * This method triggers a NFC-DEP Transceive containing a complete PDU
+ * It transmits the given message and handles all protocol retransmitions,
+ * error handling and control messages
+ * 
+ * The txBuf  contains a complete PDU to be transmitted 
+ * The Prologue field will be manipulated by the Transceive
+ *  
+ * \warning the txBuf will be modified during the transmission
+ * \warning the maximum RF frame which can be received is limited by param.tmpBuf
+ * 
+ * \param[in] param: reference parameters to be used for the Transceive
+ *                    
+ * \return ERR_PARAM       : Bad request
+ * \return ERR_WRONG_STATE : The module is not in a proper state
+ * \return ERR_NONE        : The Transceive request has been started
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepStartPduTransceive(rfalNfcDepPduTxRxParam param);
+
+/*!
+ *****************************************************************************
+ * \brief Return the PSU Transceive status
+ *
+ * Returns the status of the NFC-DEP PDU Transceive
+ * 
+ * 
+ * \return ERR_NONE      : Transceive has been completed successfully
+ * \return ERR_BUSY      : Transceive is ongoing
+ * \return ERR_PROTO     : Protocol error occurred
+ * \return ERR_TIMEOUT   : Timeout error occurred
+ * \return ERR_SLEEP_REQ : Deselect has been received and responded
+ * \return ERR_NOMEM     : The received I-PDU does not fit into the
+ *                            receive buffer
+ * \return ERR_LINK_LOSS : Communication is lost because Reader/Writer 
+ *                            has turned off its field
+ *****************************************************************************
+ */
+ReturnCode rfalNfcDepGetPduTransceiveStatus(void);
+
+#endif /* RFAL_NFCDEP_H_ */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 497 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfca.h

@@ -0,0 +1,497 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfca.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides several NFC-A convenience methods and definitions
+ *  
+ *  It provides a Poller (ISO14443A PCD) interface and as well as 
+ *  some NFC-A Listener (ISO14443A PICC) helpers.
+ *
+ *  The definitions and helpers methods provided by this module are only
+ *  up to ISO14443-3 layer
+ *  
+ *  
+ *  An usage example is provided here: \ref exampleRfalNfca.c
+ *  \example exampleRfalNfca.c
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup NFC-A
+ * \brief RFAL NFC-A Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_NFCA_H
+#define RFAL_NFCA_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+#include "rfal_t1t.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCA_CASCADE_1_UID_LEN \
+    4U /*!< UID length of cascade level 1 only tag                            */
+#define RFAL_NFCA_CASCADE_2_UID_LEN \
+    7U /*!< UID length of cascade level 2 only tag                            */
+#define RFAL_NFCA_CASCADE_3_UID_LEN \
+    10U /*!< UID length of cascade level 3 only tag                            */
+
+#define RFAL_NFCA_SENS_RES_PLATFORM_MASK \
+    0x0FU /*!< SENS_RES (ATQA) platform configuration mask  Digital 1.1 Table 10 */
+#define RFAL_NFCA_SENS_RES_PLATFORM_T1T \
+    0x0CU /*!< SENS_RES (ATQA) T1T platform configuration  Digital 1.1 Table 10  */
+
+#define RFAL_NFCA_SEL_RES_CONF_MASK \
+    0x60U /*!< SEL_RES (SAK) platform configuration mask  Digital 1.1 Table 19   */
+#define RFAL_NFCA_SEL_RES_CONF_T2T \
+    0x00U /*!< SEL_RES (SAK) T2T configuration  Digital 1.1 Table 19             */
+#define RFAL_NFCA_SEL_RES_CONF_T4T \
+    0x20U /*!< SEL_RES (SAK) T4T configuration  Digital 1.1 Table 19             */
+#define RFAL_NFCA_SEL_RES_CONF_NFCDEP \
+    0x40U /*!< SEL_RES (SAK) NFC-DEP configuration  Digital 1.1 Table 19         */
+#define RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP \
+    0x60U /*!< SEL_RES (SAK) T4T and NFC-DEP configuration  Digital 1.1 Table 19 */
+
+/*! NFC-A minimum FDT(listen) = ((n * 128 + (84)) / fc) with n_min = 9      Digital 1.1  6.10.1
+ *                            = (1236)/fc
+ * Relax with 3etu: (3*128)/fc as with multiple NFC-A cards, response may take longer (JCOP cards)
+ *                            = (1236 + 384)/fc = 1620 / fc                                      */
+#define RFAL_NFCA_FDTMIN 1620U
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*! Checks if device is a T1T given its SENS_RES */
+#define rfalNfcaIsSensResT1T(sensRes)                                                    \
+    ((((rfalNfcaSensRes*)(sensRes))->platformInfo & RFAL_NFCA_SENS_RES_PLATFORM_MASK) == \
+     RFAL_NFCA_SENS_RES_PLATFORM_T1T)
+
+/*! Checks if device is a T2T given its SENS_RES */
+#define rfalNfcaIsSelResT2T(selRes)                                      \
+    ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
+     RFAL_NFCA_SEL_RES_CONF_T2T)
+
+/*! Checks if device is a T4T given its SENS_RES */
+#define rfalNfcaIsSelResT4T(selRes)                                      \
+    ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
+     RFAL_NFCA_SEL_RES_CONF_T4T)
+
+/*! Checks if device supports NFC-DEP protocol given its SENS_RES */
+#define rfalNfcaIsSelResNFCDEP(selRes)                                   \
+    ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
+     RFAL_NFCA_SEL_RES_CONF_NFCDEP)
+
+/*! Checks if device supports ISO-DEP and NFC-DEP protocol given its SENS_RES */
+#define rfalNfcaIsSelResT4TNFCDEP(selRes)                                \
+    ((((rfalNfcaSelRes*)(selRes))->sak & RFAL_NFCA_SEL_RES_CONF_MASK) == \
+     RFAL_NFCA_SEL_RES_CONF_T4T_NFCDEP)
+
+/*! Checks if a NFC-A listener device supports multiple protocols (ISO-DEP and NFC-DEP) */
+#define rfalNfcaLisDevIsMultiProto(lisDev) \
+    (((rfalNfcaListenDevice*)(lisDev))->type == RFAL_NFCA_T4T_NFCDEP)
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-A Listen device types */
+typedef enum {
+    RFAL_NFCA_T1T =
+        0x01, /* Device configured for T1T  Digital 1.1 Table 9                               */
+    RFAL_NFCA_T2T =
+        0x00, /* Device configured for T2T  Digital 1.1 Table 19                              */
+    RFAL_NFCA_T4T =
+        0x20, /* Device configured for T4T  Digital 1.1 Table 19                              */
+    RFAL_NFCA_NFCDEP =
+        0x40, /* Device configured for NFC-DEP  Digital 1.1 Table 19                          */
+    RFAL_NFCA_T4T_NFCDEP =
+        0x60 /* Device configured for NFC-DEP and T4T  Digital 1.1 Table 19                  */
+} rfalNfcaListenDeviceType;
+
+/*! SENS_RES (ATQA) format  Digital 1.1  6.6.3 & Table 7 */
+typedef struct {
+    uint8_t
+        anticollisionInfo; /*!< SENS_RES Anticollision Information                                         */
+    uint8_t
+        platformInfo; /*!< SENS_RES Platform Information                                              */
+} rfalNfcaSensRes;
+
+/*! SDD_REQ (Anticollision) format   Digital 1.1  6.7.1 & Table 11 */
+typedef struct {
+    uint8_t
+        selCmd; /*!< SDD_REQ SEL_CMD: cascade Level                                             */
+    uint8_t
+        selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/
+} rfalNfcaSddReq;
+
+/*! SDD_RES (UID CLn) format   Digital 1.1  6.7.2 & Table 15 */
+typedef struct {
+    uint8_t nfcid1
+        [RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 cascade level NFCID                                                 */
+    uint8_t bcc; /*!< BCC Exclusive-OR over first 4 bytes of SDD_RES                             */
+} rfalNfcaSddRes;
+
+/*! SEL_REQ (Select) format   Digital 1.1  6.8.1 & Table 17 */
+typedef struct {
+    uint8_t
+        selCmd; /*!< SDD_REQ SEL_CMD: cascade Level                                             */
+    uint8_t
+        selPar; /*!< SDD_REQ SEL_PAR: Byte Count[4b] | Bit Count[4b] (NVB: Number of Valid Bits)*/
+    uint8_t nfcid1
+        [RFAL_NFCA_CASCADE_1_UID_LEN]; /*!< NFCID1 data                                                                */
+    uint8_t bcc; /*!< Checksum calculated as exclusive-OR over the 4 bytes of NFCID1 CLn         */
+} rfalNfcaSelReq;
+
+/*! SEL_RES (SAK) format   Digital 1.1  6.8.2 & Table 19 */
+typedef struct {
+    uint8_t sak; /*!< Select Acknowledge                                                         */
+} rfalNfcaSelRes;
+
+/*! NFC-A listener device (PICC) struct  */
+typedef struct {
+    rfalNfcaListenDeviceType
+        type; /*!< NFC-A Listen device type                                                   */
+    rfalNfcaSensRes
+        sensRes; /*!< SENS_RES (ATQA)                                                            */
+    rfalNfcaSelRes
+        selRes; /*!< SEL_RES  (SAK)                                                             */
+    uint8_t
+        nfcId1Len; /*!< NFCID1 Length                                                              */
+    uint8_t nfcId1
+        [RFAL_NFCA_CASCADE_3_UID_LEN]; /*!< NFCID1   (UID)                                                             */
+#ifdef RFAL_FEATURE_T1T
+    rfalT1TRidRes
+        ridRes; /*!< RID_RES                                                                    */
+#endif /* RFAL_FEATURE_T1T */
+    bool isSleep; /*!< Device sleeping flag                                                       */
+} rfalNfcaListenDevice;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize NFC-A Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFC-A Poller/RW (ISO14443A PCD) including all default timings and bit rate
+ * to 106 kbps
+ 
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Check Presence
+ *  
+ * This method checks if a NFC-A Listen device (PICC) is present on the field
+ * by sending an ALL_REQ (WUPA) or SENS_REQ (REQA)
+ *  
+ * \param[in]  cmd     : Indicate if to send an ALL_REQ or a SENS_REQ
+ * \param[out] sensRes : If received, the SENS_RES
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_RF_COLLISION : Collision detected one or more device in the field
+ * \return ERR_PAR          : Parity error detected, one or more device in the field
+ * \return ERR_CRC          : CRC error detected, one or more device in the field
+ * \return ERR_FRAMING      : Framing error detected, one or more device in the field
+ * \return ERR_PROTO        : Protocol error detected, one or more device in the field
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_NONE         : No error, one or more device in the field
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerCheckPresence(rfal14443AShortFrameCmd cmd, rfalNfcaSensRes* sensRes);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Select
+ *  
+ * This method selects a NFC-A Listener device (PICC) 
+ *  
+ * \param[in]  nfcid1   : Listener device NFCID1 to be selected
+ * \param[in]  nfcidLen : Length of the NFCID1 to be selected  
+ * \param[out] selRes   : pointer to place the SEL_RES
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_PAR          : Parity error detected
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error, SEL_RES received
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerSelect(const uint8_t* nfcid1, uint8_t nfcidLen, rfalNfcaSelRes* selRes);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Sleep
+ *  
+ * This method sends a SLP_REQ (HLTA)
+ * No response is expected afterwards   Digital 1.1  6.9.2.1 
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerSleep(void);
+
+/*!
+ *****************************************************************************
+ * \brief  NFC-A Technology Detection
+ *  
+ * This method performs NFC-A Technology Detection as defined in the spec
+ * given in the compliance mode
+ *  
+ * \param[in]  compMode  : compliance mode to be performed
+ * \param[out] sensRes   : location to store the SENS_RES, if received
+ * 
+ * When compMode is set to ISO compliance a SLP_REQ (HLTA) is not sent 
+ * after detection. When set to EMV a ALL_REQ (WUPA) is sent instead of 
+ * a SENS_REQ (REQA)
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error, one or more device in the field
+ *****************************************************************************
+ */
+ReturnCode
+    rfalNfcaPollerTechnologyDetection(rfalComplianceMode compMode, rfalNfcaSensRes* sensRes);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Collision Resolution
+ *  
+ * Collision resolution for one NFC-A Listener device/card (PICC) as 
+ * defined in Activity 2.1  9.3.4
+ * 
+ * This method executes anti collision loop and select the device with higher NFCID1
+ * 
+ * When devLimit = 0 it is configured to perform collision detection only. Once a collision 
+ * is detected the collision resolution is aborted immediately. If only one device is found
+ * with no collisions, it will properly resolved. 
+ *
+ * \param[in]  devLimit    : device limit value (CON_DEVICES_LIMIT)
+ * \param[out] collPending : pointer to collision pending flag (INT_COLL_PEND)
+ * \param[out] selRes      : location to store the last Select Response from listener device (PICC)
+ * \param[out] nfcId1      : location to store the NFCID1 (UID), ensure RFAL_NFCA_CASCADE_3_UID_LEN
+ * \param[out] nfcId1Len   : pointer to length of NFCID1 (UID)
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_PROTO        : Card length invalid
+ * \return ERR_IGNORE       : conDevLimit is 0 and there is a collision
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerSingleCollisionResolution(
+    uint8_t devLimit,
+    bool* collPending,
+    rfalNfcaSelRes* selRes,
+    uint8_t* nfcId1,
+    uint8_t* nfcId1Len);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Full Collision Resolution
+ *  
+ * Performs a full Collision resolution as defined in Activity 2.1  9.3.4
+ *
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[in]  devLimit    : device limit value, and size nfcaDevList
+ * \param[out] nfcaDevList : NFC-A listener device info
+ * \param[out] devCnt      : Devices found counter
+ *
+ * When compMode is set to ISO compliance it assumes that the device is
+ * not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning.
+ * When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent 
+ * at the beginning.
+ *  
+ *  
+ * When devLimit = 0 it is configured to perform collision detection only. Once a collision 
+ * is detected the collision resolution is aborted immediately. If only one device is found
+ * with no collisions, it will properly resolved.
+ *
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerFullCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Full Collision Resolution with Sleep
+ *  
+ * Performs a full Collision resolution similar to rfalNfcaPollerFullCollisionResolution
+ * but an additional SLP_REQ (HLTA) -> SENS_RES (REQA) is sent regardless if there 
+ * was a collision.
+ * This proprietary behaviour ensures proper activation of certain devices that suffer
+ * from influence of Type B commands as foreseen in ISO14443-3 5.2.3 or were somehow
+ * not detected by the first round of collision resolution
+ *
+ * \param[in]  devLimit    : device limit value, and size nfcaDevList
+ * \param[out] nfcaDevList : NFC-A listener device info
+ * \param[out] devCnt      : Devices found counter
+ *  
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerSleepFullCollisionResolution(
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A Poller Start Full Collision Resolution
+ *  
+ * This method starts the full Collision resolution as defined 
+  * in Activity 1.0 or 1.1  9.3.4
+ *
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[in]  devLimit    : device limit value, and size nfcaDevList
+ * \param[out] nfcaDevList : NFC-A listener device info
+ * \param[out] devCnt      : Devices found counter
+ *
+ * When compMode is set to ISO compliance it assumes that the device is
+ * not sleeping and therefore no ALL_REQ (WUPA) is sent at the beginning.
+ * When compMode is set to NFC compliance an additional ALL_REQ (WUPA) is sent at 
+ * the beginning.
+ *  
+ *  
+ * When devLimit = 0 it is configured to perform collision detection only. Once a collision 
+ * is detected the collision resolution is aborted immediately. If only one device is found
+ * with no collisions, it will properly resolved.
+ *
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerStartFullCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt);
+
+/*!
+ *****************************************************************************
+ *  \brief  NFC-A Get Full Collision Resolution Status
+ *
+ *  Returns the Collision Resolution status
+ *
+ *  \return ERR_BUSY         : Operation is ongoing
+ *  \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ *  \return ERR_PARAM        : Invalid parameters
+ *  \return ERR_IO           : Generic internal error
+ *  \return ERR_TIMEOUT      : Timeout error
+ *  \return ERR_PAR          : Parity error detected
+ *  \return ERR_CRC          : CRC error detected
+ *  \return ERR_FRAMING      : Framing error detected
+ *  \return ERR_PROTO        : Protocol error detected
+ *  \return ERR_NONE         : No error, activation successful
+ *****************************************************************************
+ */
+ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus(void);
+
+/*!
+ *****************************************************************************
+ * \brief NFC-A Listener is SLP_REQ 
+ * 
+ * Checks if the given buffer contains valid NFC-A SLP_REQ (HALT)
+ * 
+ * \param[in] buf: buffer containing data
+ * \param[in] bufLen: length of the data in buffer to be checked
+ * 
+ * \return true if data in buf contains a SLP_REQ ; false otherwise
+ *****************************************************************************
+ */
+bool rfalNfcaListenerIsSleepReq(const uint8_t* buf, uint16_t bufLen);
+
+#endif /* RFAL_NFCA_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 425 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcb.h

@@ -0,0 +1,425 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcb.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-B (ISO14443B) helpers 
+ *  
+ *  It provides a NFC-B Poller (ISO14443B PCD) interface and 
+ *  also provides some NFC-B Listener (ISO14443B PICC) helpers
+ *
+ *  The definitions and helpers methods provided by this module are only
+ *  up to ISO14443-3 layer (excluding ATTRIB)
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup NFC-B
+ * \brief RFAL NFC-B Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_NFCB_H
+#define RFAL_NFCB_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCB_FWTSENSB 7680U /*!< NFC-B FWT(SENSB)  Digital 2.0  B.3        */
+#define RFAL_NFCB_DFWT 49152U /*!< NFC-B dFWT Delta 2.0  7.9.1.3 & B.3       */
+#define RFAL_NFCB_DTPOLL_10 rfalConvMsTo1fc(20) /*!< NFC-B Delta Tb Poll  Digital 1.0  A.2     */
+#define RFAL_NFCB_DTPOLL_20 rfalConvMsTo1fc(17) /*!< NFC-B Delta Tb Poll  Digital 2.1  B.3     */
+
+#define RFAL_NFCB_AFI 0x00U /*!< NFC-B default Application Family   Digital 1.1 7.6.1.1 */
+#define RFAL_NFCB_PARAM 0x00U /*!< NFC-B default SENSB_REQ PARAM                          */
+#define RFAL_NFCB_CRC_LEN 2U /*!< NFC-B CRC length and CRC_B(AID)   Digital 1.1 Table 28 */
+#define RFAL_NFCB_NFCID0_LEN 4U /*!< Length of NFC-B NFCID0                                 */
+#define RFAL_NFCB_CMD_LEN 1U /*!< Length of NFC-B Command                                */
+
+#define RFAL_NFCB_SENSB_RES_LEN 12U /*!< Standard length of SENSB_RES without SFGI byte         */
+#define RFAL_NFCB_SENSB_RES_EXT_LEN \
+    13U /*!< Extended length of SENSB_RES with SFGI byte            */
+
+#define RFAL_NFCB_SENSB_REQ_ADV_FEATURE \
+    0x20U /*!< Bit mask for Advance Feature in SENSB_REQ              */
+#define RFAL_NFCB_SENSB_RES_FSCI_MASK \
+    0x0FU /*!< Bit mask for FSCI value in SENSB_RES                   */
+#define RFAL_NFCB_SENSB_RES_FSCI_SHIFT \
+    4U /*!< Shift for FSCI value in SENSB_RES                      */
+#define RFAL_NFCB_SENSB_RES_PROTO_RFU_MASK \
+    0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES            */
+#define RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK \
+    0x03U /*!< Bit mask for Protocol Type TR2 in SENSB_RES            */
+#define RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT \
+    1U /*!< Shift for Protocol Type TR2 in SENSB_RES               */
+#define RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK \
+    0x01U /*!< Bit mask Protocol Type ISO14443 Compliant in SENSB_RES */
+#define RFAL_NFCB_SENSB_RES_FWI_MASK \
+    0x0FU /*!< Bit mask for FWI value in SENSB_RES                    */
+#define RFAL_NFCB_SENSB_RES_FWI_SHIFT \
+    4U /*!< Bit mask for FWI value in SENSB_RES                    */
+#define RFAL_NFCB_SENSB_RES_ADC_MASK \
+    0x0CU /*!< Bit mask for ADC value in SENSB_RES                    */
+#define RFAL_NFCB_SENSB_RES_ADC_ADV_FEATURE_MASK \
+    0x08U /*!< Bit mask for ADC.Advanced Proto Features in SENSB_RES  */
+#define RFAL_NFCB_SENSB_RES_ADC_PROPRIETARY_MASK \
+    0x04U /*!< Bit mask for ADC.Proprietary Application in SENSB_RES  */
+#define RFAL_NFCB_SENSB_RES_FO_DID_MASK \
+    0x01U /*!< Bit mask for DID in SENSB_RES                          */
+#define RFAL_NFCB_SENSB_RES_FO_NAD_MASK \
+    0x02U /*!< Bit mask for DID in SENSB_RES                          */
+#define RFAL_NFCB_SENSB_RES_FO_MASK \
+    0x03U /*!< Bit mask for FO value in SENSB_RES (NAD and DID)       */
+#define RFAL_NFCB_SENSB_RES_SFGI_MASK \
+    0x0FU /*!< Bit mask for SFGI in SENSB_RES                         */
+#define RFAL_NFCB_SENSB_RES_SFGI_SHIFT \
+    4U /*!< Shift for SFGI in SENSB_RES                            */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*! Get device's FSCI given its SENSB_RES  Digital 1.1 7.6.2  */
+#define rfalNfcbGetFSCI(sensbRes)                                                                \
+    ((((rfalNfcbSensbRes*)(sensbRes))->protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_FSCI_SHIFT) & \
+     RFAL_NFCB_SENSB_RES_FSCI_MASK)
+
+/*! Checks if the given NFC-B device indicates ISO-DEP support */
+#define rfalNfcbIsIsoDepSupported(dev)                                \
+    ((((rfalNfcbListenDevice*)(dev))->sensbRes.protInfo.FsciProType & \
+      RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK) != 0U)
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! SENSB_REQ and ALLB_REQ param   Digital 1.1 7.6.1  */
+typedef enum {
+    RFAL_NFCB_SENS_CMD_ALLB_REQ = 0x08, /*!< ALLB_REQ  (WUPB)  */
+    RFAL_NFCB_SENS_CMD_SENSB_REQ = 0x00 /*!< SENSB_REQ (REQB)  */
+} rfalNfcbSensCmd;
+
+/*! Number of Slots (NI) codes used for NFC-B anti collision  Digital 1.1 Table 26 */
+typedef enum {
+    RFAL_NFCB_SLOT_NUM_1 = 0, /*!< N=0 :  1 slot   */
+    RFAL_NFCB_SLOT_NUM_2 = 1, /*!< N=1 :  2 slots  */
+    RFAL_NFCB_SLOT_NUM_4 = 2, /*!< N=2 :  4 slots  */
+    RFAL_NFCB_SLOT_NUM_8 = 3, /*!< N=3 :  8 slots  */
+    RFAL_NFCB_SLOT_NUM_16 = 4 /*!< N=4 : 16 slots  */
+} rfalNfcbSlots;
+
+/*! SENSB_RES (ATQB) Application Data Format   Digital 1.1 Table 28 */
+typedef struct {
+    uint8_t AFI; /*!< Application Family Identifier */
+    uint8_t CRC_B[RFAL_NFCB_CRC_LEN]; /*!< CRC_B of AID                  */
+    uint8_t numApps; /*!< Number of Applications        */
+} rfalNfcbSensbResAppData;
+
+/*! SENSB_RES Protocol Info format Digital 1.1 Table 29 */
+typedef struct {
+    uint8_t
+        BRC; /*!< Bit Rate Capability                                                            */
+    uint8_t
+        FsciProType; /*!< Frame Size Card Integer [4b] | Protocol Type[4 bits]                           */
+    uint8_t
+        FwiAdcFo; /*!< Frame Waiting Integer [4b] | Application Data Coding [2b] | Frame Options [2b] */
+    uint8_t
+        SFGI; /*!< Optional: Start-Up Frame Guard Time Integer[4b] | RFU [4b]                     */
+} rfalNfcbSensbResProtocolInfo;
+
+/*! SENSB_RES format   Digital 1.1  7.6.2 */
+typedef struct {
+    uint8_t cmd; /*!< SENSB_RES: 50h       */
+    uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/
+    rfalNfcbSensbResAppData appData; /*!< Application Data     */
+    rfalNfcbSensbResProtocolInfo protInfo; /*!< Protocol Information */
+} rfalNfcbSensbRes;
+
+/*! NFC-B listener device (PICC) struct  */
+typedef struct {
+    uint8_t sensbResLen; /*!< SENSB_RES length      */
+    rfalNfcbSensbRes sensbRes; /*!< SENSB_RES             */
+    bool isSleep; /*!< Device sleeping flag  */
+} rfalNfcbListenDevice;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize NFC-B Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFC-B Poller/RW (ISO14443B PCD) including all default timings
+ * 
+ * It sets NFC-B parameters (AFI, PARAM) to default values
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Set NFC-B Poller parameters
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFCA Poller/RW (ISO14443A PCD) including all default timings
+ * 
+ * Additionally configures NFC-B specific parameters to be used on the 
+ * following communications
+ * 
+ * \param[in]  AFI   : Application Family Identifier to be used
+ * \param[in]  PARAM : PARAM to be used, it announces whether Advanced
+ *                     Features or Extended SENSB_RES is supported
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerInitializeWithParams(uint8_t AFI, uint8_t PARAM);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Poller Check Presence
+ *  
+ * This method checks if a NFC-B Listen device (PICC) is present on the field
+ * by sending an ALLB_REQ (WUPB) or SENSB_REQ (REQB)
+ *  
+ * \param[in]  cmd         : Indicate if to send an ALL_REQ or a SENS_REQ
+ * \param[in]  slots       : The number of slots to be announced
+ * \param[out] sensbRes    : If received, the SENSB_RES
+ * \param[out] sensbResLen : If received, the SENSB_RES length
+ * 
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_RF_COLLISION : Collision detected one or more device in the field
+ * \return ERR_PAR          : Parity error detected, one or more device in the field
+ * \return ERR_CRC          : CRC error detected, one or more device in the field
+ * \return ERR_FRAMING      : Framing error detected, one or more device in the field
+ * \return ERR_PROTO        : Protocol error detected, invalid SENSB_RES received
+ * \return ERR_NONE         : No error, SENSB_RES received
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerCheckPresence(
+    rfalNfcbSensCmd cmd,
+    rfalNfcbSlots slots,
+    rfalNfcbSensbRes* sensbRes,
+    uint8_t* sensbResLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Poller Sleep
+ *  
+ * This function is used to send the SLPB_REQ (HLTB) command to put the PICC with 
+ * the given NFCID0 to state HALT so that they do not reply to further SENSB_REQ 
+ * commands (only to ALLB_REQ)
+ * 
+ * \param[in]  nfcid0       : NFCID of the device to be put to Sleep
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerSleep(const uint8_t* nfcid0);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Poller Slot Marker
+ *  
+ * This method selects a NFC-B Slot marker frame 
+ *  
+ * \param[in]  slotCode     : Slot Code [1-15] 
+ * \param[out] sensbRes     : If received, the SENSB_RES
+ * \param[out] sensbResLen  : If received, the SENSB_RES length
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_PAR          : Parity error detected
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error, SEL_RES received
+ *****************************************************************************
+ */
+ReturnCode
+    rfalNfcbPollerSlotMarker(uint8_t slotCode, rfalNfcbSensbRes* sensbRes, uint8_t* sensbResLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Technology Detection
+ *  
+ * This method performs NFC-B Technology Detection as defined in the spec
+ * given in the compliance mode
+ *  
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[out] sensbRes    : location to store the SENSB_RES, if received
+ * \param[out] sensbResLen : length of the SENSB_RES, if received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error, one or more device in the field
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerTechnologyDetection(
+    rfalComplianceMode compMode,
+    rfalNfcbSensbRes* sensbRes,
+    uint8_t* sensbResLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Poller Collision Resolution
+ *  
+ * NFC-B Collision resolution  Listener device/card (PICC) as 
+ * defined in Activity 1.1  9.3.5
+ * 
+ * This function is used to perform collision resolution for detection in case 
+ * of multiple NFC Forum Devices with Technology B detected. 
+ * Target with valid SENSB_RES will be stored in devInfo and nfcbDevCount incremented.  
+ *
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[in]  devLimit    : device limit value, and size nfcbDevList
+ * \param[out] nfcbDevList : NFC-B listener device info
+ * \param[out] devCnt      : devices found counter
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcbListenDevice* nfcbDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B Poller Collision Resolution Slotted
+ *  
+ * NFC-B Collision resolution  Listener device/card (PICC). The sequence can 
+ * be configured to be according to NFC Forum Activity 1.1  9.3.5, ISO10373
+ * or EMVCo 
+ * 
+ * This function is used to perform collision resolution for detection in case 
+ * of multiple NFC Forum Devices with Technology B are detected. 
+ * Target with valid SENSB_RES will be stored in devInfo and nfcbDevCount incremented.  
+ * 
+ * This method provides the means to perform a collision resolution loop with specific
+ * initial and end number of slots. This allows to user to start the loop already with 
+ * greater number of slots, and or limit the end number of slots. At the end a flag
+ * indicating whether there were collisions pending is returned.
+ * 
+ * If RFAL_COMPLIANCE_MODE_ISO is used \a initSlots must be set to RFAL_NFCB_SLOT_NUM_1
+ *  
+ *
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[in]  devLimit    : device limit value, and size nfcbDevList
+ * \param[in]  initSlots   : number of slots to open initially 
+ * \param[in]  endSlots    : number of slots when to stop collision resolution 
+ * \param[out] nfcbDevList : NFC-B listener device info
+ * \param[out] devCnt      : devices found counter
+ * \param[out] colPending  : flag indicating whether collision are still pending
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcbPollerSlottedCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcbSlots initSlots,
+    rfalNfcbSlots endSlots,
+    rfalNfcbListenDevice* nfcbDevList,
+    uint8_t* devCnt,
+    bool* colPending);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-B TR2 code to FDT
+ *    
+ *  Converts the TR2 code as defined in Digital 1.1 Table 33 Minimum 
+ *  TR2 Coding to Frame Delay Time (FDT) in 1/Fc
+ *
+ * \param[in]  tr2Code : TR2 code as defined in Digital 1.1 Table 33
+ * 
+ * \return FDT in 1/Fc
+ *****************************************************************************
+ */
+uint32_t rfalNfcbTR2ToFDT(uint8_t tr2Code);
+
+#endif /* RFAL_NFCB_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 403 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcf.h

@@ -0,0 +1,403 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcf.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-F Poller (FeliCa PCD) device
+ *
+ *  The definitions and helpers methods provided by this module are 
+ *  aligned with NFC-F (FeliCa - JIS X6319-4)
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup NFC-F
+ * \brief RFAL NFC-F Module
+ * @{  
+ *  
+ */
+
+#ifndef RFAL_NFCF_H
+#define RFAL_NFCF_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCF_NFCID2_LEN 8U /*!< NFCID2 (FeliCa IDm) length                        */
+#define RFAL_NFCF_SENSF_RES_LEN_MIN 16U /*!< SENSF_RES minimum length                          */
+#define RFAL_NFCF_SENSF_RES_LEN_MAX 18U /*!< SENSF_RES maximum length                          */
+#define RFAL_NFCF_SENSF_RES_PAD0_LEN 2U /*!< SENSF_RES PAD0 length                             */
+#define RFAL_NFCF_SENSF_RES_PAD1_LEN 2U /*!< SENSF_RES PAD1 length                             */
+#define RFAL_NFCF_SENSF_RES_RD_LEN 2U /*!< SENSF_RES Request Data length                     */
+#define RFAL_NFCF_SENSF_RES_BYTE1 1U /*!< SENSF_RES first byte value                        */
+#define RFAL_NFCF_SENSF_SC_LEN 2U /*!< Felica SENSF_REQ System Code length               */
+#define RFAL_NFCF_SENSF_PARAMS_SC1_POS 0U /*!< System Code byte1 position in the SENSF_REQ       */
+#define RFAL_NFCF_SENSF_PARAMS_SC2_POS 1U /*!< System Code byte2 position in the SENSF_REQ       */
+#define RFAL_NFCF_SENSF_PARAMS_RC_POS 2U /*!< Request Code position in the SENSF_REQ            */
+#define RFAL_NFCF_SENSF_PARAMS_TSN_POS 3U /*!< Time Slot Number position in the SENSF_REQ        */
+#define RFAL_NFCF_POLL_MAXCARDS 16U /*!< Max number slots/cards 16                         */
+
+#define RFAL_NFCF_CMD_POS 0U /*!< Command/Response code length                      */
+#define RFAL_NFCF_CMD_LEN 1U /*!< Command/Response code length                      */
+#define RFAL_NFCF_LENGTH_LEN 1U /*!< LEN field length                                  */
+#define RFAL_NFCF_HEADER_LEN (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN) /*!< Header length*/
+
+#define RFAL_NFCF_SENSF_NFCID2_BYTE1_POS \
+    0U /*!< NFCID2 byte1 position                             */
+#define RFAL_NFCF_SENSF_NFCID2_BYTE2_POS \
+    1U /*!< NFCID2 byte2 position                             */
+
+#define RFAL_NFCF_SENSF_NFCID2_PROT_TYPE_LEN \
+    2U /*!< NFCID2 length for byte 1 and byte 2 indicating NFC-DEP or T3T support */
+#define RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP \
+    0x01U /*!< NFCID2 byte1 NFC-DEP support            Digital 1.0 Table 44 */
+#define RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP \
+    0xFEU /*!< NFCID2 byte2 NFC-DEP support            Digital 1.0 Table 44 */
+
+#define RFAL_NFCF_SYSTEMCODE \
+    0xFFFFU /*!< SENSF_RES Default System Code            Digital 1.0 6.6.1.1 */
+
+#define RFAL_NFCF_BLOCK_LEN \
+    16U /*!< NFCF T3T Block size                        T3T 1.0  4.1      */
+#define RFAL_NFCF_CHECKUPDATE_RES_ST1_POS \
+    9U /*!< Check|Update Res Status Flag 1 position    T3T 1.0  Table 8  */
+#define RFAL_NFCF_CHECKUPDATE_RES_ST2_POS \
+    10U /*!< Check|Update Res Status Flag 2 position    T3T 1.0  Table 8  */
+#define RFAL_NFCF_CHECKUPDATE_RES_NOB_POS \
+    11U /*!< Check|Update Res Number of Blocks position T3T 1.0  Table 8  */
+
+#define RFAL_NFCF_STATUS_FLAG_SUCCESS \
+    0x00U /*!< Check response Number of Blocks position   T3T 1.0  Table 11 */
+#define RFAL_NFCF_STATUS_FLAG_ERROR \
+    0xFFU /*!< Check response Number of Blocks position   T3T 1.0  Table 11 */
+
+#define RFAL_NFCF_BLOCKLISTELEM_LEN \
+    0x80U /*!< Block List Element Length bit (2|3 bytes)      T3T 1.0 5.6.1 */
+
+#define RFAL_NFCF_SERVICECODE_RDONLY \
+    0x000BU /*!< NDEF Service Code as Read-Only                 T3T 1.0 7.2.1 */
+#define RFAL_NFCF_SERVICECODE_RDWR \
+    0x0009U /*!< NDEF Service Code as Read and Write            T3T 1.0 7.2.1 */
+
+/*! NFC-F Felica command set   JIS X6319-4  9.1 */
+enum {
+    RFAL_NFCF_CMD_POLLING =
+        0x00, /*!< SENSF_REQ (Felica Poll/REQC command to identify a card )       */
+    RFAL_NFCF_CMD_POLLING_RES =
+        0x01, /*!< SENSF_RES (Felica Poll/REQC command response )                 */
+    RFAL_NFCF_CMD_REQUEST_SERVICE =
+        0x02, /*!< verify the existence of Area and Service                       */
+    RFAL_NFCF_CMD_REQUEST_RESPONSE =
+        0x04, /*!< verify the existence of a card                                 */
+    RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION =
+        0x06, /*!< read Block Data from a Service that requires no authentication */
+    RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES =
+        0x07, /*!< read Block Data response from a Service with no authentication */
+    RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION =
+        0x08, /*!< write Block Data to a Service that requires no authentication  */
+    RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES =
+        0x09, /*!< write Block Data response to a Service with no authentication  */
+    RFAL_NFCF_CMD_REQUEST_SYSTEM_CODE =
+        0x0c, /*!< acquire the System Code registered to a card                   */
+    RFAL_NFCF_CMD_AUTHENTICATION1 =
+        0x10, /*!< authenticate a card                                            */
+    RFAL_NFCF_CMD_AUTHENTICATION2 =
+        0x12, /*!< allow a card to authenticate a Reader/Writer                   */
+    RFAL_NFCF_CMD_READ =
+        0x14, /*!< read Block Data from a Service that requires authentication    */
+    RFAL_NFCF_CMD_WRITE =
+        0x16, /*!< write Block Data to a Service that requires authentication     */
+};
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*! Checks if the given NFC-F device indicates NFC-DEP support */
+#define rfalNfcfIsNfcDepSupported(dev)                                                     \
+    ((((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE1_POS] == \
+      RFAL_NFCF_SENSF_NFCID2_BYTE1_NFCDEP) &&                                              \
+     (((rfalNfcfListenDevice*)(dev))->sensfRes.NFCID2[RFAL_NFCF_SENSF_NFCID2_BYTE2_POS] == \
+      RFAL_NFCF_SENSF_NFCID2_BYTE2_NFCDEP))
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-F SENSF_RES format  Digital 1.1  8.6.2 */
+typedef struct {
+    uint8_t CMD; /*!< Command Code: 01h  */
+    uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2             */
+    uint8_t PAD0[RFAL_NFCF_SENSF_RES_PAD0_LEN]; /*!< PAD0               */
+    uint8_t PAD1[RFAL_NFCF_SENSF_RES_PAD1_LEN]; /*!< PAD1               */
+    uint8_t MRTIcheck; /*!< MRTIcheck          */
+    uint8_t MRTIupdate; /*!< MRTIupdate         */
+    uint8_t PAD2; /*!< PAD2               */
+    uint8_t RD[RFAL_NFCF_SENSF_RES_RD_LEN]; /*!< Request Data       */
+} rfalNfcfSensfRes;
+
+/*! NFC-F poller device (PCD) struct  */
+typedef struct {
+    uint8_t NFCID2[RFAL_NFCF_NFCID2_LEN]; /*!< NFCID2             */
+} rfalNfcfPollDevice;
+
+/*! NFC-F listener device (PICC) struct  */
+typedef struct {
+    uint8_t sensfResLen; /*!< SENF_RES length    */
+    rfalNfcfSensfRes sensfRes; /*!< SENF_RES           */
+} rfalNfcfListenDevice;
+
+typedef uint16_t rfalNfcfServ; /*!< NFC-F Service Code */
+
+/*! NFC-F Block List Element (2 or 3 bytes element)       T3T 1.0 5.6.1 */
+typedef struct {
+    uint8_t conf; /*!<  Access Mode | Serv Code List Order */
+    uint16_t blockNum; /*!<  Block Number                       */
+} rfalNfcfBlockListElem;
+
+/*! Check Update Service list and Block list parameter */
+typedef struct {
+    uint8_t numServ; /*!< Number of Services */
+    rfalNfcfServ* servList; /*!< Service Code List  */
+    uint8_t numBlock; /*!< Number of Blocks   */
+    rfalNfcfBlockListElem* blockList; /*!< Block Number List  */
+} rfalNfcfServBlockListParam;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize NFC-F Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFC-F Poller/RW (FeliCa PCD) including all default timings
+ * 
+ * \param[in]  bitRate      : NFC-F bitrate to be initialize (212 or 424)
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Incorrect bitrate
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerInitialize(rfalBitRate bitRate);
+
+/*! 
+ *****************************************************************************
+ *  \brief NFC-F Poller Check Presence
+ *  
+ *  This function sends a Poll/SENSF command according to NFC Activity spec
+ *  It detects if a NCF-F device is within range
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_NONE         : No error and some NFC-F device was detected
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerCheckPresence(void);
+
+/*! 
+ *****************************************************************************
+ * \brief NFC-F Poller Poll
+ * 
+ * This function sends to all PICCs in field the POLL command with the given
+ * number of slots.
+ *
+ * \param[in]  slots      : the number of slots to be performed
+ * \param[in]  sysCode    : as given in FeliCa poll command  
+ * \param[in]  reqCode    : FeliCa communication parameters
+ * \param[out] cardList   : Parameter of type rfalFeliCaPollRes which will hold the cards found
+ * \param[out] devCnt     : actual number of cards found
+ * \param[out] collisions : number of collisions encountered
+ *
+ * \warning the list cardList has to be as big as the number of slots for the Poll
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_NONE         : No error and some NFC-F device was detected
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerPoll(
+    rfalFeliCaPollSlots slots,
+    uint16_t sysCode,
+    uint8_t reqCode,
+    rfalFeliCaPollRes* cardList,
+    uint8_t* devCnt,
+    uint8_t* collisions);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-F Poller Full Collision Resolution
+ *  
+ * Performs a full Collision resolution as defined in Activity 1.1  9.3.4
+ *
+ * \param[in]  compMode    : compliance mode to be performed
+ * \param[in]  devLimit    : device limit value, and size nfcaDevList
+ * \param[out] nfcfDevList : NFC-F listener devices list
+ * \param[out] devCnt      : Devices found counter
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcfListenDevice* nfcfDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-F Poller Check/Read
+ *  
+ * It computes a Check / Read command according to T3T 1.0 and JIS X6319-4 and 
+ * sends it to PICC. If successfully, the rxBuf will contain the the number of 
+ * blocks in the first byte followed by the blocks data.
+ *
+ * \param[in]  nfcid2      : nfcid2 of the device
+ * \param[in]  servBlock   : parameter containing the list of Services and
+ *                           Blocks to be addressed by this command
+ * \param[out] rxBuf       : buffer to place check/read data 
+ * \param[in]  rxBufLen    : size of the rxBuf
+ * \param[out] rcvdLen     : length of data placed in rxBuf
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_REQUEST      : The request was executed with error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerCheck(
+    const uint8_t* nfcid2,
+    const rfalNfcfServBlockListParam* servBlock,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvdLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-F Poller Update/Write
+ *  
+ * It computes a Update / Write command according to T3T 1.0 and JIS X6319-4 and 
+ * sends it to PICC.
+ *
+ * \param[in]  nfcid2      : nfcid2 of the device
+ * \param[in]  servBlock   : parameter containing the list of Services and
+ *                           Blocks to be addressed by this command
+ * \param[in]  txBuf       : buffer where the request will be composed
+ * \param[in]  txBufLen    : size of txBuf
+ * \param[in]  blockData   : data to written on the given block(s)
+ * \param[out] rxBuf       : buffer to place check/read data 
+ * \param[in]  rxBufLen    : size of the rxBuf
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_REQUEST      : The request was executed with error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcfPollerUpdate(
+    const uint8_t* nfcid2,
+    const rfalNfcfServBlockListParam* servBlock,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    const uint8_t* blockData,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen);
+
+/*!
+ *****************************************************************************
+ * \brief NFC-F Listener is T3T Request  
+ * 
+ * This method checks if the given data is a valid T3T command (Read or Write) 
+ * and in case a valid request has been received it may output the request's NFCID2
+ * 
+ * \param[in]   buf : buffer holding Initiator's received command
+ * \param[in]   bufLen : length of received command in bytes
+ * \param[out]  nfcid2 : pointer to where the NFCID2 may be outputted, 
+ *                       nfcid2 has NFCF_SENSF_NFCID2_LEN as length
+ *                       Pass NULL if output parameter not desired 
+ * 
+ * \return true  : Valid T3T command (Read or Write) received
+ * \return false : Invalid protocol request
+ * 
+ *****************************************************************************
+ */
+bool rfalNfcfListenerIsT3TReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2);
+
+#endif /* RFAL_NFCF_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 923 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_nfcv.h

@@ -0,0 +1,923 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcv.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-V Poller (ISO15693) device
+ *
+ *  The definitions and helpers methods provided by this module 
+ *  are aligned with NFC-V Digital 2.1
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup NFC-V
+ * \brief RFAL NFC-V Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_NFCV_H
+#define RFAL_NFCV_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCV_UID_LEN 8U /*!< NFC-V UID length                                             */
+#define RFAL_NFCV_MAX_BLOCK_LEN \
+    32U /*!< Max Block size: can be of up to 256 bits  ISO 15693 2000  5  */
+#define RFAL_NFCV_BNO_LEN 1U /*!< NFC-V Block Number length                                    */
+#define RFAL_NFCV_CRC_LEN 2U /*!< NFC-V CRC length                                             */
+#define RFAL_NFCV_MAX_GEN_DATA_LEN \
+    (RFAL_NFCV_MAX_BLOCK_LEN + RFAL_NFCV_BNO_LEN + RFAL_NFCV_UID_LEN) /*!<Max data    */
+#define RFAL_NFCV_BLOCKNUM_LEN \
+    1U /*!< Block Number length on normal commands: 8 bits               */
+#define RFAL_NFCV_BLOCKNUM_EXTENDED_LEN \
+    2U /*!< Block Number length on extended commands: 16 bits            */
+#define RFAL_NFCV_PARAM_SKIP \
+    0U /*!< Skip proprietary Param Request                               */
+
+/*! NFC-V RequestFlags   ISO15693 2000 7.3.1 */
+enum {
+    RFAL_NFCV_REQ_FLAG_DEFAULT =
+        0x02U, /*!< Default Request Flags                                        */
+    RFAL_NFCV_REQ_FLAG_SUB_CARRIER =
+        0x01U, /*!< Sub Carrier flag                                             */
+    RFAL_NFCV_REQ_FLAG_DATA_RATE =
+        0x02U, /*!< Data Rate flag                                               */
+    RFAL_NFCV_REQ_FLAG_INVENTORY =
+        0x04U, /*!< Inventory flag                                               */
+    RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT =
+        0x08U, /*!< Protocol Extension flag                                      */
+    RFAL_NFCV_REQ_FLAG_SELECT =
+        0x10U, /*!< Select flag                                                  */
+    RFAL_NFCV_REQ_FLAG_ADDRESS =
+        0x20U, /*!< Address flag                                                 */
+    RFAL_NFCV_REQ_FLAG_OPTION =
+        0x40U, /*!< Option flag                                                  */
+    RFAL_NFCV_REQ_FLAG_RFU =
+        0x80U, /*!< RFU flag                                                     */
+    RFAL_NFCV_REQ_FLAG_AFI =
+        0x10U, /*!< AFI flag                                                     */
+    RFAL_NFCV_REQ_FLAG_NB_SLOTS =
+        0x20U, /*!< Number of Slots flag                                         */
+};
+
+/*! NFC-V Response Flags   ISO15693 2000 7.4.1 */
+enum {
+    RFAL_NFCV_RES_FLAG_ERROR =
+        0x01U, /*!< Error flag                                                   */
+    RFAL_NFCV_RES_FLAG_RFU1 =
+        0x02U, /*!< RFU flag                                                     */
+    RFAL_NFCV_RES_FLAG_RFU2 =
+        0x04U, /*!< RFU flag                                                     */
+    RFAL_NFCV_RES_FLAG_EXTENSION =
+        0x08U, /*!< Extension flag                                               */
+    RFAL_NFCV_RES_FLAG_RFU3 =
+        0x10U, /*!< RFU flag                                                     */
+    RFAL_NFCV_RES_FLAG_RFU4 =
+        0x20U, /*!< RFU flag                                                     */
+    RFAL_NFCV_RES_FLAG_RFU5 =
+        0x40U, /*!< RFU flag                                                     */
+    RFAL_NFCV_RES_FLAG_RFU6 =
+        0x80U /*!< RFU flag                                                     */
+};
+
+/*! NFC-V Error code  ISO15693 2000 7.4.2 */
+enum {
+    RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED =
+        0x01U, /*!< The command is not supported, code is not recognised         */
+    RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED =
+        0x02U, /*!< The command is not recognised, format error occurred         */
+    RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED =
+        0x03U, /*!< The option is not supported                                  */
+    RFAL_NFCV_ERROR_UNKNOWN =
+        0x0FU, /*!< Unknown error                                                */
+    RFAL_NFCV_ERROR_BLOCK_NOT_AVALIABLE =
+        0x10U, /*!< The specified block is not available                         */
+    RFAL_NFCV_ERROR_BLOCK_ALREDY_LOCKED =
+        0x11U, /*!< The specified block is already locked                        */
+    RFAL_NFCV_ERROR_BLOCK_LOCKED =
+        0x12U, /*!< The specified block is locked                                */
+    RFAL_NFCV_ERROR_WRITE_FAILED =
+        0x13U, /*!< The specified block was not successfully programmed          */
+    RFAL_NFCV_ERROR_BLOCK_FAILED =
+        0x14U /*!< The specified block was not successfully locked              */
+};
+
+/*! NFC-V command set   ISO15693 2000 9.1 */
+enum {
+    RFAL_NFCV_CMD_INVENTORY =
+        0x01U, /*!< INVENTORY_REQ (Inventory) command                            */
+    RFAL_NFCV_CMD_SLPV =
+        0x02U, /*!< SLPV_REQ (Stay quiet) command                                */
+    RFAL_NFCV_CMD_READ_SINGLE_BLOCK =
+        0x20U, /*!< Read single block command                                    */
+    RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK =
+        0x21U, /*!< Write single block command                                   */
+    RFAL_NFCV_CMD_LOCK_BLOCK =
+        0x22U, /*!< Lock block command                                           */
+    RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS =
+        0x23U, /*!< Read multiple blocks command                                 */
+    RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS =
+        0x24U, /*!< Write multiple blocks command                                */
+    RFAL_NFCV_CMD_SELECT =
+        0x25U, /*!< Select command                                               */
+    RFAL_NFCV_CMD_RESET_TO_READY =
+        0x26U, /*!< Reset To Ready command                                       */
+    RFAL_NFCV_CMD_GET_SYS_INFO =
+        0x2BU, /*!< Get System Information command                               */
+    RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK =
+        0x30U, /*!< Extended read single block command                           */
+    RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK =
+        0x31U, /*!< Extended write single block command                          */
+    RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK =
+        0x32U, /*!< Extended lock single block command                           */
+    RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK =
+        0x33U, /*!< Extended read multiple block command                         */
+    RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK =
+        0x34U, /*!< Extended read multiple block command                         */
+    RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO =
+        0x3BU /*!< Extended Get System Information command                      */
+};
+
+/*! ST25TV/ST25DV command set  */
+enum {
+    RFAL_NFCV_CMD_READ_CONFIGURATION =
+        0xA0U, /*!< Read configuration command                                 */
+    RFAL_NFCV_CMD_WRITE_CONFIGURATION =
+        0xA1U, /*!< Write configuration command                                */
+    RFAL_NFCV_CMD_SET_EAS =
+        0xA2U, /*!< Set EAS command                                            */
+    RFAL_NFCV_CMD_RESET_EAS =
+        0xA3U, /*!< Reset EAS command                                          */
+    RFAL_NFCV_CMD_LOCK_EAS =
+        0xA4U, /*!< Lock EAS command                                           */
+    RFAL_NFCV_CMD_ENABLE_EAS =
+        0xA5U, /*!< Enable EAS command                                         */
+    RFAL_NFCV_CMD_KILL = 0xA6U, /*!< Kill command                                               */
+    RFAL_NFCV_CMD_WRITE_EAS_ID =
+        0xA7U, /*!< Write EAS ID command                                       */
+    RFAL_NFCV_CMD_WRITE_EAS_CONFIG =
+        0xA8U, /*!< Write EAS CONFIG command                                   */
+    RFAL_NFCV_CMD_MANAGE_GPO =
+        0xA9U, /*!< Manage GPO command                                         */
+    RFAL_NFCV_CMD_WRITE_MESSAGE =
+        0xAAU, /*!< Write Message command                                      */
+    RFAL_NFCV_CMD_READ_MESSAGE_LENGTH =
+        0xABU, /*!< Read Message Length command                                */
+    RFAL_NFCV_CMD_READ_MESSAGE =
+        0xACU, /*!< Read Message command                                       */
+    RFAL_NFCV_CMD_READ_DYN_CONFIGURATION =
+        0xADU, /*!< Read Dynamic Configuration command                         */
+    RFAL_NFCV_CMD_WRITE_DYN_CONFIGURATION =
+        0xAEU, /*!< Write Dynamic Configuration command                        */
+    RFAL_NFCV_CMD_WRITE_PASSWORD =
+        0xB1U, /*!< Write Kill Password / Write Password command               */
+    RFAL_NFCV_CMD_LOCK_KILL =
+        0xB2U, /*!< Lock Kill command                                          */
+    RFAL_NFCV_CMD_PRESENT_PASSWORD =
+        0xB3U, /*!< Present Password command                                   */
+    RFAL_NFCV_CMD_GET_RANDOM_NUMBER =
+        0xB4U, /*!< Get Random Number command                                  */
+    RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK =
+        0xC0U, /*!< Fast Read single block command                             */
+    RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS =
+        0xC3U, /*!< Fast Read multiple blocks command                          */
+    RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK =
+        0xC4U, /*!< Fast Extended Read single block command                    */
+    RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS =
+        0xC5U, /*!< Fast Extended Read multiple blocks command                 */
+    RFAL_NFCV_CMD_FAST_WRITE_MESSAGE =
+        0xCAU, /*!< Fast Write Message                                         */
+    RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH =
+        0xCBU, /*!< Fast Read Message Length                                   */
+    RFAL_NFCV_CMD_FAST_READ_MESSAGE =
+        0xCCU, /*!< Fast Read Message                                          */
+    RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION =
+        0xCDU, /*!< Fast Read Dynamic configuration                            */
+    RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION =
+        0xCEU /*!< Fast Write Dynamic Configuration                           */
+};
+
+/*! ISO 15693 Get System info parameter request field ISO15693 2018 Table 94 */
+enum {
+    RFAL_NFCV_SYSINFO_DFSID =
+        0x01U, /*!< Get System info DFSID flag                                   */
+    RFAL_NFCV_SYSINFO_AFI =
+        0x02U, /*!< Get System info AFI flag                                     */
+    RFAL_NFCV_SYSINFO_MEMSIZE =
+        0x04U, /*!< Get System info MEMSIZE flag                                 */
+    RFAL_NFCV_SYSINFO_ICREF =
+        0x08U, /*!< Get System info ICREF flag                                   */
+    RFAL_NFCV_SYSINFO_MOI =
+        0x10U, /*!< Get System info MOI flag                                     */
+    RFAL_NFCV_SYSINFO_CMDLIST =
+        0x20U, /*!< Get System info CMDLIST flag                                 */
+    RFAL_NFCV_SYSINFO_CSI =
+        0x40U, /*!< Get System info CSI flag                                     */
+    RFAL_NFCV_SYSINFO_REQ_ALL =
+        0x7FU /*!< Get System info request of all parameters                    */
+};
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-V Number of slots  Digital 2.0  9.6.1 */
+typedef enum {
+    RFAL_NFCV_NUM_SLOTS_1 = 0x20, /*!< Number of slots: 1             */
+    RFAL_NFCV_NUM_SLOTS_16 = 0x00, /*!< Number of slots: 16            */
+} rfalNfcvNumSlots;
+
+/*! NFC-V INVENTORY_RES format   Digital 2.0  9.6.2 */
+typedef struct {
+    uint8_t RES_FLAG; /*!< Response Flags                 */
+    uint8_t DSFID; /*!< Data Storage Format Identifier */
+    uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< NFC-V device UID               */
+    uint8_t crc[RFAL_CRC_LEN]; /*!< CRC                            */
+} rfalNfcvInventoryRes;
+
+/*! NFC-V Generic Req format  */
+typedef struct {
+    uint8_t REQ_FLAG; /*!< Request Flags      */
+    uint8_t CMD; /*!< Command code       */
+    union { /*  PRQA S 0750 # MISRA 19.2 - Both members are of the same type, just different names.  Thus no problem can occur. */
+        uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value         */
+        uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data               */
+    } payload; /*!< Payload            */
+} rfalNfcvGenericReq;
+
+/*! NFC-V Generic Response format */
+typedef struct {
+    uint8_t RES_FLAG; /*!< Response Flags     */
+    uint8_t data[RFAL_NFCV_MAX_GEN_DATA_LEN]; /*!< Data               */
+} rfalNfcvGenericRes;
+
+/*! NFC-V listener device (VICC) struct  */
+typedef struct {
+    rfalNfcvInventoryRes InvRes; /*!< INVENTORY_RES                  */
+    bool isSleep; /*!< Device sleeping flag           */
+} rfalNfcvListenDevice;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize NFC-V Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFC-F Poller/RW (ISO15693) including all default timings 
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Incorrect bitrate
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Check Presence
+ *  
+ * This method checks if a NFC-V Listen device (VICC) is present on the field
+ * by sending an Inventory (INVENTORY_REQ) 
+ *  
+ * \param[out] invRes : If received, the INVENTORY_RES
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detectedd
+ * \return ERR_NONE         : No error, one or more device in the field
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerCheckPresence(rfalNfcvInventoryRes* invRes);
+
+/*! 
+ *****************************************************************************
+ * \brief NFC-F Poller Poll
+ * 
+ * This function sends to all VICCs in field the INVENTORY command with the 
+ * given number of slots
+ * 
+ * If more than one slot is used the following EOF need to be handled
+ * by the caller using rfalISO15693TransceiveEOFAnticollision()
+ *
+ * \param[in]  nSlots  : Number of Slots to be sent (1 or 16)
+ * \param[in]  maskLen : Number bits on the Mask value
+ * \param[in]  maskVal : location of the Mask value
+ * \param[out] invRes  : location to place the INVENTORY_RES
+ * \param[out] rcvdLen : number of bits received (without collision)
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_RF_COLLISION : Collision detected 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerInventory(
+    rfalNfcvNumSlots nSlots,
+    uint8_t maskLen,
+    const uint8_t* maskVal,
+    rfalNfcvInventoryRes* invRes,
+    uint16_t* rcvdLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Full Collision Resolution
+ *  
+ * Performs a full Collision resolution as defined in Activity 2.0   9.3.7
+ * Once done, the devCnt will indicate how many (if any) devices have 
+ * been identified and their details are contained on nfcvDevList
+ *
+ * \param[in]  compMode     : compliance mode to be performed
+ * \param[in]  devLimit     : device limit value, and size nfcaDevList
+ * \param[out] nfcvDevList  : NFC-v listener devices list
+ * \param[out] devCnt       : Devices found counter
+ *
+ * When compMode is set to ISO the function immediately goes to 16 slots improving
+ * chances to detect more than only one strong card.
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcvListenDevice* nfcvDevList,
+    uint8_t* devCnt);
+
+/*!
+ *****************************************************************************
+ * \brief  NFC-V Poller Full Collision Resolution With Sleep
+ *
+ * Performs a full Collision resolution which is different from Activity 2.0 9.3.7.
+ * The implementation uses SLPV (StayQuiet) command to make sure all cards are found.
+ * Once done, the devCnt will indicate how many (if any) devices have
+ * been identified and their details are contained on nfcvDevList
+ *
+ * \param[in]  devLimit     : device limit value, and size nfcaDevList
+ * \param[out] nfcvDevList  : NFC-v listener devices list
+ * \param[out] devCnt       : Devices found counter
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerSleepCollisionResolution(
+    uint8_t devLimit,
+    rfalNfcvListenDevice* nfcvDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Sleep
+ *  
+ * This function is used to send the SLPV_REQ (Stay Quiet) command to put the VICC 
+ * with the given UID to state QUIET so that they do not reply to more Inventory
+ * 
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to Sleep
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Select
+ *  
+ * Selects a device (VICC) by its UID 
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be Selected
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Single Block
+ *  
+ * Reads a Single Block from a device (VICC)  
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to read
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Single Block
+ *  
+ * Writes a Single Block from a device (VICC)
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be written
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to write
+ * \param[in]  wrData       : data to be written on the given block
+ * \param[in]  blockLen     : number of bytes of a block
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Multiple Blocks
+ *  
+ * Reads Multiple Blocks from a device (VICC)  
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  firstBlockNum  : first block to be read
+ * \param[in]  numOfBlocks    : number of block to read
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Multiple Blocks
+ *  
+ * Reads Multiple Blocks from a device (VICC)
+ * In order to not limit the length of the Write multiple command, a buffer
+ * must be provided where the request will be composed and then sent.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  firstBlockNum  : first block to be write
+ * \param[in]  numOfBlocks    : number of consecutive blocks to write
+ * \param[in]  txBuf          : buffer where the request will be composed
+ * \param[in]  txBufLen       : length of txBuf
+ * \param[in]  blockLen       : number of bytes of a block
+ * \param[in]  wrData         : data to be written
+ * \param[in]  wrDataLen      : length of the data do be written. Must be
+ *                              aligned with number of blocks to write and
+ *                              the size of a block
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerWriteMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t blockLen,
+    const uint8_t* wrData,
+    uint16_t wrDataLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Lock Single Block
+ *  
+ * Blocks a Single Block from a device (VICC) supporting extended commands
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to be locked
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Lock Single Block
+ *  
+ * Blocks a Single Block from a device (VICC) supporting extended commands
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to be locked (16 bits)
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode
+    rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Read Single Block
+ *  
+ * Reads a Single Block from a device (VICC) supporting extended commands
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to read (16 bits)
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Write Single Block
+ *  
+ * Writes a Single Block from a device (VICC) supporting extended commands
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device
+ *                             if UID is provided Addressed mode will be used
+ * \param[in]  blockNum     : Number of the block to write (16 bits)
+ * \param[in]  wrData       : data to be written on the given block
+ * \param[in]  blockLen     : number of bytes of a block
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Read Multiple Blocks
+ *  
+ * Reads Multiple Blocks from a device (VICC) supporting extended commands  
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  firstBlockNum  : first block to be read (16 bits)
+ * \param[in]  numOfBlocks    : number of consecutive blocks to read (16 bits)
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Extended Write Multiple Blocks
+ *  
+ * Writes Multiple Blocks from a device (VICC) supporting extended commands 
+ * In order to not limit the length of the Write multiple command, a buffer
+ * must be provided where the request will be composed and then sent.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  firstBlockNum  : first block to be write (16 bits)
+ * \param[in]  numOfBlocks    : number of consecutive blocks to write (16 bits)
+ * \param[in]  txBuf          : buffer where the request will be composed
+ * \param[in]  txBufLen       : length of txBuf
+ * \param[in]  blockLen       : number of bytes of a block
+ * \param[in]  wrData         : data to be written
+ * \param[in]  wrDataLen      : length of the data do be written. Must be
+ *                              aligned with number of blocks to write and
+ *                              the size of a block
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t blockLen,
+    const uint8_t* wrData,
+    uint16_t wrDataLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Get System Information
+ *  
+ * Sends Get System Information command  
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerGetSystemInformation(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Extended Get System Information
+ *  
+ * Sends Extended Get System Information command  
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  requestField   : Get System info parameter request field
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t requestField,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Transceive Request
+ *  
+ * Performs a generic transceive with an ISO15693 tag
+ *
+ * \param[in]  cmd            : NFC-V command
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  param          : Prepend parameter on certain proprietary requests
+ *                              For default commands skip: RFAL_NFCV_PARAM_SKIP
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if UID is provided Addressed mode will be used
+ * \param[in]  data           : command parameters append after UID
+ * \param[in]  dataLen        : command parameters Len
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalNfcvPollerTransceiveReq(
+    uint8_t cmd,
+    uint8_t flags,
+    uint8_t param,
+    const uint8_t* uid,
+    const uint8_t* data,
+    uint16_t dataLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+#endif /* RFAL_NFCV_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 1724 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_rf.h

@@ -0,0 +1,1724 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_rf.h
+ *
+ *  \author Gustavo Patricio 
+ *
+ *  \brief RF Abstraction Layer (RFAL)
+ *  
+ *  RFAL (RF Abstraction Layer) provides several functionalities required to 
+ *  perform RF/NFC communications. <br>The RFAL encapsulates the different 
+ *  RF ICs (ST25R3911, ST25R391x, etc) into a common and easy to use interface.
+ *  
+ *  It provides interfaces to configure the RF IC, set/get timings, modes, bit rates,
+ *  specific handlings, execute listen mode, etc. 
+ *  
+ *  Furthermore it provides a common interface to perform a Transceive operations.
+ *  The Transceive can be executed in a blocking or non blocking way.<br>
+ *  Additionally few specific Transceive methods are available to cope with the
+ *  specifics of these particular operations.
+ *  
+ *  The most common interfaces are:
+ *    <br>&nbsp; rfalInitialize()
+ *    <br>&nbsp; rfalSetFDTPoll()
+ *    <br>&nbsp; rfalSetFDTListen()
+ *    <br>&nbsp; rfalSetGT()
+ *    <br>&nbsp; rfalSetBitRate()
+ *    <br>&nbsp; rfalSetMode()
+ *    <br>&nbsp; rfalFieldOnAndStartGT()
+ *    <br>&nbsp; rfalFieldOff()
+ *    <br>&nbsp; rfalStartTransceive()
+ *    <br>&nbsp; rfalGetTransceiveStatus()
+ *    <br>&nbsp; rfalTransceiveBlockingTxRx()
+ *    
+ *  An usage example is provided here: \ref exampleRfalPoller.c
+ *  \example exampleRfalPoller.c
+ *    
+ * \addtogroup RFAL
+ * @{
+ * 
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ * 
+ * \addtogroup RF
+ * \brief RFAL RF Abstraction Layer
+ * @{
+ *  
+ */
+
+#ifndef RFAL_RF_H
+#define RFAL_RF_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../platform.h"
+#include "../st_errno.h"
+#include "../source/st25r3916/rfal_features.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+#define RFAL_VERSION 0x020200U /*!< RFAL Current Version: v2.2.0                      */
+
+#define RFAL_FWT_NONE 0xFFFFFFFFU /*!< Disabled FWT: Wait forever for a response         */
+#define RFAL_GT_NONE RFAL_TIMING_NONE /*!< Disabled GT: No GT will be applied after Field On */
+
+#define RFAL_TIMING_NONE 0x00U /*!< Timing disabled | Don't apply                     */
+
+#define RFAL_1FC_IN_4096FC \
+    (uint32_t)4096U /*!< Number of 1/fc cycles in one 4096/fc              */
+#define RFAL_1FC_IN_512FC (uint32_t)512U /*!< Number of 1/fc cycles in one 512/fc               */
+#define RFAL_1FC_IN_64FC (uint32_t)64U /*!< Number of 1/fc cycles in one 64/fc                */
+#define RFAL_1FC_IN_8FC (uint32_t)8U /*!< Number of 1/fc cycles in one 8/fc                 */
+#define RFAL_US_IN_MS (uint32_t)1000U /*!< Number of us in one ms                            */
+#define RFAL_1MS_IN_1FC (uint32_t)13560U /*!< Number of 1/fc cycles in 1ms                      */
+#define RFAL_BITS_IN_BYTE (uint16_t)8U /*!< Number of bits in one byte                        */
+
+#define RFAL_CRC_LEN 2U /*!< RF CRC LEN                                        */
+
+/*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */
+#define RFAL_TXRX_FLAGS_DEFAULT                                                      \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
+     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |       \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
+     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+#define RFAL_TXRX_FLAGS_RAW                                                            \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
+     (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON |         \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE |   \
+     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
+
+#define RFAL_LM_MASK_NFCA \
+    ((uint32_t)1U         \
+     << (uint8_t)RFAL_MODE_LISTEN_NFCA) /*!< Bitmask for Listen Mode enabling NFCA    */
+#define RFAL_LM_MASK_NFCB \
+    ((uint32_t)1U         \
+     << (uint8_t)RFAL_MODE_LISTEN_NFCB) /*!< Bitmask for Listen Mode enabling NFCB    */
+#define RFAL_LM_MASK_NFCF \
+    ((uint32_t)1U         \
+     << (uint8_t)RFAL_MODE_LISTEN_NFCF) /*!< Bitmask for Listen Mode enabling NFCF    */
+#define RFAL_LM_MASK_ACTIVE_P2P \
+    ((uint32_t)1U               \
+     << (uint8_t)RFAL_MODE_LISTEN_ACTIVE_P2P) /*!< Bitmask for Listen Mode enabling AP2P    */
+
+#define RFAL_LM_SENS_RES_LEN 2U /*!< NFC-A SENS_RES (ATQA) length                      */
+#define RFAL_LM_SENSB_RES_LEN 13U /*!< NFC-B SENSB_RES (ATQB) length                     */
+#define RFAL_LM_SENSF_RES_LEN 19U /*!< NFC-F SENSF_RES  length                           */
+#define RFAL_LM_SENSF_SC_LEN 2U /*!< NFC-F System Code length                          */
+
+#define RFAL_NFCID3_LEN 10U /*!< NFCID3 length                                     */
+#define RFAL_NFCID2_LEN 8U /*!< NFCID2 length                                     */
+#define RFAL_NFCID1_TRIPLE_LEN 10U /*!< NFCID1 length                                     */
+#define RFAL_NFCID1_DOUBLE_LEN 7U /*!< NFCID1 length                                     */
+#define RFAL_NFCID1_SINGLE_LEN 4U /*!< NFCID1 length                                     */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*! Returns the maximum supported bit rate for RW mode. Caller must check if mode is supported before, as even if mode is not supported will return the min  */
+#define rfalGetMaxBrRW()                             \
+    (((RFAL_SUPPORT_BR_RW_6780) ?                    \
+          RFAL_BR_6780 :                             \
+          ((RFAL_SUPPORT_BR_RW_3390) ?               \
+               RFAL_BR_3390 :                        \
+               ((RFAL_SUPPORT_BR_RW_1695) ?          \
+                    RFAL_BR_1695 :                   \
+                    ((RFAL_SUPPORT_BR_RW_848) ?      \
+                         RFAL_BR_848 :               \
+                         ((RFAL_SUPPORT_BR_RW_424) ? \
+                              RFAL_BR_424 :          \
+                              ((RFAL_SUPPORT_BR_RW_212) ? RFAL_BR_212 : RFAL_BR_106)))))))
+
+/*! Returns the maximum supported bit rate for AP2P mode. Caller must check if mode is supported before, as even if mode is not supported will return the min  */
+#define rfalGetMaxBrAP2P()              \
+    (((RFAL_SUPPORT_BR_AP2P_848) ?      \
+          RFAL_BR_848 :                 \
+          ((RFAL_SUPPORT_BR_AP2P_424) ? \
+               RFAL_BR_424 :            \
+               ((RFAL_SUPPORT_BR_AP2P_212) ? RFAL_BR_212 : RFAL_BR_106))))
+
+/*! Returns the maximum supported bit rate for CE-A mode. Caller must check if mode is supported before, as even if mode is not supported will return the min  */
+#define rfalGetMaxBrCEA()               \
+    (((RFAL_SUPPORT_BR_CE_A_848) ?      \
+          RFAL_BR_848 :                 \
+          ((RFAL_SUPPORT_BR_CE_A_424) ? \
+               RFAL_BR_424 :            \
+               ((RFAL_SUPPORT_BR_CE_A_212) ? RFAL_BR_212 : RFAL_BR_106))))
+
+/*! Returns the maximum supported bit rate for CE-B mode. Caller must check if mode is supported before, as even if mode is not supported will return the min  */
+#define rfalGetMaxBrCEB()               \
+    (((RFAL_SUPPORT_BR_CE_B_848) ?      \
+          RFAL_BR_848 :                 \
+          ((RFAL_SUPPORT_BR_CE_B_424) ? \
+               RFAL_BR_424 :            \
+               ((RFAL_SUPPORT_BR_CE_B_212) ? RFAL_BR_212 : RFAL_BR_106))))
+
+/*! Returns the maximum supported bit rate for CE-F mode. Caller must check if mode is supported before, as even if mode is not supported will return the min  */
+#define rfalGetMaxBrCEF() (((RFAL_SUPPORT_BR_CE_F_424) ? RFAL_BR_424 : RFAL_BR_212))
+
+#define rfalIsModeActiveComm(md)            \
+    (((md) == RFAL_MODE_POLL_ACTIVE_P2P) || \
+     ((md) == RFAL_MODE_LISTEN_ACTIVE_P2P)) /*!< Checks if mode md is Active Communication  */
+#define rfalIsModePassiveComm(md) \
+    (!rfalIsModeActiveComm(md)) /*!< Checks if mode md is Passive Communication */
+#define rfalIsModePassiveListen(md)                                        \
+    (((md) == RFAL_MODE_LISTEN_NFCA) || ((md) == RFAL_MODE_LISTEN_NFCB) || \
+     ((md) == RFAL_MODE_LISTEN_NFCF)) /*!< Checks if mode md is Passive Listen        */
+#define rfalIsModePassivePoll(md) \
+    (rfalIsModePassiveComm(md) && \
+     !rfalIsModePassiveListen(md)) /*!< Checks if mode md is Passive Poll          */
+
+#define rfalConv1fcTo8fc(t) \
+    (uint32_t)((uint32_t)(t) / RFAL_1FC_IN_8FC) /*!< Converts the given t from 1/fc to 8/fc     */
+#define rfalConv8fcTo1fc(t) \
+    (uint32_t)((uint32_t)(t) * RFAL_1FC_IN_8FC) /*!< Converts the given t from 8/fc to 1/fc     */
+
+#define rfalConv1fcTo64fc(t) \
+    (uint32_t)((uint32_t)(t) / RFAL_1FC_IN_64FC) /*!< Converts the given t from 1/fc  to 64/fc   */
+#define rfalConv64fcTo1fc(t) \
+    (uint32_t)((uint32_t)(t) * RFAL_1FC_IN_64FC) /*!< Converts the given t from 64/fc to 1/fc    */
+
+#define rfalConv1fcTo512fc(t) \
+    (uint32_t)(               \
+        (uint32_t)(t) / RFAL_1FC_IN_512FC) /*!< Converts the given t from 1/fc  to 512/fc  */
+#define rfalConv512fcTo1fc(t) \
+    (uint32_t)(               \
+        (uint32_t)(t) * RFAL_1FC_IN_512FC) /*!< Converts the given t from 512/fc to 1/fc   */
+
+#define rfalConv1fcTo4096fc(t) \
+    (uint32_t)(                \
+        (uint32_t)(t) / RFAL_1FC_IN_4096FC) /*!< Converts the given t from 1/fc to 4096/fc  */
+#define rfalConv4096fcTo1fc(t) \
+    (uint32_t)(                \
+        (uint32_t)(t) * RFAL_1FC_IN_4096FC) /*!< Converts the given t from 4096/fc to 1/fc  */
+
+#define rfalConv1fcToMs(t) \
+    (uint32_t)((uint32_t)(t) / RFAL_1MS_IN_1FC) /*!< Converts the given t from 1/fc to ms       */
+#define rfalConvMsTo1fc(t) \
+    (uint32_t)((uint32_t)(t) * RFAL_1MS_IN_1FC) /*!< Converts the given t from ms to 1/fc       */
+
+#define rfalConv1fcToUs(t)                \
+    (uint32_t)(                           \
+        ((uint32_t)(t) * RFAL_US_IN_MS) / \
+        RFAL_1MS_IN_1FC) /*!< Converts the given t from 1/fc to us       */
+#define rfalConvUsTo1fc(t)                  \
+    (uint32_t)(                             \
+        ((uint32_t)(t) * RFAL_1MS_IN_1FC) / \
+        RFAL_US_IN_MS) /*!< Converts the given t from us to 1/fc       */
+
+#define rfalConv64fcToMs(t) \
+    (uint32_t)(             \
+        (uint32_t)(t) /     \
+        (RFAL_1MS_IN_1FC / RFAL_1FC_IN_64FC)) /*!< Converts the given t from 64/fc to ms      */
+#define rfalConvMsTo64fc(t) \
+    (uint32_t)(             \
+        (uint32_t)(t) *     \
+        (RFAL_1MS_IN_1FC / RFAL_1FC_IN_64FC)) /*!< Converts the given t from ms to 64/fc      */
+
+#define rfalConvBitsToBytes(n)                       \
+    (uint16_t)(                                      \
+        ((uint16_t)(n) + (RFAL_BITS_IN_BYTE - 1U)) / \
+        (RFAL_BITS_IN_BYTE)) /*!< Converts the given n from bits to bytes    */
+#define rfalConvBytesToBits(n) \
+    (uint32_t)(                \
+        (uint32_t)(n) * (RFAL_BITS_IN_BYTE)) /*!< Converts the given n from bytes to bits    */
+
+/*! Computes a Transceive context \a ctx with default flags and the lengths 
+ * in bytes with the given arguments
+ *    \a ctx   : Transceive context to be assigned  
+ *    \a tB    : txBuf the pointer to the buffer to be sent
+ *    \a tBL   : txBuf length in bytes
+ *    \a rB    : rxBuf the pointer to the buffer to place the received frame
+ *    \a rBL   : rxBuf length in bytes
+ *    \a rBL   : rxBuf length in bytes
+ *    \a t     : FWT to be used on this transceive in 1/fc
+ */
+#define rfalCreateByteTxRxContext(ctx, tB, tBL, rB, rBL, rdL, t) \
+    (ctx).txBuf = (uint8_t*)(tB);                                \
+    (ctx).txBufLen = (uint16_t)rfalConvBytesToBits(tBL);         \
+    (ctx).rxBuf = (uint8_t*)(rB);                                \
+    (ctx).rxBufLen = (uint16_t)rfalConvBytesToBits(rBL);         \
+    (ctx).rxRcvdLen = (uint16_t*)(rdL);                          \
+    (ctx).flags = (uint32_t)RFAL_TXRX_FLAGS_DEFAULT;             \
+    (ctx).fwt = (uint32_t)(t);
+
+/*! Computes a Transceive context \a ctx using lengths in bytes 
+ * with the given flags and arguments
+ *    \a ctx   : Transceive context to be assigned  
+ *    \a tB    : txBuf the pointer to the buffer to be sent
+ *    \a tBL   : txBuf length in bytes
+ *    \a rB    : rxBuf the pointer to the buffer to place the received frame
+ *    \a rBL   : rxBuf length in bytes
+ *    \a rBL   : rxBuf length in bytes
+ *    \a t     : FWT to be used on this transceive in 1/fc
+ */
+#define rfalCreateByteFlagsTxRxContext(ctx, tB, tBL, rB, rBL, rdL, fl, t) \
+    (ctx).txBuf = (uint8_t*)(tB);                                         \
+    (ctx).txBufLen = (uint16_t)rfalConvBytesToBits(tBL);                  \
+    (ctx).rxBuf = (uint8_t*)(rB);                                         \
+    (ctx).rxBufLen = (uint16_t)rfalConvBytesToBits(rBL);                  \
+    (ctx).rxRcvdLen = (uint16_t*)(rdL);                                   \
+    (ctx).flags = (uint32_t)(fl);                                         \
+    (ctx).fwt = (uint32_t)(t);
+
+#define rfalLogE(...) \
+    platformLog(__VA_ARGS__) /*!< Macro for the error log method                  */
+#define rfalLogW(...) \
+    platformLog(__VA_ARGS__) /*!< Macro for the warning log method                */
+#define rfalLogI(...) \
+    platformLog(__VA_ARGS__) /*!< Macro for the info log method                   */
+#define rfalLogD(...) \
+    platformLog(__VA_ARGS__) /*!< Macro for the debug log method                  */
+
+/*
+******************************************************************************
+* GLOBAL ENUMS
+******************************************************************************
+*/
+
+/* RFAL Guard Time (GT) default values                 */
+#define RFAL_GT_NFCA \
+    rfalConvMsTo1fc( \
+        5U) /*!< GTA  Digital 2.0  6.10.4.1 & B.2                                                                 */
+#define RFAL_GT_NFCB \
+    rfalConvMsTo1fc( \
+        5U) /*!< GTB  Digital 2.0  7.9.4.1  & B.3                                                                 */
+#define RFAL_GT_NFCF \
+    rfalConvMsTo1fc( \
+        20U) /*!< GTF  Digital 2.0  8.7.4.1  & B.4                                                                 */
+#define RFAL_GT_NFCV \
+    rfalConvMsTo1fc( \
+        5U) /*!< GTV  Digital 2.0  9.7.5.1  & B.5                                                                 */
+#define RFAL_GT_PICOPASS \
+    rfalConvMsTo1fc(     \
+        1U) /*!< GT Picopass                                                                                      */
+#define RFAL_GT_AP2P \
+    rfalConvMsTo1fc( \
+        5U) /*!< TIRFG  Ecma 340  11.1.1                                                                          */
+#define RFAL_GT_AP2P_ADJUSTED \
+    rfalConvMsTo1fc(          \
+        5U +                  \
+        25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2)                    */
+
+/* RFAL Frame Delay Time (FDT) Listen default values   */
+#define RFAL_FDT_LISTEN_NFCA_POLLER \
+    1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1  6.10 ;  EMV CCP Spec Book D v2.01  4.8.1.3   */
+#define RFAL_FDT_LISTEN_NFCB_POLLER \
+    1008U /*!< TR0B,MIN         Digital 1.1  7.1.3 & A.3  ; EMV CCP Spec Book D v2.01  4.8.1.3 & Table A.5                     */
+#define RFAL_FDT_LISTEN_NFCF_POLLER \
+    2672U /*!< TR0F,LISTEN,MIN  Digital 1.1  8.7.1.1 & A.4                                                                     */
+#define RFAL_FDT_LISTEN_NFCV_POLLER \
+    4310U /*!< FDTV,LISTEN,MIN  t1 min       Digital 2.1  B.5  ;  ISO15693-3 2009  9.1                                          */
+#define RFAL_FDT_LISTEN_PICOPASS_POLLER \
+    3400U /*!< ISO15693 t1 min - observed adjustment                                                                           */
+#define RFAL_FDT_LISTEN_AP2P_POLLER \
+    64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance                               */
+#define RFAL_FDT_LISTEN_NFCA_LISTENER \
+    1172U /*!< FDTA,LISTEN,MIN  Digital 1.1  6.10                                                                              */
+#define RFAL_FDT_LISTEN_NFCB_LISTENER \
+    1024U /*!< TR0B,MIN         Digital 1.1  7.1.3 & A.3  ;  EMV CCP Spec Book D v2.01  4.8.1.3 & Table A.5                    */
+#define RFAL_FDT_LISTEN_NFCF_LISTENER \
+    2688U /*!< TR0F,LISTEN,MIN  Digital 2.1  8.7.1.1 & B.4                                                                     */
+#define RFAL_FDT_LISTEN_AP2P_LISTENER \
+    64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance                                    */
+
+/*  RFAL Frame Delay Time (FDT) Poll default values    */
+#define RFAL_FDT_POLL_NFCA_POLLER \
+    6780U /*!< FDTA,POLL,MIN   Digital 1.1  6.10.3.1 & A.2                                                                     */
+#define RFAL_FDT_POLL_NFCA_T1T_POLLER \
+    384U /*!< RRDDT1T,MIN,B1  Digital 1.1  10.7.1 & A.5                                                                       */
+#define RFAL_FDT_POLL_NFCB_POLLER \
+    6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3  ;  EMVCo 3.0 FDTB,PCD,MIN  Table A.5                  */
+#define RFAL_FDT_POLL_NFCF_POLLER \
+    6800U /*!< FDTF,POLL,MIN   Digital 2.1  8.7.3 & B.4                                                                        */
+#define RFAL_FDT_POLL_NFCV_POLLER \
+    4192U /*!< FDTV,POLL  Digital 2.1  9.7.3.1  & B.5                                                                          */
+#define RFAL_FDT_POLL_PICOPASS_POLLER \
+    1790U /*!< FDT Max                                                                                                         */
+#define RFAL_FDT_POLL_AP2P_POLLER \
+    0U /*!< FDT AP2P No actual FDTPoll exists as fields switch and collision avoidance                                      */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! RFAL modes    */
+typedef enum {
+    RFAL_MODE_NONE = 0, /*!< No mode selected/defined                                         */
+    RFAL_MODE_POLL_NFCA =
+        1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD)                 */
+    RFAL_MODE_POLL_NFCA_T1T =
+        2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD)                 */
+    RFAL_MODE_POLL_NFCB =
+        3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD)                 */
+    RFAL_MODE_POLL_B_PRIME =
+        4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD)                 */
+    RFAL_MODE_POLL_B_CTS =
+        5, /*!< Mode to perform as CTS Poller (PCD)                              */
+    RFAL_MODE_POLL_NFCF =
+        6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD)                    */
+    RFAL_MODE_POLL_NFCV =
+        7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD)                  */
+    RFAL_MODE_POLL_PICOPASS =
+        8, /*!< Mode to perform as PicoPass / iClass Poller (PCD)                */
+    RFAL_MODE_POLL_ACTIVE_P2P =
+        9, /*!< Mode to perform as Active P2P (ISO18092) Initiator               */
+    RFAL_MODE_LISTEN_NFCA =
+        10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC)              */
+    RFAL_MODE_LISTEN_NFCB =
+        11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC)              */
+    RFAL_MODE_LISTEN_NFCF =
+        12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC)               */
+    RFAL_MODE_LISTEN_ACTIVE_P2P =
+        13 /*!< Mode to perform as Active P2P (ISO18092) Target                  */
+} rfalMode;
+
+/*! RFAL Bit rates    */
+typedef enum {
+    RFAL_BR_106 = 0, /*!< Bit Rate 106 kbit/s (fc/128)                                     */
+    RFAL_BR_212 = 1, /*!< Bit Rate 212 kbit/s (fc/64)                                      */
+    RFAL_BR_424 = 2, /*!< Bit Rate 424 kbit/s (fc/32)                                      */
+    RFAL_BR_848 = 3, /*!< Bit Rate 848 kbit/s (fc/16)                                      */
+    RFAL_BR_1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8)                                      */
+    RFAL_BR_3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4)                                      */
+    RFAL_BR_6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2)                                      */
+    RFAL_BR_13560 = 7, /*!< Bit Rate 13560 kbit/s (fc)                                       */
+    RFAL_BR_52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD               */
+    RFAL_BR_26p48 = 0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4   */
+    RFAL_BR_1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256             */
+    RFAL_BR_KEEP = 0xFF /*!< Value indicating to keep the same previous bit rate              */
+} rfalBitRate;
+
+/*! RFAL Compliance modes for upper modules  */
+typedef enum {
+    RFAL_COMPLIANCE_MODE_NFC, /*!< Perform with NFC Forum 1.1 compliance                            */
+    RFAL_COMPLIANCE_MODE_EMV, /*!< Perform with EMVCo compliance                                    */
+    RFAL_COMPLIANCE_MODE_ISO /*!< Perform with ISO10373 compliance                                 */
+} rfalComplianceMode;
+
+/*! RFAL main states flags    */
+typedef enum {
+    RFAL_STATE_IDLE = 0,
+    RFAL_STATE_INIT = 1,
+    RFAL_STATE_MODE_SET = 2,
+
+    RFAL_STATE_TXRX = 3,
+    RFAL_STATE_LM = 4,
+    RFAL_STATE_WUM = 5
+
+} rfalState;
+
+/*! RFAL transceive states    */
+typedef enum {
+    RFAL_TXRX_STATE_IDLE = 0,
+    RFAL_TXRX_STATE_INIT = 1,
+    RFAL_TXRX_STATE_START = 2,
+
+    RFAL_TXRX_STATE_TX_IDLE = 11,
+    RFAL_TXRX_STATE_TX_WAIT_GT = 12,
+    RFAL_TXRX_STATE_TX_WAIT_FDT = 13,
+    RFAL_TXRX_STATE_TX_TRANSMIT = 14,
+    RFAL_TXRX_STATE_TX_WAIT_WL = 15,
+    RFAL_TXRX_STATE_TX_RELOAD_FIFO = 16,
+    RFAL_TXRX_STATE_TX_WAIT_TXE = 17,
+    RFAL_TXRX_STATE_TX_DONE = 18,
+    RFAL_TXRX_STATE_TX_FAIL = 19,
+
+    RFAL_TXRX_STATE_RX_IDLE = 81,
+    RFAL_TXRX_STATE_RX_WAIT_EON = 82,
+    RFAL_TXRX_STATE_RX_WAIT_RXS = 83,
+    RFAL_TXRX_STATE_RX_WAIT_RXE = 84,
+    RFAL_TXRX_STATE_RX_READ_FIFO = 85,
+    RFAL_TXRX_STATE_RX_ERR_CHECK = 86,
+    RFAL_TXRX_STATE_RX_READ_DATA = 87,
+    RFAL_TXRX_STATE_RX_WAIT_EOF = 88,
+    RFAL_TXRX_STATE_RX_DONE = 89,
+    RFAL_TXRX_STATE_RX_FAIL = 90,
+
+} rfalTransceiveState;
+
+/*! RFAL transceive flags                                                                                                                    */
+enum {
+    RFAL_TXRX_FLAGS_CRC_TX_AUTO =
+        (0U
+         << 0), /*!< CRC will be generated automatic upon transmission                                     */
+    RFAL_TXRX_FLAGS_CRC_TX_MANUAL =
+        (1U
+         << 0), /*!< CRC was calculated manually, included in txBuffer                                     */
+    RFAL_TXRX_FLAGS_CRC_RX_KEEP =
+        (1U
+         << 1), /*!< Upon Reception keep the CRC in rxBuffer (reflected on rcvd length)                    */
+    RFAL_TXRX_FLAGS_CRC_RX_REMV =
+        (0U
+         << 1), /*!< Enable CRC check and remove the CRC from rxBuffer                                     */
+    RFAL_TXRX_FLAGS_NFCIP1_ON =
+        (1U
+         << 2), /*!< Enable NFCIP1 mode: Add SB(F0) and LEN bytes during Tx and skip SB(F0) byte during Rx */
+    RFAL_TXRX_FLAGS_NFCIP1_OFF =
+        (0U
+         << 2), /*!< Disable NFCIP1 mode: do not append protocol bytes while Tx nor skip while Rx          */
+    RFAL_TXRX_FLAGS_AGC_OFF =
+        (1U
+         << 3), /*!< Disable Automatic Gain Control, improving multiple devices collision detection        */
+    RFAL_TXRX_FLAGS_AGC_ON =
+        (0U
+         << 3), /*!< Enable Automatic Gain Control, improving single device reception                      */
+    RFAL_TXRX_FLAGS_PAR_RX_KEEP =
+        (1U
+         << 4), /*!< Disable Parity and CRC check and keep the Parity and CRC bits in the received buffer  */
+    RFAL_TXRX_FLAGS_PAR_RX_REMV =
+        (0U
+         << 0), /*!< Enable Parity check and remove the parity bits from the received buffer               */
+    RFAL_TXRX_FLAGS_PAR_TX_NONE =
+        (1U
+         << 5), /*!< Disable automatic Parity generation (ISO14443A) and use the one provided in the buffer*/
+    RFAL_TXRX_FLAGS_PAR_TX_AUTO =
+        (0U
+         << 5), /*!< Enable automatic Parity generation (ISO14443A)                                        */
+    RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL =
+        (1U
+         << 6), /*!< Disable automatic adaption of flag byte (ISO15693) according to current comm params   */
+    RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO =
+        (0U
+         << 6), /*!< Enable automatic adaption of flag byte (ISO115693) according to current comm params   */
+};
+
+/*! RFAL error handling                                                                                                                      */
+typedef enum {
+    RFAL_ERRORHANDLING_NONE =
+        0, /*!< No special error handling will be performed                                           */
+    RFAL_ERRORHANDLING_NFC =
+        1, /*!< Error handling set to perform as NFC compliant device                                 */
+    RFAL_ERRORHANDLING_EMVCO =
+        2 /*!< Error handling set to perform as EMVCo compliant device                               */
+} rfalEHandling;
+
+/*! Struct that holds all context to be used on a Transceive                                                */
+typedef struct {
+    uint8_t* txBuf; /*!< (In)  Buffer where outgoing message is located       */
+    uint16_t txBufLen; /*!< (In)  Length of the outgoing message in bits         */
+
+    uint8_t* rxBuf; /*!< (Out) Buffer where incoming message will be placed   */
+    uint16_t rxBufLen; /*!< (In)  Maximum length of the incoming message in bits */
+    uint16_t* rxRcvdLen; /*!< (Out) Actual received length in bits                 */
+
+    uint32_t flags; /*!< (In)  TransceiveFlags indication special handling    */
+    uint32_t fwt; /*!< (In)  Frame Waiting Time in 1/fc                     */
+} rfalTransceiveContext;
+
+/*! System callback to indicate an event that requires a system reRun        */
+typedef void (*rfalUpperLayerCallback)(void);
+
+/*! Callback to be executed before a Transceive                              */
+typedef void (*rfalPreTxRxCallback)(void* context);
+
+/*! Callback to be executed after a Transceive                               */
+typedef void (*rfalPostTxRxCallback)(void* context);
+
+/** Callback to be executed on each RFAL state change */
+typedef void (*RfalStateChangedCallback)(void* context);
+
+/*******************************************************************************/
+/*  ISO14443A                                                                  */
+/*******************************************************************************/
+
+/*! RFAL ISO 14443A Short Frame Command */
+typedef enum {
+    RFAL_14443A_SHORTFRAME_CMD_WUPA = 0x52, /*!< ISO14443A WUPA / NFC-A ALL_REQ  */
+    RFAL_14443A_SHORTFRAME_CMD_REQA = 0x26 /*!< ISO14443A REQA / NFC-A SENS_REQ */
+} rfal14443AShortFrameCmd;
+
+/*******************************************************************************/
+
+/*******************************************************************************/
+/*  FeliCa                                                                     */
+/*******************************************************************************/
+
+#define RFAL_FELICA_LEN_LEN \
+    1U /*!< FeliCa LEN byte length                                              */
+#define RFAL_FELICA_POLL_REQ_LEN          \
+    (RFAL_FELICA_LEN_LEN + 1U + 2U + 1U + \
+     1U) /*!< FeliCa Poll Request length (LEN + CMD + SC + RC + TSN)              */
+#define RFAL_FELICA_POLL_RES_LEN          \
+    (RFAL_FELICA_LEN_LEN + 1U + 8U + 8U + \
+     2U) /*!< Maximum FeliCa Poll Response length (LEN + CMD + NFCID2 + PAD + RD) */
+#define RFAL_FELICA_POLL_MAX_SLOTS \
+    16U /*!< Maximum number of slots (TSN) on FeliCa Poll                        */
+
+/*! NFC-F RC (Request Code) codes  NFC Forum Digital 1.1 Table 42                                                                                                        */
+enum {
+    RFAL_FELICA_POLL_RC_NO_REQUEST =
+        0x00, /*!< RC: No System Code information requested                            */
+    RFAL_FELICA_POLL_RC_SYSTEM_CODE =
+        0x01, /*!< RC: System Code information requested                               */
+    RFAL_FELICA_POLL_RC_COM_PERFORMANCE =
+        0x02 /*!< RC: Advanced protocol features supported                            */
+};
+
+/*! NFC-F TSN (Time Slot Number) codes  NFC Forum Digital 1.1 Table 43   */
+typedef enum {
+    RFAL_FELICA_1_SLOT = 0, /*!< TSN with number of Time Slots: 1  */
+    RFAL_FELICA_2_SLOTS = 1, /*!< TSN with number of Time Slots: 2  */
+    RFAL_FELICA_4_SLOTS = 3, /*!< TSN with number of Time Slots: 4  */
+    RFAL_FELICA_8_SLOTS = 7, /*!< TSN with number of Time Slots: 8  */
+    RFAL_FELICA_16_SLOTS = 15 /*!< TSN with number of Time Slots: 16 */
+} rfalFeliCaPollSlots;
+
+/*! NFCF Poll Response  NFC Forum Digital 1.1 Table 44 */
+typedef uint8_t rfalFeliCaPollRes[RFAL_FELICA_POLL_RES_LEN];
+
+/*******************************************************************************/
+
+/*******************************************************************************/
+/*  Listen Mode                                                                */
+/*******************************************************************************/
+
+/*! RFAL Listen Mode NFCID Length */
+typedef enum {
+    RFAL_LM_NFCID_LEN_04 = RFAL_NFCID1_SINGLE_LEN, /*!< Listen mode indicates  4 byte NFCID */
+    RFAL_LM_NFCID_LEN_07 = RFAL_NFCID1_DOUBLE_LEN, /*!< Listen mode indicates  7 byte NFCID */
+    RFAL_LM_NFCID_LEN_10 = RFAL_NFCID1_TRIPLE_LEN, /*!< Listen mode indicates 10 byte NFCID */
+} rfalLmNfcidLen;
+
+/*! RFAL Listen Mode States */
+typedef enum {
+    RFAL_LM_STATE_NOT_INIT = 0x00, /*!< Not Initialized state                       */
+    RFAL_LM_STATE_POWER_OFF = 0x01, /*!< Power Off state                             */
+    RFAL_LM_STATE_IDLE = 0x02, /*!< Idle state  Activity 1.1  5.2               */
+    RFAL_LM_STATE_READY_A = 0x03, /*!< Ready A state  Activity 1.1  5.3 5.4 & 5.5  */
+    RFAL_LM_STATE_READY_B = 0x04, /*!< Ready B state  Activity 1.1  5.11 5.12      */
+    RFAL_LM_STATE_READY_F = 0x05, /*!< Ready F state  Activity 1.1  5.15           */
+    RFAL_LM_STATE_ACTIVE_A = 0x06, /*!< Active A state  Activity 1.1  5.6           */
+    RFAL_LM_STATE_CARDEMU_4A = 0x07, /*!< Card Emulation 4A state  Activity 1.1  5.10 */
+    RFAL_LM_STATE_CARDEMU_4B = 0x08, /*!< Card Emulation 4B state  Activity 1.1  5.14 */
+    RFAL_LM_STATE_CARDEMU_3 = 0x09, /*!< Card Emulation 3 state  Activity 1.1  5.18  */
+    RFAL_LM_STATE_TARGET_A = 0x0A, /*!< Target A state  Activity 1.1  5.9           */
+    RFAL_LM_STATE_TARGET_F = 0x0B, /*!< Target F state  Activity 1.1  5.17          */
+    RFAL_LM_STATE_SLEEP_A = 0x0C, /*!< Sleep A state  Activity 1.1  5.7            */
+    RFAL_LM_STATE_SLEEP_B = 0x0D, /*!< Sleep B state  Activity 1.1  5.13           */
+    RFAL_LM_STATE_READY_Ax = 0x0E, /*!< Ready A* state  Activity 1.1  5.3 5.4 & 5.5 */
+    RFAL_LM_STATE_ACTIVE_Ax = 0x0F, /*!< Active A* state  Activity 1.1  5.6          */
+    RFAL_LM_STATE_SLEEP_AF = 0x10, /*!< Sleep AF state  Activity 1.1  5.19          */
+} rfalLmState;
+
+/*! RFAL Listen Mode Passive A configs */
+typedef struct {
+    rfalLmNfcidLen nfcidLen; /*!< NFCID Len (4, 7 or 10 bytes)              */
+    uint8_t nfcid[RFAL_NFCID1_TRIPLE_LEN]; /*!< NFCID                                     */
+    uint8_t SENS_RES[RFAL_LM_SENS_RES_LEN]; /*!< NFC-106k; SENS_REQ Response               */
+    uint8_t SEL_RES; /*!< SEL_RES (SAK) with complete NFCID1 (UID)  */
+} rfalLmConfPA;
+
+/*! RFAL Listen Mode Passive B configs */
+typedef struct {
+    uint8_t SENSB_RES[RFAL_LM_SENSB_RES_LEN]; /*!< SENSF_RES                               */
+} rfalLmConfPB;
+
+/*! RFAL Listen Mode Passive F configs */
+typedef struct {
+    uint8_t SC[RFAL_LM_SENSF_SC_LEN]; /*!< System Code to listen for               */
+    uint8_t SENSF_RES[RFAL_LM_SENSF_RES_LEN]; /*!< SENSF_RES                               */
+} rfalLmConfPF;
+
+/*******************************************************************************/
+
+/*******************************************************************************/
+/*  Wake-Up Mode                                                               */
+/*******************************************************************************/
+
+#define RFAL_WUM_REFERENCE_AUTO 0xFFU /*!< Indicates new reference is set by the driver*/
+
+/*! RFAL Wake-Up Mode States */
+typedef enum {
+    RFAL_WUM_STATE_NOT_INIT = 0x00, /*!< Not Initialized state                       */
+    RFAL_WUM_STATE_ENABLED = 0x01, /*!< Wake-Up mode is enabled                     */
+    RFAL_WUM_STATE_ENABLED_WOKE = 0x02, /*!< Wake-Up mode enabled and has received IRQ(s)*/
+} rfalWumState;
+
+/*! RFAL Wake-Up Period/Timer */
+typedef enum {
+    RFAL_WUM_PERIOD_10MS = 0x00, /*!< Wake-Up timer 10ms                          */
+    RFAL_WUM_PERIOD_20MS = 0x01, /*!< Wake-Up timer 20ms                          */
+    RFAL_WUM_PERIOD_30MS = 0x02, /*!< Wake-Up timer 30ms                          */
+    RFAL_WUM_PERIOD_40MS = 0x03, /*!< Wake-Up timer 40ms                          */
+    RFAL_WUM_PERIOD_50MS = 0x04, /*!< Wake-Up timer 50ms                          */
+    RFAL_WUM_PERIOD_60MS = 0x05, /*!< Wake-Up timer 60ms                          */
+    RFAL_WUM_PERIOD_70MS = 0x06, /*!< Wake-Up timer 70ms                          */
+    RFAL_WUM_PERIOD_80MS = 0x07, /*!< Wake-Up timer 80ms                          */
+    RFAL_WUM_PERIOD_100MS = 0x10, /*!< Wake-Up timer 100ms                         */
+    RFAL_WUM_PERIOD_200MS = 0x11, /*!< Wake-Up timer 200ms                         */
+    RFAL_WUM_PERIOD_300MS = 0x12, /*!< Wake-Up timer 300ms                         */
+    RFAL_WUM_PERIOD_400MS = 0x13, /*!< Wake-Up timer 400ms                         */
+    RFAL_WUM_PERIOD_500MS = 0x14, /*!< Wake-Up timer 500ms                         */
+    RFAL_WUM_PERIOD_600MS = 0x15, /*!< Wake-Up timer 600ms                         */
+    RFAL_WUM_PERIOD_700MS = 0x16, /*!< Wake-Up timer 700ms                         */
+    RFAL_WUM_PERIOD_800MS = 0x17, /*!< Wake-Up timer 800ms                         */
+} rfalWumPeriod;
+
+/*! RFAL Wake-Up Period/Timer */
+typedef enum {
+    RFAL_WUM_AA_WEIGHT_4 = 0x00, /*!< Wake-Up Auto Average Weight 4              */
+    RFAL_WUM_AA_WEIGHT_8 = 0x01, /*!< Wake-Up Auto Average Weight 8              */
+    RFAL_WUM_AA_WEIGHT_16 = 0x02, /*!< Wake-Up Auto Average Weight 16             */
+    RFAL_WUM_AA_WEIGHT_32 = 0x03, /*!< Wake-Up Auto Average Weight 32             */
+} rfalWumAAWeight;
+
+/*! RFAL Wake-Up Mode configuration */
+typedef struct {
+    rfalWumPeriod period; /*!< Wake-Up Timer period;how often measurement(s) is performed */
+    bool irqTout; /*!< IRQ at every timeout will refresh the measurement(s)       */
+    bool swTagDetect; /*!< Use SW Tag Detection instead of HW Wake-Up mode            */
+
+    struct {
+        bool enabled; /*!< Inductive Amplitude measurement enabled                   */
+        uint8_t delta; /*!< Delta between the reference and measurement to wake-up    */
+        uint16_t reference; /*!< Reference to be used;RFAL_WUM_REFERENCE_AUTO sets it auto */
+        bool autoAvg; /*!< Use the HW Auto Averaging feature                         */
+        bool aaInclMeas; /*!< When AutoAvg is enabled, include IRQ measurement          */
+        rfalWumAAWeight aaWeight; /*!< When AutoAvg is enabled, last measure weight              */
+    } indAmp; /*!< Inductive Amplitude Configuration                         */
+    struct {
+        bool enabled; /*!< Inductive Phase measurement enabled                       */
+        uint8_t delta; /*!< Delta between the reference and measurement to wake-up    */
+        uint16_t reference; /*!< Reference to be used;RFAL_WUM_REFERENCE_AUTO sets it auto */
+        bool autoAvg; /*!< Use the HW Auto Averaging feature                         */
+        bool aaInclMeas; /*!< When AutoAvg is enabled, include IRQ measurement          */
+        rfalWumAAWeight aaWeight; /*!< When AutoAvg is enabled, last measure weight              */
+    } indPha; /*!< Inductive Phase Configuration                             */
+    struct {
+        bool enabled; /*!< Capacitive measurement enabled                            */
+        uint8_t delta; /*!< Delta between the reference and measurement to wake-up    */
+        uint16_t reference; /*!< Reference to be used;RFAL_WUM_REFERENCE_AUTO sets it auto */
+        bool autoAvg; /*!< Use the HW Auto Averaging feature                         */
+        bool aaInclMeas; /*!< When AutoAvg is enabled, include IRQ measurement          */
+        rfalWumAAWeight aaWeight; /*!< When AutoAvg is enabled, last measure weight              */
+    } cap; /*!< Capacitive Configuration                                  */
+} rfalWakeUpConfig;
+
+/*******************************************************************************/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Initialize
+ *  
+ * Initializes RFAL layer and the ST25R391x
+ * Ensures that ST25R391x is properly connected and returns error if any problem 
+ * is detected
+ *
+ * \warning rfalAnalogConfigInitialize() should be called before so that 
+ *           the Analog config table has been previously initialized.
+ *           
+ * \return ERR_HW_MISMATCH  : Expected HW do not match or communication error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalInitialize(void);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL Calibrate 
+ *  
+ * Performs necessary calibration of RF chip in case it is indicated by current
+ * register settings. E.g. antenna calibration and regulator calibration
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized
+ * \return ERR_NONE         : No error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalCalibrate(void);
+
+/*!
+ *****************************************************************************
+ * \brief  RFAL Adjust Regulators 
+ *  
+ * Adjusts ST25R391x regulators 
+ * 
+ * \param[out]  result : the result of the calibrate antenna in mV
+ *                       NULL if result not requested
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized
+ * \return ERR_NONE         : No error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalAdjustRegulators(uint16_t* result);
+
+/*!
+ *****************************************************************************
+ * \brief RFAL Set System Callback
+ *
+ * Sets a callback for the driver to call when an event has occurred that 
+ * may require the system to be notified
+ * 
+ * \param[in]  pFunc : method pointer for the upper layer callback 
+ * 
+ *****************************************************************************
+ */
+void rfalSetUpperLayerCallback(rfalUpperLayerCallback pFunc);
+
+/*!
+ *****************************************************************************
+ * \brief RFAL Set Pre Tx Callback
+ *
+ * Sets a callback for the driver to call before a Transceive 
+ * 
+ * \param[in]  pFunc : method pointer for the Pre Tx callback 
+ * 
+ *****************************************************************************
+ */
+void rfalSetPreTxRxCallback(rfalPreTxRxCallback pFunc);
+
+/*!
+ *****************************************************************************
+ * \brief RFAL Set Post Tx Callback
+ *
+ * Sets a callback for the driver to call after a Transceive 
+ * 
+ * \param[in]  pFunc : method pointer for the Post Tx callback 
+ * 
+ *****************************************************************************
+ */
+void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc);
+
+/** Set RFAL state changed callback
+ *
+ * @param cb    RfalStateChangedCallback instance
+ * @param ctx   pointer to context
+ */
+void rfal_set_state_changed_callback(RfalStateChangedCallback callback);
+
+/** Set callback context
+ *
+ * @param ctx pointer to context
+ */
+void rfal_set_callback_context(void* context);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Deinitialize
+ *  
+ * Deinitializes RFAL layer and the ST25R391x
+ *
+ * \return ERR_NONE : No error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalDeinitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set Mode
+ *  
+ * Sets the mode that RFAL will operate on the following communications.
+ * Proper initializations will be performed on the ST25R391x
+ * 
+ * \warning bit rate value RFAL_BR_KEEP is not allowed, only in rfalSetBitRate()
+ * 
+ * \warning the mode will be applied immediately on the RFchip regardless of 
+ *          any ongoing operations like Transceive, ListenMode
+ * 
+ * \param[in]  mode : mode for the RFAL/RFchip to perform
+ * \param[in]  txBR : transmit bit rate
+ * \param[in]  rxBR : receive bit rate 
+ * 
+ * \see rfalIsGTExpired
+ * \see rfalMode
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_NONE         : No error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalSetMode(rfalMode mode, rfalBitRate txBR, rfalBitRate rxBR);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Get Mode
+ *  
+ * Gets the mode that RFAL is set to operate
+ * 
+ * \see rfalMode
+ *
+ * \return rfalMode : The current RFAL mode
+ *****************************************************************************
+ */
+rfalMode rfalGetMode(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set Bit Rate
+ *  
+ * Sets the Tx and Rx bit rates with the given values 
+ * The bit rate change is applied on the RF chip remaining in the same  
+ * mode previous defined with rfalSetMode()
+ * 
+ * If no mode is defined bit rates will not be applied and an error 
+ * is returned
+ * 
+ * \param[in]  txBR : transmit bit rate
+ * \param[in]  rxBR : receive bit rate 
+ * 
+ * \see rfalSetMode
+ * \see rfalMode
+ * \see rfalBitRate
+ *
+ * \return ERR_WRONG_STATE     : RFAL not initialized
+ * \return ERR_PARAM           : Invalid parameter
+ * \return ERR_NOT_IMPLEMENTED : Mode not implemented
+ * \return ERR_NONE            : No error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalSetBitRate(rfalBitRate txBR, rfalBitRate rxBR);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Get Bit Rate
+ *  
+ * Gets the Tx and Rx current bit rates 
+ * 
+ * If RFAL is not initialized or mode not set the bit rates return will 
+ * be invalid RFAL_BR_KEEP
+ * 
+ * \param[out]  txBR : RFAL's current Tx Bit Rate
+ * \param[out]  rxBR : RFAL's current Rx Bit Rate
+ * 
+ * \see rfalSetBitRate
+ * \see rfalBitRate
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalGetBitRate(rfalBitRate* txBR, rfalBitRate* rxBR);
+
+/*! 
+ *****************************************************************************
+ * \brief Set Error Handling Mode
+ *  
+ *  Sets the error handling mode to be used by the RFAL
+ *  
+ * \param[in]  eHandling : the error handling mode
+ * 
+ *****************************************************************************
+ */
+void rfalSetErrorHandling(rfalEHandling eHandling);
+
+/*! 
+ *****************************************************************************
+ * \brief Get Error Handling Mode
+ *  
+ *  Gets the error handling mode currently used by the RFAL 
+ *  
+ * \return rfalEHandling : Current error handling mode
+ *****************************************************************************
+ */
+rfalEHandling rfalGetErrorHandling(void);
+
+/*! 
+ *****************************************************************************
+ * \brief Set Observation Mode
+ *  
+ * Sets ST25R391x observation modes for RF debug purposes
+ *
+ * \param[in]  txMode : the observation mode to be used during transmission
+ * \param[in]  rxMode : the observation mode to be used during reception
+ * 
+ * \warning The Observation Mode is an advanced feature and should be set 
+ *          according to the documentation of the part number in use.
+ *          Please refer to the corresponding Datasheet or Application Note(s)
+ *****************************************************************************
+ */
+void rfalSetObsvMode(uint8_t txMode, uint8_t rxMode);
+
+/*! 
+ *****************************************************************************
+ * \brief Get Observation Mode
+ *  
+ * Gets ST25R391x the current configured observation modes
+ *
+ * \param[in]  txMode : the current observation mode configured for transmission
+ * \param[in]  rxMode : the current observation mode configured for reception
+ * 
+ *****************************************************************************
+ */
+void rfalGetObsvMode(uint8_t* txMode, uint8_t* rxMode);
+
+/*! 
+ *****************************************************************************
+ * \brief Disable Observation Mode
+ *  
+ * Disables the ST25R391x observation mode
+ *****************************************************************************
+ */
+void rfalDisableObsvMode(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set FDT Poll
+ *  
+ * Sets the Frame Delay Time (FDT) to be used on the following
+ * communications.
+ * 
+ * FDT Poll is the minimum time following a Poll Frame during 
+ * which no subsequent Poll Frame can be sent (without a response from 
+ * the Listener in between)
+ * FDTx,PP,MIN - Digital 1.1  6.10.2  &  7.9.2  &  8.7.2
+ * 
+ * \param[in]  FDTPoll : Frame Delay Time in 1/fc cycles
+ *
+ *****************************************************************************
+ */
+void rfalSetFDTPoll(uint32_t FDTPoll);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set FDT Poll
+ *  
+ * Gets the current Frame Delay Time (FDT) 
+ * 
+ * FDT Poll is the minimum time following a Poll Frame during 
+ * which no subsequent Poll Frame can be sent (without a response from 
+ * the Listener in between)
+ * FDTx,PP,MIN - Digital 1.1  6.10.2  &  7.9.2  &  8.7.2
+ *  
+ * \return FDT : current FDT value in 1/fc cycles
+ *
+ *****************************************************************************
+ */
+uint32_t rfalGetFDTPoll(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set FDT Listen
+ *  
+ * Sets the Frame Delay Time (FDT) Listen minimum to be used on the 
+ * following communications.
+ * 
+ * FDT Listen is the minimum time between a Poll Frame and a Listen Frame
+ * FDTx,LISTEN,MIN - Digital 1.1  6.10.1  &  7.9.1  &  8.7.1
+ *  
+ * \param[in]  FDTListen : Frame Delay Time in 1/fc cycles
+ *
+ *****************************************************************************
+ */
+void rfalSetFDTListen(uint32_t FDTListen);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set FDT Listen
+ *  
+ * Gets the Frame Delay Time (FDT) Listen minimum  
+ * 
+ * FDT Listen is the minimum time between a Poll Frame and a Listen Frame
+ * FDTx,LISTEN,MIN - Digital 1.1  6.10.1  &  7.9.1  &  8.7.1
+ *  
+ * \return FDT : current FDT value in 1/fc cycles
+ *
+ *****************************************************************************
+ */
+uint32_t rfalGetFDTListen(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Get GT
+ *  
+ * Gets the current Guard Time (GT)
+ *  
+ * GT is the minimum time when a device in Listen Mode is exposed to an 
+ * unmodulated carrier
+ *  
+ * \return GT :  Guard Time in 1/fc cycles
+ *
+ *****************************************************************************
+ */
+uint32_t rfalGetGT(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set GT
+ *  
+ * Sets the Guard Time (GT) to be used on the following communications.
+ * 
+ * GT is the minimum time when a device in Listen Mode is exposed to an 
+ * unmodulated carrier
+ *  
+ * \param[in]  GT : Guard Time in 1/fc cycles
+ *                  RFAL_GT_NONE if no GT should be applied
+ *
+ *****************************************************************************
+ */
+void rfalSetGT(uint32_t GT);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Is GT expired 
+ *  
+ * Checks whether the GT timer has expired
+ *    
+ * \return true  : GT has expired or not running
+ * \return false : GT is still running
+ *
+ *****************************************************************************
+ */
+bool rfalIsGTExpired(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Turn Field On and Start GT
+ *  
+ * Turns the Field On, performing Initial Collision Avoidance
+ * 
+ * After Field On, if GT was set before, it starts the GT timer to be 
+ * used on the following communications.
+ *  
+ * \return ERR_RF_COLLISION : External field detected
+ * \return ERR_NONE         : Field turned On
+ *
+ *****************************************************************************
+ */
+ReturnCode rfalFieldOnAndStartGT(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Turn Field Off
+ *  
+ * Turns the Field Off  
+ *   
+ * \return ERR_NONE : Field turned Off
+ *****************************************************************************
+ */
+ReturnCode rfalFieldOff(void);
+
+/*****************************************************************************
+ *  Transceive                                                               *  
+ *****************************************************************************/
+
+/*! 
+ *****************************************************************************
+ * \brief  RFAL Set transceive context
+ *  
+ * Set the context that will be used for the following Transceive
+ * Output and input buffers have to be passed and all other details prior to 
+ * the Transceive itself has been started
+ * 
+ * This method only sets the context, once set rfalWorker has
+ * to be executed until is done
+ * 
+ * \param[in]  ctx : the context for the following Transceive
+ * 
+ * \see  rfalWorker
+ * \see  rfalGetTransceiveStatus
+ *
+ * \return ERR_NONE        : Done with no error
+ * \return ERR_WRONG_STATE : Not initialized properly 
+ * \return ERR_PARAM       : Invalid parameter or configuration
+ *****************************************************************************
+ */
+ReturnCode rfalStartTransceive(const rfalTransceiveContext* ctx);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get Transceive State
+ *  
+ * Gets current Transceive internal State
+ *
+ * \return rfalTransceiveState : the current Transceive internal State
+ *****************************************************************************
+ */
+rfalTransceiveState rfalGetTransceiveState(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get Transceive Status
+ *  
+ * Gets current Transceive status
+ *
+ * \return  ERR_NONE         : Transceive done with no error
+ * \return  ERR_BUSY         : Transceive ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * \return  ERR_TIMEOUT      : No response
+ * \return  ERR_FRAMING      : Framing error detected
+ * \return  ERR_PAR          : Parity error detected
+ * \return  ERR_CRC          : CRC error detected
+ * \return  ERR_LINK_LOSS    : Link Loss - External Field is Off
+ * \return  ERR_RF_COLLISION : Collision detected
+ * \return  ERR_IO           : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalGetTransceiveStatus(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Is Transceive in Tx
+ *  
+ * Checks if Transceive is in Transmission state
+ *
+ * \return true   Transmission ongoing
+ * \return false  Not in transmission state
+ *****************************************************************************
+ */
+bool rfalIsTransceiveInTx(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Is Transceive in Rx
+ *  
+ * Checks if Transceive is in Reception state 
+ *
+ * \return true   Transmission done/reception ongoing
+ * \return false  Not in reception state
+ *****************************************************************************
+ */
+bool rfalIsTransceiveInRx(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Get Transceive RSSI
+ *  
+ * Gets the RSSI value of the last executed Transceive in mV
+ *
+ * \param[out]  rssi : RSSI value
+ *
+ * \return  ERR_NOTSUPP : Feature not supported
+ * \return  ERR_PARAM   : Invalid parameter
+ * \return  ERR_NONE    : No error
+ *****************************************************************************
+ */
+ReturnCode rfalGetTransceiveRSSI(uint16_t* rssi);
+
+/*! 
+ *****************************************************************************
+ *  \brief RFAL Worker
+ *  
+ *  This runs RFAL layer, which drives the actual Transceive procedure
+ *  It MUST be executed frequently in order to execute the RFAL internal
+ *  states and perform the requested operations
+ *
+ *****************************************************************************
+ */
+void rfalWorker(void);
+
+/*****************************************************************************
+ *  ISO1443A                                                                 *  
+ *****************************************************************************/
+
+/*! 
+ *****************************************************************************
+ *  \brief Transceives an ISO14443A ShortFrame  
+ *  
+ *  Sends REQA to detect if there is any PICC in the field 
+ *
+ * \param[in]  txCmd:     Command to be sent:
+ *                           0x52 WUPA / ALL_REQ
+ *                           0x26 REQA / SENS_REQ
+ *                           
+ * \param[in]  txCmd    : type of short frame to be sent REQA or WUPA                          
+ * \param[out] rxBuf    : buffer to place the response
+ * \param[in]  rxBufLen : length of rxBuf
+ * \param[out] rxRcvdLen: received length
+ * \param[in]  fwt      : Frame Waiting Time in 1/fc
+ * 
+ * \warning If fwt is set to RFAL_FWT_NONE it will make endlessly for 
+ *         a response, which on a blocking method may not be the 
+ *         desired usage 
+ * 
+ * \return ERR_NONE if there is response
+ * \return ERR_TIMEOUT if there is no response
+ * \return ERR_COLLISION collision has occurred
+ *  
+ *****************************************************************************
+ */
+ReturnCode rfalISO14443ATransceiveShortFrame(
+    rfal14443AShortFrameCmd txCmd,
+    uint8_t* rxBuf,
+    uint8_t rxBufLen,
+    uint16_t* rxRcvdLen,
+    uint32_t fwt);
+
+/*!
+ *****************************************************************************
+ * \brief Sends an ISO14443A Anticollision Frame 
+ * 
+ * This is use to perform ISO14443A anti-collision. 
+ * \note Anticollision is sent without CRC
+ * 
+ * 
+ * \param[in]   buf        : reference to ANTICOLLISION command (with known UID if any) to be sent (also out param)
+ *                           reception will be place on this buf after bytesToSend 
+ * \param[in]   bytesToSend: reference number of full bytes to be sent (including CMD byte and SEL_PAR)
+ *                           if a collision occurs will contain the number of clear bytes  
+ * \param[in]   bitsToSend : reference to number of bits (0-7) to be sent; and received (also out param)
+ *                           if a collision occurs will indicate the number of clear bits (also out param)
+ * \param[out]  rxLength   : reference to the return the received length
+ * \param[in]   fwt        : Frame Waiting Time in 1/fc
+ * 
+ * \return ERR_NONE if there is no error
+ *****************************************************************************
+ */
+ReturnCode rfalISO14443ATransceiveAnticollisionFrame(
+    uint8_t* buf,
+    uint8_t* bytesToSend,
+    uint8_t* bitsToSend,
+    uint16_t* rxLength,
+    uint32_t fwt);
+
+/*****************************************************************************
+ *  FeliCa                                                                   *  
+ *****************************************************************************/
+
+/*!
+ *****************************************************************************
+ * \brief FeliCa Poll 
+ * 
+ * Sends a Poll Request and collects all Poll Responses according to the 
+ * given slots  
+ * 
+ * 
+ * \param[in]   slots             : number of slots for the Poll Request
+ * \param[in]   sysCode           : system code (SC) for the Poll Request  
+ * \param[in]   reqCode           : request code (RC) for the Poll Request
+ * \param[out]  pollResList       : list of all responses
+ * \param[in]   pollResListSize   : number of responses that can be placed in pollResList 
+ * \param[out]  devicesDetected   : number of cards found
+ * \param[out]  collisionsDetected: number of collisions detected
+ * 
+ * \return ERR_NONE if there is no error
+ * \return ERR_TIMEOUT if there is no response
+ *****************************************************************************
+ */
+ReturnCode rfalFeliCaPoll(
+    rfalFeliCaPollSlots slots,
+    uint16_t sysCode,
+    uint8_t reqCode,
+    rfalFeliCaPollRes* pollResList,
+    uint8_t pollResListSize,
+    uint8_t* devicesDetected,
+    uint8_t* collisionsDetected);
+
+/*****************************************************************************
+ *  ISO15693                                                                 *  
+ *****************************************************************************/
+
+/*!
+ *****************************************************************************
+ * \brief Sends an ISO15693 Anticollision Frame 
+ * 
+ * This send the Anticollision|Inventory frame (INVENTORY_REQ)
+ *
+ * \warning rxBuf must be able to contain the payload and CRC
+ * 
+ * \param[in]  txBuf        : Buffer where outgoing message is located
+ * \param[in]  txBufLen     : Length of the outgoing message in bytes
+ * \param[out] rxBuf        : Buffer where incoming message will be placed
+ * \param[in]  rxBufLen     : Maximum length of the incoming message in bytes
+ * \param[out] actLen       : Actual received length in bits
+ * 
+ * \return  ERR_NONE        : Transceive done with no error
+ * \return  ERR_WRONG_STATE : RFAL not initialized or mode not set
+ * \return  ERR_IO          : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalISO15693TransceiveAnticollisionFrame(
+    uint8_t* txBuf,
+    uint8_t txBufLen,
+    uint8_t* rxBuf,
+    uint8_t rxBufLen,
+    uint16_t* actLen);
+
+/*!
+ *****************************************************************************
+ * \brief Sends an ISO15693 Anticollision EOF
+ * 
+ * This sends the Anticollision|Inventory EOF used as a slot marker
+ * 
+ * \warning rxBuf must be able to contain the payload and CRC
+ * 
+ * \param[out] rxBuf        : Buffer where incoming message will be placed
+ * \param[in] rxBufLen      : Maximum length of the incoming message in bytes
+ * \param[out] actLen       : Actual received length in bits
+ * 
+ * \return  ERR_NONE        : Transceive done with no error
+ * \return  ERR_WRONG_STATE : RFAL not initialized or mode not set
+ * \return  ERR_IO          : Internal error
+ *****************************************************************************
+ */
+ReturnCode
+    rfalISO15693TransceiveEOFAnticollision(uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* actLen);
+
+/*!
+ *****************************************************************************
+ * \brief Sends an ISO15693 EOF
+ *
+ * This is method sends an ISO15693 (EoF) used for a Write operation
+ * 
+ * \warning rxBuf must be able to contain the payload and CRC
+ * 
+ * \param[out] rxBuf        : Buffer where incoming message will be placed
+ * \param[in] rxBufLen      : Maximum length of the incoming message in bytes
+ * \param[out] actLen       : Actual received length in bytes
+ * 
+ * \return  ERR_NONE        : Transceive done with no error
+ * \return  ERR_IO          : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalISO15693TransceiveEOF(uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* actLen);
+
+/*!
+ *****************************************************************************
+ * \brief Transceive Blocking Tx 
+ *
+ * This is method triggers a Transceive and executes it blocking until the 
+ * Tx has been completed
+ * 
+ * \param[in]  txBuf    : Buffer where outgoing message is located
+ * \param[in]  txBufLen : Length of the outgoing message in bytes
+ * \param[out] rxBuf    : Buffer where incoming message will be placed
+ * \param[in]  rxBufLen : Maximum length of the incoming message in bytes
+ * \param[out] actLen   : Actual received length in bits
+ * \param[in]  flags    : TransceiveFlags indication special handling
+ * \param[in]  fwt      : Frame Waiting Time in 1/fc
+ * 
+ * \return  ERR_NONE         : Transceive done with no error
+ * \return  ERR_BUSY         : Transceive ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * \return  ERR_LINK_LOSS    : Link Loss - External Field is Off
+ * \return  ERR_RF_COLLISION : Collision detected
+ * \return  ERR_IO           : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalTransceiveBlockingTx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+/*!
+ *****************************************************************************
+ * \brief Transceive Blocking Rx 
+ *
+ * This is method executes the reception of an ongoing Transceive triggered 
+ * before by rfalTransceiveBlockingTx()
+ * 
+ * \return  ERR_NONE         : Transceive done with no error
+ * \return  ERR_BUSY         : Transceive ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * \return  ERR_TIMEOUT      : No response
+ * \return  ERR_FRAMING      : Framing error detected
+ * \return  ERR_PAR          : Parity error detected
+ * \return  ERR_CRC          : CRC error detected
+ * \return  ERR_LINK_LOSS    : Link Loss - External Field is Off
+ * \return  ERR_RF_COLLISION : Collision detected
+ * \return  ERR_IO           : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalTransceiveBlockingRx(void);
+
+/*!
+ *****************************************************************************
+ * \brief Transceive Blocking 
+ *
+ * This is method triggers a Transceive and executes it blocking until it 
+ * has been completed
+ * 
+ * \param[in]  txBuf    : Buffer where outgoing message is located
+ * \param[in]  txBufLen : Length of the outgoing message in bytes
+ * \param[out] rxBuf    : Buffer where incoming message will be placed
+ * \param[in]  rxBufLen : Maximum length of the incoming message in bytes
+ * \param[out] actLen   : Actual received length in bytes
+ * \param[in]  flags    : TransceiveFlags indication special handling
+ * \param[in]  fwt      : Frame Waiting Time in 1/fc
+ * 
+ * \return  ERR_NONE         : Transceive done with no error
+ * \return  ERR_BUSY         : Transceive ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * \return  ERR_TIMEOUT      : No response
+ * \return  ERR_FRAMING      : Framing error detected
+ * \return  ERR_PAR          : Parity error detected
+ * \return  ERR_CRC          : CRC error detected
+ * \return  ERR_LINK_LOSS    : Link Loss - External Field is Off
+ * \return  ERR_RF_COLLISION : Collision detected
+ * \return  ERR_IO           : Internal error
+ *****************************************************************************
+ */
+ReturnCode rfalTransceiveBlockingTxRx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+ReturnCode rfalTransceiveBitsBlockingTxRx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+ReturnCode rfalTransceiveBitsBlockingTx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+/*****************************************************************************
+ *  Listen Mode                                                              *  
+ *****************************************************************************/
+
+/*!
+ *****************************************************************************
+ * \brief Is external Field On
+ * 
+ * Checks if external field (other peer/device) is on/detected
+ * 
+ * \return true  External field is On
+ * \return false No external field is detected
+ * 
+ *****************************************************************************
+ */
+bool rfalIsExtFieldOn(void);
+
+/*!
+ *****************************************************************************
+ * \brief Listen Mode start
+ * 
+ * Configures RF Chip to go into listen mode enabling the given technologies
+ * 
+ * 
+ * \param[in]  lmMask:    mask with the enabled/disabled listen modes
+ *                        use: RFAL_LM_MASK_NFCA ; RFAL_LM_MASK_NFCB ; 
+ *                             RFAL_LM_MASK_NFCF ; RFAL_LM_MASK_ACTIVE_P2P 
+ * \param[in]  confA:     pointer to Passive A configurations (NULL if disabled)
+ * \param[in]  confB:     pointer to Passive B configurations (NULL if disabled)
+ * \param[in]  confF:     pointer to Passive F configurations (NULL if disabled)
+ * \param[in]  rxBuf:     buffer to place incoming data
+ * \param[in]  rxBufLen:  length in bits of rxBuf
+ * \param[in]  rxLen:     pointer to write the data length in bits placed into rxBuf
+ *  
+ * 
+ * \return ERR_PARAM    Invalid parameter
+ * \return ERR_REQUEST  Invalid listen mode mask
+ * \return ERR_NONE     Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalListenStart(
+    uint32_t lmMask,
+    const rfalLmConfPA* confA,
+    const rfalLmConfPB* confB,
+    const rfalLmConfPF* confF,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rxLen);
+
+/*!
+ *****************************************************************************
+ * \brief Listen Mode start Sleeping
+ * 
+ * 
+ *****************************************************************************
+ */
+ReturnCode
+    rfalListenSleepStart(rfalLmState sleepSt, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxLen);
+
+/*!
+ *****************************************************************************
+ * \brief Listen Mode Stop
+ * 
+ * Disables the listen mode on the RF Chip 
+ * 
+ * \warning the listen mode will be disabled immediately on the RFchip regardless 
+ *          of any ongoing operations like Transceive
+ * 
+ * \return ERR_NONE Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalListenStop(void);
+
+/*!
+ *****************************************************************************
+ * \brief Listen Mode get state
+ *
+ * Sets the new state of the Listen Mode and applies the necessary changes 
+ * on the RF Chip
+ *
+ * \param[out]  dataFlag: indicates that Listen Mode has rcvd data and caller
+ *                         must process it. The received message is located
+ *                         at the rxBuf passed on rfalListenStart().
+ *                         rfalListenSetState() will clear this flag
+ *                         if NULL output parameter will no be written/returned
+ * \param[out]  lastBR:   bit rate detected  of the last initiator request 
+ *                         if NULL output parameter will no be written/returned
+ * 
+ * \return rfalLmState  RFAL_LM_STATE_NOT_INIT : LM not initialized properly
+ *                      Any Other              : LM State
+ * 
+ *****************************************************************************
+ */
+rfalLmState rfalListenGetState(bool* dataFlag, rfalBitRate* lastBR);
+
+/*!
+ *****************************************************************************
+ * \brief Listen Mode set state
+ *
+ * Sets the new state of the Listen Mode and applies the necessary changes 
+ * on the RF Chip
+ *  
+ * \param[in] newSt : New state to go to
+ * 
+ * \return ERR_WRONG_STATE : Not initialized properly
+ * \return ERR_PARAM       : Invalid parameter
+ * \return ERR_NONE        : Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalListenSetState(rfalLmState newSt);
+
+/*****************************************************************************
+ *  Wake-Up Mode                                                             *  
+ *****************************************************************************/
+
+/*!
+ *****************************************************************************
+ * \brief Wake-Up Mode Start
+ *
+ * Sets the RF Chip in Low Power Wake-Up Mode according to the given 
+ * configuration.
+ * 
+ * \param[in] config       : Generic Wake-Up configuration provided by lower 
+ *                            layers. If NULL will automatically configure the 
+ *                            Wake-Up mode
+ * 
+ * \return ERR_WRONG_STATE : Not initialized properly
+ * \return ERR_PARAM       : Invalid parameter
+ * \return ERR_NONE        : Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalWakeUpModeStart(const rfalWakeUpConfig* config);
+
+/*!
+ *****************************************************************************
+ * \brief Wake-Up Has Woke
+ *
+ * Returns true if the Wake-Up mode is enabled and it has already received 
+ * the indication from the RF Chip that the surrounding environment has changed
+ * and flagged at least one wake-Up interrupt
+ * 
+ * \return true  : Wake-Up mode enabled and has received a wake-up IRQ
+ * \return false : no Wake-Up IRQ has been received
+ * 
+ *****************************************************************************
+ */
+bool rfalWakeUpModeHasWoke(void);
+
+/*!
+ *****************************************************************************
+ * \brief Wake-Up Mode Stop
+ *
+ * Stops the Wake-Up Mode
+ * 
+ * \return ERR_WRONG_STATE : Not initialized properly
+ * \return ERR_PARAM       : Invalid parameter
+ * \return ERR_NONE        : Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalWakeUpModeStop(void);
+
+/*!
+ *****************************************************************************
+ * \brief Low Power Mode Start
+ *
+ * Sets the RF Chip in Low Power Mode. 
+ * In this mode the RF Chip is placed in Low Power Mode, similar to Wake-up 
+ * mode but no operation nor period measurement is performed.
+ * Mode must be terminated by rfalLowPowerModeStop()
+ * 
+ * \return ERR_WRONG_STATE : Not initialized properly
+ * \return ERR_PARAM       : Invalid parameter
+ * \return ERR_NONE        : Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalLowPowerModeStart(void);
+
+/*!
+ *****************************************************************************
+ * \brief Low Power Mode Stop
+ *
+ * Stops the Low Power Mode re-enabling the device
+ * 
+ * \return ERR_WRONG_STATE : Not initialized properly
+ * \return ERR_PARAM       : Invalid parameter
+ * \return ERR_NONE        : Done with no error
+ * 
+ *****************************************************************************
+ */
+ReturnCode rfalLowPowerModeStop(void);
+
+#endif /* RFAL_RF_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 340 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_st25tb.h

@@ -0,0 +1,340 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_st25tb.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of ST25TB interface 
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25TB
+ * \brief RFAL ST25TB Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_ST25TB_H
+#define RFAL_ST25TB_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+#include "rfal_nfcb.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_ST25TB_CHIP_ID_LEN 1U /*!< ST25TB chip ID length       */
+#define RFAL_ST25TB_CRC_LEN 2U /*!< ST25TB CRC length           */
+#define RFAL_ST25TB_UID_LEN 8U /*!< ST25TB Unique ID length     */
+#define RFAL_ST25TB_BLOCK_LEN 4U /*!< ST25TB Data Block length    */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+typedef uint8_t rfalSt25tbUID[RFAL_ST25TB_UID_LEN]; /*!< ST25TB UID type          */
+typedef uint8_t rfalSt25tbBlock[RFAL_ST25TB_BLOCK_LEN]; /*!< ST25TB Block type        */
+
+/*! ST25TB listener device (PICC) struct  */
+typedef struct {
+    uint8_t chipID; /*!< Device's session Chip ID */
+    rfalSt25tbUID UID; /*!< Device's UID             */
+    bool isDeselected; /*!< Device deselect flag     */
+} rfalSt25tbListenDevice;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize ST25TB Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * ST25TB Poller/RW including all default timings
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Check Presence
+ *  
+ * This method checks if a ST25TB Listen device (PICC) is present on the field
+ * by sending an Initiate command
+ * 
+ * \param[out] chipId : if successfully retrieved, the device's chip ID
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_RF_COLLISION : Collision detected one or more device in the field
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerCheckPresence(uint8_t* chipId);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Collision Resolution
+ *  
+ * This method performs ST25TB Collision resolution, selects the each device,
+ * retrieves its UID and then deselects.
+ * In case only one device is identified the ST25TB device is left in select
+ * state.
+ *   
+ * \param[in]  devLimit      : device limit value, and size st25tbDevList
+ * \param[out] st25tbDevList : ST35TB listener device info
+ * \param[out] devCnt        : Devices found counter
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_RF_COLLISION : Collision detected one or more device in the field
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerCollisionResolution(
+    uint8_t devLimit,
+    rfalSt25tbListenDevice* st25tbDevList,
+    uint8_t* devCnt);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Initiate
+ *  
+ * This method sends an Initiate command 
+ * 
+ * If a single device responds the chip ID will be retrieved
+ *   
+ * \param[out]  chipId      : chip ID of the device 
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerInitiate(uint8_t* chipId);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Pcall
+ *  
+ * This method sends a Pcall command 
+ * If successful the device's chip ID will be retrieved
+ *   
+ * \param[out]  chipId      : Chip ID of the device 
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerPcall(uint8_t* chipId);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Slot Marker
+ *  
+ * This method sends a Slot Marker
+ * 
+ * If a single device responds the chip ID will be retrieved
+ *
+ * \param[in]  slotNum      : Slot Number    
+ * \param[out]  chipIdRes   : Chip ID of the device 
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerSlotMarker(uint8_t slotNum, uint8_t* chipIdRes);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Select
+ *  
+ * This method sends a ST25TB Select command with the given chip ID.
+ * 
+ * If the device is already in Selected state and receives an incorrect chip 
+ * ID, it goes into Deselected state
+ *   
+ * \param[in]  chipId       : chip ID of the device to be selected
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerSelect(uint8_t chipId);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Get UID
+ *  
+ * This method sends a Get_UID command
+ * 
+ * If a single device responds the chip UID will be retrieved
+ *
+ * \param[out]  UID      : UID of the found device
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerGetUID(rfalSt25tbUID* UID);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Read Block
+ *  
+ * This method reads a block of the ST25TB
+ * 
+ * \param[in]   blockAddress : address of the block to be read
+ * \param[out]  blockData    : location to place the data read from block
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerReadBlock(uint8_t blockAddress, rfalSt25tbBlock* blockData);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Write Block
+ *  
+ * This method writes a block of the ST25TB
+ * 
+ * \param[in]  blockAddress : address of the block to be written
+ * \param[in]  blockData    : data to be written on the block
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerWriteBlock(uint8_t blockAddress, const rfalSt25tbBlock* blockData);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Completion 
+ *  
+ * This method sends a completion command to the ST25TB. After the 
+ * completion the card no longer will reply to any command.
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected, invalid SENSB_RES received
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerCompletion(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Reset to Inventory
+ *  
+ * This method sends a Reset to Inventory command to the ST25TB.
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error
+ * \return ERR_TIMEOUT      : Timeout error, no listener device detected
+ * \return ERR_PROTO        : Protocol error detected, invalid SENSB_RES received
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalSt25tbPollerResetToInventory(void);
+
+#endif /* RFAL_ST25TB_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 844 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_st25xv.h

@@ -0,0 +1,844 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_st25xv.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief NFC-V ST25 NFC-V Tag specific features
+ *
+ *  This module provides support for ST's specific features available on
+ *  NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25xV
+ * \brief RFAL ST25xV Module
+ * @{
+ * 
+ */
+
+#ifndef RFAL_ST25xV_H
+#define RFAL_ST25xV_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_nfc.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCV_BLOCKNUM_M24LR_LEN \
+    2U /*!< Block Number length of MR24LR tags: 16 bits                */
+#define RFAL_NFCV_ST_IC_MFG_CODE \
+    0x02 /*!< ST IC Mfg code (used for custom commands)                  */
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Single Block (M24LR)
+ *  
+ * Reads a Single Block from a M24LR tag which has the number of blocks 
+ * bigger than 256 (M24LR16 ; M24LR64)
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            default: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if not provided Select mode will be used 
+ * \param[in]  blockNum     : Number of the block to read (16 bits)
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerM24LRReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Single Block (M24LR)
+ *  
+ * Reads a Single Block from a M24LR tag which has the number of blocks 
+ * bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            default: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if not provided Select mode will be used 
+ * \param[in]  blockNum     : Number of the block to read (16 bits)
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Single Block (M24LR)
+ *  
+ * Writes a Single Block from a M24LR tag which has the number of blocks 
+ * bigger than 256 (M24LR16 ; M24LR64)
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be written
+ *                             if not provided Select mode will be used 
+ * \param[in]  blockNum     : Number of the block to write (16 bits)
+ * \param[in]  wrData       : data to be written on the given block
+ * \param[in]  blockLen     : number of bytes of a block
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerM24LRWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Multiple Blocks (M24LR)
+ *  
+ * Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks 
+ * bigger than 256 (M24LR16 ; M24LR64)  
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  firstBlockNum  : first block to be read (16 bits)
+ * \param[in]  numOfBlocks    : number of block to read
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Multiple Blocks (M24LR)
+ *  
+ * Reads Multiple Blocks from a device from a M24LR tag which has the number of blocks 
+ * bigger than 256 (M24LR16 ; M24LR64) using ST Fast mode
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  firstBlockNum  : first block to be read (16 bits)
+ * \param[in]  numOfBlocks    : number of block to read
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Single Block
+ *  
+ * Reads a Single Block from a device (VICC) using ST Fast mode
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if not provided Select mode will be used 
+ * \param[in]  blockNum     : Number of the block to read
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Multiple Blocks
+ *  
+ * Reads Multiple Blocks from a device (VICC) using ST Fast mode
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  firstBlockNum  : first block to be read
+ * \param[in]  numOfBlocks    : number of block to read
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Extended Read Single Block
+ *  
+ * Reads a Single Block from a device (VICC) supporting extended commands using ST Fast mode
+ *
+ * \param[in]  flags        : Flags to be used: Sub-carrier; Data_rate; Option
+ *                            for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid          : UID of the device to be put to be read
+ *                             if not provided Select mode will be used 
+ * \param[in]  blockNum     : Number of the block to read (16 bits)
+ * \param[out] rxBuf        : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen     : length of rxBuf
+ * \param[out] rcvLen       : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE  : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM        : Invalid parameters
+ * \return ERR_IO           : Generic internal error 
+ * \return ERR_CRC          : CRC error detected
+ * \return ERR_FRAMING      : Framing error detected
+ * \return ERR_PROTO        : Protocol error detected
+ * \return ERR_TIMEOUT      : Timeout error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Extended Read Multiple Blocks
+ *  
+ * Reads Multiple Blocks from a device (VICC) supporting extended commands using ST Fast mode
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  firstBlockNum  : first block to be read (16 bits)
+ * \param[in]  numOfBlocks    : number of consecutive blocks to read (16 bits)
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Configuration
+ *  
+ * Reads static configuration registers at the Pointer address
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[out] regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerReadConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Configuration
+ *  
+ * Writes static configuration registers at the Pointer address
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[in]  regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerWriteConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Dynamic Configuration
+ *  
+ * Reads dynamic registers at the Pointer address
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[out] regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerReadDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Dynamic Configuration
+ *  
+ * Writes dynamic registers at the Pointer address
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[in]  regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerWriteDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Dynamic Configuration
+ *  
+ * Reads dynamic registers at the Pointer address using ST Fast mode
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[out] regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastReadDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Write Dynamic Configuration
+ *  
+ * Writes dynamic registers at the Pointer address using ST Fast mode
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pointer        : Pointer address
+ * \param[in]  regValue       : Register value
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Present Password
+ *  
+ * Sends the Present Password command
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  pwdNum         : Password number
+ * \param[in]  pwd            : Password
+ * \param[in]  pwdLen         : Password length
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerPresentPassword(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pwdNum,
+    const uint8_t* pwd,
+    uint8_t pwdLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Get Random Number
+ *  
+ *  Returns a 16 bit random number
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerGetRandomNumber(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Message length
+ *  
+ * Sends a Read Message Length message to retrieve the value of MB_LEN_Dyn 
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[out] msgLen         : Message Length
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerReadMessageLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Message length
+ *  
+ * Sends a Fast Read Message Length message to retrieve the value of MB_LEN_Dyn using ST Fast mode.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[out] msgLen         : Message Length
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastReadMsgLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Read Message
+ *  
+ * Reads up to 256 bytes in the Mailbox from the location
+ * specified by MBpointer and sends back their value in the rxBuf response.
+ * First MailBox location is '00'. When Number of bytes is set to 00h 
+ * and MBPointer is equals to 00h, the MB_LEN bytes of the full message 
+ * are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes 
+ * (i.e. 01h returns 2 bytes, FFh returns 256 bytes).
+ * An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length. 
+ * RF Reading of the last byte of the mailbox message automatically clears b1 
+ * of MB_CTRL_Dyn HOST_PUT_MSG, and allows RF to put a new message.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  mbPointer      : MPpointer
+ * \param[in]  numBytes       : number of bytes
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerReadMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Read Message
+ *  
+ * Reads up to 256 bytes in the Mailbox from the location
+ * specified by MBpointer and sends back their value in the rxBuf response using ST Fast mode.
+ * First MailBox location is '00'. When Number of bytes is set to 00h 
+ * and MBPointer is equals to 00h, the MB_LEN bytes of the full message 
+ * are returned. Otherwise, Read Message command returns (Number of Bytes + 1) bytes 
+ * (i.e. 01h returns 2 bytes, FFh returns 256 bytes).
+ * An error is reported if (Pointer + Nb of bytes + 1) is greater than the message length. 
+ * RF Reading of the last byte of the mailbox message automatically clears b1 
+ * of MB_CTRL_Dyn  HOST_PUT_MSG, and allows RF to put a new message.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  mbPointer      : MPpointer
+ * \param[in]  numBytes       : number of bytes
+ * \param[out] rxBuf          : buffer to store response (also with RES_FLAGS)
+ * \param[in]  rxBufLen       : length of rxBuf
+ * \param[out] rcvLen         : number of bytes received
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastReadMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Write Message
+ *  
+ * Sends Write message Command
+ *
+ * On receiving the Write Message command, the ST25DVxxx puts the data contained 
+ * in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and 
+ * set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful 
+ * in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the
+ *  first location '00'. MSGlength parameter of the command is the number of 
+ * Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data). 
+ * Write Message could be executed only when Mailbox is accessible by RF.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  msgLen         : MSGLen  number of Data bytes minus 1
+ * \param[in]  msgData        : Message Data
+ * \param[out] txBuf          : buffer to used to build the Write Message command 
+ * \param[in]  txBufLen       : length of txBuf
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerWriteMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-V Poller Fast Write Message
+ *  
+ * Sends Fast Write message Command using ST Fast mode
+ * 
+ * On receiving the Write Message command, the ST25DVxxx puts the data contained 
+ * in the request into the Mailbox buffer, update the MB_LEN_Dyn register, and 
+ * set bit RF_PUT_MSG in MB_CTRL_Dyn register. It then reports if the write operation was successful 
+ * in the response. The ST25DVxxx Mailbox contains up to 256 data bytes which are filled from the
+ *  first location '00'. MSGlength parameter of the command is the number of 
+ * Data bytes minus 1 (00 for 1 byte of data, FFh for 256 bytes of data). 
+ * Write Message could be executed only when Mailbox is accessible by RF.
+ *
+ * \param[in]  flags          : Flags to be used: Sub-carrier; Data_rate; Option
+ *                              for NFC-Forum use: RFAL_NFCV_REQ_FLAG_DEFAULT
+ * \param[in]  uid            : UID of the device to be put to be read
+ *                               if not provided Select mode will be used 
+ * \param[in]  msgLen         : MSGLen  number of Data bytes minus 1
+ * \param[in]  msgData        : Message Data
+ * \param[out] txBuf          : buffer to used to build the Write Message command 
+ * \param[in]  txBufLen       : length of txBuf
+ *  
+ * \return ERR_WRONG_STATE    : RFAL not initialized or incorrect mode
+ * \return ERR_PARAM          : Invalid parameters
+ * \return ERR_IO             : Generic internal error 
+ * \return ERR_CRC            : CRC error detected
+ * \return ERR_FRAMING        : Framing error detected
+ * \return ERR_PROTO          : Protocol error detected
+ * \return ERR_TIMEOUT        : Timeout error
+ * \return ERR_NONE           : No error
+ *****************************************************************************
+ */
+ReturnCode rfalST25xVPollerFastWriteMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen);
+
+#endif /* RFAL_ST25xV_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 178 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t1t.h

@@ -0,0 +1,178 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t1t.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides NFC-A T1T convenience methods and definitions
+ *  
+ *  This module provides an interface to perform as a NFC-A Reader/Writer
+ *  to handle a Type 1 Tag T1T (Topaz)
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup T1T
+ * \brief RFAL T1T Module
+ * @{
+ *  
+ */
+
+#ifndef RFAL_T1T_H
+#define RFAL_T1T_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+#define RFAL_T1T_UID_LEN 4 /*!< T1T UID length of cascade level 1 only tag  */
+#define RFAL_T1T_HR_LENGTH 2 /*!< T1T HR(Header ROM) length                   */
+
+#define RFAL_T1T_HR0_NDEF_MASK 0xF0 /*!< T1T HR0 NDEF capability mask  T1T 1.2 2.2.2 */
+#define RFAL_T1T_HR0_NDEF_SUPPORT 0x10 /*!< T1T HR0 NDEF capable value    T1T 1.2 2.2.2 */
+
+/*! NFC-A T1T (Topaz) command set */
+typedef enum {
+    RFAL_T1T_CMD_RID = 0x78, /*!< T1T Read UID                                */
+    RFAL_T1T_CMD_RALL = 0x00, /*!< T1T Read All                                */
+    RFAL_T1T_CMD_READ = 0x01, /*!< T1T Read                                    */
+    RFAL_T1T_CMD_WRITE_E = 0x53, /*!< T1T Write with erase (single byte)          */
+    RFAL_T1T_CMD_WRITE_NE = 0x1A /*!< T1T Write with no erase (single byte)       */
+} rfalT1Tcmds;
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-A T1T (Topaz) RID_RES  Digital 1.1  10.6.2 & Table 50 */
+typedef struct {
+    uint8_t hr0; /*!< T1T Header ROM: HR0                         */
+    uint8_t hr1; /*!< T1T Header ROM: HR1                         */
+    uint8_t uid[RFAL_T1T_UID_LEN]; /*!< T1T UID                                     */
+} rfalT1TRidRes;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Initialize NFC-A T1T Poller mode
+ *  
+ * This methods configures RFAL RF layer to perform as a 
+ * NFC-A T1T Poller/RW (Topaz) including all default timings 
+ *
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT1TPollerInitialize(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T1T Poller RID
+ *  
+ * This method reads the UID of a NFC-A T1T Listener device  
+ *
+ *
+ * \param[out]  ridRes : pointer to place the RID_RES
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT1TPollerRid(rfalT1TRidRes* ridRes);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T1T Poller RALL
+ *  
+ * This method send a Read All command to a NFC-A T1T Listener device  
+ *
+ *
+ * \param[in]   uid       : the UID of the device to read data
+ * \param[out]  rxBuf     : pointer to place the read data
+ * \param[in]   rxBufLen  : size of rxBuf
+ * \param[out]  rxRcvdLen : actual received data
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode
+    rfalT1TPollerRall(const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxRcvdLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T1T Poller Write
+ *  
+ * This method writes the given data on the address of a NFC-A T1T Listener device  
+ *
+ *
+ * \param[in]   uid       : the UID of the device to read data
+ * \param[in]   address   : address to write the data
+ * \param[in]   data      : the data to be written
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT1TPollerWrite(const uint8_t* uid, uint8_t address, uint8_t data);
+
+#endif /* RFAL_T1T_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 150 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t2t.h

@@ -0,0 +1,150 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t2t.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides NFC-A T2T convenience methods and definitions
+ *  
+ *  This module provides an interface to perform as a NFC-A Reader/Writer
+ *  to handle a Type 2 Tag T2T
+ *  
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup T2T
+ * \brief RFAL T2T Module
+ * @{
+ *  
+ */
+
+#ifndef RFAL_T2T_H
+#define RFAL_T2T_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_T2T_BLOCK_LEN 4U /*!< T2T block length           */
+#define RFAL_T2T_READ_DATA_LEN (4U * RFAL_T2T_BLOCK_LEN) /*!< T2T READ data length       */
+#define RFAL_T2T_WRITE_DATA_LEN RFAL_T2T_BLOCK_LEN /*!< T2T WRITE data length      */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T2T Poller Read
+ *  
+ * This method sends a Read command to a NFC-A T2T Listener device  
+ *
+ *
+ * \param[in]   blockNum    : Number of the block to read
+ * \param[out]  rxBuf       : pointer to place the read data
+ * \param[in]   rxBufLen    : size of rxBuf (RFAL_T2T_READ_DATA_LEN)
+ * \param[out]  rcvLen   : actual received data
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode
+    rfalT2TPollerRead(uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rcvLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T2T Poller Write
+ *  
+ * This method sends a Write command to a NFC-A T2T Listener device  
+ *
+ *
+ * \param[in]  blockNum     : Number of the block to write
+ * \param[in]  wrData       : data to be written on the given block
+ *                            size must be of RFAL_T2T_WRITE_DATA_LEN
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT2TPollerWrite(uint8_t blockNum, const uint8_t* wrData);
+
+/*! 
+ *****************************************************************************
+ * \brief  NFC-A T2T Poller Sector Select 
+ *  
+ * This method sends a Sector Select commands to a NFC-A T2T Listener device  
+ *
+ * \param[in]  sectorNum    : Sector Number
+ * 
+ * \return ERR_WRONG_STATE  : RFAL not initialized or mode not set
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT2TPollerSectorSelect(uint8_t sectorNum);
+
+#endif /* RFAL_T2T_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 395 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/include/rfal_t4t.h

@@ -0,0 +1,395 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t4t.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides convenience methods and definitions for T4T (ISO7816-4)
+ *  
+ *  This module provides an interface to exchange T4T APDUs according to 
+ *  NFC Forum T4T and ISO7816-4
+ *  
+ *  This implementation was based on the following specs:
+ *    - ISO/IEC 7816-4  3rd Edition 2013-04-15
+ *    - NFC Forum T4T Technical Specification 1.0 2017-08-28
+ *  
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-AL
+ * \brief RFAL Abstraction Layer
+ * @{
+ *
+ * \addtogroup T4T
+ * \brief RFAL T4T Module
+ * @{
+ *  
+ */
+
+#ifndef RFAL_T4T_H
+#define RFAL_T4T_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../platform.h"
+#include "../st_errno.h"
+#include "rfal_rf.h"
+#include "rfal_isoDep.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN \
+    4U /*!< Command-APDU prologue length (CLA INS P1 P2)                    */
+#define RFAL_T4T_LE_LEN 1U /*!< Le Expected Response Length (short field coding)                */
+#define RFAL_T4T_LC_LEN 1U /*!< Lc Data field length  (short field coding)                      */
+#define RFAL_T4T_MAX_RAPDU_SW1SW2_LEN \
+    2U /*!< SW1 SW2 length                                                  */
+#define RFAL_T4T_CLA 0x00U /*!< Class byte (contains 00h because secure message are not used)   */
+
+#define RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME \
+    0x04U /*!< P1 value for Select by name                                     */
+#define RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID \
+    0x00U /*!< P1 value for Select by file identifier                          */
+#define RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE \
+    0x00U /*!<      b2b1 P2 value for First or only occurrence                 */
+#define RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE \
+    0x00U /*!< b4b3      P2 value for Return FCI template                      */
+#define RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA \
+    0x0CU /*!< b4b3      P2 value for No response data                         */
+
+#define RFAL_T4T_ISO7816_STATUS_COMPLETE \
+    0x9000U /*!< Command completed \ Normal processing - No further qualification*/
+
+/*
+******************************************************************************
+* GLOBAL VARIABLES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+/*! NFC-A T4T Command-APDU structure */
+typedef struct {
+    uint8_t CLA; /*!< Class byte                                         */
+    uint8_t INS; /*!< Instruction byte                                   */
+    uint8_t P1; /*!< Parameter byte 1                                   */
+    uint8_t P2; /*!< Parameter byte 2                                   */
+    uint8_t Lc; /*!< Data field length                                  */
+    bool LcFlag; /*!< Lc flag (append Lc when true)                      */
+    uint8_t Le; /*!< Expected Response Length                           */
+    bool LeFlag; /*!< Le flag (append Le when true)                      */
+
+    rfalIsoDepApduBufFormat* cApduBuf; /*!< Command-APDU buffer  (Tx)                          */
+    uint16_t* cApduLen; /*!< Command-APDU Length                                */
+} rfalT4tCApduParam;
+
+/*! NFC-A T4T Response-APDU structure */
+typedef struct {
+    rfalIsoDepApduBufFormat* rApduBuf; /*!< Response-APDU buffer (Rx)                          */
+    uint16_t rcvdLen; /*!< Full response length                               */
+    uint16_t rApduBodyLen; /*!< Response body length                               */
+    uint16_t statusWord; /*!< R-APDU Status Word SW1|SW2                         */
+} rfalT4tRApduParam;
+
+/*! NFC-A T4T command set    T4T 1.0 & ISO7816-4 2013 Table 4 */
+typedef enum {
+    RFAL_T4T_INS_SELECT = 0xA4U, /*!< T4T Select                                         */
+    RFAL_T4T_INS_READBINARY = 0xB0U, /*!< T4T ReadBinary                                     */
+    RFAL_T4T_INS_UPDATEBINARY = 0xD6U, /*!< T4T UpdateBinay                                    */
+    RFAL_T4T_INS_READBINARY_ODO = 0xB1U, /*!< T4T ReadBinary using ODO                           */
+    RFAL_T4T_INS_UPDATEBINARY_ODO =
+        0xD7U /*!< T4T UpdateBinay using ODO                          */
+} rfalT4tCmds;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose APDU
+ *  
+ * This method computes a C-APDU according to NFC Forum T4T and ISO7816-4.
+ * 
+ * If C-APDU contains data to be sent, it must be placed inside the buffer
+ *   rfalT4tTxRxApduParam.txRx.cApduBuf.apdu and signaled by Lc
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * \see rfalT4TPollerParseRAPDU()
+ *
+ * \warning The ISO-DEP module is used to perform the tranceive. Usually 
+ *          activation has been done via ISO-DEP activatiavtion. If not
+ *          please call rfalIsoDepInitialize() before.
+ * 
+ * \param[in,out] apduParam : APDU parameters
+ *                            apduParam.cApduLen will contain the APDU length 
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeCAPDU(const rfalT4tCApduParam* apduParam);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Parse R-APDU
+ *  
+ * This method parses a R-APDU according to NFC Forum T4T and ISO7816-4.
+ * It will extract the data length and check if the Status word is expected.
+ *
+ * \param[in,out] apduParam : APDU parameters
+ *                            apduParam.rApduBodyLen will contain the data length 
+ *                            apduParam.statusWord will contain the SW1 and SW2 
+ * 
+ * \return ERR_REQUEST      : Status word (SW1 SW2) different from 9000
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerParseRAPDU(rfalT4tRApduParam* apduParam);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Select Application APDU
+ *  
+ * This method computes a Select Application APDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      aid      : Application ID to be used
+ * \param[in]      aidLen   : Application ID length
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeSelectAppl(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* aid,
+    uint8_t aidLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Select File APDU
+ *  
+ * This method computes a Select File APDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      fid      : File ID to be used
+ * \param[in]      fidLen   : File ID length
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeSelectFile(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* fid,
+    uint8_t fidLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Select File APDU for Mapping Version 1
+ *  
+ * This method computes a Select File APDU according to NFC Forum T4TOP_v1.0
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      fid      : File ID to be used
+ * \param[in]      fidLen   : File ID length
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeSelectFileV1Mapping(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* fid,
+    uint8_t fidLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Read Data APDU
+ *  
+ * This method computes a Read Data APDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      offset   : File offset
+ * \param[in]      expLen   : Expected length (Le)
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeReadData(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint16_t offset,
+    uint8_t expLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Read Data ODO APDU
+ *  
+ * This method computes a Read Data ODO APDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      offset   : File offset
+ * \param[in]      expLen   : Expected length (Le)
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeReadDataODO(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint32_t offset,
+    uint8_t expLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Write Data APDU
+ *  
+ * This method computes a Write Data APDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      offset   : File offset
+ * \param[in]      data     : Data to be written
+ * \param[in]      dataLen  : Data length to be written (Lc)
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeWriteData(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint16_t offset,
+    const uint8_t* data,
+    uint8_t dataLen,
+    uint16_t* cApduLen);
+
+/*! 
+ *****************************************************************************
+ * \brief  T4T Compose Write Data ODO APDU
+ *  
+ * This method computes a Write Data ODO sAPDU according to NFC Forum T4T
+ *
+ * To transceive the formed APDU the ISO-DEP layer shall be used
+ *
+ * \see rfalIsoDepStartApduTransceive()
+ * \see rfalIsoDepGetApduTransceiveStatus()
+ * 
+ * \param[out]     cApduBuf : buffer where the C-APDU will be placed
+ * \param[in]      offset   : File offset
+ * \param[in]      data     : Data to be written
+ * \param[in]      dataLen  : Data length to be written (Lc)
+ * \param[out]     cApduLen : Composed C-APDU length
+ * 
+ * \return ERR_PARAM        : Invalid parameter
+ * \return ERR_PROTO        : Protocol error
+ * \return ERR_NONE         : No error
+ *****************************************************************************
+ */
+ReturnCode rfalT4TPollerComposeWriteDataODO(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint32_t offset,
+    const uint8_t* data,
+    uint8_t dataLen,
+    uint16_t* cApduLen);
+
+#endif /* RFAL_T4T_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  */

+ 104 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/platform.c

@@ -0,0 +1,104 @@
+#include "platform.h"
+#include <assert.h>
+#include <furi.h>
+#include <furi_hal_spi.h>
+
+typedef struct {
+    FuriThread* thread;
+    volatile PlatformIrqCallback callback;
+    bool need_spi_lock;
+} RfalPlatform;
+
+static volatile RfalPlatform rfal_platform = {
+    .thread = NULL,
+    .callback = NULL,
+    .need_spi_lock = true,
+};
+
+void nfc_isr(void* _ctx) {
+    UNUSED(_ctx);
+    if(rfal_platform.callback && platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
+        furi_thread_flags_set(furi_thread_get_id(rfal_platform.thread), 0x1);
+    }
+}
+
+int32_t rfal_platform_irq_thread(void* context) {
+    UNUSED(context);
+
+    while(1) {
+        uint32_t flags = furi_thread_flags_wait(0x1, FuriFlagWaitAny, FuriWaitForever);
+        if(flags & 0x1) {
+            rfal_platform.callback();
+        }
+    }
+}
+
+void platformEnableIrqCallback() {
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedLow);
+    furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull);
+}
+
+void platformDisableIrqCallback() {
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
+    furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
+}
+
+void platformSetIrqCallback(PlatformIrqCallback callback) {
+    rfal_platform.callback = callback;
+
+    if(!rfal_platform.thread) {
+        rfal_platform.thread =
+            furi_thread_alloc_ex("RfalIrqDriver", 1024, rfal_platform_irq_thread, NULL);
+        furi_thread_set_priority(rfal_platform.thread, FuriThreadPriorityIsr);
+        furi_thread_start(rfal_platform.thread);
+    }
+
+    furi_hal_gpio_remove_int_callback(&gpio_nfc_irq_rfid_pull);
+
+    furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, nfc_isr, NULL);
+    // Disable interrupt callback as the pin is shared between 2 apps
+    // It is enabled in rfalLowPowerModeStop()
+    furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull);
+}
+
+bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) {
+    bool ret = false;
+    if(txBuf && rxBuf) {
+        ret =
+            furi_hal_spi_bus_trx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, rxBuf, len, 1000);
+    } else if(txBuf) {
+        ret = furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, len, 1000);
+    } else if(rxBuf) {
+        ret = furi_hal_spi_bus_rx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)rxBuf, len, 1000);
+    }
+
+    return ret;
+}
+
+// Until we completely remove RFAL, NFC works with SPI from rfal_platform_irq_thread and nfc_worker
+// threads. Some nfc features already stop using RFAL and work with SPI from nfc_worker only.
+// rfal_platform_spi_acquire() and rfal_platform_spi_release() functions are used to lock SPI for a
+// long term without locking it for each SPI transaction. This is needed for time critical communications.
+void rfal_platform_spi_acquire() {
+    platformDisableIrqCallback();
+    rfal_platform.need_spi_lock = false;
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
+}
+
+void rfal_platform_spi_release() {
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
+    rfal_platform.need_spi_lock = true;
+    platformEnableIrqCallback();
+}
+
+void platformProtectST25RComm() {
+    if(rfal_platform.need_spi_lock) {
+        furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
+    }
+}
+
+void platformUnprotectST25RComm() {
+    if(rfal_platform.need_spi_lock) {
+        furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
+    }
+}

+ 188 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/platform.h

@@ -0,0 +1,188 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <limits.h>
+#include "timer.h"
+#include "math.h"
+#include <furi_hal_gpio.h>
+#include <furi_hal_light.h>
+#include <furi_hal_spi.h>
+
+typedef void (*PlatformIrqCallback)();
+void platformSetIrqCallback(PlatformIrqCallback cb);
+void platformEnableIrqCallback();
+void platformDisableIrqCallback();
+
+bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len);
+void platformProtectST25RComm();
+void platformUnprotectST25RComm();
+void rfal_platform_spi_acquire();
+void rfal_platform_spi_release();
+
+#define ST25R_SS_PIN NFC_CS_Pin
+#define ST25R_SS_PORT NFC_CS_GPIO_Port
+
+#define ST25R_INT_PIN NFC_IRQ_Pin
+#define ST25R_INT_PORT NFC_IRQ_GPIO_Port
+
+#define RFAL_ANALOG_CONFIG_CUSTOM \
+    true /*!< Enable/Disable RFAL custom analog configuration                           */
+
+#define RFAL_FEATURE_LISTEN_MODE \
+    true /*!< Enable/Disable RFAL support for Listen Mode                               */
+#define RFAL_FEATURE_WAKEUP_MODE \
+    true /*!< Enable/Disable RFAL support for the Wake-Up mode                          */
+#define RFAL_FEATURE_LOWPOWER_MODE \
+    true /*!< Enable/Disable RFAL support for the Low Power mode                        */
+#define RFAL_FEATURE_NFCA \
+    true /*!< Enable/Disable RFAL support for NFC-A (ISO14443A)                         */
+#define RFAL_FEATURE_NFCB \
+    true /*!< Enable/Disable RFAL support for NFC-B (ISO14443B)                         */
+#define RFAL_FEATURE_NFCF \
+    true /*!< Enable/Disable RFAL support for NFC-F (FeliCa)                            */
+#define RFAL_FEATURE_NFCV \
+    true /*!< Enable/Disable RFAL support for NFC-V (ISO15693)                          */
+#define RFAL_FEATURE_T1T \
+    true /*!< Enable/Disable RFAL support for T1T (Topaz)                               */
+#define RFAL_FEATURE_T2T \
+    true /*!< Enable/Disable RFAL support for T2T (MIFARE Ultralight)                   */
+#define RFAL_FEATURE_T4T \
+    true /*!< Enable/Disable RFAL support for T4T                                       */
+#define RFAL_FEATURE_ST25TB \
+    true /*!< Enable/Disable RFAL support for ST25TB                                    */
+#define RFAL_FEATURE_ST25xV \
+    true /*!< Enable/Disable RFAL support for ST25TV/ST25DV                             */
+#define RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG \
+    false /*!< Enable/Disable Analog Configs to be dynamically updated (RAM)             */
+#define RFAL_FEATURE_DPO \
+    false /*!< Enable/Disable RFAL Dynamic Power Output upport                           */
+#define RFAL_FEATURE_ISO_DEP \
+    true /*!< Enable/Disable RFAL support for ISO-DEP (ISO14443-4)                      */
+#define RFAL_FEATURE_ISO_DEP_POLL \
+    true /*!< Enable/Disable RFAL support for Poller mode (PCD) ISO-DEP (ISO14443-4)    */
+#define RFAL_FEATURE_ISO_DEP_LISTEN \
+    true /*!< Enable/Disable RFAL support for Listen mode (PICC) ISO-DEP (ISO14443-4)   */
+#define RFAL_FEATURE_NFC_DEP \
+    true /*!< Enable/Disable RFAL support for NFC-DEP (NFCIP1/P2P)                      */
+
+#define RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN \
+    256U /*!< ISO-DEP I-Block max length. Please use values as defined by rfalIsoDepFSx */
+#define RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN \
+    254U /*!< NFC-DEP Block/Payload length. Allowed values: 64, 128, 192, 254           */
+#define RFAL_FEATURE_NFC_RF_BUF_LEN \
+    256U /*!< RF buffer length used by RFAL NFC layer                                   */
+
+#define RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN \
+    512U /*!< ISO-DEP APDU max length.                                                  */
+#define RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN \
+    512U /*!< NFC-DEP PDU max length.                                                   */
+
+#define platformIrqST25RSetCallback(cb) platformSetIrqCallback(cb)
+
+#define platformProtectST25RIrqStatus() \
+    platformProtectST25RComm() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */
+#define platformUnprotectST25RIrqStatus() \
+    platformUnprotectST25RComm() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment         */
+
+#define platformGpioSet(port, pin) \
+    furi_hal_gpio_write_port_pin(  \
+        port, pin, true) /*!< Turns the given GPIO High                   */
+#define platformGpioClear(port, pin) \
+    furi_hal_gpio_write_port_pin(    \
+        port, pin, false) /*!< Turns the given GPIO Low                    */
+
+#define platformGpioIsHigh(port, pin)          \
+    (furi_hal_gpio_read_port_pin(port, pin) == \
+     true) /*!< Checks if the given LED is High             */
+#define platformGpioIsLow(port, pin) \
+    (!platformGpioIsHigh(port, pin)) /*!< Checks if the given LED is Low              */
+
+#define platformTimerCreate(t) \
+    timerCalculateTimer(t) /*!< Create a timer with the given time (ms)     */
+#define platformTimerIsExpired(timer) \
+    timerIsExpired(timer) /*!< Checks if the given timer is expired        */
+#define platformDelay(t) furi_delay_ms(t) /*!< Performs a delay for the given time (ms)    */
+
+#define platformGetSysTick() furi_get_tick() /*!< Get System Tick (1 tick = 1 ms)             */
+
+#define platformAssert(exp) assert_param(exp) /*!< Asserts whether the given expression is true*/
+
+#define platformSpiSelect() \
+    platformGpioClear(      \
+        ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Select                */
+#define platformSpiDeselect() \
+    platformGpioSet(          \
+        ST25R_SS_PORT, ST25R_SS_PIN) /*!< SPI SS\CS: Chip|Slave Deselect              */
+
+#define platformI2CTx(txBuf, len, last, txOnly) /*!< I2C Transmit                                */
+#define platformI2CRx(txBuf, len) /*!< I2C Receive                                 */
+#define platformI2CStart() /*!< I2C Start condition                         */
+#define platformI2CStop() /*!< I2C Stop condition                          */
+#define platformI2CRepeatStart() /*!< I2C Repeat Start                            */
+#define platformI2CSlaveAddrWR(add) /*!< I2C Slave address for Write operation       */
+#define platformI2CSlaveAddrRD(add) /*!< I2C Slave address for Read operation        */
+
+#define platformLog(...) /*!< Log  method                                 */
+
+/*
+ ******************************************************************************
+ * RFAL OPTIONAL MACROS            (Do not change)
+ ******************************************************************************
+ */
+#ifndef platformProtectST25RIrqStatus
+#define platformProtectST25RIrqStatus() /*!< Protect unique access to IRQ status var - IRQ disable on single thread environment (MCU) ; Mutex lock on a multi thread environment */
+#endif /* platformProtectST25RIrqStatus */
+
+#ifndef platformUnprotectST25RIrqStatus
+#define platformUnprotectST25RIrqStatus() /*!< Unprotect the IRQ status var - IRQ enable on a single thread environment (MCU) ; Mutex unlock on a multi thread environment         */
+#endif /* platformUnprotectST25RIrqStatus */
+
+#ifndef platformProtectWorker
+#define platformProtectWorker() /* Protect RFAL Worker/Task/Process from concurrent execution on multi thread platforms   */
+#endif /* platformProtectWorker */
+
+#ifndef platformUnprotectWorker
+#define platformUnprotectWorker() /* Unprotect RFAL Worker/Task/Process from concurrent execution on multi thread platforms */
+#endif /* platformUnprotectWorker */
+
+#ifndef platformIrqST25RPinInitialize
+#define platformIrqST25RPinInitialize() /*!< Initializes ST25R IRQ pin                    */
+#endif /* platformIrqST25RPinInitialize */
+
+#ifndef platformIrqST25RSetCallback
+#define platformIrqST25RSetCallback(cb) /*!< Sets ST25R ISR callback                      */
+#endif /* platformIrqST25RSetCallback */
+
+#ifndef platformLedsInitialize
+#define platformLedsInitialize() /*!< Initializes the pins used as LEDs to outputs */
+#endif /* platformLedsInitialize */
+
+#ifndef platformLedOff
+#define platformLedOff(port, pin) /*!< Turns the given LED Off                      */
+#endif /* platformLedOff */
+
+#ifndef platformLedOn
+#define platformLedOn(port, pin) /*!< Turns the given LED On                       */
+#endif /* platformLedOn */
+
+#ifndef platformLedToogle
+#define platformLedToogle(port, pin) /*!< Toggles the given LED                        */
+#endif /* platformLedToogle */
+
+#ifndef platformGetSysTick
+#define platformGetSysTick() /*!< Get System Tick (1 tick = 1 ms)              */
+#endif /* platformGetSysTick */
+
+#ifndef platformTimerDestroy
+#define platformTimerDestroy(timer) /*!< Stops and released the given timer           */
+#endif /* platformTimerDestroy */
+
+#ifndef platformAssert
+#define platformAssert(exp) /*!< Asserts whether the given expression is true */
+#endif /* platformAssert */
+
+#ifndef platformErrorHandle
+#define platformErrorHandle() /*!< Global error handler or trap                 */
+#endif /* platformErrorHandle */

+ 777 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/custom_analog_config.c

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

+ 480 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_analogConfig.c

@@ -0,0 +1,480 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_analogConfig.c
+ *
+ *  \author bkam
+ *
+ *  \brief Functions to manage and set analog settings.
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_analogConfig.h"
+#include "../include/rfal_chip.h"
+#include "../st_errno.h"
+#include "../platform.h"
+#include "../utils.h"
+
+/* Check whether the Default Analog settings are to be used or custom ones */
+#ifdef RFAL_ANALOG_CONFIG_CUSTOM
+extern const uint8_t* rfalAnalogConfigCustomSettings;
+extern const uint16_t rfalAnalogConfigCustomSettingsLength;
+#else
+#include "st25r3916/rfal_analogConfigTbl.h"
+#endif
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_TEST_REG 0x0080U /*!< Test Register indicator  */
+
+/*
+ ******************************************************************************
+ * MACROS
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * LOCAL DATA TYPES
+ ******************************************************************************
+ */
+
+#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
+static uint8_t
+    gRfalAnalogConfig[RFAL_ANALOG_CONFIG_TBL_SIZE]; /*!< Analog Configuration Settings List */
+#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
+
+/*! Struct for Analog Config Look Up Table Update */
+typedef struct {
+    const uint8_t*
+        currentAnalogConfigTbl; /*!< Reference to start of current Analog Configuration      */
+    uint16_t configTblSize; /*!< Total size of Analog Configuration                      */
+    bool ready; /*!< Indicate if Look Up Table is complete and ready for use */
+} rfalAnalogConfigMgmt;
+
+static rfalAnalogConfigMgmt gRfalAnalogConfigMgmt; /*!< Analog Configuration LUT management */
+
+/*
+ ******************************************************************************
+ * LOCAL TABLES
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+static rfalAnalogConfigNum
+    rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset);
+
+#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
+static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl);
+#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
+
+/*
+ ******************************************************************************
+ * GLOBAL VARIABLE DEFINITIONS
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+
+void rfalAnalogConfigInitialize(void) {
+    /* Use default Analog configuration settings in Flash by default. */
+
+/* Check whether the Default Analog settings are to be used or custom ones */
+#ifdef RFAL_ANALOG_CONFIG_CUSTOM
+    gRfalAnalogConfigMgmt.currentAnalogConfigTbl = (const uint8_t*)&rfalAnalogConfigCustomSettings;
+    gRfalAnalogConfigMgmt.configTblSize = rfalAnalogConfigCustomSettingsLength;
+#else
+    gRfalAnalogConfigMgmt.currentAnalogConfigTbl =
+        (const uint8_t*)&rfalAnalogConfigDefaultSettings;
+    gRfalAnalogConfigMgmt.configTblSize = sizeof(rfalAnalogConfigDefaultSettings);
+#endif
+
+    gRfalAnalogConfigMgmt.ready = true;
+} /* rfalAnalogConfigInitialize() */
+
+bool rfalAnalogConfigIsReady(void) {
+    return gRfalAnalogConfigMgmt.ready;
+}
+
+ReturnCode rfalAnalogConfigListWriteRaw(const uint8_t* configTbl, uint16_t configTblSize) {
+#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
+
+    /* Check if the Configuration Table exceed the Table size */
+    if(configTblSize >= RFAL_ANALOG_CONFIG_TBL_SIZE) {
+        rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
+        return ERR_NOMEM;
+    }
+
+    /* Check for invalid parameters */
+    if((configTbl == NULL) || (configTblSize == 0U)) {
+        return ERR_PARAM;
+    }
+
+    /* NOTE: Function does not check for the validity of the Table contents (conf IDs, conf sets, register address)  */
+    ST_MEMCPY(gRfalAnalogConfig, configTbl, configTblSize);
+
+    /* Update the total size of configuration settings */
+    gRfalAnalogConfigMgmt.configTblSize = configTblSize;
+
+    rfalAnalogConfigPtrUpdate(gRfalAnalogConfig);
+    return ERR_NONE;
+
+#else
+
+    // If Analog Configuration Update is to be disabled
+    NO_WARNING(configTbl);
+    NO_WARNING(configTblSize);
+    return ERR_REQUEST;
+
+#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
+}
+
+ReturnCode rfalAnalogConfigListWrite(uint8_t more, const rfalAnalogConfig* config) {
+#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
+
+    rfalAnalogConfigId configId;
+    rfalAnalogConfigNum numConfig;
+    uint8_t configSize;
+
+    if(true == gRfalAnalogConfigMgmt.ready) { /* First Update to the Configuration list. */
+        gRfalAnalogConfigMgmt.ready = false; // invalidate the config List
+        gRfalAnalogConfigMgmt.configTblSize = 0; // Clear the config List
+    }
+
+    configId = GETU16(config->id);
+
+    /* Check validity of the Configuration ID. */
+    if((RFAL_ANALOG_CONFIG_TECH_RFU <= RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) ||
+       ((RFAL_ANALOG_CONFIG_BITRATE_6780 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId)) &&
+        (RFAL_ANALOG_CONFIG_BITRATE_1OF4 > RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) ||
+       (RFAL_ANALOG_CONFIG_BITRATE_1OF256 < RFAL_ANALOG_CONFIG_ID_GET_BITRATE(configId))) {
+        rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
+        return ERR_PARAM;
+    }
+
+    numConfig = config->num;
+    configSize = (uint8_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) +
+                           (numConfig * sizeof(rfalAnalogConfigRegAddrMaskVal)));
+
+    /* Check if the Configuration Set exceed the Table size. */
+    if(RFAL_ANALOG_CONFIG_TBL_SIZE <= (gRfalAnalogConfigMgmt.configTblSize + configSize)) {
+        rfalAnalogConfigInitialize(); /* Revert to default Analog Configuration */
+        return ERR_NOMEM;
+    }
+
+    /* NOTE: Function does not check for the validity of the Register Address. */
+    ST_MEMCPY(
+        &gRfalAnalogConfig[gRfalAnalogConfigMgmt.configTblSize],
+        (const uint8_t*)config,
+        configSize);
+
+    /* Increment the total size of configuration settings. */
+    gRfalAnalogConfigMgmt.configTblSize += configSize;
+
+    /* Check if it is the last Analog Configuration to load. */
+    if(RFAL_ANALOG_CONFIG_UPDATE_LAST ==
+       more) { /* Update the Analog Configuration to the new settings. */
+        rfalAnalogConfigPtrUpdate(gRfalAnalogConfig);
+    }
+
+    return ERR_NONE;
+
+#else
+
+    // If Analog Configuration Update is to be disabled
+    NO_WARNING(config);
+    NO_WARNING(more);
+    return ERR_DISABLED;
+
+#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
+
+} /* rfalAnalogConfigListUpdate() */
+
+ReturnCode
+    rfalAnalogConfigListReadRaw(uint8_t* tblBuf, uint16_t tblBufLen, uint16_t* configTblSize) {
+    /* Check if the the current table will fit into the given buffer */
+    if(tblBufLen < gRfalAnalogConfigMgmt.configTblSize) {
+        return ERR_NOMEM;
+    }
+
+    /* Check for invalid parameters */
+    if(configTblSize == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Copy the whole Table to the given buffer */
+    if(gRfalAnalogConfigMgmt.configTblSize > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(
+            tblBuf,
+            gRfalAnalogConfigMgmt.currentAnalogConfigTbl,
+            gRfalAnalogConfigMgmt.configTblSize);
+    }
+    *configTblSize = gRfalAnalogConfigMgmt.configTblSize;
+
+    return ERR_NONE;
+}
+
+ReturnCode rfalAnalogConfigListRead(
+    rfalAnalogConfigOffset* configOffset,
+    uint8_t* more,
+    rfalAnalogConfig* config,
+    rfalAnalogConfigNum numConfig) {
+    uint16_t configSize;
+    rfalAnalogConfigOffset offset = *configOffset;
+    rfalAnalogConfigNum numConfigSet;
+
+    /* Check if the number of register-mask-value settings for the respective Configuration ID will fit into the buffer passed in. */
+    if(gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)] >
+       numConfig) {
+        return ERR_NOMEM;
+    }
+
+    /* Get the number of Configuration set */
+    numConfigSet =
+        gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset + sizeof(rfalAnalogConfigId)];
+
+    /* Pass Configuration Register-Mask-Value sets */
+    configSize =
+        (sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) +
+         (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal)));
+    ST_MEMCPY((uint8_t*)config, &gRfalAnalogConfigMgmt.currentAnalogConfigTbl[offset], configSize);
+    *configOffset = offset + configSize;
+
+    /* Check if it is the last Analog Configuration in the Table.*/
+    *more = (uint8_t)((*configOffset >= gRfalAnalogConfigMgmt.configTblSize) ?
+                          RFAL_ANALOG_CONFIG_UPDATE_LAST :
+                          RFAL_ANALOG_CONFIG_UPDATE_MORE);
+
+    return ERR_NONE;
+} /* rfalAnalogConfigListRead() */
+
+ReturnCode rfalSetAnalogConfig(rfalAnalogConfigId configId) {
+    rfalAnalogConfigOffset configOffset = 0;
+    rfalAnalogConfigNum numConfigSet;
+    const rfalAnalogConfigRegAddrMaskVal* configTbl;
+    ReturnCode retCode = ERR_NONE;
+    rfalAnalogConfigNum i;
+
+    if(true != gRfalAnalogConfigMgmt.ready) {
+        return ERR_REQUEST;
+    }
+
+    /* Search LUT for the specific Configuration ID. */
+    while(true) {
+        numConfigSet = rfalAnalogConfigSearch(configId, &configOffset);
+        if(RFAL_ANALOG_CONFIG_LUT_NOT_FOUND == numConfigSet) {
+            break;
+        }
+
+        configTbl =
+            (rfalAnalogConfigRegAddrMaskVal*)((uint32_t)
+                                                  gRfalAnalogConfigMgmt.currentAnalogConfigTbl +
+                                              (uint32_t)configOffset);
+        /* Increment the offset to the next index to search from. */
+        configOffset += (uint16_t)(numConfigSet * sizeof(rfalAnalogConfigRegAddrMaskVal));
+
+        if((gRfalAnalogConfigMgmt.configTblSize + 1U) <
+           configOffset) { /* Error check make sure that the we do not access outside the configuration Table Size */
+            return ERR_NOMEM;
+        }
+
+        for(i = 0; i < numConfigSet; i++) {
+            if((GETU16(configTbl[i].addr) & RFAL_TEST_REG) != 0U) {
+                EXIT_ON_ERR(
+                    retCode,
+                    rfalChipChangeTestRegBits(
+                        (GETU16(configTbl[i].addr) & ~RFAL_TEST_REG),
+                        configTbl[i].mask,
+                        configTbl[i].val));
+            } else {
+                EXIT_ON_ERR(
+                    retCode,
+                    rfalChipChangeRegBits(
+                        GETU16(configTbl[i].addr), configTbl[i].mask, configTbl[i].val));
+            }
+        }
+
+    } /* while(found Analog Config Id) */
+
+    return retCode;
+
+} /* rfalSetAnalogConfig() */
+
+uint16_t rfalAnalogConfigGenModeID(rfalMode md, rfalBitRate br, uint16_t dir) {
+    uint16_t id;
+
+    /* Assign Poll/Listen Mode */
+    id = ((md >= RFAL_MODE_LISTEN_NFCA) ? RFAL_ANALOG_CONFIG_LISTEN : RFAL_ANALOG_CONFIG_POLL);
+
+    /* Assign Technology */
+    switch(md) {
+    case RFAL_MODE_POLL_NFCA:
+    case RFAL_MODE_POLL_NFCA_T1T:
+    case RFAL_MODE_LISTEN_NFCA:
+        id |= RFAL_ANALOG_CONFIG_TECH_NFCA;
+        break;
+
+    case RFAL_MODE_POLL_NFCB:
+    case RFAL_MODE_POLL_B_PRIME:
+    case RFAL_MODE_POLL_B_CTS:
+    case RFAL_MODE_LISTEN_NFCB:
+        id |= RFAL_ANALOG_CONFIG_TECH_NFCB;
+        break;
+
+    case RFAL_MODE_POLL_NFCF:
+    case RFAL_MODE_LISTEN_NFCF:
+        id |= RFAL_ANALOG_CONFIG_TECH_NFCF;
+        break;
+
+    case RFAL_MODE_POLL_NFCV:
+    case RFAL_MODE_POLL_PICOPASS:
+        id |= RFAL_ANALOG_CONFIG_TECH_NFCV;
+        break;
+
+    case RFAL_MODE_POLL_ACTIVE_P2P:
+    case RFAL_MODE_LISTEN_ACTIVE_P2P:
+        id |= RFAL_ANALOG_CONFIG_TECH_AP2P;
+        break;
+
+    default:
+        id = RFAL_ANALOG_CONFIG_TECH_CHIP;
+        break;
+    }
+
+    /* Assign Bitrate */
+    id |=
+        (((((uint16_t)(br) >= (uint16_t)RFAL_BR_52p97) ? (uint16_t)(br) : ((uint16_t)(br) + 1U))
+          << RFAL_ANALOG_CONFIG_BITRATE_SHIFT) &
+         RFAL_ANALOG_CONFIG_BITRATE_MASK);
+
+    /* Assign Direction */
+    id |= ((dir << RFAL_ANALOG_CONFIG_DIRECTION_SHIFT) & RFAL_ANALOG_CONFIG_DIRECTION_MASK);
+
+    return id;
+
+} /* rfalAnalogConfigGenModeID() */
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*! 
+ *****************************************************************************
+ * \brief  Update the link to Analog Configuration LUT
+ *  
+ * Update the link to the Analog Configuration LUT for the subsequent search 
+ * of Analog Settings.
+ * 
+ * \param[in]  analogConfigTbl: reference to the start of the new Analog Configuration Table
+ *
+ *****************************************************************************
+ */
+#if RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG
+static void rfalAnalogConfigPtrUpdate(const uint8_t* analogConfigTbl) {
+    gRfalAnalogConfigMgmt.currentAnalogConfigTbl = analogConfigTbl;
+    gRfalAnalogConfigMgmt.ready = true;
+
+} /* rfalAnalogConfigPtrUpdate() */
+#endif /* RFAL_FEATURE_DYNAMIC_ANALOG_CONFIG */
+
+/*! 
+ *****************************************************************************
+ * \brief  Search the Analog Configuration LUT for a specific Configuration ID.
+ *  
+ * Search the Analog Configuration LUT for the Configuration ID.
+ * 
+ * \param[in]  configId: Configuration ID to search for.
+ * \param[in]  configOffset: Configuration Offset in Table
+ * 
+ * \return number of Configuration Sets
+ * \return #RFAL_ANALOG_CONFIG_LUT_NOT_FOUND in case Configuration ID is not found.
+ *****************************************************************************
+ */
+static rfalAnalogConfigNum
+    rfalAnalogConfigSearch(rfalAnalogConfigId configId, uint16_t* configOffset) {
+    rfalAnalogConfigId foundConfigId;
+    rfalAnalogConfigId configIdMaskVal;
+    const uint8_t* configTbl;
+    const uint8_t* currentConfigTbl;
+    uint16_t i;
+
+    currentConfigTbl = gRfalAnalogConfigMgmt.currentAnalogConfigTbl;
+    configIdMaskVal =
+        ((RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_BITRATE_MASK) |
+         ((RFAL_ANALOG_CONFIG_TECH_CHIP == RFAL_ANALOG_CONFIG_ID_GET_TECH(configId)) ?
+              (RFAL_ANALOG_CONFIG_TECH_MASK | RFAL_ANALOG_CONFIG_CHIP_SPECIFIC_MASK) :
+              configId) |
+         ((RFAL_ANALOG_CONFIG_NO_DIRECTION == RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId)) ?
+              RFAL_ANALOG_CONFIG_DIRECTION_MASK :
+              configId));
+
+    /* When specific ConfigIDs are to be used, override search mask */
+    if((RFAL_ANALOG_CONFIG_ID_GET_DIRECTION(configId) == RFAL_ANALOG_CONFIG_DPO)) {
+        configIdMaskVal =
+            (RFAL_ANALOG_CONFIG_POLL_LISTEN_MODE_MASK | RFAL_ANALOG_CONFIG_TECH_MASK |
+             RFAL_ANALOG_CONFIG_BITRATE_MASK | RFAL_ANALOG_CONFIG_DIRECTION_MASK);
+    }
+
+    i = *configOffset;
+    while(i < gRfalAnalogConfigMgmt.configTblSize) {
+        configTbl = &currentConfigTbl[i];
+        foundConfigId = GETU16(configTbl);
+        if(configId == (foundConfigId & configIdMaskVal)) {
+            *configOffset =
+                (uint16_t)(i + sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum));
+            return configTbl[sizeof(rfalAnalogConfigId)];
+        }
+
+        /* If Config Id does not match, increment to next Configuration Id */
+        i += (uint16_t)(sizeof(rfalAnalogConfigId) + sizeof(rfalAnalogConfigNum) +
+                        (configTbl[sizeof(rfalAnalogConfigId)] *
+                         sizeof(rfalAnalogConfigRegAddrMaskVal)));
+    } /* for */
+
+    return RFAL_ANALOG_CONFIG_LUT_NOT_FOUND;
+} /* rfalAnalogConfigSearch() */

+ 82 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_crc.c

@@ -0,0 +1,82 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_crc.c
+ *
+ *  \author Oliver Regenfelder
+ *
+ *  \brief CRC calculation implementation
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../include/rfal_crc.h"
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte);
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+uint16_t rfalCrcCalculateCcitt(uint16_t preloadValue, const uint8_t* buf, uint16_t length) {
+    uint16_t crc = preloadValue;
+    uint16_t index;
+
+    for(index = 0; index < length; index++) {
+        crc = rfalCrcUpdateCcitt(crc, buf[index]);
+    }
+
+    return crc;
+}
+
+/*
+******************************************************************************
+* LOCAL FUNCTIONS
+******************************************************************************
+*/
+static uint16_t rfalCrcUpdateCcitt(uint16_t crcSeed, uint8_t dataByte) {
+    uint16_t crc = crcSeed;
+    uint8_t dat = dataByte;
+
+    dat ^= (uint8_t)(crc & 0xFFU);
+    dat ^= (dat << 4);
+
+    crc = (crc >> 8) ^ (((uint16_t)dat) << 8) ^ (((uint16_t)dat) << 3) ^ (((uint16_t)dat) >> 4);
+
+    return crc;
+}

+ 232 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_dpo.c

@@ -0,0 +1,232 @@
+
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      $Revision: $
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_dpo.c
+ *
+ *  \author Martin Zechleitner
+ *
+ *  \brief Functions to manage and set dynamic power settings.
+ *  
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "st25r3916/rfal_dpoTbl.h"
+#include "../include/rfal_dpo.h"
+#include "../platform.h"
+#include "../include/rfal_rf.h"
+#include "../include/rfal_chip.h"
+#include "../include/rfal_analogConfig.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_DPO
+#define RFAL_FEATURE_DPO \
+    false /* Dynamic Power Module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_DPO
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+#define RFAL_DPO_ANALOGCONFIG_SHIFT 13U
+#define RFAL_DPO_ANALOGCONFIG_MASK 0x6000U
+
+/*
+ ******************************************************************************
+ * LOCAL DATA TYPES
+ ******************************************************************************
+ */
+
+static bool gRfalDpoIsEnabled = false;
+static uint8_t* gRfalCurrentDpo;
+static uint8_t gRfalDpoTableEntries;
+static uint8_t gRfalDpo[RFAL_DPO_TABLE_SIZE_MAX];
+static uint8_t gRfalDpoTableEntry;
+static rfalDpoMeasureFunc gRfalDpoMeasureCallback = NULL;
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+void rfalDpoInitialize(void) {
+    /* Use the default Dynamic Power values */
+    gRfalCurrentDpo = (uint8_t*)rfalDpoDefaultSettings;
+    gRfalDpoTableEntries = (sizeof(rfalDpoDefaultSettings) / RFAL_DPO_TABLE_PARAMETER);
+
+    ST_MEMCPY(gRfalDpo, gRfalCurrentDpo, sizeof(rfalDpoDefaultSettings));
+
+    /* by default use amplitude measurement */
+    gRfalDpoMeasureCallback = rfalChipMeasureAmplitude;
+
+    /* by default DPO is disabled */
+    gRfalDpoIsEnabled = false;
+
+    gRfalDpoTableEntry = 0;
+}
+
+void rfalDpoSetMeasureCallback(rfalDpoMeasureFunc pMeasureFunc) {
+    gRfalDpoMeasureCallback = pMeasureFunc;
+}
+
+/*******************************************************************************/
+ReturnCode rfalDpoTableWrite(rfalDpoEntry* powerTbl, uint8_t powerTblEntries) {
+    uint8_t entry = 0;
+
+    /* check if the table size parameter is too big */
+    if((powerTblEntries * RFAL_DPO_TABLE_PARAMETER) > RFAL_DPO_TABLE_SIZE_MAX) {
+        return ERR_NOMEM;
+    }
+
+    /* check if the first increase entry is 0xFF */
+    if((powerTblEntries == 0) || (powerTbl == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* check if the entries of the dynamic power table are valid */
+    for(entry = 0; entry < powerTblEntries; entry++) {
+        if(powerTbl[entry].inc < powerTbl[entry].dec) {
+            return ERR_PARAM;
+        }
+    }
+
+    /* copy the data set  */
+    ST_MEMCPY(gRfalDpo, powerTbl, (powerTblEntries * RFAL_DPO_TABLE_PARAMETER));
+    gRfalCurrentDpo = gRfalDpo;
+    gRfalDpoTableEntries = powerTblEntries;
+
+    if(gRfalDpoTableEntry > powerTblEntries) {
+        /* is always greater then zero, otherwise we already returned ERR_PARAM */
+        gRfalDpoTableEntry = (powerTblEntries - 1);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalDpoTableRead(rfalDpoEntry* tblBuf, uint8_t tblBufEntries, uint8_t* tableEntries) {
+    /* wrong request */
+    if((tblBuf == NULL) || (tblBufEntries < gRfalDpoTableEntries) || (tableEntries == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Copy the whole Table to the given buffer */
+    ST_MEMCPY(tblBuf, gRfalCurrentDpo, (tblBufEntries * RFAL_DPO_TABLE_PARAMETER));
+    *tableEntries = gRfalDpoTableEntries;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalDpoAdjust(void) {
+    uint8_t refValue = 0;
+    uint16_t modeID;
+    rfalBitRate br;
+    rfalDpoEntry* dpoTable = (rfalDpoEntry*)gRfalCurrentDpo;
+
+    /* Check if the Power Adjustment is disabled and                  *
+     * if the callback to the measurement method is properly set      */
+    if((gRfalCurrentDpo == NULL) || (!gRfalDpoIsEnabled) || (gRfalDpoMeasureCallback == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Ensure that the current mode is Passive Poller */
+    if(!rfalIsModePassivePoll(rfalGetMode())) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Ensure a proper measure reference value */
+    if(ERR_NONE != gRfalDpoMeasureCallback(&refValue)) {
+        return ERR_IO;
+    }
+
+    if(refValue >= dpoTable[gRfalDpoTableEntry].inc) { /* Increase the output power */
+        /* the top of the table represents the highest amplitude value*/
+        if(gRfalDpoTableEntry == 0) {
+            /* maximum driver value has been reached */
+        } else {
+            /* go up in the table to decrease the driver resistance */
+            gRfalDpoTableEntry--;
+        }
+    } else if(refValue <= dpoTable[gRfalDpoTableEntry].dec) { /* decrease the output power */
+        /* The bottom is the highest possible value */
+        if((gRfalDpoTableEntry + 1) >= gRfalDpoTableEntries) {
+            /* minimum driver value has been reached */
+        } else {
+            /* go down in the table to increase the driver resistance */
+            gRfalDpoTableEntry++;
+        }
+    } else {
+        /* Fall through to always write dpo and its associated analog configs */
+    }
+
+    /* Get the new value for RFO resistance form the table and apply the new RFO resistance setting */
+    rfalChipSetRFO(dpoTable[gRfalDpoTableEntry].rfoRes);
+
+    /* Apply the DPO Analog Config according to this treshold */
+    /* Technology field is being extended for DPO: 2msb are used for treshold step (only 4 allowed) */
+    rfalGetBitRate(&br, NULL); /* Obtain current Tx bitrate       */
+    modeID = rfalAnalogConfigGenModeID(
+        rfalGetMode(), br, RFAL_ANALOG_CONFIG_DPO); /* Generate Analog Config mode ID  */
+    modeID |=
+        ((gRfalDpoTableEntry << RFAL_DPO_ANALOGCONFIG_SHIFT) &
+         RFAL_DPO_ANALOGCONFIG_MASK); /* Add DPO treshold step|level     */
+    rfalSetAnalogConfig(modeID); /* Apply DPO Analog Config         */
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+rfalDpoEntry* rfalDpoGetCurrentTableEntry(void) {
+    rfalDpoEntry* dpoTable = (rfalDpoEntry*)gRfalCurrentDpo;
+    return &dpoTable[gRfalDpoTableEntry];
+}
+
+/*******************************************************************************/
+void rfalDpoSetEnabled(bool enable) {
+    gRfalDpoIsEnabled = enable;
+}
+
+/*******************************************************************************/
+bool rfalDpoIsEnabled(void) {
+    return gRfalDpoIsEnabled;
+}
+
+#endif /* RFAL_FEATURE_DPO */

+ 516 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_iso15693_2.c

@@ -0,0 +1,516 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_iso15693_2.c
+ *
+ *  \author Ulrich Herrmann
+ *
+ *  \brief Implementation of ISO-15693-2
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../include/rfal_iso15693_2.h"
+#include "../include/rfal_crc.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFCV
+#define RFAL_FEATURE_NFCV false /* NFC-V module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_NFCV
+
+/*
+******************************************************************************
+* LOCAL MACROS
+******************************************************************************
+*/
+
+#define ISO_15693_DEBUG(...) /*!< Macro for the log method  */
+
+/*
+******************************************************************************
+* LOCAL DEFINES
+******************************************************************************
+*/
+#define ISO15693_DAT_SOF_1_4 0x21 /* LSB constants */
+#define ISO15693_DAT_EOF_1_4 0x04
+#define ISO15693_DAT_00_1_4 0x02
+#define ISO15693_DAT_01_1_4 0x08
+#define ISO15693_DAT_10_1_4 0x20
+#define ISO15693_DAT_11_1_4 0x80
+
+#define ISO15693_DAT_SOF_1_256 0x81
+#define ISO15693_DAT_EOF_1_256 0x04
+#define ISO15693_DAT_SLOT0_1_256 0x02
+#define ISO15693_DAT_SLOT1_1_256 0x08
+#define ISO15693_DAT_SLOT2_1_256 0x20
+#define ISO15693_DAT_SLOT3_1_256 0x80
+
+#define ISO15693_PHY_DAT_MANCHESTER_1 0xaaaa
+
+#define ISO15693_PHY_BIT_BUFFER_SIZE \
+    1000 /*!< size of the receiving buffer. Might be adjusted if longer datastreams are expected. */
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+static iso15693PhyConfig_t iso15693PhyConfig; /*!< current phy configuration */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static ReturnCode iso15693PhyVCDCode1Of4(
+    const uint8_t data,
+    uint8_t* outbuffer,
+    uint16_t maxOutBufLen,
+    uint16_t* outBufLen);
+static ReturnCode iso15693PhyVCDCode1Of256(
+    const uint8_t data,
+    uint8_t* outbuffer,
+    uint16_t maxOutBufLen,
+    uint16_t* outBufLen);
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+ReturnCode iso15693PhyConfigure(
+    const iso15693PhyConfig_t* config,
+    const struct iso15693StreamConfig** needed_stream_config) {
+    static struct iso15693StreamConfig stream_config = {
+        /* MISRA 8.9 */
+        .useBPSK = 0, /* 0: subcarrier, 1:BPSK */
+        .din = 5, /* 2^5*fc = 423750 Hz: divider for the in subcarrier frequency */
+        .dout = 7, /*!< 2^7*fc = 105937 : divider for the in subcarrier frequency */
+        .report_period_length = 3, /*!< 8=2^3 the length of the reporting period */
+    };
+
+    /* make a copy of the configuration */
+    ST_MEMCPY((uint8_t*)&iso15693PhyConfig, (const uint8_t*)config, sizeof(iso15693PhyConfig_t));
+
+    if(config->speedMode <= 3U) { /* If valid speed mode adjust report period accordingly */
+        stream_config.report_period_length = (3U - (uint8_t)config->speedMode);
+    } else { /* If invalid default to normal (high) speed */
+        stream_config.report_period_length = 3;
+    }
+
+    *needed_stream_config = &stream_config;
+
+    return ERR_NONE;
+}
+
+ReturnCode iso15693PhyGetConfiguration(iso15693PhyConfig_t* config) {
+    ST_MEMCPY(config, &iso15693PhyConfig, sizeof(iso15693PhyConfig_t));
+
+    return ERR_NONE;
+}
+
+ReturnCode iso15693VCDCode(
+    uint8_t* buffer,
+    uint16_t length,
+    bool sendCrc,
+    bool sendFlags,
+    bool picopassMode,
+    uint16_t* subbit_total_length,
+    uint16_t* offset,
+    uint8_t* outbuf,
+    uint16_t outBufSize,
+    uint16_t* actOutBufSize) {
+    ReturnCode err = ERR_NONE;
+    uint8_t eof, sof;
+    uint8_t transbuf[2];
+    uint16_t crc = 0;
+    ReturnCode (*txFunc)(
+        const uint8_t data, uint8_t* outbuffer, uint16_t maxOutBufLen, uint16_t* outBufLen);
+    uint8_t crc_len;
+    uint8_t* outputBuf;
+    uint16_t outputBufSize;
+
+    crc_len = (uint8_t)((sendCrc) ? 2 : 0);
+
+    *actOutBufSize = 0;
+
+    if(ISO15693_VCD_CODING_1_4 == iso15693PhyConfig.coding) {
+        sof = ISO15693_DAT_SOF_1_4;
+        eof = ISO15693_DAT_EOF_1_4;
+        txFunc = iso15693PhyVCDCode1Of4;
+        *subbit_total_length =
+            ((1U /* SOF */
+              + ((length + (uint16_t)crc_len) * 4U) + 1U) /* EOF */
+            );
+        if(outBufSize < 5U) { /* 5 should be safe: enough for sof + 1byte data in 1of4 */
+            return ERR_NOMEM;
+        }
+    } else {
+        sof = ISO15693_DAT_SOF_1_256;
+        eof = ISO15693_DAT_EOF_1_256;
+        txFunc = iso15693PhyVCDCode1Of256;
+        *subbit_total_length =
+            ((1U /* SOF */
+              + ((length + (uint16_t)crc_len) * 64U) + 1U) /* EOF */
+            );
+
+        if(*offset != 0U) {
+            if(outBufSize < 64U) { /* 64 should be safe: enough a single byte data in 1of256 */
+                return ERR_NOMEM;
+            }
+        } else {
+            if(outBufSize <
+               65U) { /* At beginning of a frame we need at least 65 bytes to start: enough for sof + 1byte data in 1of256 */
+                return ERR_NOMEM;
+            }
+        }
+    }
+
+    if(length == 0U) {
+        *subbit_total_length = 1;
+    }
+
+    if((length != 0U) && (0U == *offset) && sendFlags && !picopassMode) {
+        /* set high datarate flag */
+        buffer[0] |= (uint8_t)ISO15693_REQ_FLAG_HIGH_DATARATE;
+        /* clear sub-carrier flag - we only support single sub-carrier */
+        buffer[0] = (uint8_t)(buffer[0] & ~ISO15693_REQ_FLAG_TWO_SUBCARRIERS); /* MISRA 10.3 */
+    }
+
+    outputBuf = outbuf; /* MISRA 17.8: Use intermediate variable */
+    outputBufSize = outBufSize; /* MISRA 17.8: Use intermediate variable */
+
+    /* Send SOF if at 0 offset */
+    if((length != 0U) && (0U == *offset)) {
+        *outputBuf = sof;
+        (*actOutBufSize)++;
+        outputBufSize--;
+        outputBuf++;
+    }
+
+    while((*offset < length) && (err == ERR_NONE)) {
+        uint16_t filled_size;
+        /* send data */
+        err = txFunc(buffer[*offset], outputBuf, outputBufSize, &filled_size);
+        (*actOutBufSize) += filled_size;
+        outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */
+        outputBufSize -= filled_size;
+        if(err == ERR_NONE) {
+            (*offset)++;
+        }
+    }
+    if(err != ERR_NONE) {
+        return ERR_AGAIN;
+    }
+
+    while((err == ERR_NONE) && sendCrc && (*offset < (length + 2U))) {
+        uint16_t filled_size;
+        if(0U == crc) {
+            crc = rfalCrcCalculateCcitt(
+                (uint16_t)((picopassMode) ?
+                               0xE012U :
+                               0xFFFFU), /* In PicoPass Mode a different Preset Value is used   */
+                ((picopassMode) ?
+                     (buffer + 1U) :
+                     buffer), /* CMD byte is not taken into account in PicoPass mode */
+                ((picopassMode) ?
+                     (length - 1U) :
+                     length)); /* CMD byte is not taken into account in PicoPass mode */
+
+            crc = (uint16_t)((picopassMode) ? crc : ~crc);
+        }
+        /* send crc */
+        transbuf[0] = (uint8_t)(crc & 0xffU);
+        transbuf[1] = (uint8_t)((crc >> 8) & 0xffU);
+        err = txFunc(transbuf[*offset - length], outputBuf, outputBufSize, &filled_size);
+        (*actOutBufSize) += filled_size;
+        outputBuf = &outputBuf[filled_size]; /* MISRA 18.4: Avoid pointer arithmetic */
+        outputBufSize -= filled_size;
+        if(err == ERR_NONE) {
+            (*offset)++;
+        }
+    }
+    if(err != ERR_NONE) {
+        return ERR_AGAIN;
+    }
+
+    if((!sendCrc && (*offset == length)) || (sendCrc && (*offset == (length + 2U)))) {
+        *outputBuf = eof;
+        (*actOutBufSize)++;
+        outputBufSize--;
+        outputBuf++;
+    } else {
+        return ERR_AGAIN;
+    }
+
+    return err;
+}
+
+ReturnCode iso15693VICCDecode(
+    const uint8_t* inBuf,
+    uint16_t inBufLen,
+    uint8_t* outBuf,
+    uint16_t outBufLen,
+    uint16_t* outBufPos,
+    uint16_t* bitsBeforeCol,
+    uint16_t ignoreBits,
+    bool picopassMode) {
+    ReturnCode err = ERR_NONE;
+    uint16_t crc;
+    uint16_t mp; /* Current bit position in manchester bit inBuf*/
+    uint16_t bp; /* Current bit position in outBuf */
+
+    *bitsBeforeCol = 0;
+    *outBufPos = 0;
+
+    /* first check for valid SOF. Since it starts with 3 unmodulated pulses it is 0x17. */
+    if((inBuf[0] & 0x1fU) != 0x17U) {
+        ISO_15693_DEBUG("0x%x\n", iso15693PhyBitBuffer[0]);
+        return ERR_FRAMING;
+    }
+    ISO_15693_DEBUG("SOF\n");
+
+    if(outBufLen == 0U) {
+        return ERR_NONE;
+    }
+
+    mp = 5; /* 5 bits were SOF, now manchester starts: 2 bits per payload bit */
+    bp = 0;
+
+    ST_MEMSET(outBuf, 0, outBufLen);
+
+    if(inBufLen == 0U) {
+        return ERR_CRC;
+    }
+
+    for(; mp < ((inBufLen * 8U) - 2U); mp += 2U) {
+        bool isEOF = false;
+
+        uint8_t man;
+        man = (inBuf[mp / 8U] >> (mp % 8U)) & 0x1U;
+        man |= ((inBuf[(mp + 1U) / 8U] >> ((mp + 1U) % 8U)) & 0x1U) << 1;
+        if(1U == man) {
+            bp++;
+        }
+        if(2U == man) {
+            outBuf[bp / 8U] = (uint8_t)(outBuf[bp / 8U] | (1U << (bp % 8U))); /* MISRA 10.3 */
+            bp++;
+        }
+        if((bp % 8U) == 0U) { /* Check for EOF */
+            ISO_15693_DEBUG("ceof %hhx %hhx\n", inBuf[mp / 8U], inBuf[mp / 8 + 1]);
+            if(((inBuf[mp / 8U] & 0xe0U) == 0xa0U) &&
+               (inBuf[(mp / 8U) + 1U] == 0x03U)) { /* Now we know that it was 10111000 = EOF */
+                ISO_15693_DEBUG("EOF\n");
+                isEOF = true;
+            }
+        }
+        if(((0U == man) || (3U == man)) && !isEOF) {
+            if(bp >= ignoreBits) {
+                err = ERR_RF_COLLISION;
+            } else {
+                /* ignored collision: leave as 0 */
+                bp++;
+            }
+        }
+        if((bp >= (outBufLen * 8U)) || (err == ERR_RF_COLLISION) ||
+           isEOF) { /* Don't write beyond the end */
+            break;
+        }
+    }
+
+    *outBufPos = (bp / 8U);
+    *bitsBeforeCol = bp;
+
+    if(err != ERR_NONE) {
+        return err;
+    }
+
+    if((bp % 8U) != 0U) {
+        return ERR_CRC;
+    }
+
+    if(*outBufPos > 2U) {
+        /* finally, check crc */
+        ISO_15693_DEBUG("Calculate CRC, val: 0x%x, outBufLen: ", *outBuf);
+        ISO_15693_DEBUG("0x%x ", *outBufPos - 2);
+
+        crc = rfalCrcCalculateCcitt(((picopassMode) ? 0xE012U : 0xFFFFU), outBuf, *outBufPos - 2U);
+        crc = (uint16_t)((picopassMode) ? crc : ~crc);
+
+        if(((crc & 0xffU) == outBuf[*outBufPos - 2U]) &&
+           (((crc >> 8U) & 0xffU) == outBuf[*outBufPos - 1U])) {
+            err = ERR_NONE;
+            ISO_15693_DEBUG("OK\n");
+        } else {
+            ISO_15693_DEBUG("error! Expected: 0x%x, got ", crc);
+            ISO_15693_DEBUG("0x%hhx 0x%hhx\n", outBuf[*outBufPos - 2], outBuf[*outBufPos - 1]);
+            err = ERR_CRC;
+        }
+    } else {
+        err = ERR_CRC;
+    }
+
+    return err;
+}
+
+/*
+******************************************************************************
+* LOCAL FUNCTIONS
+******************************************************************************
+*/
+/*! 
+ *****************************************************************************
+ *  \brief  Perform 1 of 4 coding and send coded data
+ *
+ *  This function takes \a length bytes from \a buffer, perform 1 of 4 coding
+ *  (see ISO15693-2 specification) and sends the data using stream mode.
+ *
+ *  \param[in] sendSof : send SOF prior to data.
+ *  \param[in] buffer : data to send.
+ *  \param[in] length : number of bytes to send.
+ *
+ *  \return ERR_IO : Error during communication.
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+static ReturnCode iso15693PhyVCDCode1Of4(
+    const uint8_t data,
+    uint8_t* outbuffer,
+    uint16_t maxOutBufLen,
+    uint16_t* outBufLen) {
+    uint8_t tmp;
+    ReturnCode err = ERR_NONE;
+    uint16_t a;
+    uint8_t* outbuf = outbuffer;
+
+    *outBufLen = 0;
+
+    if(maxOutBufLen < 4U) {
+        return ERR_NOMEM;
+    }
+
+    tmp = data;
+    for(a = 0; a < 4U; a++) {
+        switch(tmp & 0x3U) {
+        case 0:
+            *outbuf = ISO15693_DAT_00_1_4;
+            break;
+        case 1:
+            *outbuf = ISO15693_DAT_01_1_4;
+            break;
+        case 2:
+            *outbuf = ISO15693_DAT_10_1_4;
+            break;
+        case 3:
+            *outbuf = ISO15693_DAT_11_1_4;
+            break;
+        default:
+            /* MISRA 16.4: mandatory default statement */
+            break;
+        }
+        outbuf++;
+        (*outBufLen)++;
+        tmp >>= 2;
+    }
+    return err;
+}
+
+/*! 
+ *****************************************************************************
+ *  \brief  Perform 1 of 256 coding and send coded data
+ *
+ *  This function takes \a length bytes from \a buffer, perform 1 of 256 coding
+ *  (see ISO15693-2 specification) and sends the data using stream mode.
+ *  \note This function sends SOF prior to the data.
+ *
+ *  \param[in] sendSof : send SOF prior to data.
+ *  \param[in] buffer : data to send.
+ *  \param[in] length : number of bytes to send.
+ *
+ *  \return ERR_IO : Error during communication.
+ *  \return ERR_NONE : No error.
+ *
+ *****************************************************************************
+ */
+static ReturnCode iso15693PhyVCDCode1Of256(
+    const uint8_t data,
+    uint8_t* outbuffer,
+    uint16_t maxOutBufLen,
+    uint16_t* outBufLen) {
+    uint8_t tmp;
+    ReturnCode err = ERR_NONE;
+    uint16_t a;
+    uint8_t* outbuf = outbuffer;
+
+    *outBufLen = 0;
+
+    if(maxOutBufLen < 64U) {
+        return ERR_NOMEM;
+    }
+
+    tmp = data;
+    for(a = 0; a < 64U; a++) {
+        switch(tmp) {
+        case 0:
+            *outbuf = ISO15693_DAT_SLOT0_1_256;
+            break;
+        case 1:
+            *outbuf = ISO15693_DAT_SLOT1_1_256;
+            break;
+        case 2:
+            *outbuf = ISO15693_DAT_SLOT2_1_256;
+            break;
+        case 3:
+            *outbuf = ISO15693_DAT_SLOT3_1_256;
+            break;
+        default:
+            *outbuf = 0;
+            break;
+        }
+        outbuf++;
+        (*outBufLen)++;
+        tmp -= 4U;
+    }
+
+    return err;
+}
+
+#endif /* RFAL_FEATURE_NFCV */

+ 3045 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_isoDep.c

@@ -0,0 +1,3045 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   NFCC firmware
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_isoDep.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of ISO-DEP protocol
+ *  
+ *  This implementation was based on the following specs:
+ *    - ISO/IEC 14443-4  2nd Edition 2008-07-15
+ *    - NFC Forum Digital Protocol  1.1 2014-01-14
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+
+#include "../include/rfal_isoDep.h"
+#include "../include/rfal_rf.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#if RFAL_FEATURE_ISO_DEP
+
+#if(!RFAL_FEATURE_ISO_DEP_POLL && !RFAL_FEATURE_ISO_DEP_LISTEN)
+#error \
+    " RFAL: Invalid ISO-DEP Configuration. Please select at least one mode: Poller and/or Listener. "
+#endif
+
+/* Check for valid I-Block length [RFAL_ISODEP_FSX_16 ; RFAL_ISODEP_FSX_4096]*/
+#if((RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN > 4096) || (RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN < 16))
+#error \
+    " RFAL: Invalid ISO-DEP IBlock Max length. Please change RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN. "
+#endif
+
+/* Check for valid APDU length. */
+#if((RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN < RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN))
+#error " RFAL: Invalid ISO-DEP APDU Max length. Please change RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN. "
+#endif
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+#define ISODEP_CRC_LEN RFAL_CRC_LEN /*!< ISO1443 CRC Length */
+
+#define ISODEP_PCB_POS (0U) /*!< PCB position on message header*/
+#define ISODEP_SWTX_INF_POS (1U) /*!< INF position in a S-WTX       */
+
+#define ISODEP_DID_POS (1U) /*!< DID position on message header*/
+#define ISODEP_SWTX_PARAM_LEN (1U) /*!< SWTX parameter length         */
+
+#define ISODEP_DSL_MAX_LEN \
+    (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN) /*!< Deselect Req/Res length */
+
+#define ISODEP_PCB_xBLOCK_MASK (0xC0U) /*!< Bit mask for Block type       */
+#define ISODEP_PCB_IBLOCK (0x00U) /*!< Bit mask indicating a I-Block */
+#define ISODEP_PCB_RBLOCK (0x80U) /*!< Bit mask indicating a R-Block */
+#define ISODEP_PCB_SBLOCK (0xC0U) /*!< Bit mask indicating a S-Block */
+#define ISODEP_PCB_INVALID (0x40U) /*!< Bit mask of an Invalid PCB    */
+
+#define ISODEP_HDR_MAX_LEN                       \
+    (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + \
+     RFAL_ISODEP_NAD_LEN) /*!< Max header length (PCB + DID + NAD)      */
+
+#define ISODEP_PCB_IB_VALID_MASK \
+    (ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT) /*!< Bit mask for the MUST bits on I-Block    */
+#define ISODEP_PCB_IB_VALID_VAL \
+    (ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on I-Block       */
+#define ISODEP_PCB_RB_VALID_MASK             \
+    (ISODEP_PCB_B6_BIT | ISODEP_PCB_B3_BIT | \
+     ISODEP_PCB_B2_BIT) /*!< Bit mask for the MUST bits on R-Block    */
+#define ISODEP_PCB_RB_VALID_VAL \
+    (ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on R-Block       */
+#define ISODEP_PCB_SB_VALID_MASK             \
+    (ISODEP_PCB_B3_BIT | ISODEP_PCB_B2_BIT | \
+     ISODEP_PCB_B1_BIT) /*!< Bit mask for the MUST bits on I-Block    */
+#define ISODEP_PCB_SB_VALID_VAL \
+    (ISODEP_PCB_B2_BIT) /*!< Value for the MUST bits on I-Block       */
+
+#define ISODEP_PCB_B1_BIT \
+    (0x01U) /*!< Bit mask for the RFU S Blocks                                        */
+#define ISODEP_PCB_B2_BIT \
+    (0x02U) /*!< Bit mask for the RFU bit2 in I,S,R Blocks                            */
+#define ISODEP_PCB_B3_BIT \
+    (0x04U) /*!< Bit mask for the RFU bit3 in R Blocks                                */
+#define ISODEP_PCB_B6_BIT \
+    (0x20U) /*!< Bit mask for the RFU bit2 in R Blocks                                */
+#define ISODEP_PCB_CHAINING_BIT \
+    (0x10U) /*!< Bit mask for the chaining bit of an ISO DEP I-Block in PCB.          */
+#define ISODEP_PCB_DID_BIT \
+    (0x08U) /*!< Bit mask for the DID presence bit of an ISO DEP I,S,R Blocks PCB.    */
+#define ISODEP_PCB_NAD_BIT \
+    (0x04U) /*!< Bit mask for the NAD presence bit of an ISO DEP I,S,R Blocks in PCB  */
+#define ISODEP_PCB_BN_MASK \
+    (0x01U) /*!< Bit mask for the block number of an ISO DEP I,R Block in PCB         */
+
+#define ISODEP_SWTX_PL_MASK \
+    (0xC0U) /*!< Bit mask for the Power Level bits of the inf byte of an WTX request or response */
+#define ISODEP_SWTX_WTXM_MASK \
+    (0x3FU) /*!< Bit mask for the WTXM bits of the inf byte of an WTX request or response        */
+
+#define ISODEP_RBLOCK_INF_LEN (0U) /*!< INF length of R-Block               Digital 1.1 15.1.3 */
+#define ISODEP_SDSL_INF_LEN (0U) /*!< INF length of S(DSL)                Digital 1.1 15.1.3 */
+#define ISODEP_SWTX_INF_LEN (1U) /*!< INF length of S(WTX)                Digital 1.1 15.2.2 */
+
+#define ISODEP_WTXM_MIN (1U) /*!< Minimum allowed value for the WTXM, Digital 1.0 13.2.2 */
+#define ISODEP_WTXM_MAX (59U) /*!< Maximum allowed value for the WTXM, Digital 1.0 13.2.2 */
+
+#define ISODEP_PCB_Sxx_MASK (0x30U) /*!< Bit mask for the S-Block type                          */
+#define ISODEP_PCB_DESELECT (0x00U) /*!< Bit mask for S-Block indicating Deselect               */
+#define ISODEP_PCB_WTX (0x30U) /*!< Bit mask for S-Block indicating Waiting Time eXtension */
+
+#define ISODEP_PCB_Rx_MASK (0x10U) /*!< Bit mask for the R-Block type       */
+#define ISODEP_PCB_ACK (0x00U) /*!< Bit mask for R-Block indicating ACK */
+#define ISODEP_PCB_NAK (0x10U) /*!< Bit mask for R-Block indicating NAK */
+
+/*! Maximum length of control message (no INF) */
+#define ISODEP_CONTROLMSG_BUF_LEN \
+    (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + RFAL_ISODEP_NAD_LEN + ISODEP_SWTX_PARAM_LEN)
+
+#define ISODEP_FWT_DEACTIVATION \
+    (71680U) /*!< FWT used for DESELECT  Digital 2.2 B10  ISO1444-4 7.2 & 8.1 */
+#define ISODEP_MAX_RERUNS (0x0FFFFFFFU) /*!< Maximum rerun retrys for a blocking protocol run*/
+
+#define ISODEP_PCBSBLOCK \
+    (0x00U | ISODEP_PCB_SBLOCK | ISODEP_PCB_B2_BIT) /*!< PCB Value of a S-Block                 */
+#define ISODEP_PCB_SDSL \
+    (ISODEP_PCBSBLOCK | ISODEP_PCB_DESELECT) /*!< PCB Value of a S-Block with DESELECT   */
+#define ISODEP_PCB_SWTX \
+    (ISODEP_PCBSBLOCK | ISODEP_PCB_WTX) /*!< PCB Value of a S-Block with WTX        */
+#define ISODEP_PCB_SPARAMETERS \
+    (ISODEP_PCB_SBLOCK | ISODEP_PCB_WTX) /*!< PCB Value of a S-Block with PARAMETERS */
+
+#define ISODEP_FWI_LIS_MAX_NFC \
+    8U /*!< FWT Listener Max FWIT4ATmax FWIBmax  Digital 1.1  A6 & A3  */
+#define ISODEP_FWI_LIS_MAX_EMVCO \
+    7U /*!< FWT Listener Max FWIMAX       EMVCo 2.6 A.5                */
+#define ISODEP_FWI_LIS_MAX                               \
+    (uint8_t)(                                           \
+        (gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) ? \
+            ISODEP_FWI_LIS_MAX_EMVCO :                   \
+            ISODEP_FWI_LIS_MAX_NFC) /*!< FWI Listener Max as NFC / EMVCo */
+#define ISODEP_FWT_LIS_MAX \
+    rfalIsoDepFWI2FWT(ISODEP_FWI_LIS_MAX) /*!< FWT Listener Max                       */
+
+#define ISODEP_FWI_MIN_10 (1U) /*!< Minimum value for FWI Digital 1.0 11.6.2.17 */
+#define ISODEP_FWI_MIN_11 (0U) /*!< Default value for FWI Digital 1.1 13.6.2    */
+#define ISODEP_FWI_MAX (14U) /*!< Maximum value for FWI Digital 1.0 11.6.2.17 */
+#define ISODEP_SFGI_MIN (0U) /*!< Default value for FWI Digital 1.1 13.6.2.22 */
+#define ISODEP_SFGI_MAX (14U) /*!< Maximum value for FWI Digital 1.1 13.6.2.22 */
+
+#define RFAL_ISODEP_SPARAM_TVL_HDR_LEN (2U) /*!< S(PARAMETERS) TVL header length: Tag + Len */
+#define RFAL_ISODEP_SPARAM_HDR_LEN \
+    (RFAL_ISODEP_PCB_LEN +         \
+     RFAL_ISODEP_SPARAM_TVL_HDR_LEN) /*!< S(PARAMETERS) header length: PCB + Tag + Len */
+
+/**********************************************************************************************************************/
+/**********************************************************************************************************************/
+#define RFAL_ISODEP_NO_PARAM (0U) /*!< No parameter flag for isoDepHandleControlMsg()     */
+
+#define RFAL_ISODEP_CMD_RATS (0xE0U) /*!< RATS command   Digital 1.1  13.6.1                 */
+
+#define RFAL_ISODEP_ATS_MIN_LEN (1U) /*!< Minimum ATS length   Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_HDR_LEN (5U) /*!< ATS headerlength     Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_MAX_LEN \
+    (RFAL_ISODEP_ATS_HDR_LEN +  \
+     RFAL_ISODEP_ATS_HB_MAX_LEN) /*!< Maximum ATS length   Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_T0_FSCI_MASK (0x0FU) /*!< ATS T0's FSCI mask   Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_TB_FWI_SHIFT (4U) /*!< ATS TB's FWI shift   Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_FWI_MASK (0x0FU) /*!< ATS TB's FWI shift   Digital 1.1  13.6.2 */
+#define RFAL_ISODEP_ATS_TL_POS (0x00U) /*!< ATS TL's position    Digital 1.1  13.6.2 */
+
+#define RFAL_ISODEP_PPS_SB (0xD0U) /*!< PPS REQ PPSS's SB value (no CID)   ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_MASK (0xF0U) /*!< PPS REQ PPSS's SB mask             ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_SB_DID_MASK \
+    (0x0FU) /*!< PPS REQ PPSS's DID|CID mask        ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_PPS0_PPS1_PRESENT \
+    (0x11U) /*!< PPS REQ PPS0 indicating that PPS1 is present       */
+#define RFAL_ISODEP_PPS_PPS1 (0x00U) /*!< PPS REQ PPS1 fixed value           ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_PPS1_DSI_SHIFT \
+    (2U) /*!< PPS REQ PPS1 fixed value           ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_PPS1_DXI_MASK \
+    (0x0FU) /*!< PPS REQ PPS1 fixed value           ISO14443-4  5.3 */
+#define RFAL_ISODEP_PPS_RES_LEN (1U) /*!< PPS Response length                ISO14443-4  5.4 */
+#define RFAL_ISODEP_PPS_STARTBYTE_POS \
+    (0U) /*!< PPS REQ PPSS's byte position       ISO14443-4  5.4 */
+#define RFAL_ISODEP_PPS_PPS0_POS (1U) /*!< PPS REQ PPS0's byte position       ISO14443-4  5.4 */
+#define RFAL_ISODEP_PPS_PPS1_POS (2U) /*!< PPS REQ PPS1's byte position       ISO14443-4  5.4 */
+#define RFAL_ISODEP_PPS0_VALID_MASK \
+    (0xEFU) /*!< PPS REQ PPS0 valid coding mask     ISO14443-4  5.4 */
+
+#define RFAL_ISODEP_CMD_ATTRIB (0x1DU) /*!< ATTRIB command                 Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_PARAM2_DSI_SHIFT \
+    (6U) /*!< ATTRIB PARAM2 DSI shift        Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_PARAM2_DRI_SHIFT \
+    (4U) /*!< ATTRIB PARAM2 DRI shift        Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_PARAM2_DXI_MASK \
+    (0xF0U) /*!< ATTRIB PARAM2 DxI mask         Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_PARAM2_FSDI_MASK \
+    (0x0FU) /*!< ATTRIB PARAM2 FSDI mask        Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_PARAM4_DID_MASK \
+    (0x0FU) /*!< ATTRIB PARAM4 DID mask         Digital 1.1  14.6.1 */
+#define RFAL_ISODEP_ATTRIB_HDR_LEN (9U) /*!< ATTRIB REQ header length       Digital 1.1  14.6.1 */
+
+#define RFAL_ISODEP_ATTRIB_RES_HDR_LEN \
+    (1U) /*!< ATTRIB RES header length       Digital 1.1  14.6.2 */
+#define RFAL_ISODEP_ATTRIB_RES_MBLIDID_POS \
+    (0U) /*!< ATTRIB RES MBLI|DID position   Digital 1.1  14.6.2 */
+#define RFAL_ISODEP_ATTRIB_RES_DID_MASK \
+    (0x0FU) /*!< ATTRIB RES DID mask            Digital 1.1  14.6.2 */
+#define RFAL_ISODEP_ATTRIB_RES_MBLI_MASK \
+    (0x0FU) /*!< ATTRIB RES MBLI mask           Digital 1.1  14.6.2 */
+#define RFAL_ISODEP_ATTRIB_RES_MBLI_SHIFT \
+    (4U) /*!< ATTRIB RES MBLI shift          Digital 1.1  14.6.2 */
+
+#define RFAL_ISODEP_DID_MASK (0x0FU) /*!< ISODEP's DID mask                                  */
+#define RFAL_ISODEP_DID_00 (0U) /*!< ISODEP's DID value 0                               */
+
+#define RFAL_ISODEP_FSDI_MAX_NFC (8U) /*!< Max FSDI value   Digital 2.0  14.6.1.9 & B7 & B8   */
+#define RFAL_ISODEP_FSDI_MAX_NFC_21 \
+    (0x0CU) /*!< Max FSDI value   Digital 2.1  14.6.1.9 & Table 72  */
+#define RFAL_ISODEP_FSDI_MAX_EMV (0x0CU) /*!< Max FSDI value   EMVCo 3.0  5.7.2.5                */
+
+#define RFAL_ISODEP_RATS_PARAM_FSDI_MASK \
+    (0xF0U) /*!< Mask bits for FSDI in RATS                         */
+#define RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT \
+    (4U) /*!< Shift for FSDI in RATS                             */
+#define RFAL_ISODEP_RATS_PARAM_DID_MASK \
+    (0x0FU) /*!< Mask bits for DID in RATS                          */
+
+#define RFAL_ISODEP_ATS_TL_OFFSET \
+    (0x00U) /*!< Offset of TL on ATS                                */
+#define RFAL_ISODEP_ATS_TA_OFFSET \
+    (0x02U) /*!< Offset of TA if it is present on ATS               */
+#define RFAL_ISODEP_ATS_TB_OFFSET \
+    (0x03U) /*!< Offset of TB if both TA and TB is present on ATS   */
+#define RFAL_ISODEP_ATS_TC_OFFSET \
+    (0x04U) /*!< Offset of TC if both TA,TB & TC are present on ATS */
+#define RFAL_ISODEP_ATS_HIST_OFFSET \
+    (0x05U) /*!< Offset of Historical Bytes if TA, TB & TC are present on ATS          */
+#define RFAL_ISODEP_ATS_TC_ADV_FEAT \
+    (0x10U) /*!< Bit mask indicating support for Advanced protocol features: DID & NAD */
+#define RFAL_ISODEP_ATS_TC_DID (0x02U) /*!< Bit mask indicating support for DID                 */
+#define RFAL_ISODEP_ATS_TC_NAD (0x01U) /*!< Bit mask indicating support for NAD                 */
+
+#define RFAL_ISODEP_PPS0_PPS1_PRESENT \
+    (0x11U) /*!< PPS0 byte indicating that PPS1 is present            */
+#define RFAL_ISODEP_PPS0_PPS1_NOT_PRESENT \
+    (0x01U) /*!< PPS0 byte indicating that PPS1 is NOT present        */
+#define RFAL_ISODEP_PPS1_DRI_MASK \
+    (0x03U) /*!< PPS1 byte DRI mask bits                              */
+#define RFAL_ISODEP_PPS1_DSI_MASK \
+    (0x0CU) /*!< PPS1 byte DSI mask bits                              */
+#define RFAL_ISODEP_PPS1_DSI_SHIFT \
+    (2U) /*!< PPS1 byte DSI shift                                  */
+#define RFAL_ISODEP_PPS1_DxI_MASK \
+    (0x03U) /*!< PPS1 byte DSI/DRS mask bits                          */
+
+/*! Delta Time for polling during Activation (ATS) : 20ms    Digital 1.0 11.7.1.1 & A.7    */
+#define RFAL_ISODEP_T4T_DTIME_POLL_10 rfalConvMsTo1fc(20)
+
+/*! Delta Time for polling during Activation (ATS) : 16.4ms  Digital 1.1 13.8.1.1 & A.6
+ *  Use 16 ms as testcase T4AT_BI_10_03 sends a frame exactly at the border */
+#define RFAL_ISODEP_T4T_DTIME_POLL_11 216960U
+
+/*! Activation frame waiting time FWT(act) = 71680/fc (~5286us) Digital 1.1 13.8.1.1 & A.6 */
+#define RFAL_ISODEP_T4T_FWT_ACTIVATION (71680U + RFAL_ISODEP_T4T_DTIME_POLL_11)
+
+/*! Delta frame waiting time = 16/fc  Digital 1.0  11.7.1.3 & A.7*/
+#define RFAL_ISODEP_DFWT_10 16U
+
+/*! Delta frame waiting time = 16/fc  Digital 2.0  14.8.1.3 & B.7*/
+#define RFAL_ISODEP_DFWT_20 49152U
+
+/*
+ ******************************************************************************
+ * MACROS
+ ******************************************************************************
+ */
+
+#define isoDep_PCBisIBlock(pcb)                                       \
+    (((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_IB_VALID_MASK)) == \
+     (ISODEP_PCB_IBLOCK | ISODEP_PCB_IB_VALID_VAL)) /*!< Checks if pcb is a I-Block */
+#define isoDep_PCBisRBlock(pcb)                                       \
+    (((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_RB_VALID_MASK)) == \
+     (ISODEP_PCB_RBLOCK | ISODEP_PCB_RB_VALID_VAL)) /*!< Checks if pcb is a R-Block */
+#define isoDep_PCBisSBlock(pcb)                                       \
+    (((pcb) & (ISODEP_PCB_xBLOCK_MASK | ISODEP_PCB_SB_VALID_MASK)) == \
+     (ISODEP_PCB_SBLOCK | ISODEP_PCB_SB_VALID_VAL)) /*!< Checks if pcb is a S-Block */
+
+#define isoDep_PCBisChaining(pcb)         \
+    (((pcb) & ISODEP_PCB_CHAINING_BIT) == \
+     ISODEP_PCB_CHAINING_BIT) /*!< Checks if pcb is indicating chaining */
+
+#define isoDep_PCBisDeselect(pcb)     \
+    (((pcb) & ISODEP_PCB_Sxx_MASK) == \
+     ISODEP_PCB_DESELECT) /*!< Checks if pcb is indicating DESELECT */
+#define isoDep_PCBisWTX(pcb) \
+    (((pcb) & ISODEP_PCB_Sxx_MASK) == ISODEP_PCB_WTX) /*!< Checks if pcb is indicating WTX      */
+
+#define isoDep_PCBisACK(pcb) \
+    (((pcb) & ISODEP_PCB_Rx_MASK) == ISODEP_PCB_ACK) /*!< Checks if pcb is indicating ACK      */
+#define isoDep_PCBisNAK(pcb) \
+    (((pcb) & ISODEP_PCB_Rx_MASK) == ISODEP_PCB_NAK) /*!< Checks if pcb is indicating ACK      */
+
+#define isoDep_PCBhasDID(pcb)        \
+    (((pcb) & ISODEP_PCB_DID_BIT) == \
+     ISODEP_PCB_DID_BIT) /*!< Checks if pcb is indicating DID      */
+#define isoDep_PCBhasNAD(pcb)        \
+    (((pcb) & ISODEP_PCB_NAD_BIT) == \
+     ISODEP_PCB_NAD_BIT) /*!< Checks if pcb is indicating NAD      */
+
+#define isoDep_PCBisIChaining(pcb) \
+    (isoDep_PCBisIBlock(pcb) &&    \
+     isoDep_PCBisChaining(pcb)) /*!< Checks if pcb is I-Block indicating chaining*/
+
+#define isoDep_PCBisSDeselect(pcb) \
+    (isoDep_PCBisSBlock(pcb) &&    \
+     isoDep_PCBisDeselect(pcb)) /*!< Checks if pcb is S-Block indicating DESELECT*/
+#define isoDep_PCBisSWTX(pcb)   \
+    (isoDep_PCBisSBlock(pcb) && \
+     isoDep_PCBisWTX(pcb)) /*!< Checks if pcb is S-Block indicating WTX     */
+
+#define isoDep_PCBisRACK(pcb)   \
+    (isoDep_PCBisRBlock(pcb) && \
+     isoDep_PCBisACK(pcb)) /*!< Checks if pcb is R-Block indicating ACK     */
+#define isoDep_PCBisRNAK(pcb)   \
+    (isoDep_PCBisRBlock(pcb) && \
+     isoDep_PCBisNAK(pcb)) /*!< Checks if pcb is R-Block indicating NAK     */
+
+#define isoDep_PCBIBlock(bn)                                   \
+    ((uint8_t)(0x00U | ISODEP_PCB_IBLOCK | ISODEP_PCB_B2_BIT | \
+               ((bn) &                                         \
+                ISODEP_PCB_BN_MASK))) /*!< Returns an I-Block with the given block number (bn)                     */
+#define isoDep_PCBIBlockChaining(bn)  \
+    ((uint8_t)(isoDep_PCBIBlock(bn) | \
+               ISODEP_PCB_CHAINING_BIT)) /*!< Returns an I-Block with the given block number (bn) indicating chaining */
+
+#define isoDep_PCBRBlock(bn)                                                       \
+    ((uint8_t)(0x00U | ISODEP_PCB_RBLOCK | ISODEP_PCB_B6_BIT | ISODEP_PCB_B2_BIT | \
+               ((bn) &                                                             \
+                ISODEP_PCB_BN_MASK))) /*!< Returns an R-Block with the given block number (bn)                */
+#define isoDep_PCBRACK(bn)            \
+    ((uint8_t)(isoDep_PCBRBlock(bn) | \
+               ISODEP_PCB_ACK)) /*!< Returns an R-Block with the given block number (bn) indicating ACK */
+#define isoDep_PCBRNAK(bn)            \
+    ((uint8_t)(isoDep_PCBRBlock(bn) | \
+               ISODEP_PCB_NAK)) /*!< Returns an R-Block with the given block number (bn) indicating NAK */
+
+#define isoDep_GetBN(pcb) \
+    ((uint8_t)((pcb) &    \
+               ISODEP_PCB_BN_MASK)) /*!< Returns the block number (bn) from the given pcb */
+#define isoDep_GetWTXM(inf) \
+    ((uint8_t)((inf) &      \
+               ISODEP_SWTX_WTXM_MASK)) /*!< Returns the WTX value from the given inf byte    */
+#define isoDep_isWTXMValid(wtxm)    \
+    (((wtxm) >= ISODEP_WTXM_MIN) && \
+     ((wtxm) <= ISODEP_WTXM_MAX)) /*!< Checks if the given wtxm is valid                */
+
+#define isoDep_WTXMListenerMax(fwt)            \
+    (MIN(                                      \
+        (uint8_t)(ISODEP_FWT_LIS_MAX / (fwt)), \
+        ISODEP_WTXM_MAX)) /*!< Calculates the Max WTXM value for the given fwt as a Listener    */
+
+#define isoDepCalcdSGFT(s) \
+    (384U * ((uint32_t)1U  \
+             << (s))) /*!< Calculates the dSFGT with given SFGI  Digital 1.1  13.8.2.1 & A.6*/
+#define isoDepCalcSGFT(s)  \
+    (4096U * ((uint32_t)1U \
+              << (s))) /*!< Calculates the SFGT with given SFGI  Digital 1.1  13.8.2         */
+
+#define isoDep_PCBNextBN(bn)   \
+    (((uint8_t)(bn) ^ 0x01U) & \
+     ISODEP_PCB_BN_MASK) /*!< Returns the value of the next block number based on bn     */
+#define isoDep_PCBPrevBN(bn) \
+    isoDep_PCBNextBN(bn) /*!< Returns the value of the previous block number based on bn */
+#define isoDep_ToggleBN(bn) \
+    ((bn) =                 \
+         (((bn) ^ 0x01U) &  \
+          ISODEP_PCB_BN_MASK)) /*!< Toggles the block number value of the given bn             */
+
+#define isoDep_WTXAdjust(v) \
+    ((v) - ((v) >> 3)) /*!< Adjust WTX timer value to a percentage of the total, current 88% */
+
+/*! ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2  The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */
+#define isoDepReEnableRx(rxB, rxBL, rxL) \
+    rfalTransceiveBlockingTx(NULL, 0, rxB, rxBL, rxL, RFAL_TXRX_FLAGS_DEFAULT, RFAL_FWT_NONE)
+
+/*! Macro used for the blocking methods */
+#define rfalIsoDepRunBlocking(e, fn) \
+    do {                             \
+        (e) = (fn);                  \
+        rfalWorker();                \
+    } while((e) == ERR_BUSY)
+
+#define isoDepTimerStart(timer, time_ms)                    \
+    do {                                                    \
+        platformTimerDestroy(timer);                        \
+        (timer) = platformTimerCreate((uint16_t)(time_ms)); \
+    } while(0) /*!< Configures and starts the WTX timer  */
+#define isoDepTimerisExpired(timer) \
+    platformTimerIsExpired(timer) /*!< Checks WTX timer has expired                     */
+#define isoDepTimerDestroy(timer) \
+    platformTimerDestroy(timer) /*!< Destroys WTX timer                               */
+
+/*
+ ******************************************************************************
+ * LOCAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! Internal structure to be used in handling of S(PARAMETERS) only */
+typedef struct {
+    uint8_t pcb; /*!< PCB byte                      */
+    rfalIsoDepSParameter sParam; /*!< S(PARAMETERS)                 */
+} rfalIsoDepControlMsgSParam;
+
+/*! Enumeration of the possible control message types */
+typedef enum {
+    ISODEP_R_ACK, /*!< R-ACK  Acknowledge            */
+    ISODEP_R_NAK, /*!< R-NACK Negative acknowledge   */
+    ISODEP_S_WTX, /*!< S-WTX  Waiting Time Extension */
+    ISODEP_S_DSL /*!< S-DSL  Deselect               */
+} rfalIsoDepControlMsg;
+
+/*! Enumeration of the IsoDep roles */
+typedef enum {
+    ISODEP_ROLE_PCD, /*!< Perform as Reader/PCD          */
+    ISODEP_ROLE_PICC /*!< Perform as Card/PICC           */
+} rfalIsoDepRole;
+
+/*! ISO-DEP layer states */
+typedef enum {
+    ISODEP_ST_IDLE, /*!< Idle State                     */
+    ISODEP_ST_PCD_TX, /*!< PCD Transmission State         */
+    ISODEP_ST_PCD_RX, /*!< PCD Reception State            */
+    ISODEP_ST_PCD_WAIT_DSL, /*!< PCD Wait for DSL response      */
+
+    ISODEP_ST_PICC_ACT_ATS, /*!< PICC has replied to RATS (ATS) */
+    ISODEP_ST_PICC_ACT_ATTRIB, /*!< PICC has replied to ATTRIB     */
+    ISODEP_ST_PICC_RX, /*!< PICC Reception State           */
+    ISODEP_ST_PICC_SWTX, /*!< PICC Waiting Time eXtension    */
+    ISODEP_ST_PICC_SDSL, /*!< PICC S(DSL) response ongoing   */
+    ISODEP_ST_PICC_TX, /*!< PICC Transmission State        */
+
+    ISODEP_ST_PCD_ACT_RATS, /*!< PCD activation (RATS)          */
+    ISODEP_ST_PCD_ACT_PPS, /*!< PCD activation (PPS)           */
+
+} rfalIsoDepState;
+
+/*! Holds all ISO-DEP data(counters, buffers, ID, timeouts, frame size)         */
+typedef struct {
+    rfalIsoDepState state; /*!< ISO-DEP module state                      */
+    rfalIsoDepRole role; /*!< Current ISO-DEP role                      */
+
+    uint8_t blockNumber; /*!< Current block number                      */
+    uint8_t did; /*!< Current DID                               */
+    uint8_t nad; /*!< Current DID                               */
+    uint8_t cntIRetrys; /*!< I-Block retry counter                     */
+    uint8_t cntRRetrys; /*!< R-Block retry counter                     */
+    uint8_t cntSDslRetrys; /*!< S(DESELECT) retry counter                 */
+    uint8_t cntSWtxRetrys; /*!< Overall S(WTX) retry counter              */
+    uint8_t cntSWtxNack; /*!< R(NACK) answered with S(WTX) counter      */
+    uint32_t fwt; /*!< Current FWT (Frame Waiting Time)          */
+    uint32_t dFwt; /*!< Current delta FWT                         */
+    uint16_t fsx; /*!< Current FSx FSC or FSD (max Frame size)   */
+    bool isTxChaining; /*!< Flag for chaining on Tx                   */
+    bool isRxChaining; /*!< Flag for chaining on Rx                   */
+    uint8_t* txBuf; /*!< Tx buffer pointer                         */
+    uint8_t* rxBuf; /*!< Rx buffer pointer                         */
+    uint16_t txBufLen; /*!< Tx buffer length                          */
+    uint16_t rxBufLen; /*!< Rx buffer length                          */
+    uint8_t txBufInfPos; /*!< Start of payload in txBuf                 */
+    uint8_t rxBufInfPos; /*!< Start of payload in rxBuf                 */
+
+    uint16_t ourFsx; /*!< Our current FSx FSC or FSD (Frame size)   */
+    uint8_t lastPCB; /*!< Last PCB sent                             */
+    uint8_t lastWTXM; /*!< Last WTXM sent                            */
+    uint8_t atsTA; /*!< TA on ATS                                 */
+    uint8_t hdrLen; /*!< Current ISO-DEP length                    */
+    rfalBitRate txBR; /*!< Current Tx Bit Rate                       */
+    rfalBitRate rxBR; /*!< Current Rx Bit Rate                       */
+    uint16_t* rxLen; /*!< Output parameter ptr to Rx length         */
+    bool* rxChaining; /*!< Output parameter ptr to Rx chaining flag  */
+    uint32_t WTXTimer; /*!< Timer used for WTX                        */
+    bool lastDID00; /*!< Last PCD block had DID flag (for DID = 0) */
+
+    bool isTxPending; /*!< Flag pending Block while waiting WTX Ack  */
+    bool isWait4WTX; /*!< Flag for waiting WTX Ack                  */
+
+    uint8_t maxRetriesI; /*!< Number of retries for a I-Block           */
+    uint8_t maxRetriesR; /*!< Number of retries for a R-Block           */
+    uint8_t maxRetriesSDSL; /*!< Number of retries for S(DESELECT) errors  */
+    uint8_t maxRetriesSWTX; /*!< Number of retries for S(WTX) errors       */
+    uint8_t maxRetriesSnWTX; /*!< Number of retries S(WTX) replied w NACK  */
+    uint8_t maxRetriesRATS; /*!< Number of retries for RATS                */
+
+    rfalComplianceMode compMode; /*!< Compliance mode                           */
+
+    uint8_t ctrlBuf[ISODEP_CONTROLMSG_BUF_LEN]; /*!< Control msg buf   */
+    uint16_t ctrlRxLen; /*!< Control msg rcvd len                         */
+
+    union { /*  PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one frame at a time */
+#if RFAL_FEATURE_NFCA
+        rfalIsoDepRats ratsReq;
+        rfalIsoDepPpsReq ppsReq;
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_NFCB
+        rfalIsoDepAttribCmd attribReq;
+#endif /* RFAL_FEATURE_NFCB */
+    } actv; /*!< Activation buffer              */
+
+    uint8_t* rxLen8; /*!< Receive length (8-bit)         */
+    rfalIsoDepDevice* actvDev; /*!< Activation Device Info         */
+    rfalIsoDepListenActvParam actvParam; /*!< Listen Activation context      */
+
+    rfalIsoDepApduTxRxParam APDUParam; /*!< APDU TxRx params               */
+    uint16_t APDUTxPos; /*!< APDU Tx position               */
+    uint16_t APDURxPos; /*!< APDU Rx position               */
+    bool isAPDURxChaining; /*!< APDU Transceive chaining flag  */
+
+} rfalIsoDep;
+
+/*
+ ******************************************************************************
+ * LOCAL VARIABLES
+ ******************************************************************************
+ */
+
+static rfalIsoDep gIsoDep; /*!< ISO-DEP Module instance               */
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+static void isoDepClearCounters(void);
+static ReturnCode
+    isoDepTx(uint8_t pcb, const uint8_t* txBuf, uint8_t* infBuf, uint16_t infLen, uint32_t fwt);
+static ReturnCode isoDepHandleControlMsg(rfalIsoDepControlMsg controlMsg, uint8_t param);
+static void rfalIsoDepApdu2IBLockParam(
+    rfalIsoDepApduTxRxParam apduParam,
+    rfalIsoDepTxRxParam* iBlockParam,
+    uint16_t txPos,
+    uint16_t rxPos);
+
+#if RFAL_FEATURE_ISO_DEP_POLL
+static ReturnCode isoDepDataExchangePCD(uint16_t* outActRxLen, bool* outIsChaining);
+static void rfalIsoDepCalcBitRate(
+    rfalBitRate maxAllowedBR,
+    uint8_t piccBRCapability,
+    rfalBitRate* dsi,
+    rfalBitRate* dri);
+static uint32_t rfalIsoDepSFGI2SFGT(uint8_t sfgi);
+
+#if RFAL_FEATURE_NFCA
+static ReturnCode
+    rfalIsoDepStartRATS(rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts* ats, uint8_t* atsLen);
+static ReturnCode rfalIsoDepGetRATSStatus(void);
+static ReturnCode
+    rfalIsoDepStartPPS(uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes* ppsRes);
+static ReturnCode rfalIsoDepGetPPSSTatus(void);
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_NFCB
+static ReturnCode rfalIsoDepStartATTRIB(
+    const uint8_t* nfcid0,
+    uint8_t PARAM1,
+    rfalBitRate DSI,
+    rfalBitRate DRI,
+    rfalIsoDepFSxI FSDI,
+    uint8_t PARAM3,
+    uint8_t DID,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    uint32_t fwt,
+    rfalIsoDepAttribRes* attribRes,
+    uint8_t* attribResLen);
+static ReturnCode rfalIsoDepGetATTRIBStatus(void);
+#endif /* RFAL_FEATURE_NFCB */
+
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+
+#if RFAL_FEATURE_ISO_DEP_LISTEN
+static ReturnCode isoDepDataExchangePICC(void);
+static ReturnCode isoDepReSendControlMsg(void);
+#endif
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*******************************************************************************/
+static void isoDepClearCounters(void) {
+    gIsoDep.cntIRetrys = 0;
+    gIsoDep.cntRRetrys = 0;
+    gIsoDep.cntSDslRetrys = 0;
+    gIsoDep.cntSWtxRetrys = 0;
+    gIsoDep.cntSWtxNack = 0;
+}
+
+/*******************************************************************************/
+static ReturnCode
+    isoDepTx(uint8_t pcb, const uint8_t* txBuf, uint8_t* infBuf, uint16_t infLen, uint32_t fwt) {
+    uint8_t* txBlock;
+    uint16_t txBufLen;
+    uint8_t computedPcb;
+    rfalTransceiveContext ctx;
+
+    txBlock = infBuf; /* Point to beginning of the INF, and go backwards     */
+    gIsoDep.lastPCB = pcb; /* Store the last PCB sent                             */
+
+    if(infLen > 0U) {
+        if(((uint32_t)infBuf - (uint32_t)txBuf) <
+           gIsoDep.hdrLen) /* Check that we can fit the header in the given space */
+        {
+            return ERR_NOMEM;
+        }
+    }
+
+    /*******************************************************************************/
+    /* Compute optional PCB bits */
+    computedPcb = pcb;
+    if((gIsoDep.did != RFAL_ISODEP_NO_DID) ||
+       ((gIsoDep.did == RFAL_ISODEP_DID_00) && gIsoDep.lastDID00)) {
+        computedPcb |= ISODEP_PCB_DID_BIT;
+    }
+    if(gIsoDep.nad != RFAL_ISODEP_NO_NAD) {
+        computedPcb |= ISODEP_PCB_NAD_BIT;
+    }
+    if((gIsoDep.isTxChaining) && (isoDep_PCBisIBlock(computedPcb))) {
+        computedPcb |= ISODEP_PCB_CHAINING_BIT;
+    }
+
+    /*******************************************************************************/
+    /* Compute Payload on the given txBuf, start by the PCB | DID | NAD | before INF */
+
+    if(gIsoDep.nad != RFAL_ISODEP_NO_NAD) {
+        *(--txBlock) = gIsoDep.nad; /* NAD is optional */
+    }
+
+    if((gIsoDep.did != RFAL_ISODEP_NO_DID) ||
+       ((gIsoDep.did == RFAL_ISODEP_DID_00) && gIsoDep.lastDID00)) {
+        *(--txBlock) = gIsoDep.did; /* DID is optional */
+    }
+
+    *(--txBlock) = computedPcb; /* PCB always present */
+
+    txBufLen =
+        (infLen +
+         (uint16_t)((uint32_t)infBuf - (uint32_t)txBlock)); /* Calculate overall buffer size */
+
+    if(txBufLen > (gIsoDep.fsx -
+                   ISODEP_CRC_LEN)) /* Check if msg length violates the maximum frame size FSC */
+    {
+        return ERR_NOTSUPP;
+    }
+
+    rfalCreateByteFlagsTxRxContext(
+        ctx,
+        txBlock,
+        txBufLen,
+        gIsoDep.rxBuf,
+        gIsoDep.rxBufLen,
+        gIsoDep.rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        ((gIsoDep.role == ISODEP_ROLE_PICC) ? RFAL_FWT_NONE : fwt));
+    return rfalStartTransceive(&ctx);
+}
+
+/*******************************************************************************/
+static ReturnCode isoDepHandleControlMsg(rfalIsoDepControlMsg controlMsg, uint8_t param) {
+    uint8_t pcb;
+    uint8_t infLen;
+    uint32_t fwtTemp;
+
+    infLen = 0;
+    fwtTemp = (gIsoDep.fwt + gIsoDep.dFwt);
+    ST_MEMSET(gIsoDep.ctrlBuf, 0x00, ISODEP_CONTROLMSG_BUF_LEN);
+
+    switch(controlMsg) {
+    /*******************************************************************************/
+    case ISODEP_R_ACK:
+
+        if(gIsoDep.cntRRetrys++ > gIsoDep.maxRetriesR) {
+            return ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */
+        }
+
+        pcb = isoDep_PCBRACK(gIsoDep.blockNumber);
+        break;
+
+    /*******************************************************************************/
+    case ISODEP_R_NAK:
+
+        if((gIsoDep.cntRRetrys++ > gIsoDep.maxRetriesR) || /* Max R Block retries reached */
+           (gIsoDep.cntSWtxNack >=
+            gIsoDep
+                .maxRetriesSnWTX)) /* Max number PICC is allowed to respond with S(WTX) to R(NAK) */
+        {
+            return ERR_TIMEOUT;
+        }
+
+        pcb = isoDep_PCBRNAK(gIsoDep.blockNumber);
+        break;
+
+    /*******************************************************************************/
+    case ISODEP_S_WTX:
+
+        if((gIsoDep.cntSWtxRetrys++ > gIsoDep.maxRetriesSWTX) &&
+           (gIsoDep.maxRetriesSWTX != RFAL_ISODEP_MAX_WTX_RETRYS_ULTD)) {
+            return ERR_PROTO;
+        }
+
+        /* Check if WTXM is valid */
+        if(!isoDep_isWTXMValid(param)) {
+            return ERR_PROTO;
+        }
+
+        if(gIsoDep.role == ISODEP_ROLE_PCD) {
+            /* Calculate temp Wait Time eXtension */
+            fwtTemp = (gIsoDep.fwt * param);
+            fwtTemp = MIN(RFAL_ISODEP_MAX_FWT, fwtTemp);
+            fwtTemp += gIsoDep.dFwt;
+        }
+
+        pcb = ISODEP_PCB_SWTX;
+        gIsoDep.ctrlBuf[RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN + infLen++] = param;
+        break;
+
+    /*******************************************************************************/
+    case ISODEP_S_DSL:
+
+        if(gIsoDep.cntSDslRetrys++ > gIsoDep.maxRetriesSDSL) {
+            return ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */
+        }
+
+        if(gIsoDep.role == ISODEP_ROLE_PCD) {
+            /* Digital 1.0 - 13.2.7.3 Poller must wait fwtDEACTIVATION */
+            fwtTemp = ISODEP_FWT_DEACTIVATION;
+            gIsoDep.state = ISODEP_ST_PCD_WAIT_DSL;
+        }
+        pcb = ISODEP_PCB_SDSL;
+        break;
+
+    /*******************************************************************************/
+    default:
+        return ERR_INTERNAL;
+    }
+
+    return isoDepTx(
+        pcb,
+        gIsoDep.ctrlBuf,
+        &gIsoDep.ctrlBuf[RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN],
+        infLen,
+        fwtTemp);
+}
+
+#if RFAL_FEATURE_ISO_DEP_LISTEN
+/*******************************************************************************/
+static ReturnCode isoDepReSendControlMsg(void) {
+    if(isoDep_PCBisRACK(gIsoDep.lastPCB)) {
+        return isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM);
+    }
+
+    if(isoDep_PCBisRNAK(gIsoDep.lastPCB)) {
+        return isoDepHandleControlMsg(ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM);
+    }
+
+    if(isoDep_PCBisSDeselect(gIsoDep.lastPCB)) {
+        return isoDepHandleControlMsg(ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM);
+    }
+
+    if(isoDep_PCBisSWTX(gIsoDep.lastPCB)) {
+        return isoDepHandleControlMsg(ISODEP_S_WTX, gIsoDep.lastWTXM);
+    }
+    return ERR_WRONG_STATE;
+}
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*******************************************************************************/
+void rfalIsoDepInitialize(void) {
+    gIsoDep.state = ISODEP_ST_IDLE;
+    gIsoDep.role = ISODEP_ROLE_PCD;
+    gIsoDep.did = RFAL_ISODEP_NO_DID;
+    gIsoDep.nad = RFAL_ISODEP_NO_NAD;
+    gIsoDep.blockNumber = 0;
+    gIsoDep.isTxChaining = false;
+    gIsoDep.isRxChaining = false;
+    gIsoDep.lastDID00 = false;
+    gIsoDep.lastPCB = ISODEP_PCB_INVALID;
+    gIsoDep.fsx = (uint16_t)RFAL_ISODEP_FSX_16;
+    gIsoDep.ourFsx = (uint16_t)RFAL_ISODEP_FSX_16;
+    gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN;
+
+    gIsoDep.rxLen = NULL;
+    gIsoDep.rxBuf = NULL;
+    gIsoDep.rxBufInfPos = 0U;
+    gIsoDep.txBufInfPos = 0U;
+
+    gIsoDep.isTxPending = false;
+    gIsoDep.isWait4WTX = false;
+
+    gIsoDep.compMode = RFAL_COMPLIANCE_MODE_NFC;
+    gIsoDep.maxRetriesR = RFAL_ISODEP_MAX_R_RETRYS;
+    gIsoDep.maxRetriesI = RFAL_ISODEP_MAX_I_RETRYS;
+    gIsoDep.maxRetriesSDSL = RFAL_ISODEP_MAX_DSL_RETRYS;
+    gIsoDep.maxRetriesSWTX = RFAL_ISODEP_MAX_WTX_RETRYS;
+    gIsoDep.maxRetriesSnWTX = RFAL_ISODEP_MAX_WTX_NACK_RETRYS;
+    gIsoDep.maxRetriesRATS = RFAL_ISODEP_RATS_RETRIES;
+
+    gIsoDep.APDURxPos = 0;
+    gIsoDep.APDUTxPos = 0;
+    gIsoDep.APDUParam.rxLen = NULL;
+    gIsoDep.APDUParam.rxBuf = NULL;
+    gIsoDep.APDUParam.txBuf = NULL;
+
+    isoDepClearCounters();
+
+    /* Destroy any ongoing WTX timer */
+    isoDepTimerDestroy(gIsoDep.WTXTimer);
+    gIsoDep.WTXTimer = 0U;
+}
+
+/*******************************************************************************/
+void rfalIsoDepInitializeWithParams(
+    rfalComplianceMode compMode,
+    uint8_t maxRetriesR,
+    uint8_t maxRetriesSnWTX,
+    uint8_t maxRetriesSWTX,
+    uint8_t maxRetriesSDSL,
+    uint8_t maxRetriesI,
+    uint8_t maxRetriesRATS) {
+    rfalIsoDepInitialize();
+
+    gIsoDep.compMode = compMode;
+    gIsoDep.maxRetriesR = maxRetriesR;
+    gIsoDep.maxRetriesSnWTX = maxRetriesSnWTX;
+    gIsoDep.maxRetriesSWTX = maxRetriesSWTX;
+    gIsoDep.maxRetriesSDSL = maxRetriesSDSL;
+    gIsoDep.maxRetriesI = maxRetriesI;
+    gIsoDep.maxRetriesRATS = maxRetriesRATS;
+}
+
+#if RFAL_FEATURE_ISO_DEP_POLL
+/*******************************************************************************/
+static ReturnCode isoDepDataExchangePCD(uint16_t* outActRxLen, bool* outIsChaining) {
+    ReturnCode ret;
+    uint8_t rxPCB;
+
+    /* Check out parameters */
+    if((outActRxLen == NULL) || (outIsChaining == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *outIsChaining = false;
+
+    /* Calculate header required and check if the buffers InfPositions are suitable */
+    gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN;
+    if(gIsoDep.did != RFAL_ISODEP_NO_DID) {
+        gIsoDep.hdrLen += RFAL_ISODEP_DID_LEN;
+    }
+    if(gIsoDep.nad != RFAL_ISODEP_NO_NAD) {
+        gIsoDep.hdrLen += RFAL_ISODEP_NAD_LEN;
+    }
+
+    /* Check if there is enough space before the infPos to append ISO-DEP headers on rx and tx */
+    if((gIsoDep.rxBufInfPos < gIsoDep.hdrLen) || (gIsoDep.txBufInfPos < gIsoDep.hdrLen)) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    switch(gIsoDep.state) {
+    /*******************************************************************************/
+    case ISODEP_ST_IDLE:
+        return ERR_NONE;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PCD_TX:
+        ret = isoDepTx(
+            isoDep_PCBIBlock(gIsoDep.blockNumber),
+            gIsoDep.txBuf,
+            &gIsoDep.txBuf[gIsoDep.txBufInfPos],
+            gIsoDep.txBufLen,
+            (gIsoDep.fwt + gIsoDep.dFwt));
+        switch(ret) {
+        case ERR_NONE:
+            gIsoDep.state = ISODEP_ST_PCD_RX;
+            break;
+
+        default:
+            return ret;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    case ISODEP_ST_PCD_WAIT_DSL: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+    case ISODEP_ST_PCD_RX:
+
+        ret = rfalGetTransceiveStatus();
+        switch(ret) {
+        /* Data rcvd with error or timeout -> Send R-NAK */
+        case ERR_TIMEOUT:
+        case ERR_CRC:
+        case ERR_PAR:
+        case ERR_FRAMING: /* added to handle test cases scenario TC_POL_NFCB_T4AT_BI_82_x_y & TC_POL_NFCB_T4BT_BI_82_x_y */
+        case ERR_INCOMPLETE_BYTE: /* added to handle test cases scenario TC_POL_NFCB_T4AT_BI_82_x_y & TC_POL_NFCB_T4BT_BI_82_x_y */
+
+            if(gIsoDep
+                   .isRxChaining) { /* Rule 5 - In PICC chaining when a invalid/timeout occurs -> R-ACK */
+                EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM));
+            } else if(
+                gIsoDep.state ==
+                ISODEP_ST_PCD_WAIT_DSL) { /* Rule 8 - If s-Deselect response fails MAY retransmit */
+                EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM));
+            } else { /* Rule 4 - When a invalid block or timeout occurs -> R-NACK */
+                EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM));
+            }
+            return ERR_BUSY;
+
+        case ERR_NONE:
+            break;
+
+        case ERR_BUSY:
+            return ERR_BUSY; /* Debug purposes */
+
+        default:
+            return ret;
+        }
+
+        /*******************************************************************************/
+        /* No error, process incoming msg                                              */
+        /*******************************************************************************/
+
+        (*outActRxLen) = rfalConvBitsToBytes(*outActRxLen);
+
+        /* Check rcvd msg length, cannot be less then the expected header */
+        if(((*outActRxLen) < gIsoDep.hdrLen) || ((*outActRxLen) >= gIsoDep.ourFsx)) {
+            return ERR_PROTO;
+        }
+
+        /* Grab rcvd PCB */
+        rxPCB = gIsoDep.rxBuf[ISODEP_PCB_POS];
+
+        /* EMVCo doesn't allow usage of for CID or NAD   EMVCo 2.6 TAble 10.2 */
+        if((gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) &&
+           (isoDep_PCBhasDID(rxPCB) || isoDep_PCBhasNAD(rxPCB))) {
+            return ERR_PROTO;
+        }
+
+        /* If we are expecting DID, check if PCB signals its presence and if device ID match*/
+        if((gIsoDep.did != RFAL_ISODEP_NO_DID) &&
+           (!isoDep_PCBhasDID(rxPCB) || (gIsoDep.did != gIsoDep.rxBuf[ISODEP_DID_POS]))) {
+            return ERR_PROTO;
+        }
+
+        /*******************************************************************************/
+        /* Process S-Block                                                             */
+        /*******************************************************************************/
+        if(isoDep_PCBisSBlock(rxPCB)) {
+            /* Check if is a Wait Time eXtension */
+            if(isoDep_PCBisSWTX(rxPCB)) {
+                /* Check if PICC has requested S(WTX) as response to R(NAK)  EMVCo 3.0 10.3.5.5 / Digital 2.0  16.2.6.5 */
+                if(isoDep_PCBisRNAK(gIsoDep.lastPCB)) {
+                    gIsoDep.cntSWtxNack++; /* Count S(WTX) upon R(NAK) */
+                    gIsoDep.cntRRetrys = 0; /* Reset R-Block counter has PICC has responded */
+                } else {
+                    gIsoDep.cntSWtxNack = 0; /* Reset R(NACK)->S(WTX) counter */
+                }
+
+                /* Rule 3 - respond to S-block: get 1st INF byte S(STW): Power + WTXM */
+                EXIT_ON_ERR(
+                    ret,
+                    isoDepHandleControlMsg(
+                        ISODEP_S_WTX, isoDep_GetWTXM(gIsoDep.rxBuf[gIsoDep.hdrLen])));
+                return ERR_BUSY;
+            }
+
+            /* Check if is a deselect response */
+            if(isoDep_PCBisSDeselect(rxPCB)) {
+                if(gIsoDep.state == ISODEP_ST_PCD_WAIT_DSL) {
+                    rfalIsoDepInitialize(); /* Session finished reInit vars */
+                    return ERR_NONE;
+                }
+
+                /* Deselect response not expected  */
+                /* fall through to PROTO error */
+            }
+            /* Unexpected S-Block */
+            return ERR_PROTO;
+        }
+
+        /*******************************************************************************/
+        /* Process R-Block                                                             */
+        /*******************************************************************************/
+        else if(isoDep_PCBisRBlock(rxPCB)) {
+            if(isoDep_PCBisRACK(rxPCB)) /* Check if is a R-ACK */
+            {
+                if(isoDep_GetBN(rxPCB) == gIsoDep.blockNumber) /* Expected block number  */
+                {
+                    /* Rule B - ACK with expected bn -> Increment block number */
+                    gIsoDep.blockNumber = isoDep_PCBNextBN(gIsoDep.blockNumber);
+
+                    /* R-ACK only allowed when PCD chaining */
+                    if(!gIsoDep.isTxChaining) {
+                        return ERR_PROTO;
+                    }
+
+                    /* Rule 7 - Chaining transaction done, continue chaining */
+                    isoDepClearCounters();
+                    return ERR_NONE; /* This block has been transmitted */
+                } else {
+                    /* Rule 6 - R-ACK with wrong block number retransmit                          */
+                    /* Digital 2.0  16.2.5.4 - Retransmit maximum two times                       */
+                    /* EMVCo 3.0 10.3.4.3 -  PCD may re-transmit the last I-Block or report error */
+                    if(gIsoDep.cntIRetrys++ < gIsoDep.maxRetriesI) {
+                        gIsoDep.cntRRetrys = 0; /* Clear R counter only */
+                        gIsoDep.state = ISODEP_ST_PCD_TX;
+                        return ERR_BUSY;
+                    }
+                    return ERR_TIMEOUT; /* NFC Forum mandates timeout or transmission error depending on previous errors */
+                }
+            } else /* Unexpected R-Block */
+            {
+                return ERR_PROTO;
+            }
+        }
+
+        /*******************************************************************************/
+        /* Process I-Block                                                             */
+        /*******************************************************************************/
+        else if(isoDep_PCBisIBlock(rxPCB)) {
+            /*******************************************************************************/
+            /* is PICC performing chaining                                                 */
+            if(isoDep_PCBisChaining(rxPCB)) {
+                gIsoDep.isRxChaining = true;
+                *outIsChaining = true;
+
+                if(isoDep_GetBN(rxPCB) == gIsoDep.blockNumber) {
+                    /* Rule B - ACK with correct block number -> Increase Block number */
+                    isoDep_ToggleBN(gIsoDep.blockNumber);
+
+                    isoDepClearCounters(); /* Clear counters in case R counter is already at max */
+
+                    /* Rule 2 - Send ACK */
+                    EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM));
+
+                    /* Received I-Block with chaining, send current data to DH */
+
+                    /* remove ISO DEP header, check is necessary to move the INF data on the buffer */
+                    *outActRxLen -= gIsoDep.hdrLen;
+                    if((gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*outActRxLen > 0U)) {
+                        ST_MEMMOVE(
+                            &gIsoDep.rxBuf[gIsoDep.rxBufInfPos],
+                            &gIsoDep.rxBuf[gIsoDep.hdrLen],
+                            *outActRxLen);
+                    }
+
+                    isoDepClearCounters();
+                    return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived */
+                } else {
+                    /* Rule 5 - PICC chaining invalid I-Block -> R-ACK */
+                    EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM));
+                }
+                return ERR_BUSY;
+            }
+
+            gIsoDep.isRxChaining = false; /* clear PICC chaining flag */
+
+            if(isoDep_GetBN(rxPCB) == gIsoDep.blockNumber) {
+                /* Rule B - I-Block with correct block number -> Increase Block number */
+                isoDep_ToggleBN(gIsoDep.blockNumber);
+
+                /* I-Block transaction done successfully */
+
+                /* remove ISO DEP header, check is necessary to move the INF data on the buffer */
+                *outActRxLen -= gIsoDep.hdrLen;
+                if((gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*outActRxLen > 0U)) {
+                    ST_MEMMOVE(
+                        &gIsoDep.rxBuf[gIsoDep.rxBufInfPos],
+                        &gIsoDep.rxBuf[gIsoDep.hdrLen],
+                        *outActRxLen);
+                }
+
+                gIsoDep.state = ISODEP_ST_IDLE;
+                isoDepClearCounters();
+                return ERR_NONE;
+            } else {
+                if((gIsoDep.compMode != RFAL_COMPLIANCE_MODE_ISO)) {
+                    /* Invalid Block (not chaining) -> Raise error   Digital 1.1  15.2.6.4   EMVCo 2.6  10.3.5.4 */
+                    return ERR_PROTO;
+                }
+
+                /* Rule 4 - Invalid Block -> R-NAK */
+                EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_NAK, RFAL_ISODEP_NO_PARAM));
+                return ERR_BUSY;
+            }
+        } else /* not S/R/I - Block */
+        {
+            return ERR_PROTO;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    default: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+        /* MISRA 16.4: no empty default (comment will suffice) */
+        break;
+    }
+
+    return ERR_INTERNAL;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepDeselect(void) {
+    ReturnCode ret;
+    uint32_t cntRerun;
+    bool dummyB;
+
+    /*******************************************************************************/
+    /* Using local static vars and static config to cope with a Deselect after     *
+     * RATS\ATTRIB without any I-Block exchanged                                   */
+    gIsoDep.rxLen = &gIsoDep.ctrlRxLen;
+    gIsoDep.rxBuf = gIsoDep.ctrlBuf;
+    gIsoDep.rxBufLen = ISODEP_CONTROLMSG_BUF_LEN - (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN);
+    gIsoDep.rxBufInfPos = (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN);
+    gIsoDep.txBufInfPos = (RFAL_ISODEP_PCB_LEN + RFAL_ISODEP_DID_LEN);
+
+    /*******************************************************************************/
+    /* The Deselect process is being done blocking, Digital 1.0 - 13.2.7.1 MUST wait response and retry*/
+    /* Set the maximum reruns while we will wait for a response */
+    cntRerun = ISODEP_MAX_RERUNS;
+
+    /* Send DSL request and run protocol until get a response, error or "timeout" */
+    EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM));
+    do {
+        ret = isoDepDataExchangePCD(gIsoDep.rxLen, &dummyB);
+        rfalWorker();
+    } while(((cntRerun--) != 0U) && (ret == ERR_BUSY));
+
+    rfalIsoDepInitialize();
+    return ((cntRerun == 0U) ? ERR_TIMEOUT : ret);
+}
+
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+
+/*******************************************************************************/
+uint32_t rfalIsoDepFWI2FWT(uint8_t fwi) {
+    uint32_t result;
+    uint8_t tmpFWI;
+
+    tmpFWI = fwi;
+
+    /* RFU values -> take the default value  
+     * Digital 1.0  11.6.2.17  FWI[1,14]
+     * Digital 1.1  7.6.2.22   FWI[0,14]
+     * EMVCo 2.6    Table A.5  FWI[0,14] */
+    if(tmpFWI > ISODEP_FWI_MAX) {
+        tmpFWI = RFAL_ISODEP_FWI_DEFAULT;
+    }
+
+    /* FWT = (256 x 16/fC) x 2^FWI => 2^(FWI+12)  Digital 1.1  13.8.1 & 7.9.1 */
+
+    result = ((uint32_t)1U << (tmpFWI + 12U));
+    result = MIN(RFAL_ISODEP_MAX_FWT, result); /* Maximum Frame Waiting Time must be fulfilled */
+
+    return result;
+}
+
+/*******************************************************************************/
+uint16_t rfalIsoDepFSxI2FSx(uint8_t FSxI) {
+    uint16_t fsx;
+    uint8_t fsi;
+
+    /* Enforce maximum FSxI/FSx allowed - NFC Forum and EMVCo differ */
+    fsi =
+        ((gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) ? MIN(FSxI, RFAL_ISODEP_FSDI_MAX_EMV) :
+                                                          MIN(FSxI, RFAL_ISODEP_FSDI_MAX_NFC));
+
+    switch(fsi) {
+    case(uint8_t)RFAL_ISODEP_FSXI_16:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_16;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_24:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_24;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_32:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_32;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_40:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_40;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_48:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_48;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_64:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_64;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_96:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_96;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_128:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_128;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_256:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_256;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_512:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_512;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_1024:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_1024;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_2048:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_2048;
+        break;
+    case(uint8_t)RFAL_ISODEP_FSXI_4096:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_4096;
+        break;
+    default:
+        fsx = (uint16_t)RFAL_ISODEP_FSX_256;
+        break;
+    }
+    return fsx;
+}
+
+#if RFAL_FEATURE_ISO_DEP_LISTEN
+
+/*******************************************************************************/
+bool rfalIsoDepIsRats(const uint8_t* buf, uint8_t bufLen) {
+    if(buf != NULL) {
+        if((RFAL_ISODEP_CMD_RATS == (uint8_t)*buf) && (sizeof(rfalIsoDepRats) == bufLen)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*******************************************************************************/
+bool rfalIsoDepIsAttrib(const uint8_t* buf, uint8_t bufLen) {
+    if(buf != NULL) {
+        if((RFAL_ISODEP_CMD_ATTRIB == (uint8_t)*buf) &&
+           (RFAL_ISODEP_ATTRIB_REQ_MIN_LEN <= bufLen) &&
+           ((RFAL_ISODEP_ATTRIB_REQ_MIN_LEN + RFAL_ISODEP_ATTRIB_HLINFO_LEN) >= bufLen)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepListenStartActivation(
+    rfalIsoDepAtsParam* atsParam,
+    const rfalIsoDepAttribResParam* attribResParam,
+    const uint8_t* buf,
+    uint16_t bufLen,
+    rfalIsoDepListenActvParam actParam) {
+    uint8_t* txBuf;
+    uint8_t bufIt;
+    const uint8_t* buffer = buf;
+
+    /*******************************************************************************/
+    bufIt = 0;
+    txBuf =
+        (uint8_t*)actParam
+            .rxBuf; /* Use the rxBuf as TxBuf as well, the struct enforces a size enough MAX( NFCA_ATS_MAX_LEN, NFCB_ATTRIB_RES_MAX_LEN ) */
+    gIsoDep.txBR = RFAL_BR_106;
+    gIsoDep.rxBR = RFAL_BR_106;
+
+    /* Check for a valid buffer pointer */
+    if(buffer == NULL) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    if(*buffer == RFAL_ISODEP_CMD_RATS) {
+        /* Check ATS parameters */
+        if(atsParam == NULL) {
+            return ERR_PARAM;
+        }
+
+        /* If requested copy RATS to device info */
+        if(actParam.isoDepDev != NULL) {
+            ST_MEMCPY(
+                (uint8_t*)&actParam.isoDepDev->activation.A.Poller.RATS,
+                buffer,
+                sizeof(rfalIsoDepRats)); /* Copy RATS' CMD + PARAM */
+        }
+
+        /*******************************************************************************/
+        /* Process RATS                                                                */
+        buffer++;
+        gIsoDep.fsx = rfalIsoDepFSxI2FSx(
+            (((*buffer) & RFAL_ISODEP_RATS_PARAM_FSDI_MASK) >> RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT));
+        gIsoDep.did = (*buffer & RFAL_ISODEP_DID_MASK);
+
+        /*******************************************************************************/
+        /* Digital 1.1  13.6.1.8 - DID as to between 0 and 14 */
+        if(gIsoDep.did > RFAL_ISODEP_DID_MAX) {
+            return ERR_PROTO;
+        }
+
+        /* Check if we are configured to support DID */
+        if((gIsoDep.did != RFAL_ISODEP_DID_00) && (!atsParam->didSupport)) {
+            return ERR_NOTSUPP;
+        }
+
+        /*******************************************************************************/
+        /* Check RFAL supported bit rates  */
+        if((!(RFAL_SUPPORT_BR_CE_A_212) &&
+            (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_212) != 0U) ||
+             ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_212) != 0U))) ||
+           (!(RFAL_SUPPORT_BR_CE_A_424) &&
+            (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_424) != 0U) ||
+             ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_424) != 0U))) ||
+           (!(RFAL_SUPPORT_BR_CE_A_848) &&
+            (((atsParam->ta & RFAL_ISODEP_ATS_TA_DPL_848) != 0U) ||
+             ((atsParam->ta & RFAL_ISODEP_ATS_TA_DLP_848) != 0U)))) {
+            return ERR_NOTSUPP;
+        }
+
+        /* Enforce proper FWI configuration */
+        if(atsParam->fwi > ISODEP_FWI_LIS_MAX) {
+            atsParam->fwi = ISODEP_FWI_LIS_MAX;
+        }
+
+        gIsoDep.atsTA = atsParam->ta;
+        gIsoDep.fwt = rfalIsoDepFWI2FWT(atsParam->fwi);
+        gIsoDep.ourFsx = rfalIsoDepFSxI2FSx(atsParam->fsci);
+
+        /* Ensure proper/maximum Historical Bytes length  */
+        atsParam->hbLen = MIN(RFAL_ISODEP_ATS_HB_MAX_LEN, atsParam->hbLen);
+
+        /*******************************************************************************/
+        /* Compute ATS                                                                 */
+
+        txBuf[bufIt++] = (RFAL_ISODEP_ATS_HIST_OFFSET + atsParam->hbLen); /* TL */
+        txBuf[bufIt++] =
+            ((RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK | RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK |
+              RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK) |
+             atsParam->fsci); /* T0 */
+        txBuf[bufIt++] = atsParam->ta; /* TA */
+        txBuf[bufIt++] =
+            ((atsParam->fwi << RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) |
+             (atsParam->sfgi & RFAL_ISODEP_RATS_PARAM_FSDI_MASK)); /* TB */
+        txBuf[bufIt++] = (uint8_t)((atsParam->didSupport) ? RFAL_ISODEP_ATS_TC_DID : 0U); /* TC */
+
+        if(atsParam->hbLen > 0U) /* MISRA 21.18 */
+        {
+            ST_MEMCPY(&txBuf[bufIt], atsParam->hb, atsParam->hbLen); /* T1-Tk */
+            bufIt += atsParam->hbLen;
+        }
+
+        gIsoDep.state = ISODEP_ST_PICC_ACT_ATS;
+
+    }
+    /*******************************************************************************/
+    else if(*buffer == RFAL_ISODEP_CMD_ATTRIB) {
+        /* Check ATTRIB parameters */
+        if(attribResParam == NULL) {
+            return ERR_PARAM;
+        }
+
+        /*  REMARK: ATTRIB handling */
+        NO_WARNING(attribResParam);
+        NO_WARNING(bufLen);
+        return ERR_NOT_IMPLEMENTED;
+    } else {
+        return ERR_PARAM;
+    }
+
+    gIsoDep.actvParam = actParam;
+
+    /*******************************************************************************/
+    /* If requested copy to ISO-DEP device info */
+    if(actParam.isoDepDev != NULL) {
+        actParam.isoDepDev->info.DID = gIsoDep.did;
+        actParam.isoDepDev->info.FSx = gIsoDep.fsx;
+        actParam.isoDepDev->info.FWT = gIsoDep.fwt;
+        actParam.isoDepDev->info.dFWT = 0;
+        actParam.isoDepDev->info.DSI = gIsoDep.txBR;
+        actParam.isoDepDev->info.DRI = gIsoDep.rxBR;
+    }
+
+    return rfalTransceiveBlockingTx(
+        txBuf,
+        bufIt,
+        (uint8_t*)actParam.rxBuf,
+        sizeof(rfalIsoDepBufFormat),
+        actParam.rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_FWT_NONE);
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepListenGetActivationStatus(void) {
+    ReturnCode err;
+    uint8_t* txBuf;
+    uint8_t bufIt;
+
+    rfalBitRate dsi;
+    rfalBitRate dri;
+
+    /* Check if Activation is running */
+    if(gIsoDep.state < ISODEP_ST_PICC_ACT_ATS) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check if Activation has finished already */
+    if(gIsoDep.state >= ISODEP_ST_PICC_RX) {
+        return ERR_NONE;
+    }
+
+    /*******************************************************************************/
+    /* Check for incoming msg */
+    err = rfalGetTransceiveStatus();
+    switch(err) {
+    /*******************************************************************************/
+    case ERR_NONE:
+        break;
+
+    /*******************************************************************************/
+    case ERR_LINK_LOSS:
+    case ERR_BUSY:
+        return err;
+
+    /*******************************************************************************/
+    case ERR_CRC:
+    case ERR_PAR:
+    case ERR_FRAMING:
+
+        /* ISO14443 4  5.6.2.2 2  If ATS has been replied upon a invalid block, PICC disables the PPS responses */
+        if(gIsoDep.state == ISODEP_ST_PICC_ACT_ATS) {
+            gIsoDep.state = ISODEP_ST_PICC_RX;
+            break;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    default: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+        /* ReEnable the receiver and wait for another frame */
+        isoDepReEnableRx(
+            (uint8_t*)gIsoDep.actvParam.rxBuf,
+            sizeof(rfalIsoDepBufFormat),
+            gIsoDep.actvParam.rxLen);
+
+        return ERR_BUSY;
+    }
+
+    txBuf =
+        (uint8_t*)gIsoDep.actvParam
+            .rxBuf; /* Use the rxBuf as TxBuf as well, the struct enforces a size enough  MAX(NFCA_PPS_RES_LEN, ISODEP_DSL_MAX_LEN) */
+    dri = RFAL_BR_KEEP; /* The RFAL_BR_KEEP is used to check if PPS with BR change was requested */
+    dsi = RFAL_BR_KEEP; /* MISRA 9.1 */
+    bufIt = 0;
+
+    /*******************************************************************************/
+    gIsoDep.role = ISODEP_ROLE_PICC;
+
+    /*******************************************************************************/
+    if(gIsoDep.state == ISODEP_ST_PICC_ACT_ATS) {
+        /* Check for a PPS    ISO 14443-4  5.3 */
+        if((((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS] &
+            RFAL_ISODEP_PPS_MASK) == RFAL_ISODEP_PPS_SB) {
+            /* ISO 14443-4  5.3.1  Check if the we are the addressed DID/CID */
+            /* ISO 14443-4  5.3.2  Check for a valid PPS0 */
+            if(((((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS] &
+                 RFAL_ISODEP_DID_MASK) != gIsoDep.did) ||
+               ((((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS0_POS] &
+                 RFAL_ISODEP_PPS0_VALID_MASK) != RFAL_ISODEP_PPS0_PPS1_NOT_PRESENT)) {
+                /* Invalid DID on PPS request or Invalid PPS0, reEnable the receiver and wait another frame */
+                isoDepReEnableRx(
+                    (uint8_t*)gIsoDep.actvParam.rxBuf,
+                    sizeof(rfalIsoDepBufFormat),
+                    gIsoDep.actvParam.rxLen);
+
+                return ERR_BUSY;
+            }
+
+            /*******************************************************************************/
+            /* Check PPS1 presence */
+            if(((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS0_POS] ==
+               RFAL_ISODEP_PPS0_PPS1_PRESENT) {
+                uint8_t newdri = ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS1_POS] &
+                                 RFAL_ISODEP_PPS1_DxI_MASK; /* MISRA 10.8 */
+                uint8_t newdsi = (((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_PPS1_POS] >>
+                                  RFAL_ISODEP_PPS1_DSI_SHIFT) &
+                                 RFAL_ISODEP_PPS1_DxI_MASK; /* MISRA 10.8 */
+                /* PRQA S 4342 2 # MISRA 10.5 - Layout of enum rfalBitRate and above masks guarantee no invalid enum values to be created */
+                dri = (rfalBitRate)(newdri);
+                dsi = (rfalBitRate)(newdsi);
+
+                if((!(RFAL_SUPPORT_BR_CE_A_106) &&
+                    ((dsi == RFAL_BR_106) || (dri == RFAL_BR_106))) ||
+                   (!(RFAL_SUPPORT_BR_CE_A_212) &&
+                    ((dsi == RFAL_BR_212) || (dri == RFAL_BR_212))) ||
+                   (!(RFAL_SUPPORT_BR_CE_A_424) &&
+                    ((dsi == RFAL_BR_424) || (dri == RFAL_BR_424))) ||
+                   (!(RFAL_SUPPORT_BR_CE_A_848) &&
+                    ((dsi == RFAL_BR_848) || (dri == RFAL_BR_848)))) {
+                    return ERR_PROTO;
+                }
+            }
+
+            /*******************************************************************************/
+            /* Compute and send PPS RES / Ack                                              */
+            txBuf[bufIt++] = ((uint8_t*)gIsoDep.actvParam.rxBuf)[RFAL_ISODEP_PPS_STARTBYTE_POS];
+
+            rfalTransceiveBlockingTx(
+                txBuf,
+                bufIt,
+                (uint8_t*)gIsoDep.actvParam.rxBuf,
+                sizeof(rfalIsoDepBufFormat),
+                gIsoDep.actvParam.rxLen,
+                RFAL_TXRX_FLAGS_DEFAULT,
+                RFAL_FWT_NONE);
+
+            /*******************************************************************************/
+            /* Exchange the bit rates if requested */
+            if(dri != RFAL_BR_KEEP) {
+                rfalSetBitRate(
+                    dsi,
+                    dri); /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset above (RFAL_SUPPORT_BR_CE_A_xxx) */
+
+                gIsoDep.txBR = dsi; /* DSI codes the divisor from PICC to PCD */
+                gIsoDep.rxBR = dri; /* DRI codes the divisor from PCD to PICC */
+
+                if(gIsoDep.actvParam.isoDepDev != NULL) {
+                    gIsoDep.actvParam.isoDepDev->info.DSI = dsi;
+                    gIsoDep.actvParam.isoDepDev->info.DRI = dri;
+                }
+            }
+        }
+        /* Check for a S-Deselect is done on Data Exchange Activity                    */
+    }
+
+    /*******************************************************************************/
+    gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN;
+    gIsoDep.hdrLen +=
+        RFAL_ISODEP_DID_LEN; /* Always assume DID to be aligned with Digital 1.1  15.1.2 and ISO14443  4 5.6.3    #454 */
+    gIsoDep.hdrLen += (uint8_t)((gIsoDep.nad != RFAL_ISODEP_NO_NAD) ? RFAL_ISODEP_NAD_LEN : 0U);
+
+    /*******************************************************************************/
+    /* Rule C - The PICC block number shall be initialized to 1 at activation */
+    gIsoDep.blockNumber = 1;
+
+    /* Activation done, keep the rcvd data in, reMap the activation buffer to the global to be retrieved by the DEP method */
+    gIsoDep.rxBuf = (uint8_t*)gIsoDep.actvParam.rxBuf;
+    gIsoDep.rxBufLen = sizeof(rfalIsoDepBufFormat);
+    gIsoDep.rxBufInfPos = (uint8_t)((uint32_t)gIsoDep.actvParam.rxBuf->inf -
+                                    (uint32_t)gIsoDep.actvParam.rxBuf->prologue);
+    gIsoDep.rxLen = gIsoDep.actvParam.rxLen;
+    gIsoDep.rxChaining = gIsoDep.actvParam.isRxChaining;
+
+    gIsoDep.state = ISODEP_ST_PICC_RX;
+    return ERR_NONE;
+}
+
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+
+/*******************************************************************************/
+uint16_t rfalIsoDepGetMaxInfLen(void) {
+    /* Check whether all parameters are valid, otherwise return minimum default value */
+    if((gIsoDep.fsx < (uint16_t)RFAL_ISODEP_FSX_16) ||
+       (gIsoDep.fsx > (uint16_t)RFAL_ISODEP_FSX_4096) || (gIsoDep.hdrLen > ISODEP_HDR_MAX_LEN)) {
+        uint16_t isodepFsx16 = (uint16_t)RFAL_ISODEP_FSX_16; /* MISRA 10.1 */
+        return (isodepFsx16 - RFAL_ISODEP_PCB_LEN - ISODEP_CRC_LEN);
+    }
+
+    return (gIsoDep.fsx - gIsoDep.hdrLen - ISODEP_CRC_LEN);
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepStartTransceive(rfalIsoDepTxRxParam param) {
+    gIsoDep.txBuf = param.txBuf->prologue;
+    gIsoDep.txBufInfPos = (uint8_t)((uint32_t)param.txBuf->inf - (uint32_t)param.txBuf->prologue);
+    gIsoDep.txBufLen = param.txBufLen;
+    gIsoDep.isTxChaining = param.isTxChaining;
+
+    gIsoDep.rxBuf = param.rxBuf->prologue;
+    gIsoDep.rxBufInfPos = (uint8_t)((uint32_t)param.rxBuf->inf - (uint32_t)param.rxBuf->prologue);
+    gIsoDep.rxBufLen = sizeof(rfalIsoDepBufFormat);
+
+    gIsoDep.rxLen = param.rxLen;
+    gIsoDep.rxChaining = param.isRxChaining;
+
+    gIsoDep.fwt = param.FWT;
+    gIsoDep.dFwt = param.dFWT;
+    gIsoDep.fsx = param.FSx;
+    gIsoDep.did = param.DID;
+
+    /* Only change the FSx from activation if no to Keep */
+    gIsoDep.ourFsx = ((param.ourFSx != RFAL_ISODEP_FSX_KEEP) ? param.ourFSx : gIsoDep.ourFsx);
+
+    /* Clear inner control params for next dataExchange */
+    gIsoDep.isRxChaining = false;
+    isoDepClearCounters();
+
+    if(gIsoDep.role == ISODEP_ROLE_PICC) {
+        if(gIsoDep.txBufLen > 0U) {
+            /* Ensure that an RTOX Ack is not being expected at moment */
+            if(!gIsoDep.isWait4WTX) {
+                gIsoDep.state = ISODEP_ST_PICC_TX;
+                return ERR_NONE;
+            } else {
+                /* If RTOX Ack is expected, signal a pending Tx to be transmitted right after */
+                gIsoDep.isTxPending = true;
+            }
+        }
+
+        /* Digital 1.1  15.2.5.1 The first block SHALL be sent by the Reader/Writer */
+        gIsoDep.state = ISODEP_ST_PICC_RX;
+        return ERR_NONE;
+    }
+
+    gIsoDep.state = ISODEP_ST_PCD_TX;
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepGetTransceiveStatus(void) {
+    if(gIsoDep.role == ISODEP_ROLE_PICC) {
+#if RFAL_FEATURE_ISO_DEP_LISTEN
+        return isoDepDataExchangePICC();
+#else
+        return ERR_NOTSUPP;
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+    } else {
+#if RFAL_FEATURE_ISO_DEP_POLL
+        return isoDepDataExchangePCD(gIsoDep.rxLen, gIsoDep.rxChaining);
+#else
+        return ERR_NOTSUPP;
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+    }
+}
+
+#if RFAL_FEATURE_ISO_DEP_LISTEN
+
+/*******************************************************************************/
+static ReturnCode isoDepDataExchangePICC(void) {
+    uint8_t rxPCB;
+    ReturnCode ret;
+
+    switch(gIsoDep.state) {
+    /*******************************************************************************/
+    case ISODEP_ST_IDLE:
+        return ERR_NONE;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PICC_TX:
+
+        ret = isoDepTx(
+            isoDep_PCBIBlock(gIsoDep.blockNumber),
+            gIsoDep.txBuf,
+            &gIsoDep.txBuf[gIsoDep.txBufInfPos],
+            gIsoDep.txBufLen,
+            RFAL_FWT_NONE);
+
+        /* Clear pending Tx flag */
+        gIsoDep.isTxPending = false;
+
+        switch(ret) {
+        case ERR_NONE:
+            gIsoDep.state = ISODEP_ST_PICC_RX;
+            return ERR_BUSY;
+
+        default:
+            /* MISRA 16.4: no empty default statement (a comment being enough) */
+            break;
+        }
+        return ret;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PICC_RX:
+
+        ret = rfalGetTransceiveStatus();
+        switch(ret) {
+        /*******************************************************************************/
+        /* Data rcvd with error or timeout -> mute */
+        case ERR_TIMEOUT:
+        case ERR_CRC:
+        case ERR_PAR:
+        case ERR_FRAMING:
+
+            /* Digital 1.1 - 15.2.6.2  The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */
+            isoDepReEnableRx((uint8_t*)gIsoDep.rxBuf, sizeof(rfalIsoDepBufFormat), gIsoDep.rxLen);
+
+            return ERR_BUSY;
+
+        /*******************************************************************************/
+        case ERR_LINK_LOSS:
+            return ret; /* Debug purposes */
+
+        case ERR_BUSY:
+            return ret; /* Debug purposes */
+
+        /*******************************************************************************/
+        case ERR_NONE:
+            *gIsoDep.rxLen = rfalConvBitsToBytes(*gIsoDep.rxLen);
+            break;
+
+        /*******************************************************************************/
+        default:
+            return ret;
+        }
+        break;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PICC_SWTX:
+
+        if(!isoDepTimerisExpired(gIsoDep.WTXTimer)) /* Do nothing until WTX timer has expired */
+        {
+            return ERR_BUSY;
+        }
+
+        /* Set waiting for WTX Ack Flag */
+        gIsoDep.isWait4WTX = true;
+
+        /* Digital 1.1  15.2.2.9 - Calculate the WTXM such that FWTtemp <= FWTmax */
+        gIsoDep.lastWTXM = (uint8_t)isoDep_WTXMListenerMax(gIsoDep.fwt);
+        EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_S_WTX, gIsoDep.lastWTXM));
+
+        gIsoDep.state = ISODEP_ST_PICC_RX; /* Go back to Rx to process WTX ack        */
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PICC_SDSL:
+
+        if(rfalIsTransceiveInRx()) /* Wait until DSL response has been sent */
+        {
+            rfalIsoDepInitialize(); /* Session finished reInit vars */
+            return ERR_SLEEP_REQ; /* Notify Deselect request      */
+        }
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    default:
+        return ERR_INTERNAL;
+    }
+
+    /* ISO 14443-4 7.5.6.2 CE SHALL NOT attempt error recovery -> clear counters */
+    isoDepClearCounters();
+
+    /*******************************************************************************/
+    /* No error, process incoming msg                                              */
+    /*******************************************************************************/
+
+    /* Grab rcvd PCB */
+    rxPCB = gIsoDep.rxBuf[ISODEP_PCB_POS];
+
+    /*******************************************************************************/
+    /* When DID=0 PCD may or may not use DID, therefore check whether current PCD request 
+     * has DID present to be reflected on max INF length                         #454  */
+
+    /* ReCalculate Header Length */
+    gIsoDep.hdrLen = RFAL_ISODEP_PCB_LEN;
+    gIsoDep.hdrLen += (uint8_t)((isoDep_PCBhasDID(rxPCB)) ? RFAL_ISODEP_DID_LEN : 0U);
+    gIsoDep.hdrLen += (uint8_t)((isoDep_PCBhasNAD(rxPCB)) ? RFAL_ISODEP_NAD_LEN : 0U);
+
+    /* Store whether last PCD block had DID. for PICC special handling of DID = 0 */
+    if(gIsoDep.did == RFAL_ISODEP_DID_00) {
+        gIsoDep.lastDID00 = ((isoDep_PCBhasDID(rxPCB)) ? true : false);
+    }
+
+    /*******************************************************************************/
+    /* Check rcvd msg length, cannot be less then the expected header    OR        * 
+     * if the rcvd msg exceeds our announced frame size (FSD)                      */
+    if(((*gIsoDep.rxLen) < gIsoDep.hdrLen) ||
+       ((*gIsoDep.rxLen) > (gIsoDep.ourFsx - ISODEP_CRC_LEN))) {
+        isoDepReEnableRx(
+            (uint8_t*)gIsoDep.actvParam.rxBuf,
+            sizeof(rfalIsoDepBufFormat),
+            gIsoDep.actvParam.rxLen);
+        return ERR_BUSY; /* ERR_PROTO Ignore this protocol request */
+    }
+
+    /* If we are expecting DID, check if PCB signals its presence and if device ID match OR
+     * If our DID=0 and DID is sent but with an incorrect value                              */
+    if(((gIsoDep.did != RFAL_ISODEP_DID_00) &&
+        (!isoDep_PCBhasDID(rxPCB) || (gIsoDep.did != gIsoDep.rxBuf[ISODEP_DID_POS]))) ||
+       ((gIsoDep.did == RFAL_ISODEP_DID_00) && isoDep_PCBhasDID(rxPCB) &&
+        (RFAL_ISODEP_DID_00 != gIsoDep.rxBuf[ISODEP_DID_POS]))) {
+        isoDepReEnableRx(
+            (uint8_t*)gIsoDep.actvParam.rxBuf,
+            sizeof(rfalIsoDepBufFormat),
+            gIsoDep.actvParam.rxLen);
+        return ERR_BUSY; /* Ignore a wrong DID request */
+    }
+
+    /* If we aren't expecting NAD and it's received */
+    if((gIsoDep.nad == RFAL_ISODEP_NO_NAD) && isoDep_PCBhasNAD(rxPCB)) {
+        isoDepReEnableRx(
+            (uint8_t*)gIsoDep.actvParam.rxBuf,
+            sizeof(rfalIsoDepBufFormat),
+            gIsoDep.actvParam.rxLen);
+        return ERR_BUSY; /* Ignore a unexpected NAD request */
+    }
+
+    /*******************************************************************************/
+    /* Process S-Block                                                             */
+    /*******************************************************************************/
+    if(isoDep_PCBisSBlock(rxPCB)) {
+        /* Check if is a Wait Time eXtension */
+        if(isoDep_PCBisSWTX(rxPCB)) {
+            /* Check if we're expecting a S-WTX */
+            if(isoDep_PCBisWTX(gIsoDep.lastPCB)) {
+                /* Digital 1.1  15.2.2.11 S(WTX) Ack with different WTXM -> Protocol Error  *
+                 *              Power level indication also should be set to 0              */
+                if((gIsoDep.rxBuf[gIsoDep.hdrLen] == gIsoDep.lastWTXM) &&
+                   ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_SWTX_INF_LEN)) {
+                    /* Clear waiting for RTOX Ack Flag */
+                    gIsoDep.isWait4WTX = false;
+
+                    /* Check if a Tx is already pending */
+                    if(gIsoDep.isTxPending) {
+                        /* Has a pending Tx, go immediately to TX */
+                        gIsoDep.state = ISODEP_ST_PICC_TX;
+                        return ERR_BUSY;
+                    }
+
+                    /* Set WTX timer */
+                    isoDepTimerStart(
+                        gIsoDep.WTXTimer,
+                        isoDep_WTXAdjust((gIsoDep.lastWTXM * rfalConv1fcToMs(gIsoDep.fwt))));
+
+                    gIsoDep.state = ISODEP_ST_PICC_SWTX;
+                    return ERR_BUSY;
+                }
+            }
+            /* Unexpected/Incorrect S-WTX, fall into reRenable */
+        }
+
+        /* Check if is a Deselect request */
+        if(isoDep_PCBisSDeselect(rxPCB) &&
+           ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_SDSL_INF_LEN)) {
+            EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_S_DSL, RFAL_ISODEP_NO_PARAM));
+
+            /* S-DSL transmission ongoing, wait until complete */
+            gIsoDep.state = ISODEP_ST_PICC_SDSL;
+            return ERR_BUSY;
+        }
+
+        /* Unexpected S-Block, fall into reRenable */
+    }
+
+    /*******************************************************************************/
+    /* Process R-Block                                                             */
+    /*******************************************************************************/
+    else if(isoDep_PCBisRBlock(rxPCB) && ((*gIsoDep.rxLen - gIsoDep.hdrLen) == ISODEP_RBLOCK_INF_LEN)) {
+        if(isoDep_PCBisRACK(rxPCB)) /* Check if is a R-ACK */
+        {
+            if(isoDep_GetBN(rxPCB) == gIsoDep.blockNumber) /* Check block number  */
+            {
+                /* Rule 11 - R(ACK) with current bn -> re-transmit */
+                if(!isoDep_PCBisIBlock(gIsoDep.lastPCB)) {
+                    isoDepReSendControlMsg();
+                } else {
+                    gIsoDep.state = ISODEP_ST_PICC_TX;
+                }
+
+                return ERR_BUSY;
+            } else {
+                if(!gIsoDep.isTxChaining) {
+                    /* Rule 13 violation R(ACK) without performing chaining */
+                    isoDepReEnableRx(
+                        (uint8_t*)gIsoDep.rxBuf, sizeof(rfalIsoDepBufFormat), gIsoDep.rxLen);
+                    return ERR_BUSY;
+                }
+
+                /* Rule E -  R(ACK) with not current bn -> toggle bn */
+                isoDep_ToggleBN(gIsoDep.blockNumber);
+
+                /* This block has been transmitted and acknowledged, perform WTX until next data is provided  */
+
+                /* Rule 9 - PICC is allowed to send an S(WTX) instead of an I-block or an R(ACK) */
+                isoDepTimerStart(gIsoDep.WTXTimer, isoDep_WTXAdjust(rfalConv1fcToMs(gIsoDep.fwt)));
+                gIsoDep.state = ISODEP_ST_PICC_SWTX;
+
+                /* Rule 13 - R(ACK) with not current bn -> continue chaining */
+                return ERR_NONE; /* This block has been transmitted */
+            }
+        } else if(isoDep_PCBisRNAK(rxPCB)) /* Check if is a R-NACK */
+        {
+            if(isoDep_GetBN(rxPCB) == gIsoDep.blockNumber) /* Check block number  */
+            {
+                /* Rule 11 - R(NAK) with current bn -> re-transmit last x-Block */
+                if(!isoDep_PCBisIBlock(gIsoDep.lastPCB)) {
+                    isoDepReSendControlMsg();
+                } else {
+                    gIsoDep.state = ISODEP_ST_PICC_TX;
+                }
+
+                return ERR_BUSY;
+            } else {
+                /* Rule 12 - R(NAK) with not current bn -> R(ACK) */
+                EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM));
+
+                return ERR_BUSY;
+            }
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+
+        /* Unexpected R-Block, fall into reRenable */
+    }
+
+    /*******************************************************************************/
+    /* Process I-Block                                                             */
+    /*******************************************************************************/
+    else if(isoDep_PCBisIBlock(rxPCB)) {
+        /* Rule D - When an I-block is received, the PICC shall toggle its block number before sending a block */
+        isoDep_ToggleBN(gIsoDep.blockNumber);
+
+        /*******************************************************************************/
+        /* Check if the block number is the one expected                               */
+        /* Check if PCD sent an I-Block instead ACK/NACK when we are chaining          */
+        if((isoDep_GetBN(rxPCB) != gIsoDep.blockNumber) || (gIsoDep.isTxChaining)) {
+            /* Remain in the same Block Number */
+            isoDep_ToggleBN(gIsoDep.blockNumber);
+
+            /* ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2  The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */
+            isoDepReEnableRx((uint8_t*)gIsoDep.rxBuf, sizeof(rfalIsoDepBufFormat), gIsoDep.rxLen);
+            return ERR_BUSY;
+        }
+
+        /*******************************************************************************/
+        /* is PCD performing chaining  ?                                               */
+        if(isoDep_PCBisChaining(rxPCB)) {
+            gIsoDep.isRxChaining = true;
+            *gIsoDep.rxChaining = true; /* Output Parameter*/
+
+            EXIT_ON_ERR(ret, isoDepHandleControlMsg(ISODEP_R_ACK, RFAL_ISODEP_NO_PARAM));
+
+            /* Received I-Block with chaining, send current data to DH */
+
+            /* remove ISO DEP header, check is necessary to move the INF data on the buffer */
+            *gIsoDep.rxLen -= gIsoDep.hdrLen;
+            if((gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*gIsoDep.rxLen > 0U)) {
+                ST_MEMMOVE(
+                    &gIsoDep.rxBuf[gIsoDep.rxBufInfPos],
+                    &gIsoDep.rxBuf[gIsoDep.hdrLen],
+                    *gIsoDep.rxLen);
+            }
+            return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/
+        }
+
+        /*******************************************************************************/
+        /* PCD is not performing chaining                                              */
+        gIsoDep.isRxChaining = false; /* clear PCD chaining flag */
+        *gIsoDep.rxChaining = false; /* Output Parameter        */
+
+        /* remove ISO DEP header, check is necessary to move the INF data on the buffer */
+        *gIsoDep.rxLen -= gIsoDep.hdrLen;
+        if((gIsoDep.hdrLen != gIsoDep.rxBufInfPos) && (*gIsoDep.rxLen > 0U)) {
+            ST_MEMMOVE(
+                &gIsoDep.rxBuf[gIsoDep.rxBufInfPos],
+                &gIsoDep.rxBuf[gIsoDep.hdrLen],
+                *gIsoDep.rxLen);
+        }
+
+        /*******************************************************************************/
+        /* Reception done, send data back and start WTX timer                          */
+        isoDepTimerStart(gIsoDep.WTXTimer, isoDep_WTXAdjust(rfalConv1fcToMs(gIsoDep.fwt)));
+
+        gIsoDep.state = ISODEP_ST_PICC_SWTX;
+        return ERR_NONE;
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /* Unexpected/Unknown Block */
+    /* ISO 14443-4 7.5.6.2 & Digital 1.1 - 15.2.6.2  The CE SHALL NOT attempt error recovery and remains in Rx mode upon Transmission or a Protocol Error */
+    isoDepReEnableRx((uint8_t*)gIsoDep.rxBuf, sizeof(rfalIsoDepBufFormat), gIsoDep.rxLen);
+
+    return ERR_BUSY;
+}
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+
+#if RFAL_FEATURE_ISO_DEP_POLL
+
+#if RFAL_FEATURE_NFCA
+
+/*******************************************************************************/
+static ReturnCode
+    rfalIsoDepStartRATS(rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts* ats, uint8_t* atsLen) {
+    rfalTransceiveContext ctx;
+
+    if(ats == NULL) {
+        return ERR_PARAM;
+    }
+
+    gIsoDep.rxBuf = (uint8_t*)ats;
+    gIsoDep.rxLen8 = atsLen;
+    gIsoDep.did = DID;
+
+    /*******************************************************************************/
+    /* Compose RATS */
+    gIsoDep.actv.ratsReq.CMD = RFAL_ISODEP_CMD_RATS;
+    gIsoDep.actv.ratsReq.PARAM =
+        (((uint8_t)FSDI << RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT) & RFAL_ISODEP_RATS_PARAM_FSDI_MASK) |
+        (DID & RFAL_ISODEP_RATS_PARAM_DID_MASK);
+
+    rfalCreateByteFlagsTxRxContext(
+        ctx,
+        (uint8_t*)&gIsoDep.actv.ratsReq,
+        sizeof(rfalIsoDepRats),
+        (uint8_t*)ats,
+        sizeof(rfalIsoDepAts),
+        &gIsoDep.rxBufLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ISODEP_T4T_FWT_ACTIVATION);
+    return rfalStartTransceive(&ctx);
+}
+
+/*******************************************************************************/
+static ReturnCode rfalIsoDepGetRATSStatus(void) {
+    ReturnCode ret;
+
+    ret = rfalGetTransceiveStatus();
+    if(ret == ERR_NONE) {
+        gIsoDep.rxBufLen = rfalConvBitsToBytes(gIsoDep.rxBufLen);
+
+        /* Check for valid ATS length  Digital 1.1  13.6.2.1 & 13.6.2.3 */
+        if((gIsoDep.rxBufLen < RFAL_ISODEP_ATS_MIN_LEN) ||
+           (gIsoDep.rxBufLen > RFAL_ISODEP_ATS_MAX_LEN) ||
+           (gIsoDep.rxBuf[RFAL_ISODEP_ATS_TL_POS] != gIsoDep.rxBufLen)) {
+            return ERR_PROTO;
+        }
+
+        /* Assign our FSx, in case the a Deselect is send without Transceive */
+        gIsoDep.ourFsx = rfalIsoDepFSxI2FSx(
+            (uint8_t)(gIsoDep.actv.ratsReq.PARAM >> RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT));
+
+        /* Check and assign if ATS length was requested (length also available on TL) */
+        if(gIsoDep.rxLen8 != NULL) {
+            *gIsoDep.rxLen8 = (uint8_t)gIsoDep.rxBufLen;
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepRATS(rfalIsoDepFSxI FSDI, uint8_t DID, rfalIsoDepAts* ats, uint8_t* atsLen) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalIsoDepStartRATS(FSDI, DID, ats, atsLen));
+    rfalIsoDepRunBlocking(ret, rfalIsoDepGetRATSStatus());
+
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode
+    rfalIsoDepStartPPS(uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes* ppsRes) {
+    rfalTransceiveContext ctx;
+
+    if((ppsRes == NULL) || (DSI > RFAL_BR_848) || (DRI > RFAL_BR_848) ||
+       (DID > RFAL_ISODEP_DID_MAX)) {
+        return ERR_PARAM;
+    }
+
+    gIsoDep.rxBuf = (uint8_t*)ppsRes;
+
+    /*******************************************************************************/
+    /* Compose PPS Request */
+    gIsoDep.actv.ppsReq.PPSS = (RFAL_ISODEP_PPS_SB | (DID & RFAL_ISODEP_PPS_SB_DID_MASK));
+    gIsoDep.actv.ppsReq.PPS0 = RFAL_ISODEP_PPS_PPS0_PPS1_PRESENT;
+    gIsoDep.actv.ppsReq.PPS1 =
+        (RFAL_ISODEP_PPS_PPS1 |
+         ((((uint8_t)DSI << RFAL_ISODEP_PPS_PPS1_DSI_SHIFT) | (uint8_t)DRI) &
+          RFAL_ISODEP_PPS_PPS1_DXI_MASK));
+
+    rfalCreateByteFlagsTxRxContext(
+        ctx,
+        (uint8_t*)&gIsoDep.actv.ppsReq,
+        sizeof(rfalIsoDepPpsReq),
+        (uint8_t*)ppsRes,
+        sizeof(rfalIsoDepPpsRes),
+        &gIsoDep.rxBufLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ISODEP_T4T_FWT_ACTIVATION);
+    return rfalStartTransceive(&ctx);
+}
+
+/*******************************************************************************/
+static ReturnCode rfalIsoDepGetPPSSTatus(void) {
+    ReturnCode ret;
+
+    ret = rfalGetTransceiveStatus();
+    if(ret == ERR_NONE) {
+        gIsoDep.rxBufLen = rfalConvBitsToBytes(gIsoDep.rxBufLen);
+
+        /* Check for valid PPS Response   */
+        if((gIsoDep.rxBufLen != RFAL_ISODEP_PPS_RES_LEN) ||
+           (*gIsoDep.rxBuf != gIsoDep.actv.ppsReq.PPSS)) {
+            return ERR_PROTO;
+        }
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPPS(uint8_t DID, rfalBitRate DSI, rfalBitRate DRI, rfalIsoDepPpsRes* ppsRes) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalIsoDepStartPPS(DID, DSI, DRI, ppsRes));
+    rfalIsoDepRunBlocking(ret, rfalIsoDepGetPPSSTatus());
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_NFCB
+
+static ReturnCode rfalIsoDepStartATTRIB(
+    const uint8_t* nfcid0,
+    uint8_t PARAM1,
+    rfalBitRate DSI,
+    rfalBitRate DRI,
+    rfalIsoDepFSxI FSDI,
+    uint8_t PARAM3,
+    uint8_t DID,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    uint32_t fwt,
+    rfalIsoDepAttribRes* attribRes,
+    uint8_t* attribResLen) {
+    rfalTransceiveContext ctx;
+
+    if((attribRes == NULL) || (attribResLen == NULL) || (DSI > RFAL_BR_848) ||
+       (DRI > RFAL_BR_848) || (DID > RFAL_ISODEP_DID_MAX)) {
+        return ERR_NONE;
+    }
+
+    gIsoDep.rxBuf = (uint8_t*)attribRes;
+    gIsoDep.rxLen8 = attribResLen;
+    gIsoDep.did = DID;
+
+    /*******************************************************************************/
+    /* Compose ATTRIB command */
+    gIsoDep.actv.attribReq.cmd = RFAL_ISODEP_CMD_ATTRIB;
+    gIsoDep.actv.attribReq.Param.PARAM1 = PARAM1;
+    gIsoDep.actv.attribReq.Param.PARAM2 =
+        (((((uint8_t)DSI << RFAL_ISODEP_ATTRIB_PARAM2_DSI_SHIFT) |
+           ((uint8_t)DRI << RFAL_ISODEP_ATTRIB_PARAM2_DRI_SHIFT)) &
+          RFAL_ISODEP_ATTRIB_PARAM2_DXI_MASK) |
+         ((uint8_t)FSDI & RFAL_ISODEP_ATTRIB_PARAM2_FSDI_MASK));
+    gIsoDep.actv.attribReq.Param.PARAM3 = PARAM3;
+    gIsoDep.actv.attribReq.Param.PARAM4 = (DID & RFAL_ISODEP_ATTRIB_PARAM4_DID_MASK);
+    ST_MEMCPY(gIsoDep.actv.attribReq.nfcid0, nfcid0, RFAL_NFCB_NFCID0_LEN);
+
+    /* Append the Higher layer Info if provided */
+    if((HLInfo != NULL) && (HLInfoLen > 0U)) {
+        ST_MEMCPY(
+            gIsoDep.actv.attribReq.HLInfo, HLInfo, MIN(HLInfoLen, RFAL_ISODEP_ATTRIB_HLINFO_LEN));
+    }
+
+    rfalCreateByteFlagsTxRxContext(
+        ctx,
+        (uint8_t*)&gIsoDep.actv.attribReq,
+        (uint16_t)(RFAL_ISODEP_ATTRIB_HDR_LEN +
+                   MIN((uint16_t)HLInfoLen, RFAL_ISODEP_ATTRIB_HLINFO_LEN)),
+        (uint8_t*)gIsoDep.rxBuf,
+        sizeof(rfalIsoDepAttribRes),
+        &gIsoDep.rxBufLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        fwt);
+    return rfalStartTransceive(&ctx);
+}
+
+/*******************************************************************************/
+static ReturnCode rfalIsoDepGetATTRIBStatus(void) {
+    ReturnCode ret;
+
+    ret = rfalGetTransceiveStatus();
+    if(ret == ERR_NONE) {
+        gIsoDep.rxBufLen = rfalConvBitsToBytes(gIsoDep.rxBufLen);
+
+        /* Check a for valid ATTRIB Response   Digital 1.1  15.6.2.1 */
+        if((gIsoDep.rxBufLen < RFAL_ISODEP_ATTRIB_RES_HDR_LEN) ||
+           ((gIsoDep.rxBuf[RFAL_ISODEP_ATTRIB_RES_MBLIDID_POS] &
+             RFAL_ISODEP_ATTRIB_RES_DID_MASK) != gIsoDep.did)) {
+            return ERR_PROTO;
+        }
+
+        if(gIsoDep.rxLen8 != NULL) {
+            *gIsoDep.rxLen8 = (uint8_t)gIsoDep.rxBufLen;
+        }
+
+        gIsoDep.ourFsx = rfalIsoDepFSxI2FSx(
+            (uint8_t)(gIsoDep.actv.attribReq.Param.PARAM2 & RFAL_ISODEP_ATTRIB_PARAM2_FSDI_MASK));
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepATTRIB(
+    const uint8_t* nfcid0,
+    uint8_t PARAM1,
+    rfalBitRate DSI,
+    rfalBitRate DRI,
+    rfalIsoDepFSxI FSDI,
+    uint8_t PARAM3,
+    uint8_t DID,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    uint32_t fwt,
+    rfalIsoDepAttribRes* attribRes,
+    uint8_t* attribResLen) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalIsoDepStartATTRIB(
+            nfcid0,
+            PARAM1,
+            DSI,
+            DRI,
+            FSDI,
+            PARAM3,
+            DID,
+            HLInfo,
+            HLInfoLen,
+            fwt,
+            attribRes,
+            attribResLen));
+    rfalIsoDepRunBlocking(ret, rfalIsoDepGetATTRIBStatus());
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFCB */
+
+#if RFAL_FEATURE_NFCA
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollAHandleActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    rfalIsoDepDevice* isoDepDev) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalIsoDepPollAStartActivation(FSDI, DID, maxBR, isoDepDev));
+    rfalIsoDepRunBlocking(ret, rfalIsoDepPollAGetActivationStatus());
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollAStartActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    rfalIsoDepDevice* isoDepDev) {
+    ReturnCode ret;
+
+    if(isoDepDev == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Enable EMD handling according   Digital 1.1  4.1.1.1 ; EMVCo 2.6  4.9.2 */
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_EMVCO);
+
+    /* Start RATS Transceive */
+    EXIT_ON_ERR(
+        ret,
+        rfalIsoDepStartRATS(
+            FSDI,
+            DID,
+            &isoDepDev->activation.A.Listener.ATS,
+            &isoDepDev->activation.A.Listener.ATSLen));
+
+    isoDepDev->info.DSI = maxBR;
+    gIsoDep.actvDev = isoDepDev;
+    gIsoDep.cntRRetrys = gIsoDep.maxRetriesRATS;
+    gIsoDep.state = ISODEP_ST_PCD_ACT_RATS;
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollAGetActivationStatus(void) {
+    ReturnCode ret;
+    uint8_t msgIt;
+    rfalBitRate maxBR;
+
+    switch(gIsoDep.state) {
+    /*******************************************************************************/
+    case ISODEP_ST_PCD_ACT_RATS:
+
+        ret = rfalIsoDepGetRATSStatus();
+        if(ret != ERR_BUSY) {
+            if(ret != ERR_NONE) {
+                /* EMVCo 2.6  9.6.1.1 & 9.6.1.2  If a timeout error is detected retransmit, on transmission error abort */
+                if((gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) && (ret != ERR_TIMEOUT)) {
+                    break;
+                }
+
+                if(gIsoDep.cntRRetrys != 0U) {
+                    /* Ensure FDT before retransmission (reuse RFAL GT timer) */
+                    rfalSetGT(rfalGetFDTPoll());
+                    rfalFieldOnAndStartGT();
+
+                    /* Send RATS retransmission */ /* PRQA S 4342 1 # MISRA 10.5 - Layout of enum rfalIsoDepFSxI is guaranteed within 4bit range */
+                    EXIT_ON_ERR(
+                        ret,
+                        rfalIsoDepStartRATS(
+                            (rfalIsoDepFSxI)(uint8_t)(gIsoDep.actv.ratsReq.PARAM >>
+                                                      RFAL_ISODEP_RATS_PARAM_FSDI_SHIFT),
+                            gIsoDep.did,
+                            &gIsoDep.actvDev->activation.A.Listener.ATS,
+                            &gIsoDep.actvDev->activation.A.Listener.ATSLen));
+                    gIsoDep.cntRRetrys--;
+                    ret = ERR_BUSY;
+                }
+                /* Switch between NFC Forum and ISO14443-4 behaviour #595
+                     *   ISO14443-4  5.6.1  If RATS fails, a Deactivation sequence should be performed as defined on clause 8  
+                     *   Activity 1.1  9.6  Device Deactivation Activity is to be only performed when there's an active device */
+                else if(gIsoDep.compMode == RFAL_COMPLIANCE_MODE_ISO) {
+                    rfalIsoDepDeselect();
+                } else {
+                    /* MISRA 15.7 - Empty else */
+                }
+            } else /* ATS received */
+            {
+                maxBR = gIsoDep.actvDev->info.DSI; /* Retrieve requested max bitrate */
+
+                /*******************************************************************************/
+                /* Process ATS Response                                                        */
+                gIsoDep.actvDev->info.FWI =
+                    RFAL_ISODEP_FWI_DEFAULT; /* Default value   EMVCo 2.6  5.7.2.6  */
+                gIsoDep.actvDev->info.SFGI = 0U;
+                gIsoDep.actvDev->info.MBL = 0U;
+                gIsoDep.actvDev->info.DSI = RFAL_BR_106;
+                gIsoDep.actvDev->info.DRI = RFAL_BR_106;
+                gIsoDep.actvDev->info.FSxI = (uint8_t)
+                    RFAL_ISODEP_FSXI_32; /* FSC default value is 32 bytes  ISO14443-A  5.2.3 */
+
+                /*******************************************************************************/
+                /* Check for ATS optional fields                                               */
+                if(gIsoDep.actvDev->activation.A.Listener.ATS.TL > RFAL_ISODEP_ATS_MIN_LEN) {
+                    msgIt = RFAL_ISODEP_ATS_MIN_LEN;
+
+                    /* Format byte T0 is optional, if present assign FSDI */
+                    gIsoDep.actvDev->info.FSxI =
+                        (gIsoDep.actvDev->activation.A.Listener.ATS.T0 &
+                         RFAL_ISODEP_ATS_T0_FSCI_MASK);
+
+                    /* T0 has already been processed, always the same position */
+                    msgIt++;
+
+                    /* Check if TA is present */
+                    if((gIsoDep.actvDev->activation.A.Listener.ATS.T0 &
+                        RFAL_ISODEP_ATS_T0_TA_PRESENCE_MASK) != 0U) {
+                        rfalIsoDepCalcBitRate(
+                            maxBR,
+                            ((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++],
+                            &gIsoDep.actvDev->info.DSI,
+                            &gIsoDep.actvDev->info.DRI);
+                    }
+
+                    /* Check if TB is present */
+                    if((gIsoDep.actvDev->activation.A.Listener.ATS.T0 &
+                        RFAL_ISODEP_ATS_T0_TB_PRESENCE_MASK) != 0U) {
+                        gIsoDep.actvDev->info.SFGI =
+                            ((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++];
+                        gIsoDep.actvDev->info.FWI = (uint8_t)((gIsoDep.actvDev->info.SFGI >>
+                                                               RFAL_ISODEP_ATS_TB_FWI_SHIFT) &
+                                                              RFAL_ISODEP_ATS_FWI_MASK);
+                        gIsoDep.actvDev->info.SFGI &= RFAL_ISODEP_ATS_TB_SFGI_MASK;
+                    }
+
+                    /* Check if TC is present */
+                    if((gIsoDep.actvDev->activation.A.Listener.ATS.T0 &
+                        RFAL_ISODEP_ATS_T0_TC_PRESENCE_MASK) != 0U) {
+                        /* Check for Protocol features support */
+                        /* Advanced protocol features defined on Digital 1.0 Table 69, removed after */
+                        gIsoDep.actvDev->info.supAdFt =
+                            (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt] &
+                               RFAL_ISODEP_ATS_TC_ADV_FEAT) != 0U) ?
+                                 true :
+                                 false);
+                        gIsoDep.actvDev->info.supDID =
+                            (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt] &
+                               RFAL_ISODEP_ATS_TC_DID) != 0U) ?
+                                 true :
+                                 false);
+                        gIsoDep.actvDev->info.supNAD =
+                            (((((uint8_t*)&gIsoDep.actvDev->activation.A.Listener.ATS)[msgIt++] &
+                               RFAL_ISODEP_ATS_TC_NAD) != 0U) ?
+                                 true :
+                                 false);
+                    }
+                }
+
+                gIsoDep.actvDev->info.FSx = rfalIsoDepFSxI2FSx(gIsoDep.actvDev->info.FSxI);
+                gIsoDep.fsx = gIsoDep.actvDev->info.FSx;
+
+                gIsoDep.actvDev->info.SFGT =
+                    rfalIsoDepSFGI2SFGT((uint8_t)gIsoDep.actvDev->info.SFGI);
+
+                /* Ensure SFGT before following frame (reuse RFAL GT timer) */
+                rfalSetGT(rfalConvMsTo1fc(gIsoDep.actvDev->info.SFGT));
+                rfalFieldOnAndStartGT();
+
+                gIsoDep.actvDev->info.FWT = rfalIsoDepFWI2FWT(gIsoDep.actvDev->info.FWI);
+                gIsoDep.actvDev->info.dFWT = RFAL_ISODEP_DFWT_20;
+
+                gIsoDep.actvDev->info.DID =
+                    ((gIsoDep.actvDev->info.supDID) ? gIsoDep.did : RFAL_ISODEP_NO_DID);
+                gIsoDep.actvDev->info.NAD = RFAL_ISODEP_NO_NAD;
+
+                /*******************************************************************************/
+                /* If higher bit rates are supported by both devices, send PPS                 */
+                if((gIsoDep.actvDev->info.DSI != RFAL_BR_106) ||
+                   (gIsoDep.actvDev->info.DRI != RFAL_BR_106)) {
+                    /* Send PPS */ /*  PRQA S 0310 1 # MISRA 11.3 - Intentional safe cast to avoiding buffer duplication */
+                    EXIT_ON_ERR(
+                        ret,
+                        rfalIsoDepStartPPS(
+                            gIsoDep.actvDev->info.DID,
+                            gIsoDep.actvDev->info.DSI,
+                            gIsoDep.actvDev->info.DRI,
+                            (rfalIsoDepPpsRes*)&gIsoDep.ctrlBuf));
+
+                    gIsoDep.state = ISODEP_ST_PCD_ACT_PPS;
+                    return ERR_BUSY;
+                }
+
+                return ERR_NONE;
+            }
+        }
+        break;
+
+    /*******************************************************************************/
+    case ISODEP_ST_PCD_ACT_PPS:
+        ret = rfalIsoDepGetPPSSTatus();
+        if(ret != ERR_BUSY) {
+            /* Check whether PPS has been acknowledge */
+            if(ret == ERR_NONE) {
+                /* DSI code the divisor from PICC to PCD */
+                /* DRI code the divisor from PCD to PICC */
+                rfalSetBitRate(gIsoDep.actvDev->info.DRI, gIsoDep.actvDev->info.DSI);
+            } else {
+                /* If PPS has faled keep activation bit rate */
+                gIsoDep.actvDev->info.DSI = RFAL_BR_106;
+                gIsoDep.actvDev->info.DRI = RFAL_BR_106;
+            }
+        }
+        break;
+
+    /*******************************************************************************/
+    default:
+        ret = ERR_WRONG_STATE;
+        break;
+    }
+
+    return ret;
+}
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_NFCB
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollBHandleActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    uint8_t PARAM1,
+    const rfalNfcbListenDevice* nfcbDev,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    rfalIsoDepDevice* isoDepDev) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalIsoDepPollBStartActivation(
+            FSDI, DID, maxBR, PARAM1, nfcbDev, HLInfo, HLInfoLen, isoDepDev));
+    rfalIsoDepRunBlocking(ret, rfalIsoDepPollBGetActivationStatus());
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollBStartActivation(
+    rfalIsoDepFSxI FSDI,
+    uint8_t DID,
+    rfalBitRate maxBR,
+    uint8_t PARAM1,
+    const rfalNfcbListenDevice* nfcbDev,
+    const uint8_t* HLInfo,
+    uint8_t HLInfoLen,
+    rfalIsoDepDevice* isoDepDev) {
+    ReturnCode ret;
+
+    /***************************************************************************/
+    /* Initialize ISO-DEP Device with info from SENSB_RES                      */
+    isoDepDev->info.FWI =
+        ((nfcbDev->sensbRes.protInfo.FwiAdcFo >> RFAL_NFCB_SENSB_RES_FWI_SHIFT) &
+         RFAL_NFCB_SENSB_RES_FWI_MASK);
+    isoDepDev->info.FWT = rfalIsoDepFWI2FWT(isoDepDev->info.FWI);
+    isoDepDev->info.dFWT = RFAL_NFCB_DFWT;
+    isoDepDev->info.SFGI =
+        (((uint32_t)nfcbDev->sensbRes.protInfo.SFGI >> RFAL_NFCB_SENSB_RES_SFGI_SHIFT) &
+         RFAL_NFCB_SENSB_RES_SFGI_MASK);
+    isoDepDev->info.SFGT = rfalIsoDepSFGI2SFGT((uint8_t)isoDepDev->info.SFGI);
+    isoDepDev->info.FSxI =
+        ((nfcbDev->sensbRes.protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_FSCI_SHIFT) &
+         RFAL_NFCB_SENSB_RES_FSCI_MASK);
+    isoDepDev->info.FSx = rfalIsoDepFSxI2FSx(isoDepDev->info.FSxI);
+    isoDepDev->info.DID = DID;
+    isoDepDev->info.supDID =
+        (((nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_FO_DID_MASK) != 0U) ? true :
+                                                                                           false);
+    isoDepDev->info.supNAD =
+        (((nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_FO_NAD_MASK) != 0U) ? true :
+                                                                                           false);
+
+    /* Check if DID requested is supported by PICC */
+    if((DID != RFAL_ISODEP_NO_DID) && (!isoDepDev->info.supDID)) {
+        return ERR_PARAM;
+    }
+
+    /* Enable EMD handling according   Digital 2.1  4.1.1.1 ; EMVCo 3.0  4.9.2 */
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_EMVCO);
+
+    /***************************************************************************/
+    /* Set FDT Poll to be used on upcoming communications                      */
+    if(gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) {
+        /* Disregard Minimum TR2 returned by PICC, always use FDTb MIN   EMVCo 3.0  6.3.2.10  */
+        rfalSetFDTPoll(RFAL_FDT_POLL_NFCB_POLLER);
+    } else {
+        /* Apply minimum TR2 from SENSB_RES   Digital 2.1  7.6.2.23 */
+        rfalSetFDTPoll(rfalNfcbTR2ToFDT(
+            ((nfcbDev->sensbRes.protInfo.FsciProType >> RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT) &
+             RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK)));
+    }
+
+    /* Calculate max Bit Rate */
+    rfalIsoDepCalcBitRate(
+        maxBR, nfcbDev->sensbRes.protInfo.BRC, &isoDepDev->info.DSI, &isoDepDev->info.DRI);
+
+    /***************************************************************************/
+    /* Send ATTRIB Command                                                     */
+    EXIT_ON_ERR(
+        ret,
+        rfalIsoDepStartATTRIB(
+            (const uint8_t*)&nfcbDev->sensbRes.nfcid0,
+            (((nfcbDev->sensbRes.protInfo.FwiAdcFo & RFAL_NFCB_SENSB_RES_ADC_ADV_FEATURE_MASK) !=
+              0U) ?
+                 PARAM1 :
+                 RFAL_ISODEP_ATTRIB_REQ_PARAM1_DEFAULT),
+            isoDepDev->info.DSI,
+            isoDepDev->info.DRI,
+            FSDI,
+            (gIsoDep.compMode == RFAL_COMPLIANCE_MODE_EMV) ?
+                RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK :
+                (nfcbDev->sensbRes.protInfo.FsciProType &
+                 ((RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK << RFAL_NFCB_SENSB_RES_PROTO_TR2_SHIFT) |
+                  RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK)), /* EMVCo 2.6 6.4.1.9 */
+            DID,
+            HLInfo,
+            HLInfoLen,
+            (isoDepDev->info.FWT + isoDepDev->info.dFWT),
+            &isoDepDev->activation.B.Listener.ATTRIB_RES,
+            &isoDepDev->activation.B.Listener.ATTRIB_RESLen));
+
+    gIsoDep.actvDev = isoDepDev;
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollBGetActivationStatus(void) {
+    ReturnCode ret;
+    uint8_t mbli;
+
+    /***************************************************************************/
+    /* Process ATTRIB Response                                                 */
+    ret = rfalIsoDepGetATTRIBStatus();
+    if(ret != ERR_BUSY) {
+        if(ret == ERR_NONE) {
+            /* Digital 1.1 14.6.2.3 - Check if received DID match */
+            if((gIsoDep.actvDev->activation.B.Listener.ATTRIB_RES.mbliDid &
+                RFAL_ISODEP_ATTRIB_RES_DID_MASK) != gIsoDep.did) {
+                return ERR_PROTO;
+            }
+
+            /* Retrieve MBLI and calculate new FDS/MBL (Maximum Buffer Length) */
+            mbli =
+                ((gIsoDep.actvDev->activation.B.Listener.ATTRIB_RES.mbliDid >>
+                  RFAL_ISODEP_ATTRIB_RES_MBLI_SHIFT) &
+                 RFAL_ISODEP_ATTRIB_RES_MBLI_MASK);
+            if(mbli > 0U) {
+                /* Digital 1.1  14.6.2  Calculate Maximum Buffer Length MBL = FSC x 2^(MBLI-1) */
+                gIsoDep.actvDev->info.MBL =
+                    (gIsoDep.actvDev->info.FSx * ((uint32_t)1U << (mbli - 1U)));
+            }
+
+            /* DSI code the divisor from PICC to PCD */
+            /* DRI code the divisor from PCD to PICC */
+            rfalSetBitRate(gIsoDep.actvDev->info.DRI, gIsoDep.actvDev->info.DSI);
+
+            /* REMARK: SoF EoF TR0 and TR1 are not passed on to RF layer */
+
+            /* Start the SFGT timer (reuse RFAL GT timer) */
+            rfalSetGT(rfalConvMsTo1fc(gIsoDep.actvDev->info.SFGT));
+            rfalFieldOnAndStartGT();
+        } else {
+            gIsoDep.actvDev->info.DSI = RFAL_BR_106;
+            gIsoDep.actvDev->info.DRI = RFAL_BR_106;
+        }
+
+        /*******************************************************************************/
+        /* Store already FS info,  rfalIsoDepGetMaxInfLen() may be called before setting TxRx params */
+        gIsoDep.fsx = gIsoDep.actvDev->info.FSx;
+    }
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFCB */
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepPollHandleSParameters(
+    rfalIsoDepDevice* isoDepDev,
+    rfalBitRate maxTxBR,
+    rfalBitRate maxRxBR) {
+    uint8_t it;
+    uint8_t supPCD2PICC;
+    uint8_t supPICC2PCD;
+    uint8_t currenttxBR;
+    uint8_t currentrxBR;
+    rfalBitRate txBR;
+    rfalBitRate rxBR;
+    uint16_t rcvLen;
+    ReturnCode ret;
+    rfalIsoDepControlMsgSParam sParam;
+
+    if((isoDepDev == NULL) || (maxTxBR > RFAL_BR_13560) || (maxRxBR > RFAL_BR_13560)) {
+        return ERR_PARAM;
+    }
+
+    it = 0;
+    supPICC2PCD = 0x00;
+    supPCD2PICC = 0x00;
+    txBR = RFAL_BR_106;
+    rxBR = RFAL_BR_106;
+    sParam.pcb = ISODEP_PCB_SPARAMETERS;
+
+    /*******************************************************************************/
+    /* Send S(PARAMETERS) - Block Info */
+    sParam.sParam.tag = RFAL_ISODEP_SPARAM_TAG_BLOCKINFO;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRREQ;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRREQ_LEN;
+    sParam.sParam.length = it;
+
+    /* Send S(PARAMETERS). Use a fixed FWI of 4   ISO14443-4 2016  7.2 */
+    EXIT_ON_ERR(
+        ret,
+        rfalTransceiveBlockingTxRx(
+            (uint8_t*)&sParam,
+            (RFAL_ISODEP_SPARAM_HDR_LEN + (uint16_t)it),
+            (uint8_t*)&sParam,
+            sizeof(rfalIsoDepControlMsgSParam),
+            &rcvLen,
+            RFAL_TXRX_FLAGS_DEFAULT,
+            ISODEP_FWT_DEACTIVATION));
+
+    it = 0;
+
+    /*******************************************************************************/
+    /* Check S(PARAMETERS) response */
+    if((sParam.pcb != ISODEP_PCB_SPARAMETERS) ||
+       (sParam.sParam.tag != RFAL_ISODEP_SPARAM_TAG_BLOCKINFO) ||
+       (sParam.sParam.value[it] != RFAL_ISODEP_SPARAM_TAG_BRIND) ||
+       (rcvLen < RFAL_ISODEP_SPARAM_HDR_LEN) ||
+       (rcvLen != ((uint16_t)sParam.sParam.length + RFAL_ISODEP_SPARAM_HDR_LEN))) {
+        return ERR_PROTO;
+    }
+
+    /* Retrieve PICC's bit rate PICC capabilities */
+    for(it = 0; it < (rcvLen - (uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN); it++) {
+        if((sParam.sParam.value[it] == RFAL_ISODEP_SPARAM_TAG_SUP_PCD2PICC) &&
+           (sParam.sParam.value[it + (uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN] ==
+            RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN)) {
+            supPCD2PICC = sParam.sParam.value[it + RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN];
+        }
+
+        if((sParam.sParam.value[it] == RFAL_ISODEP_SPARAM_TAG_SUP_PICC2PCD) &&
+           (sParam.sParam.value[it + (uint16_t)RFAL_ISODEP_SPARAM_TAG_LEN] ==
+            RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN)) {
+            supPICC2PCD = sParam.sParam.value[it + RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN];
+        }
+    }
+
+    /*******************************************************************************/
+    /* Check if requested bit rates are supported by PICC */
+    if((supPICC2PCD == 0x00U) || (supPCD2PICC == 0x00U)) {
+        return ERR_PROTO;
+    }
+
+    for(it = 0; it <= (uint8_t)maxTxBR; it++) {
+        if((supPCD2PICC & (0x01U << it)) != 0U) {
+            txBR = (rfalBitRate)
+                it; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and above clamping of maxTxBR guarantee no invalid enum values to be created */
+        }
+    }
+    for(it = 0; it <= (uint8_t)maxRxBR; it++) {
+        if((supPICC2PCD & (0x01U << it)) != 0U) {
+            rxBR = (rfalBitRate)
+                it; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and above clamping of maxTxBR guarantee no invalid enum values to be created */
+        }
+    }
+
+    it = 0;
+    currenttxBR = (uint8_t)txBR;
+    currentrxBR = (uint8_t)rxBR;
+
+    /*******************************************************************************/
+    /* Send S(PARAMETERS) - Bit rates Activation */
+    sParam.sParam.tag = RFAL_ISODEP_SPARAM_TAG_BLOCKINFO;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_BRACT;
+    sParam.sParam.value[it++] =
+        (RFAL_ISODEP_SPARAM_TVL_HDR_LEN + RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN +
+         RFAL_ISODEP_SPARAM_TVL_HDR_LEN + RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN);
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_SEL_PCD2PICC;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_PCD2PICC_LEN;
+    sParam.sParam.value[it++] = ((uint8_t)0x01U << currenttxBR);
+    sParam.sParam.value[it++] = 0x00U;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_SEL_PICC2PCD;
+    sParam.sParam.value[it++] = RFAL_ISODEP_SPARAM_TAG_PICC2PCD_LEN;
+    sParam.sParam.value[it++] = ((uint8_t)0x01U << currentrxBR);
+    sParam.sParam.value[it++] = 0x00U;
+    sParam.sParam.length = it;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalTransceiveBlockingTxRx(
+            (uint8_t*)&sParam,
+            (RFAL_ISODEP_SPARAM_HDR_LEN + (uint16_t)it),
+            (uint8_t*)&sParam,
+            sizeof(rfalIsoDepControlMsgSParam),
+            &rcvLen,
+            RFAL_TXRX_FLAGS_DEFAULT,
+            (isoDepDev->info.FWT + isoDepDev->info.dFWT)));
+
+    it = 0;
+
+    /*******************************************************************************/
+    /* Check S(PARAMETERS) Acknowledge  */
+    if((sParam.pcb != ISODEP_PCB_SPARAMETERS) ||
+       (sParam.sParam.tag != RFAL_ISODEP_SPARAM_TAG_BLOCKINFO) ||
+       (sParam.sParam.value[it] != RFAL_ISODEP_SPARAM_TAG_BRACK) ||
+       (rcvLen < RFAL_ISODEP_SPARAM_HDR_LEN)) {
+        return ERR_PROTO;
+    }
+
+    EXIT_ON_ERR(ret, rfalSetBitRate(txBR, rxBR));
+
+    isoDepDev->info.DRI = txBR;
+    isoDepDev->info.DSI = rxBR;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+static void rfalIsoDepCalcBitRate(
+    rfalBitRate maxAllowedBR,
+    uint8_t piccBRCapability,
+    rfalBitRate* dsi,
+    rfalBitRate* dri) {
+    uint8_t driMask;
+    uint8_t dsiMask;
+    int8_t i;
+    bool bitrateFound;
+    rfalBitRate curMaxBR;
+
+    curMaxBR = maxAllowedBR;
+
+    do {
+        bitrateFound = true;
+
+        (*dsi) = RFAL_BR_106;
+        (*dri) = RFAL_BR_106;
+
+        /* Digital 1.0  5.6.2.5 & 11.6.2.14: A received RFU value of b4 = 1b MUST be interpreted as if b7 to b1 ? 0000000b (only 106 kbits/s in both direction) */
+        if(((RFAL_ISODEP_BITRATE_RFU_MASK & piccBRCapability) != 0U) || (curMaxBR > RFAL_BR_848) ||
+           (curMaxBR == RFAL_BR_KEEP)) {
+            return;
+        }
+
+        /***************************************************************************/
+        /* Determine Listen->Poll bit rate */
+        dsiMask = (piccBRCapability & RFAL_ISODEP_BSI_MASK);
+        for(i = 2; i >= 0; i--) // Check supported bit rate from the highest
+        {
+            if(((dsiMask & (0x10U << (uint8_t)i)) != 0U) &&
+               (((uint8_t)i + 1U) <= (uint8_t)curMaxBR)) {
+                uint8_t newdsi = ((uint8_t)i) + 1U;
+                (*dsi) = (rfalBitRate)
+                    newdsi; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and range of loop variable guarantee no invalid enum values to be created */
+                break;
+            }
+        }
+
+        /***************************************************************************/
+        /* Determine Poll->Listen bit rate */
+        driMask = (piccBRCapability & RFAL_ISODEP_BRI_MASK);
+        for(i = 2; i >= 0; i--) /* Check supported bit rate from the highest */
+        {
+            if(((driMask & (0x01U << (uint8_t)i)) != 0U) &&
+               (((uint8_t)i + 1U) <= (uint8_t)curMaxBR)) {
+                uint8_t newdri = ((uint8_t)i) + 1U;
+                (*dri) = (rfalBitRate)
+                    newdri; /* PRQA S 4342 # MISRA 10.5 - Layout of enum rfalBitRate and range of loop variable guarantee no invalid enum values to be created */
+                break;
+            }
+        }
+
+        /***************************************************************************/
+        /* Check if different bit rate is supported */
+
+        /* Digital 1.0 Table 67: if b8=1b, then only the same bit rate divisor for both directions is supported */
+        if((piccBRCapability & RFAL_ISODEP_SAME_BITRATE_MASK) != 0U) {
+            (*dsi) = MIN((*dsi), (*dri));
+            (*dri) = (*dsi);
+            /* Check that the baudrate is supported */
+            if((RFAL_BR_106 != (*dsi)) &&
+               (!(((dsiMask & (0x10U << ((uint8_t)(*dsi) - 1U))) != 0U) &&
+                  ((driMask & (0x01U << ((uint8_t)(*dri) - 1U))) != 0U)))) {
+                bitrateFound = false;
+                curMaxBR =
+                    (*dsi); /* set allowed bitrate to be lowest and determine bit rate again */
+            }
+        }
+    } while(!(bitrateFound));
+}
+
+/*******************************************************************************/
+static uint32_t rfalIsoDepSFGI2SFGT(uint8_t sfgi) {
+    uint32_t sfgt;
+    uint8_t tmpSFGI;
+
+    tmpSFGI = sfgi;
+
+    if(tmpSFGI > ISODEP_SFGI_MAX) {
+        tmpSFGI = ISODEP_SFGI_MIN;
+    }
+
+    if(tmpSFGI != ISODEP_SFGI_MIN) {
+        /* If sfgi != 0 wait SFGT + dSFGT   Digital 1.1  13.8.2.1 */
+        sfgt = isoDepCalcSGFT(sfgi) + isoDepCalcdSGFT(sfgi);
+    }
+    /* Otherwise use FDTPoll min Digital  1.1  13.8.2.3*/
+    else {
+        sfgt = RFAL_FDT_POLL_NFCA_POLLER;
+    }
+
+    /* Convert carrier cycles to milli seconds */
+    return (rfalConv1fcToMs(sfgt) + 1U);
+}
+
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+
+/*******************************************************************************/
+static void rfalIsoDepApdu2IBLockParam(
+    rfalIsoDepApduTxRxParam apduParam,
+    rfalIsoDepTxRxParam* iBlockParam,
+    uint16_t txPos,
+    uint16_t rxPos) {
+    NO_WARNING(rxPos); /* Keep this param for future use */
+
+    iBlockParam->DID = apduParam.DID;
+    iBlockParam->FSx = apduParam.FSx;
+    iBlockParam->ourFSx = apduParam.ourFSx;
+    iBlockParam->FWT = apduParam.FWT;
+    iBlockParam->dFWT = apduParam.dFWT;
+
+    if((apduParam.txBufLen - txPos) > rfalIsoDepGetMaxInfLen()) {
+        iBlockParam->isTxChaining = true;
+        iBlockParam->txBufLen = rfalIsoDepGetMaxInfLen();
+    } else {
+        iBlockParam->isTxChaining = false;
+        iBlockParam->txBufLen = (apduParam.txBufLen - txPos);
+    }
+
+    /* TxBuf is moved to the beginning for every I-Block */
+    iBlockParam->txBuf =
+        (rfalIsoDepBufFormat*)apduParam
+            .txBuf; /*  PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */
+    iBlockParam->rxBuf =
+        apduParam
+            .tmpBuf; /* Simply using the apdu buffer is not possible because of current ACK handling */
+    iBlockParam->isRxChaining = &gIsoDep.isAPDURxChaining;
+    iBlockParam->rxLen = apduParam.rxLen;
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepStartApduTransceive(rfalIsoDepApduTxRxParam param) {
+    rfalIsoDepTxRxParam txRxParam;
+
+    /* Initialize and store APDU context */
+    gIsoDep.APDUParam = param;
+    gIsoDep.APDUTxPos = 0;
+    gIsoDep.APDURxPos = 0;
+
+    /* Assign current FSx to calculate INF length (only change the FSx from activation if no to Keep) */
+    gIsoDep.ourFsx = ((param.ourFSx != RFAL_ISODEP_FSX_KEEP) ? param.ourFSx : gIsoDep.ourFsx);
+    gIsoDep.fsx = param.FSx;
+
+    /* Convert APDU TxRxParams to I-Block TxRxParams */
+    rfalIsoDepApdu2IBLockParam(
+        gIsoDep.APDUParam, &txRxParam, gIsoDep.APDUTxPos, gIsoDep.APDURxPos);
+
+    return rfalIsoDepStartTransceive(txRxParam);
+}
+
+/*******************************************************************************/
+ReturnCode rfalIsoDepGetApduTransceiveStatus(void) {
+    ReturnCode ret;
+    rfalIsoDepTxRxParam txRxParam;
+
+    ret = rfalIsoDepGetTransceiveStatus();
+    switch(ret) {
+    /*******************************************************************************/
+    case ERR_NONE:
+
+        /* Check if we are still doing chaining on Tx */
+        if(gIsoDep.isTxChaining) {
+            /* Add already Tx bytes */
+            gIsoDep.APDUTxPos += gIsoDep.txBufLen;
+
+            /* Convert APDU TxRxParams to I-Block TxRxParams */
+            rfalIsoDepApdu2IBLockParam(
+                gIsoDep.APDUParam, &txRxParam, gIsoDep.APDUTxPos, gIsoDep.APDURxPos);
+
+            if(txRxParam.txBufLen > 0U) /* MISRA 21.18 */
+            {
+                /* Move next I-Block to beginning of APDU Tx buffer */
+                ST_MEMCPY(
+                    gIsoDep.APDUParam.txBuf->apdu,
+                    &gIsoDep.APDUParam.txBuf->apdu[gIsoDep.APDUTxPos],
+                    txRxParam.txBufLen);
+            }
+
+            EXIT_ON_ERR(ret, rfalIsoDepStartTransceive(txRxParam));
+            return ERR_BUSY;
+        }
+
+        /* APDU TxRx is done */
+        /* fall through */
+
+    /*******************************************************************************/
+    case ERR_AGAIN: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* Check if no APDU transceive has been started before (data from rfalIsoDepListenStartActivation) */
+        if(gIsoDep.APDUParam.rxLen == NULL) {
+            if(ret == ERR_AGAIN) {
+                /* In Listen mode first chained packet cannot be retrieved via APDU interface */
+                return ERR_NOTSUPP;
+            }
+
+            /* TxRx is complete and full data is already available */
+            return ERR_NONE;
+        }
+
+        if(*gIsoDep.APDUParam.rxLen > 0U) /* MISRA 21.18 */
+        {
+            /* Ensure that data in tmpBuf still fits into APDU buffer */
+            if((gIsoDep.APDURxPos + (*gIsoDep.APDUParam.rxLen)) >
+               (uint16_t)RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) {
+                return ERR_NOMEM;
+            }
+
+            /* Copy chained packet from tmp buffer to APDU buffer */
+            ST_MEMCPY(
+                &gIsoDep.APDUParam.rxBuf->apdu[gIsoDep.APDURxPos],
+                gIsoDep.APDUParam.tmpBuf->inf,
+                *gIsoDep.APDUParam.rxLen);
+            gIsoDep.APDURxPos += *gIsoDep.APDUParam.rxLen;
+        }
+
+        /* Update output param rxLen */
+        *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos * 8;
+
+        /* Wait for following I-Block or APDU TxRx has finished */
+        return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);
+
+    /*******************************************************************************/
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_ISO_DEP */

+ 2126 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfc.c

@@ -0,0 +1,2126 @@
+/**
+  ******************************************************************************
+  *
+  * COPYRIGHT(c) 2020 STMicroelectronics
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+
+/*! \file rfal_nfc.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief RFAL NFC device  
+ *  
+ *  This module provides the required features to behave as an NFC Poller 
+ *  or Listener device. It grants an easy to use interface for the following
+ *  activities: Technology Detection, Collision Resollution, Activation,
+ *  Data Exchange, and Deactivation
+ *  
+ *  This layer is influenced by (but not fully aligned with) the NFC Forum 
+ *  specifications, in particular: Activity 2.0 and NCI 2.0
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfc.h"
+#include "../utils.h"
+#include "../include/rfal_analogConfig.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+#define RFAL_NFC_MAX_DEVICES 5U /* Max number of devices supported */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+#define rfalNfcNfcNotify(st) \
+    if(gNfcDev.disc.notifyCb != NULL) gNfcDev.disc.notifyCb(st)
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Buffer union, only one interface is used at a time                                                             */
+typedef union { /*  PRQA S 0750 # MISRA 19.2 - Members of the union will not be used concurrently, only one interface at a time */
+    rfalIsoDepBufFormat isoDepBuf; /*!< ISO-DEP buffer format (with header/prologue)       */
+    rfalNfcDepBufFormat nfcDepBuf; /*!< NFC-DEP buffer format (with header/prologue)       */
+} rfalNfcTmpBuffer;
+
+typedef struct {
+    rfalNfcState state; /* Main state                                      */
+    uint16_t techsFound; /* Technologies found bitmask                      */
+    uint16_t techs2do; /* Technologies still to be performed              */
+    rfalBitRate ap2pBR; /* Bit rate to poll for AP2P                       */
+    uint8_t selDevIdx; /* Selected device index                           */
+    rfalNfcDevice* activeDev; /* Active device pointer                           */
+    rfalNfcDiscoverParam disc; /* Discovery parameters                            */
+    rfalNfcDevice devList[RFAL_NFC_MAX_DEVICES]; /*!< Location of device list          */
+    uint8_t devCnt; /* Devices found counter                           */
+    uint32_t discTmr; /* Discovery Total duration timer                  */
+    ReturnCode dataExErr; /* Last Data Exchange error                        */
+    bool discRestart; /* Restart discover after deactivation flag        */
+    bool isRxChaining; /* Flag indicating Other device is chaining        */
+    uint32_t lmMask; /* Listen Mode mask                                */
+    bool isTechInit; /* Flag indicating technology has been set         */
+    bool isOperOngoing; /* Flag indicating operation is ongoing             */
+
+    rfalNfcBuffer txBuf; /* Tx buffer for Data Exchange                     */
+    rfalNfcBuffer rxBuf; /* Rx buffer for Data Exchange                     */
+    uint16_t rxLen; /* Length of received data on Data Exchange        */
+
+#if RFAL_FEATURE_NFC_DEP || RFAL_FEATURE_ISO_DEP
+    rfalNfcTmpBuffer tmpBuf; /* Tmp buffer for Data Exchange                    */
+#endif /* RFAL_FEATURE_NFC_DEP || RFAL_FEATURE_ISO_DEP */
+
+} rfalNfc;
+
+/*
+ ******************************************************************************
+ * LOCAL VARIABLES
+ ******************************************************************************
+ */
+#ifdef RFAL_TEST_MODE
+rfalNfc gNfcDev;
+#else /* RFAL_TEST_MODE */
+static rfalNfc gNfcDev;
+#endif /* RFAL_TEST_MODE */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static ReturnCode rfalNfcPollTechDetetection(void);
+static ReturnCode rfalNfcPollCollResolution(void);
+static ReturnCode rfalNfcPollActivation(uint8_t devIt);
+static ReturnCode rfalNfcDeactivation(void);
+
+#if RFAL_FEATURE_NFC_DEP
+static ReturnCode rfalNfcNfcDepActivate(
+    rfalNfcDevice* device,
+    rfalNfcDepCommMode commMode,
+    const uint8_t* atrReq,
+    uint16_t atrReqLen);
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+#if RFAL_FEATURE_LISTEN_MODE
+static ReturnCode rfalNfcListenActivation(void);
+#endif /* RFAL_FEATURE_LISTEN_MODE*/
+
+/*******************************************************************************/
+ReturnCode rfalNfcInitialize(void) {
+    ReturnCode err;
+
+    gNfcDev.state = RFAL_NFC_STATE_NOTINIT;
+
+    rfalAnalogConfigInitialize(); /* Initialize RFAL's Analog Configs */
+    EXIT_ON_ERR(err, rfalInitialize()); /* Initialize RFAL */
+
+    gNfcDev.state = RFAL_NFC_STATE_IDLE; /* Go to initialized */
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDiscover(const rfalNfcDiscoverParam* disParams) {
+    /* Check if initialization has been performed */
+    if(gNfcDev.state != RFAL_NFC_STATE_IDLE) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check valid parameters */
+    if((disParams == NULL) || (disParams->devLimit > RFAL_NFC_MAX_DEVICES) ||
+       (disParams->devLimit == 0U) ||
+       ((disParams->maxBR > RFAL_BR_1695) && (disParams->maxBR != RFAL_BR_KEEP)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) &&
+        (disParams->nfcfBR != RFAL_BR_212) && (disParams->nfcfBR != RFAL_BR_424)) ||
+       ((((disParams->techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) &&
+         (disParams->ap2pBR > RFAL_BR_424)) ||
+        (disParams->GBLen > RFAL_NFCDEP_GB_MAX_LEN))) {
+        return ERR_PARAM;
+    }
+
+    if((((disParams->techs2Find & RFAL_NFC_POLL_TECH_A) != 0U) && !((bool)RFAL_FEATURE_NFCA)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_B) != 0U) && !((bool)RFAL_FEATURE_NFCB)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) && !((bool)RFAL_FEATURE_NFCF)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_V) != 0U) && !((bool)RFAL_FEATURE_NFCV)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_ST25TB) != 0U) &&
+        !((bool)RFAL_FEATURE_ST25TB)) ||
+       (((disParams->techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) &&
+        !((bool)RFAL_FEATURE_NFC_DEP)) ||
+       (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_A) != 0U) && !((bool)RFAL_FEATURE_NFCA)) ||
+       (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_B) != 0U) && !((bool)RFAL_FEATURE_NFCB)) ||
+       (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_F) != 0U) && !((bool)RFAL_FEATURE_NFCF)) ||
+       (((disParams->techs2Find & RFAL_NFC_LISTEN_TECH_AP2P) != 0U) &&
+        !((bool)RFAL_FEATURE_NFC_DEP))) {
+        return ERR_DISABLED; /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset  */
+    }
+
+    /* Initialize context for discovery */
+    gNfcDev.activeDev = NULL;
+    gNfcDev.techsFound = RFAL_NFC_TECH_NONE;
+    gNfcDev.devCnt = 0;
+    gNfcDev.discRestart = true;
+    gNfcDev.isTechInit = false;
+    gNfcDev.disc = *disParams;
+
+    /* Calculate Listen Mask */
+    gNfcDev.lmMask = 0U;
+    gNfcDev.lmMask |=
+        (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_A) != 0U) ? RFAL_LM_MASK_NFCA : 0U);
+    gNfcDev.lmMask |=
+        (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_B) != 0U) ? RFAL_LM_MASK_NFCB : 0U);
+    gNfcDev.lmMask |=
+        (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_F) != 0U) ? RFAL_LM_MASK_NFCF : 0U);
+    gNfcDev.lmMask |=
+        (((gNfcDev.disc.techs2Find & RFAL_NFC_LISTEN_TECH_AP2P) != 0U) ? RFAL_LM_MASK_ACTIVE_P2P :
+                                                                         0U);
+
+#if !RFAL_FEATURE_LISTEN_MODE
+    /* Check if Listen Mode is supported/Enabled */
+    if(gNfcDev.lmMask != 0U) {
+        return ERR_DISABLED;
+    }
+#endif
+
+    gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDeactivate(bool discovery) {
+    /* Check for valid state */
+    if(gNfcDev.state <= RFAL_NFC_STATE_IDLE) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check if discovery is to continue afterwards */
+    if((discovery == true) && (gNfcDev.disc.techs2Find != RFAL_NFC_TECH_NONE)) {
+        /* If so let the state machine continue*/
+        gNfcDev.discRestart = discovery;
+        gNfcDev.state = RFAL_NFC_STATE_DEACTIVATION;
+    } else {
+        /* Otherwise deactivate immediately and go to IDLE */
+        rfalNfcDeactivation();
+        gNfcDev.state = RFAL_NFC_STATE_IDLE;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcSelect(uint8_t devIdx) {
+    /* Check for valid state */
+    if(gNfcDev.state != RFAL_NFC_STATE_POLL_SELECT) {
+        return ERR_WRONG_STATE;
+    }
+
+    gNfcDev.selDevIdx = devIdx;
+    gNfcDev.state = RFAL_NFC_STATE_POLL_ACTIVATION;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+rfalNfcState rfalNfcGetState(void) {
+    return gNfcDev.state;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcGetDevicesFound(rfalNfcDevice** devList, uint8_t* devCnt) {
+    /* Check for valid state */
+    if(gNfcDev.state < RFAL_NFC_STATE_POLL_SELECT) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check valid parameters */
+    if((devList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *devCnt = gNfcDev.devCnt;
+    *devList = gNfcDev.devList;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcGetActiveDevice(rfalNfcDevice** dev) {
+    /* Check for valid state */
+    if(gNfcDev.state < RFAL_NFC_STATE_ACTIVATED) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check valid parameter */
+    if(dev == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Check for valid state */
+    if((gNfcDev.devCnt == 0U) || (gNfcDev.activeDev == NULL)) {
+        return ERR_REQUEST;
+    }
+
+    *dev = gNfcDev.activeDev;
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+void rfalNfcWorker(void) {
+    ReturnCode err;
+
+    rfalWorker(); /* Execute RFAL process  */
+
+    switch(gNfcDev.state) {
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_NOTINIT:
+    case RFAL_NFC_STATE_IDLE:
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_START_DISCOVERY:
+
+        /* Initialize context for discovery cycle */
+        gNfcDev.devCnt = 0;
+        gNfcDev.selDevIdx = 0;
+        gNfcDev.techsFound = RFAL_NFC_TECH_NONE;
+        gNfcDev.techs2do = gNfcDev.disc.techs2Find;
+        gNfcDev.state = RFAL_NFC_STATE_POLL_TECHDETECT;
+
+#if RFAL_FEATURE_WAKEUP_MODE
+        /* Check if Low power Wake-Up is to be performed */
+        if(gNfcDev.disc.wakeupEnabled) {
+            /* Initialize Low power Wake-up mode and wait */
+            err = rfalWakeUpModeStart(
+                (gNfcDev.disc.wakeupConfigDefault ? NULL : &gNfcDev.disc.wakeupConfig));
+            if(err == ERR_NONE) {
+                gNfcDev.state = RFAL_NFC_STATE_WAKEUP_MODE;
+                rfalNfcNfcNotify(gNfcDev.state); /* Notify caller that WU was started */
+            }
+        }
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_WAKEUP_MODE:
+
+#if RFAL_FEATURE_WAKEUP_MODE
+        /* Check if the Wake-up mode has woke */
+        if(rfalWakeUpModeHasWoke()) {
+            rfalWakeUpModeStop(); /* Disable Wake-up mode           */
+            gNfcDev.state = RFAL_NFC_STATE_POLL_TECHDETECT; /* Go to Technology detection     */
+
+            rfalNfcNfcNotify(gNfcDev.state); /* Notify caller that WU has woke */
+        }
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_POLL_TECHDETECT:
+
+        /* Start total duration timer */
+        platformTimerDestroy(gNfcDev.discTmr);
+        gNfcDev.discTmr = (uint32_t)platformTimerCreate(gNfcDev.disc.totalDuration);
+
+        err =
+            rfalNfcPollTechDetetection(); /* Perform Technology Detection                         */
+        if(err != ERR_BUSY) /* Wait until all technologies are performed            */
+        {
+            if((err != ERR_NONE) ||
+               (gNfcDev.techsFound ==
+                RFAL_NFC_TECH_NONE)) /* Check if any error occurred or no techs were found   */
+            {
+                rfalFieldOff();
+                gNfcDev.state =
+                    RFAL_NFC_STATE_LISTEN_TECHDETECT; /* Nothing found as poller, go to listener */
+                break;
+            }
+
+            gNfcDev.techs2do =
+                gNfcDev.techsFound; /* Store the found technologies for collision resolution */
+            gNfcDev.state =
+                RFAL_NFC_STATE_POLL_COLAVOIDANCE; /* One or more devices found, go to Collision Avoidance  */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_POLL_COLAVOIDANCE:
+
+        err =
+            rfalNfcPollCollResolution(); /* Resolve any eventual collision                       */
+        if(err != ERR_BUSY) /* Wait until all technologies are performed            */
+        {
+            if((err != ERR_NONE) ||
+               (gNfcDev.devCnt == 0U)) /* Check if any error occurred or no devices were found */
+            {
+                gNfcDev.state = RFAL_NFC_STATE_DEACTIVATION;
+                break; /* Unable to retrieve any device, restart loop          */
+            }
+
+            /* Check if more than one device has been found */
+            if(gNfcDev.devCnt > 1U) {
+                /* If more than one device was found inform upper layer to choose which one to activate */
+                if(gNfcDev.disc.notifyCb != NULL) {
+                    gNfcDev.state = RFAL_NFC_STATE_POLL_SELECT;
+                    gNfcDev.disc.notifyCb(gNfcDev.state);
+                    break;
+                }
+            }
+
+            /* If only one device or no callback has been set, activate the first device found */
+            gNfcDev.selDevIdx = 0U;
+            gNfcDev.state = RFAL_NFC_STATE_POLL_ACTIVATION;
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_POLL_ACTIVATION:
+
+        err = rfalNfcPollActivation(gNfcDev.selDevIdx);
+        if(err != ERR_BUSY) /* Wait until all Activation is complete */
+        {
+            if(err != ERR_NONE) /* Activation failed selected device  */
+            {
+                gNfcDev.state =
+                    RFAL_NFC_STATE_DEACTIVATION; /* If Activation failed, restart loop */
+                break;
+            }
+
+            gNfcDev.state = RFAL_NFC_STATE_ACTIVATED; /* Device has been properly activated */
+            rfalNfcNfcNotify(
+                gNfcDev.state); /* Inform upper layer that a device has been activated */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_DATAEXCHANGE:
+
+        rfalNfcDataExchangeGetStatus(); /* Run the internal state machine */
+
+        if(gNfcDev.dataExErr != ERR_BUSY) /* If Dataexchange has terminated */
+        {
+            gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE; /* Go to done state               */
+            rfalNfcNfcNotify(gNfcDev.state); /* And notify caller              */
+        }
+        if(gNfcDev.dataExErr == ERR_SLEEP_REQ) /* Check if Listen mode has to go to Sleep */
+        {
+            gNfcDev.state = RFAL_NFC_STATE_LISTEN_SLEEP; /* Go to Listen Sleep state       */
+            rfalNfcNfcNotify(gNfcDev.state); /* And notify caller              */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_DEACTIVATION:
+
+        rfalNfcDeactivation(); /* Deactivate current device */
+
+        gNfcDev.state =
+            ((gNfcDev.discRestart) ? RFAL_NFC_STATE_START_DISCOVERY : RFAL_NFC_STATE_IDLE);
+        rfalNfcNfcNotify(gNfcDev.state); /* Notify caller             */
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_LISTEN_TECHDETECT:
+
+        if(platformTimerIsExpired(gNfcDev.discTmr)) {
+#if RFAL_FEATURE_LISTEN_MODE
+            rfalListenStop();
+#else
+            rfalFieldOff();
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+            gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */
+            rfalNfcNfcNotify(gNfcDev.state); /* Notify caller             */
+            break;
+        }
+
+#if RFAL_FEATURE_LISTEN_MODE
+
+        if(gNfcDev.lmMask != 0U) /* Check if configured to perform Listen mode */
+        {
+            err = rfalListenStart(
+                gNfcDev.lmMask,
+                &gNfcDev.disc.lmConfigPA,
+                NULL,
+                &gNfcDev.disc.lmConfigPF,
+                (uint8_t*)&gNfcDev.rxBuf.rfBuf,
+                (uint16_t)rfalConvBytesToBits(sizeof(gNfcDev.rxBuf.rfBuf)),
+                &gNfcDev.rxLen);
+            if(err == ERR_NONE) {
+                gNfcDev.state =
+                    RFAL_NFC_STATE_LISTEN_COLAVOIDANCE; /* Wait for listen mode to be activated */
+            }
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_LISTEN_COLAVOIDANCE:
+
+        if(platformTimerIsExpired(
+               gNfcDev.discTmr)) /* Check if the total duration has been reached */
+        {
+            rfalListenStop();
+            gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */
+            rfalNfcNfcNotify(gNfcDev.state); /* Notify caller             */
+            break;
+        }
+
+        /* Check for external field */
+        if(rfalListenGetState(NULL, NULL) >= RFAL_LM_STATE_IDLE) {
+            gNfcDev.state =
+                RFAL_NFC_STATE_LISTEN_ACTIVATION; /* Wait for listen mode to be activated */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_LISTEN_ACTIVATION:
+    case RFAL_NFC_STATE_LISTEN_SLEEP:
+
+        err = rfalNfcListenActivation();
+        if(err != ERR_BUSY) {
+            if(err == ERR_NONE) {
+                gNfcDev.activeDev =
+                    gNfcDev.devList; /* Assign the active device to be used further on */
+                gNfcDev.devCnt++;
+
+                gNfcDev.state = RFAL_NFC_STATE_ACTIVATED; /* Device has been properly activated */
+                rfalNfcNfcNotify(
+                    gNfcDev.state); /* Inform upper layer that a device has been activated */
+            } else {
+                rfalListenStop();
+                gNfcDev.state = RFAL_NFC_STATE_START_DISCOVERY; /* Restart the discovery loop */
+                rfalNfcNfcNotify(gNfcDev.state); /* Notify caller             */
+            }
+        }
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFC_STATE_ACTIVATED:
+    case RFAL_NFC_STATE_POLL_SELECT:
+    case RFAL_NFC_STATE_DATAEXCHANGE_DONE:
+    default:
+        return;
+    }
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDataExchangeStart(
+    uint8_t* txData,
+    uint16_t txDataLen,
+    uint8_t** rxData,
+    uint16_t** rvdLen,
+    uint32_t fwt,
+    uint32_t flags) {
+    ReturnCode err;
+    rfalTransceiveContext ctx;
+
+    /*******************************************************************************/
+    /* The Data Exchange is divided in two different moments, the trigger/Start of *
+     *  the transfer followed by the check until its completion                    */
+    if((gNfcDev.state >= RFAL_NFC_STATE_ACTIVATED) && (gNfcDev.activeDev != NULL)) {
+        /*******************************************************************************/
+        /* In Listen mode is the Poller that initiates the communicatation             */
+        /* Assign output parameters and rfalNfcDataExchangeGetStatus will return       */
+        /* incoming data from Poller/Initiator                                         */
+        if((gNfcDev.state == RFAL_NFC_STATE_ACTIVATED) &&
+           rfalNfcIsRemDevPoller(gNfcDev.activeDev->type)) {
+            if(txDataLen > 0U) {
+                return ERR_WRONG_STATE;
+            }
+
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+            *rxData =
+                (uint8_t*)((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ?
+                               gNfcDev.rxBuf.isoDepBuf.apdu :
+                               ((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ?
+                                    gNfcDev.rxBuf.nfcDepBuf.pdu :
+                                    gNfcDev.rxBuf.rfBuf));
+            if(gNfcDev.disc.activate_after_sak) {
+                gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
+            }
+            return ERR_NONE;
+        }
+
+        /*******************************************************************************/
+        switch(gNfcDev.activeDev
+                   ->rfInterface) /* Check which RF interface shall be used/has been activated */
+        {
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_RF:
+
+            rfalCreateByteFlagsTxRxContext(
+                ctx,
+                (uint8_t*)txData,
+                txDataLen,
+                gNfcDev.rxBuf.rfBuf,
+                sizeof(gNfcDev.rxBuf.rfBuf),
+                &gNfcDev.rxLen,
+                flags,
+                fwt);
+            if(flags == RFAL_TXRX_FLAGS_RAW) {
+                ctx.txBufLen = txDataLen;
+            }
+            *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+            err = rfalStartTransceive(&ctx);
+            break;
+
+#if RFAL_FEATURE_ISO_DEP
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_ISODEP: {
+            rfalIsoDepApduTxRxParam isoDepTxRx;
+
+            if(txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
+                return ERR_NOMEM;
+            }
+
+            if(txDataLen > 0U) {
+                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen);
+            }
+
+            isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
+            isoDepTxRx.ourFSx = RFAL_ISODEP_FSX_KEEP;
+            isoDepTxRx.FSx = gNfcDev.activeDev->proto.isoDep.info.FSx;
+            isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
+            isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
+            isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
+            isoDepTxRx.txBufLen = txDataLen;
+            isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
+            isoDepTxRx.rxLen = &gNfcDev.rxLen;
+            isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.isoDepBuf.apdu;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+
+            /*******************************************************************************/
+            /* Trigger a RFAL ISO-DEP Transceive                                           */
+            err = rfalIsoDepStartApduTransceive(isoDepTxRx);
+            break;
+        }
+#endif /* RFAL_FEATURE_ISO_DEP */
+
+#if RFAL_FEATURE_NFC_DEP
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_NFCDEP: {
+            rfalNfcDepPduTxRxParam nfcDepTxRx;
+
+            if(txDataLen > sizeof(gNfcDev.txBuf.nfcDepBuf.pdu)) {
+                return ERR_NOMEM;
+            }
+
+            if(txDataLen > 0U) {
+                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.nfcDepBuf.pdu, txData, txDataLen);
+            }
+
+            nfcDepTxRx.DID = RFAL_NFCDEP_DID_KEEP;
+            nfcDepTxRx.FSx =
+                rfalNfcIsRemDevListener(gNfcDev.activeDev->type) ?
+                    rfalNfcDepLR2FS((uint8_t)rfalNfcDepPP2LR(
+                        gNfcDev.activeDev->proto.nfcDep.activation.Target.ATR_RES.PPt)) :
+                    rfalNfcDepLR2FS((uint8_t)rfalNfcDepPP2LR(
+                        gNfcDev.activeDev->proto.nfcDep.activation.Initiator.ATR_REQ.PPi));
+            nfcDepTxRx.dFWT = gNfcDev.activeDev->proto.nfcDep.info.dFWT;
+            nfcDepTxRx.FWT = gNfcDev.activeDev->proto.nfcDep.info.FWT;
+            nfcDepTxRx.txBuf = &gNfcDev.txBuf.nfcDepBuf;
+            nfcDepTxRx.txBufLen = txDataLen;
+            nfcDepTxRx.rxBuf = &gNfcDev.rxBuf.nfcDepBuf;
+            nfcDepTxRx.rxLen = &gNfcDev.rxLen;
+            nfcDepTxRx.tmpBuf = &gNfcDev.tmpBuf.nfcDepBuf;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.nfcDepBuf.pdu;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+
+            /*******************************************************************************/
+            /* Trigger a RFAL NFC-DEP Transceive                                           */
+            err = rfalNfcDepStartPduTransceive(nfcDepTxRx);
+            break;
+        }
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+        /*******************************************************************************/
+        default:
+            err = ERR_PARAM;
+            break;
+        }
+
+        /* If a transceive has successfuly started flag Data Exchange as ongoing */
+        if(err == ERR_NONE) {
+            gNfcDev.dataExErr = ERR_BUSY;
+            gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE;
+        }
+
+        return err;
+    }
+
+    return ERR_WRONG_STATE;
+}
+
+ReturnCode rfalNfcDataExchangeCustomStart(
+    uint8_t* txData,
+    uint16_t txDataLen,
+    uint8_t** rxData,
+    uint16_t** rvdLen,
+    uint32_t fwt,
+    uint32_t flags) {
+    ReturnCode err;
+    rfalTransceiveContext ctx;
+
+    /*******************************************************************************/
+    /* The Data Exchange is divided in two different moments, the trigger/Start of *
+     *  the transfer followed by the check until its completion                    */
+    if((gNfcDev.state >= RFAL_NFC_STATE_ACTIVATED) && (gNfcDev.activeDev != NULL)) {
+        /*******************************************************************************/
+        /* In Listen mode is the Poller that initiates the communicatation             */
+        /* Assign output parameters and rfalNfcDataExchangeGetStatus will return       */
+        /* incoming data from Poller/Initiator                                         */
+        if((gNfcDev.state == RFAL_NFC_STATE_ACTIVATED) &&
+           rfalNfcIsRemDevPoller(gNfcDev.activeDev->type)) {
+            if(txDataLen > 0U) {
+                return ERR_WRONG_STATE;
+            }
+
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+            *rxData =
+                (uint8_t*)((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ?
+                               gNfcDev.rxBuf.isoDepBuf.apdu :
+                               ((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ?
+                                    gNfcDev.rxBuf.nfcDepBuf.pdu :
+                                    gNfcDev.rxBuf.rfBuf));
+            if(gNfcDev.disc.activate_after_sak) {
+                gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
+            }
+            return ERR_NONE;
+        }
+
+        /*******************************************************************************/
+        switch(gNfcDev.activeDev
+                   ->rfInterface) /* Check which RF interface shall be used/has been activated */
+        {
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_RF:
+            ctx.rxBuf = gNfcDev.rxBuf.rfBuf;
+            ctx.rxBufLen = 8 * sizeof(gNfcDev.rxBuf.rfBuf);
+            ctx.rxRcvdLen = &gNfcDev.rxLen;
+            ctx.txBuf = txData;
+            ctx.txBufLen = txDataLen;
+            ctx.flags = flags;
+            ctx.fwt = fwt;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+            err = rfalStartTransceive(&ctx);
+            break;
+
+#if RFAL_FEATURE_ISO_DEP
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_ISODEP: {
+            rfalIsoDepApduTxRxParam isoDepTxRx;
+            uint16_t tx_bytes = txDataLen / 8;
+
+            if(tx_bytes > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
+                return ERR_NOMEM;
+            }
+
+            if(tx_bytes > 0U) {
+                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, tx_bytes);
+            }
+
+            isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
+            isoDepTxRx.ourFSx = RFAL_ISODEP_FSX_KEEP;
+            isoDepTxRx.FSx = gNfcDev.activeDev->proto.isoDep.info.FSx;
+            isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
+            isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
+            isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
+            isoDepTxRx.txBufLen = tx_bytes;
+            isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
+            isoDepTxRx.rxLen = &gNfcDev.rxLen;
+            isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.isoDepBuf.apdu;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+
+            /*******************************************************************************/
+            /* Trigger a RFAL ISO-DEP Transceive                                           */
+            err = rfalIsoDepStartApduTransceive(isoDepTxRx);
+            break;
+        }
+#endif /* RFAL_FEATURE_ISO_DEP */
+
+#if RFAL_FEATURE_NFC_DEP
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_NFCDEP: {
+            rfalNfcDepPduTxRxParam nfcDepTxRx;
+
+            if(txDataLen > sizeof(gNfcDev.txBuf.nfcDepBuf.pdu)) {
+                return ERR_NOMEM;
+            }
+
+            if(txDataLen > 0U) {
+                ST_MEMCPY((uint8_t*)gNfcDev.txBuf.nfcDepBuf.pdu, txData, txDataLen);
+            }
+
+            nfcDepTxRx.DID = RFAL_NFCDEP_DID_KEEP;
+            nfcDepTxRx.FSx =
+                rfalNfcIsRemDevListener(gNfcDev.activeDev->type) ?
+                    rfalNfcDepLR2FS((uint8_t)rfalNfcDepPP2LR(
+                        gNfcDev.activeDev->proto.nfcDep.activation.Target.ATR_RES.PPt)) :
+                    rfalNfcDepLR2FS((uint8_t)rfalNfcDepPP2LR(
+                        gNfcDev.activeDev->proto.nfcDep.activation.Initiator.ATR_REQ.PPi));
+            nfcDepTxRx.dFWT = gNfcDev.activeDev->proto.nfcDep.info.dFWT;
+            nfcDepTxRx.FWT = gNfcDev.activeDev->proto.nfcDep.info.FWT;
+            nfcDepTxRx.txBuf = &gNfcDev.txBuf.nfcDepBuf;
+            nfcDepTxRx.txBufLen = txDataLen;
+            nfcDepTxRx.rxBuf = &gNfcDev.rxBuf.nfcDepBuf;
+            nfcDepTxRx.rxLen = &gNfcDev.rxLen;
+            nfcDepTxRx.tmpBuf = &gNfcDev.tmpBuf.nfcDepBuf;
+            *rxData = (uint8_t*)gNfcDev.rxBuf.nfcDepBuf.pdu;
+            *rvdLen = (uint16_t*)&gNfcDev.rxLen;
+
+            /*******************************************************************************/
+            /* Trigger a RFAL NFC-DEP Transceive                                           */
+            err = rfalNfcDepStartPduTransceive(nfcDepTxRx);
+            break;
+        }
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+        /*******************************************************************************/
+        default:
+            err = ERR_PARAM;
+            break;
+        }
+
+        /* If a transceive has successfuly started flag Data Exchange as ongoing */
+        if(err == ERR_NONE) {
+            gNfcDev.dataExErr = ERR_BUSY;
+            gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE;
+        }
+
+        return err;
+    }
+
+    return ERR_WRONG_STATE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDataExchangeGetStatus(void) {
+    /*******************************************************************************/
+    /* Check if it's the first frame received in Listen mode */
+    if(gNfcDev.state == RFAL_NFC_STATE_ACTIVATED) {
+        /* Continue data exchange as normal */
+        gNfcDev.dataExErr = ERR_BUSY;
+        gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE;
+
+        /* Check if we performing in T3T CE */
+        if((gNfcDev.activeDev->type == RFAL_NFC_POLL_TYPE_NFCF) &&
+           (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_RF)) {
+            /* The first frame has been retrieved by rfalListenMode, flag data immediately                  */
+            /* Can only call rfalGetTransceiveStatus() after starting a transceive with rfalStartTransceive */
+            gNfcDev.dataExErr = ERR_NONE;
+        }
+    }
+
+    /*******************************************************************************/
+    /* Check if we are in we have been placed to sleep, and return last error     */
+    if(gNfcDev.state == RFAL_NFC_STATE_LISTEN_SLEEP) {
+        return gNfcDev.dataExErr; /* ERR_SLEEP_REQ */
+    }
+
+    /*******************************************************************************/
+    /* Check if Data exchange has been started */
+    if((gNfcDev.state != RFAL_NFC_STATE_DATAEXCHANGE) &&
+       (gNfcDev.state != RFAL_NFC_STATE_DATAEXCHANGE_DONE)) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check if Data exchange is still ongoing */
+    if(gNfcDev.dataExErr == ERR_BUSY) {
+        switch(gNfcDev.activeDev->rfInterface) {
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_RF:
+            gNfcDev.dataExErr = rfalGetTransceiveStatus();
+            break;
+
+#if RFAL_FEATURE_ISO_DEP
+        /*******************************************************************************/
+        case RFAL_NFC_INTERFACE_ISODEP:
+            gNfcDev.dataExErr = rfalIsoDepGetApduTransceiveStatus();
+            break;
+#endif /* RFAL_FEATURE_ISO_DEP */
+
+            /*******************************************************************************/
+#if RFAL_FEATURE_NFC_DEP
+        case RFAL_NFC_INTERFACE_NFCDEP:
+            gNfcDev.dataExErr = rfalNfcDepGetPduTransceiveStatus();
+            break;
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+        /*******************************************************************************/
+        default:
+            gNfcDev.dataExErr = ERR_PARAM;
+            break;
+        }
+
+#if RFAL_FEATURE_LISTEN_MODE
+        /*******************************************************************************/
+        /* If a Sleep request has been received (Listen Mode) go to sleep immediately  */
+        if(gNfcDev.dataExErr == ERR_SLEEP_REQ) {
+            EXIT_ON_ERR(
+                gNfcDev.dataExErr,
+                rfalListenSleepStart(
+                    RFAL_LM_STATE_SLEEP_A,
+                    gNfcDev.rxBuf.rfBuf,
+                    sizeof(gNfcDev.rxBuf.rfBuf),
+                    &gNfcDev.rxLen));
+
+            /* If set Sleep was successful keep restore the Sleep request signal */
+            gNfcDev.dataExErr = ERR_SLEEP_REQ;
+        }
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+    }
+
+    return gNfcDev.dataExErr;
+}
+
+/*!
+ ******************************************************************************
+ * \brief Poller Technology Detection
+ * 
+ * This method implements the Technology Detection / Poll for different 
+ * device technologies.
+ * 
+ * \return  ERR_NONE         : Operation completed with no error
+ * \return  ERR_BUSY         : Operation ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * 
+ ******************************************************************************
+ */
+static ReturnCode rfalNfcPollTechDetetection(void) {
+    ReturnCode err;
+
+    err = ERR_NONE;
+
+    /* Suppress warning when specific RFAL features have been disabled */
+    NO_WARNING(err);
+
+    /*******************************************************************************/
+    /* AP2P Technology Detection                                                   */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_AP2P) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_AP2P) != 0U)) {
+#if RFAL_FEATURE_NFC_DEP
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(
+                err,
+                rfalSetMode(RFAL_MODE_POLL_ACTIVE_P2P, gNfcDev.disc.ap2pBR, gNfcDev.disc.ap2pBR));
+            rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+            rfalSetFDTListen(RFAL_FDT_LISTEN_AP2P_POLLER);
+            rfalSetFDTPoll(RFAL_TIMING_NONE);
+            rfalSetGT(RFAL_GT_AP2P_ADJUSTED);
+            EXIT_ON_ERR(err, rfalFieldOnAndStartGT()); /* Turns the Field On and starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_AP2P;
+
+            err = rfalNfcNfcDepActivate(
+                gNfcDev.devList, RFAL_NFCDEP_COMM_ACTIVE, NULL, 0); /* Poll for NFC-A devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_AP2P;
+
+                gNfcDev.devList->type = RFAL_NFC_LISTEN_TYPE_AP2P;
+                gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_NFCDEP;
+                gNfcDev.devCnt++;
+
+                return ERR_NONE;
+            }
+
+            gNfcDev.isTechInit = false;
+            rfalFieldOff();
+        }
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFC_DEP */
+    }
+
+    /*******************************************************************************/
+    /* Passive NFC-A Technology Detection                                          */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_A) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_A) != 0U)) {
+#if RFAL_FEATURE_NFCA
+
+        rfalNfcaSensRes sensRes;
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcaPollerInitialize()); /* Initialize RFAL for NFC-A */
+            EXIT_ON_ERR(err, rfalFieldOnAndStartGT()); /* Turns the Field On and starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            err = rfalNfcaPollerTechnologyDetection(
+                gNfcDev.disc.compMode, &sensRes); /* Poll for NFC-A devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_A;
+            }
+
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_A;
+        }
+
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFCA */
+    }
+
+    /*******************************************************************************/
+    /* Passive NFC-B Technology Detection                                          */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_B) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_B) != 0U)) {
+#if RFAL_FEATURE_NFCB
+
+        rfalNfcbSensbRes sensbRes;
+        uint8_t sensbResLen;
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcbPollerInitialize()); /* Initialize RFAL for NFC-B */
+            EXIT_ON_ERR(
+                err, rfalFieldOnAndStartGT()); /* As field is already On only starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            err = rfalNfcbPollerTechnologyDetection(
+                gNfcDev.disc.compMode, &sensbRes, &sensbResLen); /* Poll for NFC-B devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_B;
+            }
+
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_B;
+        }
+
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFCB */
+    }
+
+    /*******************************************************************************/
+    /* Passive NFC-F Technology Detection                                          */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_F) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_F) != 0U)) {
+#if RFAL_FEATURE_NFCF
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(
+                err,
+                rfalNfcfPollerInitialize(gNfcDev.disc.nfcfBR)); /* Initialize RFAL for NFC-F */
+            EXIT_ON_ERR(
+                err, rfalFieldOnAndStartGT()); /* As field is already On only starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            err = rfalNfcfPollerCheckPresence(); /* Poll for NFC-F devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_F;
+            }
+
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_F;
+        }
+
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFCF */
+    }
+
+    /*******************************************************************************/
+    /* Passive NFC-V Technology Detection                                          */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_V) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_V) != 0U)) {
+#if RFAL_FEATURE_NFCV
+
+        rfalNfcvInventoryRes invRes;
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcvPollerInitialize()); /* Initialize RFAL for NFC-V */
+            EXIT_ON_ERR(
+                err, rfalFieldOnAndStartGT()); /* As field is already On only starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            err = rfalNfcvPollerCheckPresence(&invRes); /* Poll for NFC-V devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_V;
+            }
+
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_V;
+        }
+
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFCV */
+    }
+
+    /*******************************************************************************/
+    /* Passive Proprietary Technology ST25TB                                       */
+    /*******************************************************************************/
+    if(((gNfcDev.disc.techs2Find & RFAL_NFC_POLL_TECH_ST25TB) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_ST25TB) != 0U)) {
+#if RFAL_FEATURE_ST25TB
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalSt25tbPollerInitialize()); /* Initialize RFAL for NFC-V */
+            EXIT_ON_ERR(
+                err, rfalFieldOnAndStartGT()); /* As field is already On only starts GT timer */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(rfalIsGTExpired()) /* Wait until Guard Time is fulfilled */
+        {
+            err = rfalSt25tbPollerCheckPresence(NULL); /* Poll for ST25TB devices */
+            if(err == ERR_NONE) {
+                gNfcDev.techsFound |= RFAL_NFC_POLL_TECH_ST25TB;
+            }
+
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_ST25TB;
+        }
+
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_ST25TB */
+    }
+
+    return ERR_NONE;
+}
+
+/*!
+ ******************************************************************************
+ * \brief Poller Collision Resolution
+ * 
+ * This method implements the Collision Resolution on all technologies that
+ * have been detected before.
+ * 
+ * \return  ERR_NONE         : Operation completed with no error
+ * \return  ERR_BUSY         : Operation ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * 
+ ******************************************************************************
+ */
+static ReturnCode rfalNfcPollCollResolution(void) {
+    uint8_t i;
+    static uint8_t devCnt;
+    ReturnCode err;
+
+    err = ERR_NONE;
+    i = 0;
+
+    /* Suppress warning when specific RFAL features have been disabled */
+    NO_WARNING(err);
+    NO_WARNING(devCnt);
+    NO_WARNING(i);
+
+    /* Check if device limit has been reached */
+    if(gNfcDev.devCnt >= gNfcDev.disc.devLimit) {
+        return ERR_NONE;
+    }
+
+    /*******************************************************************************/
+    /* NFC-A Collision Resolution                                                  */
+    /*******************************************************************************/
+#if RFAL_FEATURE_NFCA
+    if(((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_A) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_A) !=
+        0U)) /* If a NFC-A device was found/detected, perform Collision Resolution */
+    {
+        static rfalNfcaListenDevice nfcaDevList[RFAL_NFC_MAX_DEVICES];
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcaPollerInitialize()); /* Initialize RFAL for NFC-A */
+            EXIT_ON_ERR(err, rfalFieldOnAndStartGT()); /* Turns the Field On and starts GT timer */
+
+            gNfcDev.isTechInit = true; /* Technology has been initialized */
+            gNfcDev.isOperOngoing = false; /* No operation currently ongoing  */
+        }
+
+        if(!rfalIsGTExpired()) {
+            return ERR_BUSY;
+        }
+
+        if(!gNfcDev.isOperOngoing) {
+            EXIT_ON_ERR(
+                err,
+                rfalNfcaPollerStartFullCollisionResolution(
+                    gNfcDev.disc.compMode,
+                    (gNfcDev.disc.devLimit - gNfcDev.devCnt),
+                    nfcaDevList,
+                    &devCnt));
+
+            gNfcDev.isOperOngoing = true;
+            return ERR_BUSY;
+        }
+
+        err = rfalNfcaPollerGetFullCollisionResolutionStatus();
+        if(err != ERR_BUSY) {
+            gNfcDev.isTechInit = false;
+            gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_A;
+
+            if((err == ERR_NONE) && (devCnt != 0U)) {
+                for(i = 0; i < devCnt;
+                    i++) /* Copy devices found form local Nfca list into global device list */
+                {
+                    gNfcDev.devList[gNfcDev.devCnt].type = RFAL_NFC_LISTEN_TYPE_NFCA;
+                    gNfcDev.devList[gNfcDev.devCnt].dev.nfca = nfcaDevList[i];
+                    gNfcDev.devCnt++;
+                }
+            }
+        }
+
+        return ERR_BUSY;
+    }
+#endif /* RFAL_FEATURE_NFCA */
+
+    /*******************************************************************************/
+    /* NFC-B Collision Resolution                                                  */
+    /*******************************************************************************/
+#if RFAL_FEATURE_NFCB
+    if(((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_B) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_B) !=
+        0U)) /* If a NFC-B device was found/detected, perform Collision Resolution */
+    {
+        rfalNfcbListenDevice nfcbDevList[RFAL_NFC_MAX_DEVICES];
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcbPollerInitialize()); /* Initialize RFAL for NFC-B */
+            EXIT_ON_ERR(
+                err,
+                rfalFieldOnAndStartGT()); /* Ensure GT again as other technologies have also been polled */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(!rfalIsGTExpired()) {
+            return ERR_BUSY;
+        }
+
+        devCnt = 0;
+        gNfcDev.isTechInit = false;
+        gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_B;
+
+        err = rfalNfcbPollerCollisionResolution(
+            gNfcDev.disc.compMode, (gNfcDev.disc.devLimit - gNfcDev.devCnt), nfcbDevList, &devCnt);
+        if((err == ERR_NONE) && (devCnt != 0U)) {
+            for(i = 0; i < devCnt;
+                i++) /* Copy devices found form local Nfcb list into global device list */
+            {
+                gNfcDev.devList[gNfcDev.devCnt].type = RFAL_NFC_LISTEN_TYPE_NFCB;
+                gNfcDev.devList[gNfcDev.devCnt].dev.nfcb = nfcbDevList[i];
+                gNfcDev.devCnt++;
+            }
+        }
+
+        return ERR_BUSY;
+    }
+#endif /* RFAL_FEATURE_NFCB*/
+
+    /*******************************************************************************/
+    /* NFC-F Collision Resolution                                                  */
+    /*******************************************************************************/
+#if RFAL_FEATURE_NFCF
+    if(((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_F) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_F) !=
+        0U)) /* If a NFC-F device was found/detected, perform Collision Resolution */
+    {
+        rfalNfcfListenDevice nfcfDevList[RFAL_NFC_MAX_DEVICES];
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(
+                err,
+                rfalNfcfPollerInitialize(gNfcDev.disc.nfcfBR)); /* Initialize RFAL for NFC-F */
+            EXIT_ON_ERR(
+                err,
+                rfalFieldOnAndStartGT()); /* Ensure GT again as other technologies have also been polled */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(!rfalIsGTExpired()) {
+            return ERR_BUSY;
+        }
+
+        devCnt = 0;
+        gNfcDev.isTechInit = false;
+        gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_F;
+
+        err = rfalNfcfPollerCollisionResolution(
+            gNfcDev.disc.compMode, (gNfcDev.disc.devLimit - gNfcDev.devCnt), nfcfDevList, &devCnt);
+        if((err == ERR_NONE) && (devCnt != 0U)) {
+            for(i = 0; i < devCnt;
+                i++) /* Copy devices found form local Nfcf list into global device list */
+            {
+                gNfcDev.devList[gNfcDev.devCnt].type = RFAL_NFC_LISTEN_TYPE_NFCF;
+                gNfcDev.devList[gNfcDev.devCnt].dev.nfcf = nfcfDevList[i];
+                gNfcDev.devCnt++;
+            }
+        }
+
+        return ERR_BUSY;
+    }
+#endif /* RFAL_FEATURE_NFCF */
+
+    /*******************************************************************************/
+    /* NFC-V Collision Resolution                                                  */
+    /*******************************************************************************/
+#if RFAL_FEATURE_NFCV
+    if(((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_V) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_V) !=
+        0U)) /* If a NFC-V device was found/detected, perform Collision Resolution */
+    {
+        rfalNfcvListenDevice nfcvDevList[RFAL_NFC_MAX_DEVICES];
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalNfcvPollerInitialize()); /* Initialize RFAL for NFC-V */
+            EXIT_ON_ERR(
+                err,
+                rfalFieldOnAndStartGT()); /* Ensure GT again as other technologies have also been polled */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(!rfalIsGTExpired()) {
+            return ERR_BUSY;
+        }
+
+        devCnt = 0;
+        gNfcDev.isTechInit = false;
+        gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_V;
+
+        err = rfalNfcvPollerCollisionResolution(
+            RFAL_COMPLIANCE_MODE_NFC,
+            (gNfcDev.disc.devLimit - gNfcDev.devCnt),
+            nfcvDevList,
+            &devCnt);
+        if((err == ERR_NONE) && (devCnt != 0U)) {
+            for(i = 0; i < devCnt;
+                i++) /* Copy devices found form local Nfcf list into global device list */
+            {
+                gNfcDev.devList[gNfcDev.devCnt].type = RFAL_NFC_LISTEN_TYPE_NFCV;
+                gNfcDev.devList[gNfcDev.devCnt].dev.nfcv = nfcvDevList[i];
+                gNfcDev.devCnt++;
+            }
+        }
+
+        return ERR_BUSY;
+    }
+#endif /* RFAL_FEATURE_NFCV */
+
+    /*******************************************************************************/
+    /* ST25TB Collision Resolution                                                 */
+    /*******************************************************************************/
+#if RFAL_FEATURE_ST25TB
+    if(((gNfcDev.techsFound & RFAL_NFC_POLL_TECH_ST25TB) != 0U) &&
+       ((gNfcDev.techs2do & RFAL_NFC_POLL_TECH_ST25TB) !=
+        0U)) /* If a ST25TB device was found/detected, perform Collision Resolution */
+    {
+        rfalSt25tbListenDevice st25tbDevList[RFAL_NFC_MAX_DEVICES];
+
+        if(!gNfcDev.isTechInit) {
+            EXIT_ON_ERR(err, rfalSt25tbPollerInitialize()); /* Initialize RFAL for ST25TB */
+            EXIT_ON_ERR(
+                err,
+                rfalFieldOnAndStartGT()); /* Ensure GT again as other technologies have also been polled */
+            gNfcDev.isTechInit = true;
+        }
+
+        if(!rfalIsGTExpired()) {
+            return ERR_BUSY;
+        }
+
+        devCnt = 0;
+        gNfcDev.isTechInit = false;
+        gNfcDev.techs2do &= ~RFAL_NFC_POLL_TECH_ST25TB;
+
+        err = rfalSt25tbPollerCollisionResolution(
+            (gNfcDev.disc.devLimit - gNfcDev.devCnt), st25tbDevList, &devCnt);
+        if((err == ERR_NONE) && (devCnt != 0U)) {
+            for(i = 0; i < devCnt;
+                i++) /* Copy devices found form local Nfcf list into global device list */
+            {
+                gNfcDev.devList[gNfcDev.devCnt].type = RFAL_NFC_LISTEN_TYPE_ST25TB;
+                gNfcDev.devList[gNfcDev.devCnt].dev.st25tb = st25tbDevList[i];
+                gNfcDev.devCnt++;
+            }
+        }
+
+        return ERR_BUSY;
+    }
+#endif /* RFAL_FEATURE_ST25TB */
+
+    return ERR_NONE; /* All technologies have been performed */
+}
+
+/*!
+ ******************************************************************************
+ * \brief Poller Activation
+ * 
+ * This method Activates a given device according to it's type and 
+ * protocols supported
+ *  
+ * \param[in]  devIt : device's position on the list to be activated 
+ * 
+ * \return  ERR_NONE         : Operation completed with no error
+ * \return  ERR_BUSY         : Operation ongoing
+ * \return  ERR_XXXX         : Error occurred
+ * 
+ ******************************************************************************
+ */
+static ReturnCode rfalNfcPollActivation(uint8_t devIt) {
+    ReturnCode err;
+
+    err = ERR_NONE;
+
+    /* Suppress warning when specific RFAL features have been disabled */
+    NO_WARNING(err);
+
+    if(devIt > gNfcDev.devCnt) {
+        return ERR_WRONG_STATE;
+    }
+
+    switch(gNfcDev.devList[devIt].type) {
+        /*******************************************************************************/
+        /* AP2P Activation                                                             */
+        /*******************************************************************************/
+#if RFAL_FEATURE_NFC_DEP
+    case RFAL_NFC_LISTEN_TYPE_AP2P:
+        /* Activation has already been performed (ATR_REQ) */
+
+        gNfcDev.devList[devIt].nfcid =
+            gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3;
+        gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+        break;
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+        /*******************************************************************************/
+        /* Passive NFC-A Activation                                                    */
+        /*******************************************************************************/
+#if RFAL_FEATURE_NFCA
+    case RFAL_NFC_LISTEN_TYPE_NFCA:
+
+        if(!gNfcDev.isTechInit) {
+            rfalNfcaPollerInitialize();
+            gNfcDev.isTechInit = true;
+            gNfcDev.isOperOngoing = false;
+            return ERR_BUSY;
+        }
+
+        if(gNfcDev.devList[devIt].dev.nfca.isSleep) /* Check if desired device is in Sleep */
+        {
+            rfalNfcaSensRes sensRes;
+            rfalNfcaSelRes selRes;
+
+            if(!gNfcDev.isOperOngoing) {
+                /* Wake up all cards  */
+                EXIT_ON_ERR(
+                    err, rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes));
+                gNfcDev.isOperOngoing = true;
+            } else {
+                /* Select specific device */
+                EXIT_ON_ERR(
+                    err,
+                    rfalNfcaPollerSelect(
+                        gNfcDev.devList[devIt].dev.nfca.nfcId1,
+                        gNfcDev.devList[devIt].dev.nfca.nfcId1Len,
+                        &selRes));
+                gNfcDev.devList[devIt].dev.nfca.isSleep = false;
+                gNfcDev.isOperOngoing = false;
+            }
+            return ERR_BUSY;
+        }
+
+        /* Set NFCID */
+        gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfca.nfcId1;
+        gNfcDev.devList[devIt].nfcidLen = gNfcDev.devList[devIt].dev.nfca.nfcId1Len;
+
+        /*******************************************************************************/
+        /* Perform protocol specific activation                                        */
+        switch(gNfcDev.devList[devIt].dev.nfca.type) {
+        /*******************************************************************************/
+        case RFAL_NFCA_T1T:
+
+            /* No further activation needed for T1T (RID already performed) */
+
+            gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfca.ridRes.uid;
+            gNfcDev.devList[devIt].nfcidLen = RFAL_T1T_UID_LEN;
+
+            gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF;
+            break;
+
+        case RFAL_NFCA_T2T:
+
+            /* No further activation needed for a T2T */
+
+            gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF;
+            break;
+
+        /*******************************************************************************/
+        case RFAL_NFCA_T4T: /* Device supports ISO-DEP */
+
+#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL
+            if(!gNfcDev.isOperOngoing) {
+                /* Perform ISO-DEP (ISO14443-4) activation: RATS and PPS if supported */
+                rfalIsoDepInitialize();
+                EXIT_ON_ERR(
+                    err,
+                    rfalIsoDepPollAStartActivation(
+                        (rfalIsoDepFSxI)RFAL_ISODEP_FSDI_DEFAULT,
+                        RFAL_ISODEP_NO_DID,
+                        gNfcDev.disc.maxBR,
+                        &gNfcDev.devList[devIt].proto.isoDep));
+
+                gNfcDev.isOperOngoing = true;
+                return ERR_BUSY;
+            }
+
+            err = rfalIsoDepPollAGetActivationStatus();
+            if(err != ERR_NONE) {
+                return err;
+            }
+
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_ISODEP; /* NFC-A T4T device activated */
+#else
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_RF; /* No ISO-DEP supported activate using RF interface */
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+            break;
+
+        /*******************************************************************************/
+        case RFAL_NFCA_T4T_NFCDEP: /* Device supports both T4T and NFC-DEP */
+        case RFAL_NFCA_NFCDEP: /* Device supports NFC-DEP */
+
+#if RFAL_FEATURE_NFC_DEP
+            /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */
+            EXIT_ON_ERR(
+                err,
+                rfalNfcNfcDepActivate(&gNfcDev.devList[devIt], RFAL_NFCDEP_COMM_PASSIVE, NULL, 0));
+
+            gNfcDev.devList[devIt].nfcid =
+                gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3;
+            gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_NFCDEP; /* NFC-A P2P device activated */
+#else
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_RF; /* No NFC-DEP supported activate using RF interface */
+#endif /* RFAL_FEATURE_NFC_DEP */
+            break;
+
+        /*******************************************************************************/
+        default:
+            return ERR_WRONG_STATE;
+        }
+        break;
+#endif /* RFAL_FEATURE_NFCA */
+
+        /*******************************************************************************/
+        /* Passive NFC-B Activation                                                    */
+        /*******************************************************************************/
+#if RFAL_FEATURE_NFCB
+    case RFAL_NFC_LISTEN_TYPE_NFCB:
+
+        if(!gNfcDev.isTechInit) {
+            rfalNfcbPollerInitialize();
+            gNfcDev.isTechInit = true;
+            gNfcDev.isOperOngoing = false;
+            return ERR_BUSY;
+        }
+
+        if(gNfcDev.devList[devIt].dev.nfcb.isSleep) /* Check if desired device is in Sleep */
+        {
+            rfalNfcbSensbRes sensbRes;
+            uint8_t sensbResLen;
+
+            /* Wake up all cards. SENSB_RES may return collision but the NFCID0 is available to explicitly select NFC-B card via ATTRIB; so error will be ignored here */
+            rfalNfcbPollerCheckPresence(
+                RFAL_NFCB_SENS_CMD_ALLB_REQ, RFAL_NFCB_SLOT_NUM_1, &sensbRes, &sensbResLen);
+        }
+
+        /* Set NFCID */
+        gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcb.sensbRes.nfcid0;
+        gNfcDev.devList[devIt].nfcidLen = RFAL_NFCB_NFCID0_LEN;
+
+#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL
+        /* Check if device supports  ISO-DEP (ISO14443-4) */
+        if((gNfcDev.devList[devIt].dev.nfcb.sensbRes.protInfo.FsciProType &
+            RFAL_NFCB_SENSB_RES_PROTO_ISO_MASK) != 0U) {
+            if(!gNfcDev.isOperOngoing) {
+                rfalIsoDepInitialize();
+                /* Perform ISO-DEP (ISO14443-4) activation: ATTRIB    */
+                EXIT_ON_ERR(
+                    err,
+                    rfalIsoDepPollBStartActivation(
+                        (rfalIsoDepFSxI)RFAL_ISODEP_FSDI_DEFAULT,
+                        RFAL_ISODEP_NO_DID,
+                        gNfcDev.disc.maxBR,
+                        0x00,
+                        &gNfcDev.devList[devIt].dev.nfcb,
+                        NULL,
+                        0,
+                        &gNfcDev.devList[devIt].proto.isoDep));
+
+                gNfcDev.isOperOngoing = true;
+                return ERR_BUSY;
+            }
+
+            err = rfalIsoDepPollBGetActivationStatus();
+            if(err != ERR_NONE) {
+                return err;
+            }
+
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_ISODEP; /* NFC-B T4T device activated */
+            break;
+        }
+
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+
+        gNfcDev.devList[devIt].rfInterface =
+            RFAL_NFC_INTERFACE_RF; /* NFC-B device activated     */
+        break;
+
+#endif /* RFAL_FEATURE_NFCB */
+
+        /*******************************************************************************/
+        /* Passive NFC-F Activation                                                    */
+        /*******************************************************************************/
+#if RFAL_FEATURE_NFCF
+    case RFAL_NFC_LISTEN_TYPE_NFCF:
+
+        rfalNfcfPollerInitialize(gNfcDev.disc.nfcfBR);
+
+#if RFAL_FEATURE_NFC_DEP
+        if(rfalNfcfIsNfcDepSupported(&gNfcDev.devList[devIt].dev.nfcf)) {
+            /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */
+            EXIT_ON_ERR(
+                err,
+                rfalNfcNfcDepActivate(&gNfcDev.devList[devIt], RFAL_NFCDEP_COMM_PASSIVE, NULL, 0));
+
+            /* Set NFCID */
+            gNfcDev.devList[devIt].nfcid =
+                gNfcDev.devList[devIt].proto.nfcDep.activation.Target.ATR_RES.NFCID3;
+            gNfcDev.devList[devIt].nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+
+            gNfcDev.devList[devIt].rfInterface =
+                RFAL_NFC_INTERFACE_NFCDEP; /* NFC-F P2P device activated */
+            break;
+        }
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+        /* Set NFCID */
+        gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcf.sensfRes.NFCID2;
+        gNfcDev.devList[devIt].nfcidLen = RFAL_NFCF_NFCID2_LEN;
+
+        gNfcDev.devList[devIt].rfInterface =
+            RFAL_NFC_INTERFACE_RF; /* NFC-F T3T device activated */
+        break;
+#endif /* RFAL_FEATURE_NFCF */
+
+        /*******************************************************************************/
+        /* Passive NFC-V Activation                                                    */
+        /*******************************************************************************/
+#if RFAL_FEATURE_NFCV
+    case RFAL_NFC_LISTEN_TYPE_NFCV:
+
+        rfalNfcvPollerInitialize();
+
+        /* No specific activation needed for a T5T */
+
+        /* Set NFCID */
+        gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.nfcv.InvRes.UID;
+        gNfcDev.devList[devIt].nfcidLen = RFAL_NFCV_UID_LEN;
+
+        gNfcDev.devList[devIt].rfInterface =
+            RFAL_NFC_INTERFACE_RF; /* NFC-V T5T device activated */
+        break;
+#endif /* RFAL_FEATURE_NFCV */
+
+        /*******************************************************************************/
+        /* Passive ST25TB Activation                                                   */
+        /*******************************************************************************/
+#if RFAL_FEATURE_ST25TB
+    case RFAL_NFC_LISTEN_TYPE_ST25TB:
+
+        rfalSt25tbPollerInitialize();
+
+        /* No specific activation needed for a ST25TB */
+
+        /* Set NFCID */
+        gNfcDev.devList[devIt].nfcid = gNfcDev.devList[devIt].dev.st25tb.UID;
+        gNfcDev.devList[devIt].nfcidLen = RFAL_ST25TB_UID_LEN;
+
+        gNfcDev.devList[devIt].rfInterface = RFAL_NFC_INTERFACE_RF; /* ST25TB device activated */
+        break;
+#endif /* RFAL_FEATURE_ST25TB */
+
+    /*******************************************************************************/
+    default:
+        return ERR_WRONG_STATE;
+    }
+
+    gNfcDev.activeDev = &gNfcDev.devList[devIt]; /* Assign active device to be used further on */
+    return ERR_NONE;
+}
+
+/*!
+ ******************************************************************************
+ * \brief Listener Activation
+ * 
+ * This method handles the listen mode Activation according to the different 
+ * protocols the Reader/Initiator performs
+ * 
+ * \return  ERR_NONE   : Operation completed with no error
+ * \return  ERR_BUSY   : Operation ongoing
+ * \return  ERR_PROTO  : Unexpected frame received
+ * \return  ERR_XXXX   : Error occurred
+ * 
+ ******************************************************************************
+ */
+#if RFAL_FEATURE_LISTEN_MODE
+static ReturnCode rfalNfcListenActivation(void) {
+    bool isDataRcvd;
+    ReturnCode ret;
+    rfalLmState lmSt;
+    rfalBitRate bitRate;
+#if RFAL_FEATURE_NFC_DEP
+    uint8_t hdrLen;
+
+    /* Set the header length in NFC-A */
+    hdrLen = (RFAL_NFCDEP_SB_LEN + RFAL_NFCDEP_LEN_LEN);
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+    lmSt = rfalListenGetState(&isDataRcvd, &bitRate);
+
+    switch(lmSt) {
+#if RFAL_FEATURE_NFCA
+    /*******************************************************************************/
+    case RFAL_LM_STATE_ACTIVE_A: /* NFC-A CE activation */
+    case RFAL_LM_STATE_ACTIVE_Ax:
+
+        if(isDataRcvd) /* Check if Reader/Initator has sent some data */
+        {
+            /* Check if received data is a Sleep request */
+            if(rfalNfcaListenerIsSleepReq(
+                   gNfcDev.rxBuf.rfBuf,
+                   rfalConvBitsToBytes(gNfcDev.rxLen))) /* Check if received data is a SLP_REQ */
+            {
+                /* Set the Listen Mode in Sleep state */
+                EXIT_ON_ERR(
+                    ret,
+                    rfalListenSleepStart(
+                        RFAL_LM_STATE_SLEEP_A,
+                        gNfcDev.rxBuf.rfBuf,
+                        sizeof(gNfcDev.rxBuf.rfBuf),
+                        &gNfcDev.rxLen));
+            }
+
+            else if(gNfcDev.disc.activate_after_sak) {
+                gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA;
+                rfalListenSetState(RFAL_LM_STATE_ACTIVE_A);
+                return ERR_NONE;
+            }
+#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN
+            /* Check if received data is a valid RATS */
+            else if(rfalIsoDepIsRats(
+                        gNfcDev.rxBuf.rfBuf, (uint8_t)rfalConvBitsToBytes(gNfcDev.rxLen))) {
+                rfalIsoDepAtsParam atsParam;
+                rfalIsoDepListenActvParam rxParam;
+
+                /* Set ATS parameters */
+                atsParam.fsci = (uint8_t)RFAL_ISODEP_DEFAULT_FSCI;
+                atsParam.fwi = RFAL_ISODEP_DEFAULT_FWI;
+                atsParam.sfgi = RFAL_ISODEP_DEFAULT_SFGI;
+                atsParam.didSupport = false;
+                atsParam.ta = RFAL_ISODEP_ATS_TA_SAME_D;
+                atsParam.hb = NULL;
+                atsParam.hbLen = 0;
+
+                /* Set Rx parameters */
+                rxParam.rxBuf =
+                    (rfalIsoDepBufFormat*)&gNfcDev.rxBuf
+                        .isoDepBuf; /*  PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */
+                rxParam.rxLen = &gNfcDev.rxLen;
+                rxParam.isoDepDev = &gNfcDev.devList->proto.isoDep;
+                rxParam.isRxChaining = &gNfcDev.isRxChaining;
+
+                rfalListenSetState(RFAL_LM_STATE_CARDEMU_4A); /* Set next state CE T4T */
+                rfalIsoDepInitialize(); /* Initialize ISO-DEP layer to handle ISO14443-a activation / RATS */
+
+                /* Set ISO-DEP layer to digest RATS and handle activation */
+                EXIT_ON_ERR(
+                    ret,
+                    rfalIsoDepListenStartActivation(
+                        &atsParam, NULL, gNfcDev.rxBuf.rfBuf, gNfcDev.rxLen, rxParam));
+            }
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+
+#if RFAL_FEATURE_NFC_DEP
+
+            /* Check if received data is a valid ATR_REQ */
+            else if(rfalNfcDepIsAtrReq(
+                        &gNfcDev.rxBuf.rfBuf[hdrLen],
+                        (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen),
+                        gNfcDev.devList->nfcid)) {
+                gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA;
+                EXIT_ON_ERR(
+                    ret,
+                    rfalNfcNfcDepActivate(
+                        gNfcDev.devList,
+                        RFAL_NFCDEP_COMM_PASSIVE,
+                        &gNfcDev.rxBuf.rfBuf[hdrLen],
+                        (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen)));
+            }
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+            else {
+                return ERR_PROTO;
+            }
+        }
+        return ERR_BUSY;
+
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_LISTEN
+    /*******************************************************************************/
+    case RFAL_LM_STATE_CARDEMU_4A: /* T4T ISO-DEP activation */
+
+        ret = rfalIsoDepListenGetActivationStatus();
+        if(ret == ERR_NONE) {
+            gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCA;
+            gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_ISODEP;
+            gNfcDev.devList->nfcid = NULL;
+            gNfcDev.devList->nfcidLen = 0;
+        }
+        return ret;
+#endif /* RFAL_FEATURE_ISO_DEP_LISTEN */
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_READY_F: /* NFC-F CE activation */
+
+        if(isDataRcvd) /* Wait for the first received data */
+        {
+#if RFAL_FEATURE_NFC_DEP
+            /* Set the header length in NFC-F */
+            hdrLen = RFAL_NFCDEP_LEN_LEN;
+
+            if(rfalNfcDepIsAtrReq(
+                   &gNfcDev.rxBuf.rfBuf[hdrLen],
+                   (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen),
+                   gNfcDev.devList->nfcid)) {
+                gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCF;
+                EXIT_ON_ERR(
+                    ret,
+                    rfalNfcNfcDepActivate(
+                        gNfcDev.devList,
+                        RFAL_NFCDEP_COMM_PASSIVE,
+                        &gNfcDev.rxBuf.rfBuf[hdrLen],
+                        (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen)));
+            } else
+#endif /* RFAL_FEATURE_NFC_DEP */
+            {
+                rfalListenSetState(
+                    RFAL_LM_STATE_CARDEMU_3); /* First data already received - set T3T CE */
+            }
+        }
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_CARDEMU_3: /* T3T activated */
+
+        gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_NFCF;
+        gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_RF;
+        gNfcDev.devList->nfcid = NULL;
+        gNfcDev.devList->nfcidLen = 0;
+
+        return ERR_NONE;
+
+#if RFAL_FEATURE_NFC_DEP
+    /*******************************************************************************/
+    case RFAL_LM_STATE_TARGET_A: /* NFC-DEP activation */
+    case RFAL_LM_STATE_TARGET_F:
+
+        ret = rfalNfcDepListenGetActivationStatus();
+        if(ret == ERR_NONE) {
+            gNfcDev.devList->rfInterface = RFAL_NFC_INTERFACE_NFCDEP;
+            gNfcDev.devList->nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+        }
+        return ret;
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_IDLE: /* AP2P activation */
+        if(isDataRcvd) /* Check if Reader/Initator has sent some data */
+        {
+            if((gNfcDev.lmMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U) /* Check if AP2P is enabled */
+            {
+#if RFAL_FEATURE_NFC_DEP
+                /* Calculate the header length in NFC-A or NFC-F mode*/
+                hdrLen =
+                    ((bitRate == RFAL_BR_106) ? (RFAL_NFCDEP_SB_LEN + RFAL_NFCDEP_LEN_LEN) :
+                                                RFAL_NFCDEP_LEN_LEN);
+
+                if(rfalNfcDepIsAtrReq(
+                       &gNfcDev.rxBuf.rfBuf[hdrLen],
+                       (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen),
+                       NULL)) {
+                    gNfcDev.devList->type = RFAL_NFC_POLL_TYPE_AP2P;
+                    rfalSetMode((RFAL_MODE_LISTEN_ACTIVE_P2P), bitRate, bitRate);
+                    EXIT_ON_ERR(
+                        ret,
+                        rfalNfcNfcDepActivate(
+                            gNfcDev.devList,
+                            RFAL_NFCDEP_COMM_ACTIVE,
+                            &gNfcDev.rxBuf.rfBuf[hdrLen],
+                            (rfalConvBitsToBytes(gNfcDev.rxLen) - hdrLen)));
+                } else
+#endif /* RFAL_FEATURE_NFC_DEP */
+                {
+                    return ERR_PROTO;
+                }
+            }
+        }
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_READY_A:
+    case RFAL_LM_STATE_READY_Ax:
+    case RFAL_LM_STATE_SLEEP_A:
+    case RFAL_LM_STATE_SLEEP_AF:
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_POWER_OFF:
+        return ERR_LINK_LOSS;
+
+    default: /* Wait for activation */
+        break;
+    }
+
+    return ERR_INTERNAL;
+}
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+/*!
+ ******************************************************************************
+ * \brief Poller NFC DEP Activate
+ * 
+ * This method performs NFC-DEP Activation 
+ *  
+ * \param[in]  device    : device info
+ * \param[in]  commMode  : communication mode (Passive/Active)
+ * \param[in]  atrReq    : received ATR_REQ
+ * \param[in]  atrReqLen : received ATR_REQ size
+ * 
+ * \return  ERR_NONE     : Operation completed with no error
+ * \return  ERR_BUSY     : Operation ongoing
+ * \return  ERR_XXXX     : Error occurred
+ * 
+ ******************************************************************************
+ */
+#if RFAL_FEATURE_NFC_DEP
+static ReturnCode rfalNfcNfcDepActivate(
+    rfalNfcDevice* device,
+    rfalNfcDepCommMode commMode,
+    const uint8_t* atrReq,
+    uint16_t atrReqLen) {
+    rfalNfcDepAtrParam initParam;
+
+    /* Suppress warnings if Listen mode is disabled */
+    NO_WARNING(atrReq);
+    NO_WARNING(atrReqLen);
+
+    /* If we are in Poll mode */
+    if(rfalNfcIsRemDevListener(device->type)) {
+        /*******************************************************************************/
+        /* If Passive F use the NFCID2 retrieved from SENSF                            */
+        if(device->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
+            initParam.nfcid = device->dev.nfcf.sensfRes.NFCID2;
+            initParam.nfcidLen = RFAL_NFCF_NFCID2_LEN;
+        } else {
+            initParam.nfcid = gNfcDev.disc.nfcid3;
+            initParam.nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+        }
+
+        initParam.BS = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+        initParam.BR = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+        initParam.DID = RFAL_NFCDEP_DID_NO;
+        initParam.NAD = RFAL_NFCDEP_NAD_NO;
+        initParam.LR = RFAL_NFCDEP_LR_254;
+        initParam.GB = gNfcDev.disc.GB;
+        initParam.GBLen = gNfcDev.disc.GBLen;
+        initParam.commMode = commMode;
+        initParam.operParam =
+            (RFAL_NFCDEP_OPER_FULL_MI_EN | RFAL_NFCDEP_OPER_EMPTY_DEP_DIS |
+             RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN);
+
+        rfalNfcDepInitialize();
+        /* Perform NFC-DEP (P2P) activation: ATR and PSL if supported */
+        return rfalNfcDepInitiatorHandleActivation(
+            &initParam, gNfcDev.disc.maxBR, &device->proto.nfcDep);
+    }
+    /* If we are in Listen mode */
+#if RFAL_FEATURE_LISTEN_MODE
+    else if(rfalNfcIsRemDevPoller(device->type)) {
+        rfalNfcDepListenActvParam actvParams;
+        rfalNfcDepTargetParam targetParam;
+
+        ST_MEMCPY(targetParam.nfcid3, (uint8_t*)gNfcDev.disc.nfcid3, RFAL_NFCDEP_NFCID3_LEN);
+        targetParam.bst = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+        targetParam.brt = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+        targetParam.to = RFAL_NFCDEP_WT_TRG_MAX_L13; /* [LLCP] 1.3 6.2.1 */
+        targetParam.ppt = rfalNfcDepLR2PP(RFAL_NFCDEP_LR_254);
+        if(gNfcDev.disc.GBLen >= RFAL_NFCDEP_GB_MAX_LEN) {
+            return ERR_PARAM;
+        }
+        targetParam.GBtLen = gNfcDev.disc.GBLen;
+        if(gNfcDev.disc.GBLen > 0U) {
+            ST_MEMCPY(targetParam.GBt, gNfcDev.disc.GB, gNfcDev.disc.GBLen);
+        }
+        targetParam.operParam =
+            (RFAL_NFCDEP_OPER_FULL_MI_EN | RFAL_NFCDEP_OPER_EMPTY_DEP_DIS |
+             RFAL_NFCDEP_OPER_ATN_EN | RFAL_NFCDEP_OPER_RTOX_REQ_EN);
+        targetParam.commMode = commMode;
+
+        /* Set activation buffer (including header) for NFC-DEP */
+        actvParams.rxBuf =
+            (rfalNfcDepBufFormat*)&gNfcDev.rxBuf
+                .nfcDepBuf; /*  PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */
+        actvParams.rxLen = &gNfcDev.rxLen;
+        actvParams.isRxChaining = &gNfcDev.isRxChaining;
+        actvParams.nfcDepDev = &gNfcDev.devList->proto.nfcDep;
+
+        rfalListenSetState(
+            ((device->type == RFAL_NFC_POLL_TYPE_NFCA) ? RFAL_LM_STATE_TARGET_A :
+                                                         RFAL_LM_STATE_TARGET_F));
+
+        rfalNfcDepInitialize();
+        /* Perform NFC-DEP (P2P) activation: send ATR_RES and handle activation */
+        return rfalNfcDepListenStartActivation(&targetParam, atrReq, atrReqLen, actvParams);
+    }
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+    else {
+        return ERR_INTERNAL;
+    }
+}
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+/*!
+ ******************************************************************************
+ * \brief Poller NFC Deactivate
+ * 
+ * This method Deactivates the device if a deactivation procedure exists 
+ * 
+ * \return  ERR_NONE  : Operation completed with no error
+ * \return  ERR_BUSY  : Operation ongoing
+ * \return  ERR_XXXX  : Error occurred
+ * 
+ ******************************************************************************
+ */
+static ReturnCode rfalNfcDeactivation(void) {
+    /* Check if a device has been activated */
+    if(gNfcDev.activeDev != NULL) {
+        if(rfalNfcIsRemDevListener(
+               gNfcDev.activeDev->type)) /* Listen mode no additional deactivation to be performed*/
+        {
+#ifndef RFAL_NFC_SKIP_DEACT
+            switch(gNfcDev.activeDev->rfInterface) {
+            /*******************************************************************************/
+            case RFAL_NFC_INTERFACE_RF:
+                break; /* No specific deactivation to be performed */
+
+                /*******************************************************************************/
+#if RFAL_FEATURE_ISO_DEP && RFAL_FEATURE_ISO_DEP_POLL
+            case RFAL_NFC_INTERFACE_ISODEP:
+                rfalIsoDepDeselect(); /* Send a Deselect to device */
+                break;
+#endif /* RFAL_FEATURE_ISO_DEP_POLL */
+
+                /*******************************************************************************/
+#if RFAL_FEATURE_NFC_DEP
+            case RFAL_NFC_INTERFACE_NFCDEP:
+                switch(gNfcDev.activeDev->type) {
+                case RFAL_NFC_LISTEN_TYPE_AP2P:
+                    rfalNfcDepRLS(); /* Send a Release to device */
+                    break;
+                default:
+                    rfalNfcDepDSL(); /* Send a Deselect to device */
+                    break;
+                }
+                break;
+#endif /* RFAL_FEATURE_NFC_DEP */
+
+            default:
+                return ERR_REQUEST;
+            }
+#endif /* RFAL_NFC_SKIP_DEACT */
+        }
+    }
+
+#if RFAL_FEATURE_WAKEUP_MODE
+    rfalWakeUpModeStop();
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+#if RFAL_FEATURE_LISTEN_MODE
+    rfalListenStop();
+#else
+    rfalFieldOff();
+#endif
+
+    gNfcDev.activeDev = NULL;
+    return ERR_NONE;
+}

+ 2741 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcDep.c

@@ -0,0 +1,2741 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   NFCC firmware
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcDep.c
+ *
+ *  \author  Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-DEP protocol
+ *  
+ *  NFC-DEP is also known as NFCIP - Near Field Communication 
+ *  Interface and Protocol
+ *  
+ *  This implementation was based on the following specs:
+ *    - NFC Forum Digital 1.1
+ *    - ECMA 340 3rd Edition 2013
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfcDep.h"
+#include "../include/rfal_nfcf.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#if RFAL_FEATURE_NFC_DEP
+
+/* Check for valid Block/Payload length  Digital 2.0 Table 90*/
+#if((RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 64) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 128) && \
+    (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 192) && (RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN != 254))
+#error \
+    " RFAL: Invalid NFC-DEP Block Max length. Please change RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN. "
+#endif
+
+/* Check for valid PDU length */
+#if((RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN < RFAL_FEATURE_NFC_DEP_BLOCK_MAX_LEN))
+#error " RFAL: Invalid NFC-DEP PDU Max length. Please change RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN. "
+#endif
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+#define NFCIP_ATR_RETRY_MAX 2U /*!< Max consecutive retrys of an ATR REQ with transm error*/
+
+#define NFCIP_PSLPAY_LEN (2U) /*!< PSL Payload length (BRS + FSL)                        */
+#define NFCIP_PSLREQ_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL REQ length (incl LEN)                             */
+#define NFCIP_PSLRES_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< PSL RES length (incl LEN)                             */
+
+#define NFCIP_ATRREQ_BUF_LEN \
+    (RFAL_NFCDEP_ATRREQ_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR REQ max length (incl LEN)     */
+#define NFCIP_ATRRES_BUF_LEN \
+    (RFAL_NFCDEP_ATRRES_MAX_LEN + RFAL_NFCDEP_LEN_LEN) /*!< ATR RES max length (incl LEN)     */
+
+#define NFCIP_RLSREQ_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< RLS REQ length (incl LEN)                             */
+#define NFCIP_RLSRES_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< RSL RES length (incl LEN)                             */
+#define NFCIP_RLSRES_MIN \
+    (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN)               */
+
+#define NFCIP_DSLREQ_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL REQ length (incl LEN)                             */
+#define NFCIP_DSLRES_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< DSL RES length (incl LEN)                             */
+#define NFCIP_DSLRES_MIN \
+    (2U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a DSL RES (incl LEN)               */
+
+#define NFCIP_DSLRES_MAX_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< Maximum length for a DSL RES (incl LEN)               */
+#define NFCIP_RLSRES_MAX_LEN \
+    (3U + RFAL_NFCDEP_LEN_LEN) /*!< Minimum length for a RLS RES (incl LEN)               */
+#define NFCIP_TARGET_RES_MAX \
+    (MAX(NFCIP_RLSRES_MAX_LEN, NFCIP_DSLRES_MAX_LEN)) /*!< Max target control res length    */
+
+#define NFCIP_NO_FWT RFAL_FWT_NONE /*!< No FWT value - Target Mode                            */
+#define NFCIP_INIT_MIN_RTOX 1U /*!< Minimum RTOX value  Digital 1.0  14.8.4.1             */
+#define NFCIP_INIT_MAX_RTOX 59U /*!< Maximum RTOX value  Digital 1.0  14.8.4.1             */
+
+#define NFCIP_TARG_MIN_RTOX 1U /*!< Minimum target RTOX value  Digital 1.0  14.8.4.1      */
+#define NFCIP_TARG_MAX_RTOX 59U /*!< Maximum target RTOX value  Digital 1.0  14.8.4.1      */
+
+#define NFCIP_TRECOV 1280U /*!< Digital 1.0  A.10  Trecov                             */
+
+#define NFCIP_TIMEOUT_ADJUSTMENT \
+    3072U /*!< Timeout Adjustment to compensate timing from end of Tx to end of frame  */
+#define NFCIP_RWT_ACTIVATION \
+    (0x1000001U +            \
+     NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2  B.11  RWT ACTIVATION  2^24 + RWT Delta + Adjustment*/
+#define NFCIP_RWT_ACM_ACTIVATION \
+    (0x200001U +                 \
+     NFCIP_TIMEOUT_ADJUSTMENT) /*!< Digital 2.2  B.11  RWT ACTIVATION  2^21 + RWT Delta + Adjustment*/
+
+#define RFAL_NFCDEP_HEADER_PAD       \
+    (RFAL_NFCDEP_DEPREQ_HEADER_LEN - \
+     RFAL_NFCDEP_LEN_MIN) /*!< Difference between expected rcvd header len and max foreseen */
+
+#ifndef RFAL_NFCDEP_MAX_TX_RETRYS
+#define RFAL_NFCDEP_MAX_TX_RETRYS \
+    (uint8_t)3U /*!< Number of retransmit retyrs                           */
+#endif /* RFAL_NFCDEP_MAX_TX_RETRYS */
+
+#ifndef RFAL_NFCDEP_TO_RETRYS
+#define RFAL_NFCDEP_TO_RETRYS \
+    (uint8_t)3U /*!< Number of retrys for Timeout                          */
+#endif /* RFAL_NFCDEP_TO_RETRYS */
+
+#ifndef RFAL_NFCDEP_MAX_RTOX_RETRYS
+#define RFAL_NFCDEP_MAX_RTOX_RETRYS \
+    (uint8_t)10U /*!< Number of retrys for RTOX    Digital 2.0 17.12.4.3    */
+#endif /* RFAL_NFCDEP_MAX_RTOX_RETRYS */
+
+#ifndef RFAL_NFCDEP_MAX_NACK_RETRYS
+#define RFAL_NFCDEP_MAX_NACK_RETRYS \
+    (uint8_t)3U /*!< Number of retrys for NACK                             */
+#endif /* RFAL_NFCDEP_MAX_NACK_RETRYS */
+
+#ifndef RFAL_NFCDEP_MAX_ATN_RETRYS
+#define RFAL_NFCDEP_MAX_ATN_RETRYS \
+    (uint8_t)3U /*!< Number of retrys for ATN                              */
+#endif /* RFAL_NFCDEP_MAX_ATN_RETRYS */
+
+#define NFCIP_MIN_TXERROR_LEN \
+    4U /*!< Minimum frame length with error to be ignored  Digital 1.0 14.12.5.4 */
+
+#define NFCIP_REQ (uint8_t)0xD4U /*!<NFCIP REQuest code                                     */
+#define NFCIP_RES (uint8_t)0xD5U /*!<NFCIP RESponce code                                    */
+
+#define NFCIP_BS_MASK 0x0FU /*!< Bit mask for BS value on a ATR REQ/RES                */
+#define NFCIP_BR_MASK NFCIP_BS_MASK /*!< Bit mask for BR value on a ATR REQ/RES                */
+
+#define NFCIP_PP_GB_MASK 0x02U /*!< Bit mask for GB value in PP byte on a ATR REQ/RES     */
+#define NFCIP_PP_NAD_MASK 0x01U /*!< Bit mask for NAD value in PP byte on a ATR REQ/RES    */
+
+#define NFCIP_PFB_xPDU_MASK 0xE0U /*!< Bit mask for PDU type                                 */
+#define NFCIP_PFB_IPDU 0x00U /*!< Bit mask indicating a Information PDU                 */
+#define NFCIP_PFB_RPDU 0x40U /*!< Bit mask indicating a Response PDU                    */
+#define NFCIP_PFB_SPDU 0x80U /*!< Bit mask indicating a Supervisory PDU                 */
+
+#define NFCIP_PFB_MI_BIT 0x10U /*!< Bit mask for the chaining bit (MI) of PFB             */
+#define NFCIP_PFB_DID_BIT 0x04U /*!< Bit mask for the DID presence bit of PFB              */
+#define NFCIP_PFB_NAD_BIT 0x08U /*!< Bit mask for the NAD presence bit of PFB              */
+#define NFCIP_PFB_PNI_MASK 0x03U /*!< Bit mask for the Packet Number Information            */
+
+#define NFCIP_PFB_Rx_MASK 0x10U /*!< Bit mask for the R-PDU type                           */
+#define NFCIP_PFB_ACK 0x00U /*!< Bit mask for R-PDU indicating ACK                     */
+#define NFCIP_PFB_NACK 0x10U /*!< Bit mask for R-PDU indicating NAK                     */
+
+#define NFCIP_PFB_Sx_MASK 0x10U /*!< Bit mask for the R-PDU type                           */
+#define NFCIP_PFB_ATN 0x00U /*!< Bit mask for R-PDU indicating ACK                     */
+#define NFCIP_PFB_TO 0x10U /*!< Bit mask for R-PDU indicating NAK                     */
+
+#define NFCIP_PFB_INVALID 0xFFU /*!< Invalid PFB value                                     */
+
+/*
+ ******************************************************************************
+ * MACROS
+ ******************************************************************************
+ */
+
+#define nfcipIsTransmissionError(e)              \
+    (((e) == ERR_CRC) || ((e) == ERR_FRAMING) || \
+     ((e) == ERR_PAR)) /*!< Checks if is a Trasmission error */
+
+#define nfcipConv1FcToMs(v) \
+    (rfalConv1fcToMs((v)) + 1U) /*!< Converts value v 1fc into milliseconds (fc=13.56)     */
+
+#define nfcipCmdIsReq(cmd) \
+    (((uint8_t)(cmd) % 2U) == 0U) /*!< Checks if the nfcip cmd is a REQ                      */
+
+#define nfcip_PFBhasDID(pfb)        \
+    (((pfb) & NFCIP_PFB_DID_BIT) == \
+     NFCIP_PFB_DID_BIT) /*!< Checks if pfb is signalling DID                       */
+#define nfcip_PFBhasNAD(pfb)        \
+    (((pfb) & NFCIP_PFB_NAD_BIT) == \
+     NFCIP_PFB_NAD_BIT) /*!< Checks if pfb is signalling NAD                       */
+
+#define nfcip_PFBisIPDU(pfb)          \
+    (((pfb) & NFCIP_PFB_xPDU_MASK) == \
+     NFCIP_PFB_IPDU) /*!< Checks if pfb is a Information PDU                    */
+#define nfcip_PFBisRPDU(pfb)          \
+    (((pfb) & NFCIP_PFB_xPDU_MASK) == \
+     NFCIP_PFB_RPDU) /*!< Checks if pfb is Response PDU                         */
+#define nfcip_PFBisSPDU(pfb)          \
+    (((pfb) & NFCIP_PFB_xPDU_MASK) == \
+     NFCIP_PFB_SPDU) /*!< Checks if pfb is a Supervisory PDU                    */
+
+#define nfcip_PFBisIMI(pfb)         \
+    (nfcip_PFBisIPDU(pfb) &&        \
+     (((pfb) & NFCIP_PFB_MI_BIT) == \
+      NFCIP_PFB_MI_BIT)) /*!< Checks if pfb is a Information PDU indicating MI chaining */
+
+#define nfcip_PFBisRNACK(pfb)                                \
+    (nfcip_PFBisRPDU(pfb) && (((pfb) & NFCIP_PFB_Rx_MASK) == \
+                              NFCIP_PFB_NACK)) /*!< Checks if pfb is a R-PDU indicating NACK  */
+#define nfcip_PFBisRACK(pfb)                                 \
+    (nfcip_PFBisRPDU(pfb) && (((pfb) & NFCIP_PFB_Rx_MASK) == \
+                              NFCIP_PFB_ACK)) /*!< Checks if pfb is a R-PDU indicating ACK   */
+
+#define nfcip_PFBisSATN(pfb)                                 \
+    (nfcip_PFBisSPDU(pfb) && (((pfb) & NFCIP_PFB_Sx_MASK) == \
+                              NFCIP_PFB_ATN)) /*!< Checks if pfb is a R-PDU indicating ATN   */
+#define nfcip_PFBisSTO(pfb)                                  \
+    (nfcip_PFBisSPDU(pfb) && (((pfb) & NFCIP_PFB_Sx_MASK) == \
+                              NFCIP_PFB_TO)) /*!< Checks if pfb is a R-PDU indicating TO    */
+
+#define nfcip_PFBIPDU(pni)              \
+    ((uint8_t)(0x00U | NFCIP_PFB_IPDU | \
+               ((pni) &                 \
+                NFCIP_PFB_PNI_MASK))) /*!< Returns a PFB I-PDU with the given packet number (pni)                   */
+#define nfcip_PFBIPDU_MI(pni)          \
+    ((uint8_t)(isoDep_PCBIBlock(pni) | \
+               NFCIP_PFB_MI_BIT)) /*!< Returns a PFB I-PDU with the given packet number (pni) indicating chaing */
+
+#define nfcip_PFBRPDU(pni)              \
+    ((uint8_t)(0x00U | NFCIP_PFB_RPDU | \
+               ((pni) &                 \
+                NFCIP_PFB_PNI_MASK))) /*!< Returns a PFB R-PDU with the given packet number (pni)                   */
+#define nfcip_PFBRPDU_NACK(pni)     \
+    ((uint8_t)(nfcip_PFBRPDU(pni) | \
+               NFCIP_PFB_NACK)) /*!< Returns a PFB R-PDU with the given packet number (pni) indicating NACK   */
+#define nfcip_PFBRPDU_ACK(pni)      \
+    ((uint8_t)(nfcip_PFBRPDU(pni) | \
+               NFCIP_PFB_ACK)) /*!< Returns a PFB R-PDU with the given packet number (pni) indicating ACK    */
+
+#define nfcip_PFBSPDU() \
+    ((uint8_t)(0x00U |  \
+               NFCIP_PFB_SPDU)) /*!< Returns a PFB S-PDU                                   */
+#define nfcip_PFBSPDU_ATN()      \
+    ((uint8_t)(nfcip_PFBSPDU() | \
+               NFCIP_PFB_ATN)) /*!< Returns a PFB S-PDU indicating ATN                    */
+#define nfcip_PFBSPDU_TO()       \
+    ((uint8_t)(nfcip_PFBSPDU() | \
+               NFCIP_PFB_TO)) /*!< Returns a PFB S-PDU indicating TO                     */
+
+#define nfcip_PNIInc(pni)     \
+    ((uint8_t)(((pni) + 1U) & \
+               NFCIP_PFB_PNI_MASK)) /*!< Returns a incremented PNI from the given (pni)        */
+#define nfcip_PNIDec(pni)   \
+    ((uint8_t)(((pni)-1U) & \
+               NFCIP_PFB_PNI_MASK)) /*!< Returns a decremented PNI from the given (pni)        */
+
+#define nfcip_PBF_PNI(pfb) \
+    ((uint8_t)((pfb) &     \
+               NFCIP_PFB_PNI_MASK)) /*!< Returns the Packet Number Information (pni)           */
+
+#define nfcip_PPwGB(lr)    \
+    (rfalNfcDepLR2PP(lr) | \
+     NFCIP_PP_GB_MASK) /*!< Returns a PP byte containing the given PP value indicating GB                  */
+
+#define nfcip_DIDMax(did) \
+    (MIN(                 \
+        (did),            \
+        RFAL_NFCDEP_DID_MAX)) /*!< Ensures that the given did has proper value  Digital 14.6.2.3 DID [0 14]       */
+#define nfcip_RTOXTargMax(wt)                             \
+    (uint8_t)(MIN(                                        \
+        (RFAL_NFCDEP_RWT_TRG_MAX / rfalNfcDepWT2RWT(wt)), \
+        NFCIP_TARG_MAX_RTOX)) /*!< Calculates the Maximum RTOX value for the given wt as a Target */
+
+#define nfcipIsInitiator(st)         \
+    (((st) >= NFCIP_ST_INIT_IDLE) && \
+     ((st) <=                        \
+      NFCIP_ST_INIT_RLS)) /*!< Checks if module is set as Initiator                                           */
+#define nfcipIsTarget(st) \
+    (!nfcipIsInitiator(   \
+        st)) /*!< Checks if module is set as Target                                              */
+
+#define nfcipIsBRAllowed(br, mBR) \
+    (((1U << (br)) & (mBR)) !=    \
+     0U) /*!< Checks bit rate is allowed by given mask                                       */
+
+#define nfcipIsEmptyDEPEnabled(op) \
+    (!nfcipIsEmptyDEPDisabled(     \
+        op)) /*!< Checks if empty payload is allowed by operation config  NCI 1.0 Table 81       */
+#define nfcipIsEmptyDEPDisabled(op)             \
+    (((op) & RFAL_NFCDEP_OPER_EMPTY_DEP_DIS) != \
+     0U) /*!< Checks if empty payload is not allowed by operation config  NCI 1.0 Table 81   */
+
+#define nfcipIsRTOXReqEnabled(op) \
+    (!nfcipIsRTOXReqDisabled(     \
+        op)) /*!< Checks if send a RTOX_REQ is allowed by operation config  NCI 1.0 Table 81     */
+#define nfcipIsRTOXReqDisabled(op)             \
+    (((op) & RFAL_NFCDEP_OPER_RTOX_REQ_DIS) != \
+     0U) /*!< Checks if send a RTOX_REQ is not allowed by operation config  NCI 1.0 Table 81 */
+
+/*! Checks if isDeactivating callback is set and calls it, otherwise returns false */
+#define nfcipIsDeactivationPending() \
+    ((gNfcip.isDeactivating == NULL) ? false : gNfcip.isDeactivating())
+
+/*! Returns the RWT Activation according to the current communication mode */
+#define nfcipRWTActivation()                                                       \
+    ((gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE) ? NFCIP_RWT_ACM_ACTIVATION : \
+                                                        NFCIP_RWT_ACTIVATION)
+
+#define nfcipRTOXAdjust(v) \
+    ((v) - ((v) >> 3)) /*!< Adjust RTOX timer value to a percentage of the total, current 88% */
+
+/*******************************************************************************/
+
+// timerPollTimeoutValue is necessary after timerCalculateTimeout so that system will wake up upon timer timeout.
+#define nfcipTimerStart(timer, time_ms)                     \
+    do {                                                    \
+        platformTimerDestroy(timer);                        \
+        (timer) = platformTimerCreate((uint16_t)(time_ms)); \
+    } while(0) /*!< Configures and starts the RTOX timer            */
+#define nfcipTimerisExpired(timer) \
+    platformTimerIsExpired(timer) /*!< Checks RTOX timer has expired                   */
+#define nfcipTimerDestroy(timer) \
+    platformTimerDestroy(timer) /*!< Destroys RTOX timer                             */
+
+#define nfcipLogE(...) /*!< Macro for the error log method                  */
+#define nfcipLogW(...) /*!< Macro for the warning log method                */
+#define nfcipLogI(...) /*!< Macro for the info log method                   */
+#define nfcipLogD(...) /*!< Macro for the debug log method                  */
+
+/*! Digital 1.1 - 16.12.5.2  The Target SHALL NOT attempt any error recovery and remains in Rx mode upon Transmission or a Protocol Error */
+#define nfcDepReEnableRx(rxB, rxBL, rxL)                                 \
+    rfalTransceiveBlockingTx(                                            \
+        NULL,                                                            \
+        0,                                                               \
+        (rxB),                                                           \
+        (rxBL),                                                          \
+        (rxL),                                                           \
+        (RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON), \
+        RFAL_FWT_NONE)
+
+/*
+ ******************************************************************************
+ * LOCAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! Struct that holds all DEP parameters/configs for the following communications */
+typedef struct {
+    uint8_t did; /*!< Device ID (DID) to be used                      */
+
+    uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent             */
+    uint16_t txBufLen; /*!< Length of the data in the txBuf                 */
+    uint8_t txBufPaylPos; /*!< Position inside txBuf where data starts         */
+    bool txChaining; /*!< Flag indicating chaining on transmission        */
+
+    uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data      */
+    uint16_t rxBufLen; /*!< Length of the data in the rxBuf                 */
+    uint8_t rxBufPaylPos; /*!< Position inside rxBuf where data is to be placed*/
+
+    uint32_t fwt; /*!< Frame Waiting Time (FWT) to be used             */
+    uint32_t dFwt; /*!< Delta Frame Waiting Time (dFWT) to be used      */
+    uint16_t fsc; /*!< Frame Size (FSC) to be used                     */
+
+} rfalNfcDepDEPParams;
+
+/*! NFCIP module states */
+typedef enum {
+    NFCIP_ST_IDLE,
+    NFCIP_ST_INIT_IDLE,
+    NFCIP_ST_INIT_ATR,
+    NFCIP_ST_INIT_PSL,
+    NFCIP_ST_INIT_DEP_IDLE,
+    NFCIP_ST_INIT_DEP_TX,
+    NFCIP_ST_INIT_DEP_RX,
+    NFCIP_ST_INIT_DEP_ATN,
+    NFCIP_ST_INIT_DSL,
+    NFCIP_ST_INIT_RLS,
+
+    NFCIP_ST_TARG_WAIT_ATR,
+    NFCIP_ST_TARG_WAIT_ACTV,
+    NFCIP_ST_TARG_DEP_IDLE,
+    NFCIP_ST_TARG_DEP_RX,
+    NFCIP_ST_TARG_DEP_RTOX,
+    NFCIP_ST_TARG_DEP_TX,
+    NFCIP_ST_TARG_DEP_SLEEP
+} rfalNfcDepState;
+
+/*! NFCIP commands (Request, Response) */
+typedef enum {
+    NFCIP_CMD_ATR_REQ = 0x00,
+    NFCIP_CMD_ATR_RES = 0x01,
+    NFCIP_CMD_WUP_REQ = 0x02,
+    NFCIP_CMD_WUP_RES = 0x03,
+    NFCIP_CMD_PSL_REQ = 0x04,
+    NFCIP_CMD_PSL_RES = 0x05,
+    NFCIP_CMD_DEP_REQ = 0x06,
+    NFCIP_CMD_DEP_RES = 0x07,
+    NFCIP_CMD_DSL_REQ = 0x08,
+    NFCIP_CMD_DSL_RES = 0x09,
+    NFCIP_CMD_RLS_REQ = 0x0A,
+    NFCIP_CMD_RLS_RES = 0x0B
+} rfalNfcDepCmd;
+
+/*! Struct that holds all NFCIP data */
+typedef struct {
+    rfalNfcDepConfigs cfg; /*!< Holds the current configuration to be used    */
+
+    rfalNfcDepState state; /*!< Current state of the NFCIP module             */
+    uint8_t pni; /*!< Packet Number Information (PNI) counter       */
+
+    uint8_t lastCmd; /*!< Last command sent                             */
+    uint8_t lastPFB; /*!< Last PFB sent                                 */
+    uint8_t lastPFBnATN; /*!< Last PFB sent (excluding  ATN)                */
+    uint8_t lastRTOX; /*!< Last RTOX value sent                          */
+
+    uint8_t cntTxRetrys; /*!< Retransmissions counter                       */
+    uint8_t cntTORetrys; /*!< Timeouts counter                              */
+    uint8_t cntRTOXRetrys; /*!< RTOX counter                                  */
+    uint8_t cntNACKRetrys; /*!< NACK counter                                  */
+    uint8_t cntATNRetrys; /*!< Attention (ATN) counter                       */
+
+    uint16_t fsc; /*!< Current Frame Size (FSC) to be used           */
+    bool isTxChaining; /*!< Flag for chaining on Transmission             */
+    bool isRxChaining; /*!< Flag for chaining on Reception                */
+    uint8_t* txBuf; /*!< Pointer to the Tx buffer to be sent           */
+    uint8_t* rxBuf; /*!< Pointer to the Rx buffer for incoming data    */
+    uint16_t txBufLen; /*!< Length of the data in the txBuf               */
+    uint16_t rxBufLen; /*!< Length of rxBuf buffer                        */
+    uint16_t* rxRcvdLen; /*!< Length of the data in the rxBuf               */
+    uint8_t txBufPaylPos; /*!< Position in txBuf where data starts           */
+    uint8_t rxBufPaylPos; /*!< Position in rxBuf where data is to be placed  */
+    bool* isChaining; /*!< Flag for chaining on Reception                */
+
+    rfalNfcDepDevice* nfcDepDev; /*!< Pointer to NFC-DEP device info                */
+
+    uint32_t RTOXTimer; /*!< Timer used for RTOX                           */
+    rfalNfcDepDeactCallback isDeactivating; /*!< Deactivating flag check callback              */
+
+    bool isReqPending; /*!< Flag pending REQ from Target activation       */
+    bool isTxPending; /*!< Flag pending DEP Block while waiting RTOX Ack */
+    bool isWait4RTOX; /*!< Flag for waiting RTOX Ack                     */
+
+    rfalNfcDepPduTxRxParam PDUParam; /*!< PDU TxRx params                               */
+    uint16_t PDUTxPos; /*!< PDU Tx position                               */
+    uint16_t PDURxPos; /*!< PDU Rx position                               */
+    bool isPDURxChaining; /*!< PDU Transceive chaining flag                  */
+} rfalNfcDep;
+
+/*
+ ******************************************************************************
+ * LOCAL VARIABLES
+ ******************************************************************************
+ */
+
+static rfalNfcDep gNfcip; /*!< NFCIP module instance                         */
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+
+static ReturnCode nfcipTxRx(
+    rfalNfcDepCmd cmd,
+    uint8_t* txBuf,
+    uint32_t fwt,
+    uint8_t* paylBuf,
+    uint8_t paylBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rxActLen);
+static ReturnCode nfcipTx(
+    rfalNfcDepCmd cmd,
+    uint8_t* txBuf,
+    uint8_t* paylBuf,
+    uint16_t paylLen,
+    uint8_t pfbData,
+    uint32_t fwt);
+static ReturnCode nfcipDEPControlMsg(uint8_t pfb, uint8_t RTOX);
+static ReturnCode nfcipInitiatorHandleDEP(
+    ReturnCode rxRes,
+    uint16_t rxLen,
+    uint16_t* outActRxLen,
+    bool* outIsChaining);
+static ReturnCode
+    nfcipTargetHandleRX(ReturnCode rxRes, uint16_t* outActRxLen, bool* outIsChaining);
+static ReturnCode nfcipTargetHandleActivation(rfalNfcDepDevice* nfcDepDev, uint8_t* outBRS);
+
+/*!
+ ******************************************************************************
+ * \brief NFCIP Configure
+ * 
+ * Configures the nfcip layer with the given configurations 
+ * 
+ * \param[in] cfg   : nfcip configuration for following communication
+ ******************************************************************************
+ */
+static void nfcipConfig(const rfalNfcDepConfigs* cfg);
+
+/*!
+ ******************************************************************************
+ * \brief Set DEP parameters
+ * 
+ * This method sets the parameters/configs for following Data Exchange
+ * Sets the nfcip module state according to the role it is configured
+ * 
+ * 
+ * \warning To be used only after proper Initiator/Target activation: 
+ *           nfcipTargetHandleActivation() or nfcipInitiatorActivate() has
+ *           returned success
+ *           
+ *  This must be called before  nfcipRun() in case of Target to pass 
+ *  rxBuffer
+ *  
+ *  Everytime some data needs to be transmitted call this to set it and 
+ *  call nfcipRun() until done or error
+ * 
+ * \param[in]  DEPParams  : the parameters to be used during Data Exchange 
+ ******************************************************************************
+ */
+static void nfcipSetDEPParams(const rfalNfcDepDEPParams* DEPParams);
+
+/*!
+ ******************************************************************************
+ * \brief NFCIP run protocol
+ * 
+ * This method handles all the nfcip protocol during Data Exchange (DEP
+ *  requests and responses).
+ *  
+ *  A data exchange cycle is considered a DEP REQ and a DEP RES.
+ *  
+ *  In case of Tx chaining(MI) must signal it with  nfcipSetDEPParams()
+ *  In case of Rx chaining(MI) outIsChaining will be set to true and the 
+ *  current data returned
+ *  
+ * \param[out] outActRxLen   : data received length
+ * \param[out] outIsChaining : true if other peer is performing chaining(MI)
+ *  
+ * \return ERR_NONE    : Data exchange cycle completed successfully
+ * \return ERR_TIMEOUT : Timeout occurred
+ * \return ERR_PROTO   : Protocol error occurred
+ * \return ERR_AGAIN   : Other peer is doing chaining(MI), current block 
+ *                       was received successfully call again until complete
+ * 
+ ******************************************************************************
+ */
+static ReturnCode nfcipRun(uint16_t* outActRxLen, bool* outIsChaining);
+
+/*!
+ ******************************************************************************
+ * \brief Transmission method
+ * 
+ * This method checks if the current communication is Active or Passive
+ * and performs the necessary procedures for each communication type
+ * 
+ * Transmits the data hold in txBuf 
+ * 
+ * \param[in]  txBuf    : buffer to transmit
+ * \param[in]  txBufLen : txBuffer capacity 
+ * \param[in]  fwt      : fwt for current Tx
+ * 
+ * \return ERR_NONE       : No error
+ ******************************************************************************
+ */
+static ReturnCode nfcipDataTx(uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt);
+
+/*!
+ ******************************************************************************
+ * \brief Reception method
+ * 
+ * This method checks if the current communication is Active or Passive
+ * and calls the appropriate reception method
+ * 
+ * Copies incoming data to rxBuf
+ * 
+ * \param[in] blocking    : reception is to be done blocking or non-blocking
+ * 
+ * \return ERR_BUSY       : Busy
+ * \return ERR_NONE       : No error
+ ******************************************************************************
+ */
+static ReturnCode nfcipDataRx(bool blocking);
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*******************************************************************************/
+
+/*******************************************************************************/
+static bool nfcipDxIsSupported(uint8_t Dx, uint8_t BRx, uint8_t BSx) {
+    uint8_t Bx;
+
+    /* Take the min of the possible bit rates, we'll use one for both directions */
+    Bx = MIN(BRx, BSx);
+
+    /* Lower bit rates must be supported for P2P */
+    if((Dx <= (uint8_t)RFAL_NFCDEP_Dx_04_424)) {
+        return true;
+    }
+
+    if((Dx == (uint8_t)RFAL_NFCDEP_Dx_08_848) && (Bx >= (uint8_t)RFAL_NFCDEP_Bx_08_848)) {
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipTxRx(
+    rfalNfcDepCmd cmd,
+    uint8_t* txBuf,
+    uint32_t fwt,
+    uint8_t* paylBuf,
+    uint8_t paylBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rxActLen) {
+    ReturnCode ret;
+
+    if((cmd == NFCIP_CMD_DEP_REQ) ||
+       (cmd == NFCIP_CMD_DEP_RES)) /* this method cannot be used for DEPs */
+    {
+        return ERR_PARAM;
+    }
+
+    /* Assign the global params for this TxRx */
+    gNfcip.rxBuf = rxBuf;
+    gNfcip.rxBufLen = rxBufLen;
+    gNfcip.rxRcvdLen = rxActLen;
+
+    /*******************************************************************************/
+    /* Transmission                                                                */
+    /*******************************************************************************/
+    if(txBuf != NULL) /* if nothing to Tx, just do Rx */
+    {
+        EXIT_ON_ERR(ret, nfcipTx(cmd, txBuf, paylBuf, paylBufLen, 0, fwt));
+    }
+
+    /*******************************************************************************/
+    /* Reception                                                                   */
+    /*******************************************************************************/
+    ret = nfcipDataRx(true);
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /*******************************************************************************/
+    *rxActLen = *rxBuf; /* Use LEN byte instead due to with/without CRC modes */
+    return ERR_NONE; /* Tx and Rx completed successfully                   */
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipDEPControlMsg(uint8_t pfb, uint8_t RTOX) {
+    uint8_t ctrlMsg[20];
+    rfalNfcDepCmd depCmd;
+    uint32_t fwt;
+
+    /*******************************************************************************/
+    /* Calculate Cmd and fwt to be used                                            */
+    /*******************************************************************************/
+    depCmd =
+        ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_CMD_DEP_RES : NFCIP_CMD_DEP_REQ);
+    fwt =
+        ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ?
+             NFCIP_NO_FWT :
+             (nfcip_PFBisSTO(pfb) ? ((RTOX * gNfcip.cfg.fwt) + gNfcip.cfg.dFwt) :
+                                    (gNfcip.cfg.fwt + gNfcip.cfg.dFwt)));
+
+    if(nfcip_PFBisSTO(pfb)) {
+        ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN] = RTOX;
+        return nfcipTx(
+            depCmd, ctrlMsg, &ctrlMsg[RFAL_NFCDEP_DEPREQ_HEADER_LEN], sizeof(uint8_t), pfb, fwt);
+    } else {
+        return nfcipTx(depCmd, ctrlMsg, NULL, 0, pfb, fwt);
+    }
+}
+
+/*******************************************************************************/
+static void nfcipClearCounters(void) {
+    gNfcip.cntATNRetrys = 0;
+    gNfcip.cntNACKRetrys = 0;
+    gNfcip.cntTORetrys = 0;
+    gNfcip.cntTxRetrys = 0;
+    gNfcip.cntRTOXRetrys = 0;
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipInitiatorHandleDEP(
+    ReturnCode rxRes,
+    uint16_t rxLen,
+    uint16_t* outActRxLen,
+    bool* outIsChaining) {
+    ReturnCode ret;
+    uint8_t nfcDepLen;
+    uint8_t rxMsgIt;
+    uint8_t rxPFB;
+    uint8_t rxRTOX;
+    uint8_t optHdrLen;
+
+    ret = ERR_INTERNAL;
+    rxMsgIt = 0;
+    optHdrLen = 0;
+
+    *outActRxLen = 0;
+    *outIsChaining = false;
+
+    /*******************************************************************************/
+    /* Handle reception errors                                                     */
+    /*******************************************************************************/
+    switch(rxRes) {
+    /*******************************************************************************/
+    /* Timeout ->  Digital 1.0 14.15.5.6 */
+    case ERR_TIMEOUT:
+
+        nfcipLogI(" NFCIP(I) TIMEOUT  TORetrys:%d \r\n", gNfcip.cntTORetrys);
+
+        /* Digital 1.0 14.15.5.6 - If nTO >= Max raise protocol error */
+        if(gNfcip.cntTORetrys++ >= RFAL_NFCDEP_TO_RETRYS) {
+            return ERR_PROTO;
+        }
+
+        /*******************************************************************************/
+        /* Upon Timeout error, if Deactivation is pending, no more error recovery 
+             * will be done #54. 
+             * This is used to address the issue some devices that havea big TO. 
+             * Normally LLCP layer has timeout already, and NFCIP layer is still
+             * running error handling, retrying ATN/NACKs                                  */
+        /*******************************************************************************/
+        if(nfcipIsDeactivationPending()) {
+            nfcipLogI(" skipping error recovery due deactivation pending \r\n");
+            return ERR_TIMEOUT;
+        }
+
+        /* Digital 1.0 14.15.5.6 1)  If last PDU was NACK */
+        if(nfcip_PFBisRNACK(gNfcip.lastPFB)) {
+            /* Digital 1.0 14.15.5.6 2)  if NACKs failed raise protocol error  */
+            if(gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS) {
+                return ERR_PROTO;
+            }
+
+            /* Send NACK */
+            nfcipLogI(" NFCIP(I) Sending NACK retry: %d \r\n", gNfcip.cntNACKRetrys);
+            EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBRPDU_NACK(gNfcip.pni), 0));
+            return ERR_BUSY;
+        }
+
+        nfcipLogI(" NFCIP(I) Checking if to send ATN  ATNRetrys: %d \r\n", gNfcip.cntATNRetrys);
+
+        /* Digital 1.0 14.15.5.6 3)  Otherwise send ATN */
+        if(gNfcip.cntATNRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS) {
+            return ERR_PROTO;
+        }
+
+        /* Send ATN */
+        nfcipLogI(" NFCIP(I) Sending ATN \r\n");
+        EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBSPDU_ATN(), 0));
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    /* Data rcvd with error ->  Digital 1.0 14.12.5.4 */
+    case ERR_CRC:
+    case ERR_PAR:
+    case ERR_FRAMING:
+    case ERR_RF_COLLISION:
+
+        nfcipLogI(" NFCIP(I) rx Error: %d \r\n", rxRes);
+
+        /* Digital 1.0 14.12.5.4 Tx Error with data, ignore */
+        if(rxLen < NFCIP_MIN_TXERROR_LEN) {
+            nfcipLogI(" NFCIP(I) Transmission error w data  \r\n");
+#if 0
+                if(gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE)
+                {
+                    nfcipLogI( " NFCIP(I) Transmission error w data -> reEnabling Rx \r\n" );
+                    nfcipReEnableRxTout( NFCIP_TRECOV );
+                    return ERR_BUSY;
+                }
+#endif /* 0 */
+        }
+
+        /* Digital 1.1 16.12.5.4  if NACKs failed raise Transmission error  */
+        if(gNfcip.cntNACKRetrys++ >= RFAL_NFCDEP_MAX_NACK_RETRYS) {
+            return ERR_FRAMING;
+        }
+
+        /* Send NACK */
+        nfcipLogI(" NFCIP(I) Sending NACK  \r\n");
+        EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBRPDU_NACK(gNfcip.pni), 0));
+        return ERR_BUSY;
+
+    case ERR_NONE:
+        break;
+
+    case ERR_BUSY:
+        return ERR_BUSY; /* Debug purposes */
+
+    default:
+        nfcipLogW(" NFCIP(I) Error: %d \r\n", rxRes);
+        return rxRes;
+    }
+
+    /*******************************************************************************/
+    /* Rx OK check if valid DEP PDU                                                */
+    /*******************************************************************************/
+
+    /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */
+    nfcDepLen = gNfcip.rxBuf[rxMsgIt++];
+
+    nfcipLogD(" NFCIP(I) rx OK: %d bytes \r\n", nfcDepLen);
+
+    /* Digital 1.0 14.15.5.5 Protocol Error  */
+    if(gNfcip.rxBuf[rxMsgIt++] != NFCIP_RES) {
+        nfcipLogW(" NFCIP(I) error %02X instead of %02X \r\n", gNfcip.rxBuf[--rxMsgIt], NFCIP_RES);
+        return ERR_PROTO;
+    }
+
+    /* Digital 1.0 14.15.5.5 Protocol Error  */
+    if(gNfcip.rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DEP_RES) {
+        nfcipLogW(
+            " NFCIP(I) error %02X instead of %02X \r\n",
+            gNfcip.rxBuf[--rxMsgIt],
+            NFCIP_CMD_DEP_RES);
+        return ERR_PROTO;
+    }
+
+    rxPFB = gNfcip.rxBuf[rxMsgIt++];
+
+    /*******************************************************************************/
+    /* Check for valid PFB type                                                    */
+    if(!(nfcip_PFBisSPDU(rxPFB) || nfcip_PFBisRPDU(rxPFB) || nfcip_PFBisIPDU(rxPFB))) {
+        return ERR_PROTO;
+    }
+
+    /*******************************************************************************/
+    /* Digital 1.0 14.8.2.1  check if DID is expected and match -> Protocol Error  */
+    if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+        if((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || !nfcip_PFBhasDID(rxPFB)) {
+            return ERR_PROTO;
+        }
+        optHdrLen++; /* Inc header optional field cnt*/
+    } else if(nfcip_PFBhasDID(rxPFB)) /* DID not expected but rcv */
+    {
+        return ERR_PROTO;
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /*******************************************************************************/
+    /* Digital 1.0 14.6.2.8 & 14.6.3.11 NAD must not be used  */
+    if(gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) {
+        if((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.nad) || !nfcip_PFBhasNAD(rxPFB)) {
+            return ERR_PROTO;
+        }
+        optHdrLen++; /* Inc header optional field cnt*/
+    } else if(nfcip_PFBhasNAD(rxPFB)) /* NAD not expected but rcv */
+    {
+        return ERR_PROTO;
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /*******************************************************************************/
+    /* Process R-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisRPDU(rxPFB)) {
+        /*******************************************************************************/
+        /* R ACK                                                                       */
+        /*******************************************************************************/
+        if(nfcip_PFBisRACK(rxPFB)) {
+            nfcipLogI(" NFCIP(I) Rcvd ACK  \r\n");
+            if(gNfcip.pni == nfcip_PBF_PNI(rxPFB)) {
+                /* 14.12.3.3 R-ACK with correct PNI -> Increment */
+                gNfcip.pni = nfcip_PNIInc(gNfcip.pni);
+
+                /* R-ACK while not performing chaining -> Protocol error*/
+                if(!gNfcip.isTxChaining) {
+                    return ERR_PROTO;
+                }
+
+                nfcipClearCounters();
+                gNfcip.state = NFCIP_ST_INIT_DEP_IDLE;
+                return ERR_NONE; /* This block has been transmitted */
+            } else /* Digital 1.0 14.12.4.5 ACK with wrong PNI Initiator may retransmit */
+            {
+                if(gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS) {
+                    return ERR_PROTO;
+                }
+
+                /* Extended the MAY in Digital 1.0 14.12.4.5 to only reTransmit if the ACK
+                 * is for the previous DEP, otherwise raise Protocol immediately 
+                 * If the PNI difference is more than 1 it is worthless to reTransmit 3x
+                 * and after raise the error                                              */
+
+                if(nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI(rxPFB)) {
+                    /* ReTransmit */
+                    nfcipLogI(" NFCIP(I) Rcvd ACK prev PNI -> reTx \r\n");
+                    gNfcip.state = NFCIP_ST_INIT_DEP_TX;
+                    return ERR_BUSY;
+                }
+
+                nfcipLogI(" NFCIP(I) Rcvd ACK unexpected far PNI -> Error \r\n");
+                return ERR_PROTO;
+            }
+        } else /* Digital 1.0 - 14.12.5.2 Target must never send NACK  */
+        {
+            return ERR_PROTO;
+        }
+    }
+
+    /*******************************************************************************/
+    /* Process S-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisSPDU(rxPFB)) {
+        nfcipLogI(" NFCIP(I) Rcvd S-PDU  \r\n");
+        /*******************************************************************************/
+        /* S ATN                                                                       */
+        /*******************************************************************************/
+        if(nfcip_PFBisSATN(rxPFB)) /* If is a S-ATN        */
+        {
+            nfcipLogI(" NFCIP(I) Rcvd ATN  \r\n");
+            if(nfcip_PFBisSATN(gNfcip.lastPFB)) /* Check if is expected */
+            {
+                gNfcip.cntATNRetrys = 0; /* Clear ATN counter    */
+
+                /* Although spec is not clear NFC Forum Digital test is expecting to
+                 * retransmit upon receiving ATN_RES */
+                if(nfcip_PFBisSTO(gNfcip.lastPFBnATN)) {
+                    nfcipLogI(" NFCIP(I) Rcvd ATN  -> reTx RTOX_RES \r\n");
+                    EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBSPDU_TO(), gNfcip.lastRTOX));
+                } else {
+                    /* ReTransmit ? */
+                    if(gNfcip.cntTxRetrys++ >= RFAL_NFCDEP_MAX_TX_RETRYS) {
+                        return ERR_PROTO;
+                    }
+
+                    nfcipLogI(" NFCIP(I) Rcvd ATN  -> reTx  PNI: %d \r\n", gNfcip.pni);
+                    gNfcip.state = NFCIP_ST_INIT_DEP_TX;
+                }
+
+                return ERR_BUSY;
+            } else /* Digital 1.0  14.12.4.4 & 14.12.4.8 */
+            {
+                return ERR_PROTO;
+            }
+        }
+        /*******************************************************************************/
+        /* S TO                                                                        */
+        /*******************************************************************************/
+        else if(nfcip_PFBisSTO(rxPFB)) /* If is a S-TO (RTOX)  */
+        {
+            nfcipLogI(" NFCIP(I) Rcvd TO  \r\n");
+
+            rxRTOX = gNfcip.rxBuf[rxMsgIt++];
+
+            /* Digital 1.1 16.12.4.3 - Initiator MAY stop accepting subsequent RTOX Req   *
+             *                       - RTOX request to an ATN -> Protocol error           */
+            if((gNfcip.cntRTOXRetrys++ > RFAL_NFCDEP_MAX_RTOX_RETRYS) ||
+               nfcip_PFBisSATN(gNfcip.lastPFB)) {
+                return ERR_PROTO;
+            }
+
+            /* Digital 1.1 16.8.4.1 RTOX must be between [1,59] */
+            if((rxRTOX < NFCIP_INIT_MIN_RTOX) || (rxRTOX > NFCIP_INIT_MAX_RTOX)) {
+                return ERR_PROTO;
+            }
+
+            EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBSPDU_TO(), rxRTOX));
+            gNfcip.lastRTOX = rxRTOX;
+
+            return ERR_BUSY;
+        } else {
+            /* Unexpected S-PDU */
+            return ERR_PROTO; /*  PRQA S  2880 # MISRA 2.1 - Guard code to prevent unexpected behavior */
+        }
+    }
+
+    /*******************************************************************************/
+    /* Process I-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisIPDU(rxPFB)) {
+        if(gNfcip.pni != nfcip_PBF_PNI(rxPFB)) {
+            nfcipLogI(
+                " NFCIP(I) Rcvd IPDU wrong PNI     curPNI: %d rxPNI: %d \r\n",
+                gNfcip.pni,
+                nfcip_PBF_PNI(rxPFB));
+            return ERR_PROTO;
+        }
+
+        nfcipLogD(" NFCIP(I) Rcvd IPDU OK    PNI: %d \r\n", gNfcip.pni);
+
+        /* 14.12.3.3 I-PDU with correct PNI -> Increment */
+        gNfcip.pni = nfcip_PNIInc(gNfcip.pni);
+
+        /* Successful data Exchange */
+        nfcipClearCounters();
+        *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen);
+
+        if((&gNfcip.rxBuf[gNfcip.rxBufPaylPos] !=
+            &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) &&
+           (*outActRxLen > 0U)) {
+            ST_MEMMOVE(
+                &gNfcip.rxBuf[gNfcip.rxBufPaylPos],
+                &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen],
+                *outActRxLen);
+        }
+
+        /*******************************************************************************/
+        /* Check if target is indicating chaining MI                                   */
+        /*******************************************************************************/
+        if(nfcip_PFBisIMI(rxPFB)) {
+            gNfcip.isRxChaining = true;
+            *outIsChaining = true;
+
+            nfcipLogD(" NFCIP(I) Rcvd IPDU OK w MI -> ACK \r\n");
+            EXIT_ON_ERR(
+                ret, nfcipDEPControlMsg(nfcip_PFBRPDU_ACK(gNfcip.pni), gNfcip.rxBuf[rxMsgIt++]));
+
+            return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/
+        } else {
+            gNfcip.isRxChaining = false;
+            gNfcip.state = NFCIP_ST_INIT_DEP_IDLE;
+
+            ret = ERR_NONE; /* Data exchange done */
+        }
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode
+    nfcipTargetHandleRX(ReturnCode rxRes, uint16_t* outActRxLen, bool* outIsChaining) {
+    ReturnCode ret;
+    uint8_t nfcDepLen;
+    uint8_t rxMsgIt;
+    uint8_t rxPFB;
+    uint8_t optHdrLen;
+    uint8_t resBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_TARGET_RES_MAX];
+
+    ret = ERR_INTERNAL;
+    rxMsgIt = 0;
+    optHdrLen = 0;
+
+    *outActRxLen = 0;
+    *outIsChaining = false;
+
+    /*******************************************************************************/
+    /* Handle reception errors                                                     */
+    /*******************************************************************************/
+    switch(rxRes) {
+    /*******************************************************************************/
+    case ERR_NONE:
+        break;
+
+    case ERR_LINK_LOSS:
+        nfcipLogW(" NFCIP(T) Error: %d \r\n", rxRes);
+        return rxRes;
+
+    case ERR_BUSY:
+        return ERR_BUSY; /* Debug purposes */
+
+    case ERR_TIMEOUT:
+    case ERR_CRC:
+    case ERR_PAR:
+    case ERR_FRAMING:
+    case ERR_PROTO:
+    default:
+        /* Digital 1.1  16.12.5.2 The Target MUST NOT attempt any error recovery.      *
+             * The Target MUST always stay in receive mode when a                          *
+             * Transmission Error or a Protocol Error occurs.                              *
+             *                                                                             *
+             * Do not push Transmission/Protocol Errors to upper layer in Listen Mode #766 */
+
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY;
+    }
+
+    /*******************************************************************************/
+    /* Rx OK check if valid DEP PDU                                                */
+    /*******************************************************************************/
+
+    /* Due to different modes on ST25R391x (with/without CRC) use NFC-DEP LEN instead of bytes retrieved */
+    nfcDepLen = gNfcip.rxBuf[rxMsgIt++];
+
+    nfcipLogD(" NFCIP(T) rx OK: %d bytes \r\n", nfcDepLen);
+
+    if(gNfcip.rxBuf[rxMsgIt++] != NFCIP_REQ) {
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY; /* ERR_PROTO - Ignore bad request */
+    }
+
+    /*******************************************************************************/
+    /* Check whether target rcvd a normal DEP or deactivation request              */
+    /*******************************************************************************/
+    switch(gNfcip.rxBuf[rxMsgIt++]) {
+    /*******************************************************************************/
+    case(uint8_t)NFCIP_CMD_DEP_REQ:
+        break; /* Continue to normal DEP processing */
+
+    /*******************************************************************************/
+    case(uint8_t)NFCIP_CMD_DSL_REQ:
+
+        nfcipLogI(" NFCIP(T) rx DSL \r\n");
+
+        /* Digital 1.0  14.9.1.2 If DID is used and incorrect ignore it */
+        /* [Digital 1.0, 16.9.1.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */
+        if((((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) ||
+             (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) &&
+            (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO)) ||
+           ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) &&
+            (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_NO_DID))) {
+            nfcipLogI(" NFCIP(T) DSL wrong DID, ignoring \r\n");
+            return ERR_BUSY;
+        }
+
+        nfcipTx(NFCIP_CMD_DSL_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT);
+
+        gNfcip.state = NFCIP_ST_TARG_DEP_SLEEP;
+        return ERR_SLEEP_REQ;
+
+    /*******************************************************************************/
+    case(uint8_t)NFCIP_CMD_RLS_REQ:
+
+        nfcipLogI(" NFCIP(T) rx RLS \r\n");
+
+        /* Digital 1.0  14.10.1.2 If DID is used and incorrect ignore it */
+        /* [Digital 1.0, 16.10.2.2]: If DID == 0, Target SHALL ignore DSL_REQ with DID */
+        if((((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) ||
+             (nfcDepLen != RFAL_NFCDEP_DSL_RLS_LEN_DID)) &&
+            (gNfcip.cfg.did != RFAL_NFCDEP_DID_NO)) ||
+           ((gNfcip.cfg.did == RFAL_NFCDEP_DID_NO) &&
+            (nfcDepLen > RFAL_NFCDEP_DSL_RLS_LEN_NO_DID))) {
+            nfcipLogI(" NFCIP(T) RLS wrong DID, ignoring \r\n");
+            return ERR_BUSY;
+        }
+
+        nfcipTx(NFCIP_CMD_RLS_RES, resBuf, NULL, 0, 0, NFCIP_NO_FWT);
+
+        gNfcip.state = NFCIP_ST_TARG_DEP_IDLE;
+        return ERR_RELEASE_REQ;
+
+    /*******************************************************************************/
+    /*case NFCIP_CMD_PSL_REQ:              PSL must be handled in Activation only */
+    /*case NFCIP_CMD_WUP_REQ:              WUP not in NFC Forum Digital 1.0       */
+    default:
+
+        /* Don't go to NFCIP_ST_TARG_DEP_IDLE state as it needs to ignore this    *
+             * invalid frame, and keep waiting for more frames                        */
+
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY; /* ERR_PROTO - Ignore bad frame */
+    }
+
+    /*******************************************************************************/
+
+    rxPFB = gNfcip.rxBuf[rxMsgIt++]; /* Store rcvd PFB  */
+
+    /*******************************************************************************/
+    /* Check for valid PFB type                                                    */
+    if(!(nfcip_PFBisSPDU(rxPFB) || nfcip_PFBisRPDU(rxPFB) || nfcip_PFBisIPDU(rxPFB))) {
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY; /* ERR_PROTO - Ignore invalid PFB  */
+    }
+
+    /*******************************************************************************/
+    if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+        if(!nfcip_PFBhasDID(rxPFB)) {
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID  */
+        }
+        if(gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) /* MISRA 13.5 */
+        {
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID  */
+        }
+        optHdrLen++; /* Inc header optional field cnt*/
+    } else if(nfcip_PFBhasDID(rxPFB)) /* DID not expected but rcv     */
+    {
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY; /* ERR_PROTO - Ignore unexpected DID  */
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /*******************************************************************************/
+    if(gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) {
+        if((gNfcip.rxBuf[rxMsgIt++] != gNfcip.cfg.did) || !nfcip_PFBhasDID(rxPFB)) {
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore bad/missing DID  */
+        }
+        optHdrLen++; /* Inc header optional field cnt*/
+    } else if(nfcip_PFBhasNAD(rxPFB)) /* NAD not expected but rcv */
+    {
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        return ERR_BUSY; /* ERR_PROTO - Ignore unexpected NAD  */
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /*******************************************************************************/
+    /* Process R-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisRPDU(rxPFB)) {
+        nfcipLogD(" NFCIP(T) Rcvd R-PDU  \r\n");
+        /*******************************************************************************/
+        /* R ACK                                                                       */
+        /*******************************************************************************/
+        if(nfcip_PFBisRACK(rxPFB)) {
+            nfcipLogI(" NFCIP(T) Rcvd ACK  \r\n");
+            if(gNfcip.pni == nfcip_PBF_PNI(rxPFB)) {
+                /* R-ACK while not performing chaining -> Protocol error */
+                if(!gNfcip.isTxChaining) {
+                    nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+                    return ERR_BUSY; /* ERR_PROTO - Ignore unexpected ACK  */
+                }
+
+                /* This block has been transmitted and acknowledged, perform RTOX until next data is provided  */
+
+                /* Digital 1.1  16.12.4.7 - If ACK rcvd continue with chaining or an RTOX */
+                nfcipTimerStart(
+                    gNfcip.RTOXTimer,
+                    nfcipRTOXAdjust(nfcipConv1FcToMs(rfalNfcDepWT2RWT(gNfcip.cfg.to))));
+                gNfcip.state = NFCIP_ST_TARG_DEP_RTOX;
+
+                return ERR_NONE; /* This block has been transmitted */
+            }
+
+            /* Digital 1.0 14.12.3.4 - If last send was ATN and rx PNI is minus 1 */
+            else if(
+                nfcip_PFBisSATN(gNfcip.lastPFB) &&
+                (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI(rxPFB))) {
+                nfcipLogI(" NFCIP(T) wrong PNI, last was ATN reTx  \r\n");
+                /* Spec says to leave current PNI as is, but will be Inc after Tx, remaining the same */
+                gNfcip.pni = nfcip_PNIDec(gNfcip.pni);
+
+                gNfcip.state = NFCIP_ST_TARG_DEP_TX;
+                return ERR_BUSY;
+            } else {
+                /* MISRA 15.7 - Empty else */
+            }
+        }
+        /*******************************************************************************/
+        /* R NACK                                                                      */
+        /*******************************************************************************/
+        /* ISO 18092 12.6.1.3.3 When rcv NACK if PNI = prev PNI sent ->  reTx          */
+        else if(nfcip_PFBisRNACK(rxPFB) && (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI(rxPFB))) {
+            nfcipLogI(" NFCIP(T) Rcvd NACK  \r\n");
+
+            gNfcip.pni = nfcip_PNIDec(gNfcip.pni); /* Dec so that has the prev PNI */
+
+            gNfcip.state = NFCIP_ST_TARG_DEP_TX;
+            return ERR_BUSY;
+        } else {
+            nfcipLogI(" NFCIP(T) Unexpected R-PDU \r\n");
+
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore unexpected R-PDU  */
+        }
+    }
+
+    /*******************************************************************************/
+    /* Process S-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisSPDU(rxPFB)) {
+        nfcipLogD(" NFCIP(T) Rcvd S-PDU  \r\n");
+
+        /*******************************************************************************/
+        /* S ATN                                                                       */
+        /*******************************************************************************/
+        /* ISO 18092 12.6.3 Attention                                                  */
+        if(nfcip_PFBisSATN(rxPFB)) /*    If is a S-ATN     */
+        {
+            nfcipLogI(" NFCIP(T) Rcvd ATN  curPNI: %d \r\n", gNfcip.pni);
+            EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBSPDU_ATN(), 0));
+            return ERR_BUSY;
+        }
+
+        /*******************************************************************************/
+        /* S TO                                                                        */
+        /*******************************************************************************/
+        else if(nfcip_PFBisSTO(rxPFB)) /* If is a S-TO (RTOX)  */
+        {
+            if(nfcip_PFBisSTO(gNfcip.lastPFBnATN)) {
+                nfcipLogI(" NFCIP(T) Rcvd TO  \r\n");
+
+                /* Digital 1.1  16.8.4.6  RTOX value in RES different that in REQ -> Protocol Error */
+                if(gNfcip.lastRTOX != gNfcip.rxBuf[rxMsgIt++]) {
+                    nfcipLogI(" NFCIP(T) Mismatched RTOX value \r\n");
+
+                    nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+                    return ERR_BUSY; /* ERR_PROTO - Ignore unexpected RTOX value  */
+                }
+
+                /* Clear waiting for RTOX Ack Flag */
+                gNfcip.isWait4RTOX = false;
+
+                /* Check if a Tx is already pending */
+                if(gNfcip.isTxPending) {
+                    nfcipLogW(" NFCIP(T) Tx pending, go immediately to TX \r\n");
+
+                    gNfcip.state = NFCIP_ST_TARG_DEP_TX;
+                    return ERR_BUSY;
+                }
+
+                /* Start RTOX timer and change to check state  */
+                nfcipTimerStart(
+                    gNfcip.RTOXTimer,
+                    nfcipRTOXAdjust(
+                        nfcipConv1FcToMs(gNfcip.lastRTOX * rfalNfcDepWT2RWT(gNfcip.cfg.to))));
+                gNfcip.state = NFCIP_ST_TARG_DEP_RTOX;
+
+                return ERR_BUSY;
+            }
+        } else {
+            /* Unexpected S-PDU */
+            nfcipLogI(
+                " NFCIP(T) Unexpected S-PDU \r\n"); /*  PRQA S  2880 # MISRA 2.1 - Guard code to prevent unexpected behavior */
+
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore unexpected S-PDU  */
+        }
+    }
+
+    /*******************************************************************************/
+    /* Process I-PDU                                                               */
+    /*******************************************************************************/
+    if(nfcip_PFBisIPDU(rxPFB)) {
+        if(gNfcip.pni != nfcip_PBF_PNI(rxPFB)) {
+            nfcipLogI(
+                " NFCIP(T) Rcvd IPDU wrong PNI     curPNI: %d rxPNI: %d \r\n",
+                gNfcip.pni,
+                nfcip_PBF_PNI(rxPFB));
+
+            /* Digital 1.1 16.12.3.4 - If last send was ATN and rx PNI is minus 1 */
+            if(nfcip_PFBisSATN(gNfcip.lastPFB) &&
+               (nfcip_PNIDec(gNfcip.pni) == nfcip_PBF_PNI(rxPFB))) {
+                /* Spec says to leave current PNI as is, but will be Inc after Data Tx, remaining the same */
+                gNfcip.pni = nfcip_PNIDec(gNfcip.pni);
+
+                if(nfcip_PFBisIMI(rxPFB)) {
+                    nfcipLogI(
+                        " NFCIP(T) PNI = prevPNI && ATN before && chaining -> send ACK  \r\n");
+                    EXIT_ON_ERR(
+                        ret,
+                        nfcipDEPControlMsg(nfcip_PFBRPDU_ACK(gNfcip.pni), gNfcip.rxBuf[rxMsgIt++]));
+
+                    /* Digital 1.1 16.12.3.4 (...) leave the current PNI unchanged afterwards */
+                    gNfcip.pni = nfcip_PNIInc(gNfcip.pni);
+                } else {
+                    nfcipLogI(" NFCIP(T) PNI = prevPNI && ATN before -> reTx last I-PDU  \r\n");
+                    gNfcip.state = NFCIP_ST_TARG_DEP_TX;
+                }
+
+                return ERR_BUSY;
+            }
+
+            nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+            return ERR_BUSY; /* ERR_PROTO - Ignore bad PNI value  */
+        }
+
+        nfcipLogD(" NFCIP(T) Rcvd IPDU OK PNI: %d  \r\n", gNfcip.pni);
+
+        /*******************************************************************************/
+        /* Successful data exchange                                                    */
+        /*******************************************************************************/
+        *outActRxLen = ((uint16_t)nfcDepLen - RFAL_NFCDEP_DEP_HEADER - (uint16_t)optHdrLen);
+
+        nfcipClearCounters();
+
+        if((&gNfcip.rxBuf[gNfcip.rxBufPaylPos] !=
+            &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen]) &&
+           (*outActRxLen > 0U)) {
+            ST_MEMMOVE(
+                &gNfcip.rxBuf[gNfcip.rxBufPaylPos],
+                &gNfcip.rxBuf[RFAL_NFCDEP_DEP_HEADER + optHdrLen],
+                *outActRxLen);
+        }
+
+        /*******************************************************************************/
+        /* Check if Initiator is indicating chaining MI                                */
+        /*******************************************************************************/
+        if(nfcip_PFBisIMI(rxPFB)) {
+            gNfcip.isRxChaining = true;
+            *outIsChaining = true;
+
+            nfcipLogD(" NFCIP(T) Rcvd IPDU OK w MI -> ACK \r\n");
+            EXIT_ON_ERR(
+                ret, nfcipDEPControlMsg(nfcip_PFBRPDU_ACK(gNfcip.pni), gNfcip.rxBuf[rxMsgIt++]));
+
+            gNfcip.pni = nfcip_PNIInc(gNfcip.pni);
+
+            return ERR_AGAIN; /* Send Again signalling to run again, but some chaining data has arrived*/
+        } else {
+            if(gNfcip.isRxChaining) {
+                nfcipLogI(" NFCIP(T) Rcvd last IPDU chaining finished \r\n");
+            }
+
+            /*******************************************************************************/
+            /* Reception done, send to DH and start RTOX timer                             */
+            /*******************************************************************************/
+            nfcipTimerStart(
+                gNfcip.RTOXTimer,
+                nfcipRTOXAdjust(nfcipConv1FcToMs(rfalNfcDepWT2RWT(gNfcip.cfg.to))));
+            gNfcip.state = NFCIP_ST_TARG_DEP_RTOX;
+
+            gNfcip.isRxChaining = false;
+            ret = ERR_NONE; /* Data exchange done */
+        }
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipTx(
+    rfalNfcDepCmd cmd,
+    uint8_t* txBuf,
+    uint8_t* paylBuf,
+    uint16_t paylLen,
+    uint8_t pfbData,
+    uint32_t fwt) {
+    uint16_t txBufIt;
+    uint8_t* txBlock;
+    uint8_t* payloadBuf;
+    uint8_t pfb;
+
+    if(txBuf == NULL) {
+        return ERR_PARAM;
+    }
+
+    payloadBuf = paylBuf; /* MISRA 17.8: Use intermediate variable */
+
+    if((paylLen == 0U) || (payloadBuf == NULL)) {
+        payloadBuf = (uint8_t*)&txBuf
+            [RFAL_NFCDEP_DEPREQ_HEADER_LEN]; /* If not a DEP (no Data) ensure enough space for header */
+    }
+
+    txBufIt = 0;
+    pfb = pfbData; /* MISRA 17.8: Use intermediate variable */
+
+    txBlock = payloadBuf; /* Point to beginning of the Data, and go backwards     */
+
+    gNfcip.lastCmd = (uint8_t)cmd; /* Store last cmd sent    */
+    gNfcip.lastPFB = NFCIP_PFB_INVALID; /* Reset last pfb sent    */
+
+    /*******************************************************************************/
+    /* Compute outgoing NFCIP message                                              */
+    /*******************************************************************************/
+    switch(cmd) {
+    /*******************************************************************************/
+    case NFCIP_CMD_ATR_RES:
+    case NFCIP_CMD_ATR_REQ:
+
+        rfalNfcDepSetNFCID(payloadBuf, gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen); /* NFCID */
+        txBufIt += RFAL_NFCDEP_NFCID3_LEN;
+
+        payloadBuf[txBufIt++] = gNfcip.cfg.did; /* DID   */
+        payloadBuf[txBufIt++] = gNfcip.cfg.bs; /* BS    */
+        payloadBuf[txBufIt++] = gNfcip.cfg.br; /* BR    */
+
+        if(cmd == NFCIP_CMD_ATR_RES) {
+            payloadBuf[txBufIt++] = gNfcip.cfg.to; /* ATR_RES[ TO ] */
+        }
+
+        if(gNfcip.cfg.gbLen > 0U) {
+            payloadBuf[txBufIt++] = nfcip_PPwGB(gNfcip.cfg.lr); /* PP signalling GB  */
+            ST_MEMCPY(
+                &payloadBuf[txBufIt], gNfcip.cfg.gb, gNfcip.cfg.gbLen); /* set General Bytes */
+            txBufIt += gNfcip.cfg.gbLen;
+        } else {
+            payloadBuf[txBufIt++] = rfalNfcDepLR2PP(gNfcip.cfg.lr); /* PP without GB     */
+        }
+
+        if((txBufIt + RFAL_NFCDEP_CMDTYPE_LEN + RFAL_NFCDEP_CMD_LEN) >
+           RFAL_NFCDEP_ATRREQ_MAX_LEN) /* Check max ATR length (ATR_REQ = ATR_RES)*/
+        {
+            return ERR_PARAM;
+        }
+        break;
+
+    /*******************************************************************************/
+    case NFCIP_CMD_WUP_REQ: /* ISO 18092 - 12.5.2.1 */
+
+        rfalNfcDepSetNFCID((payloadBuf), gNfcip.cfg.nfcid, gNfcip.cfg.nfcidLen); /* NFCID */
+        txBufIt += RFAL_NFCDEP_NFCID3_LEN;
+
+        *(--txBlock) = gNfcip.cfg.did; /* DID   */
+        break;
+
+    /*******************************************************************************/
+    case NFCIP_CMD_WUP_RES: /* ISO 18092 - 12.5.2.2 */
+    case NFCIP_CMD_PSL_REQ:
+    case NFCIP_CMD_PSL_RES:
+
+        *(--txBlock) = gNfcip.cfg.did; /* DID   */
+        break;
+
+    /*******************************************************************************/
+    case NFCIP_CMD_RLS_REQ:
+    case NFCIP_CMD_RLS_RES:
+    case NFCIP_CMD_DSL_REQ:
+    case NFCIP_CMD_DSL_RES:
+
+        /* Digital 1.0 - 14.8.1.1 & 14.9.1.1 & 14.10.1.1 Only add DID if not 0 */
+        if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+            *(--txBlock) = gNfcip.cfg.did; /* DID   */
+        }
+        break;
+
+    /*******************************************************************************/
+    case NFCIP_CMD_DEP_REQ:
+    case NFCIP_CMD_DEP_RES:
+
+        /* Compute optional PFB bits */
+        if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+            pfb |= NFCIP_PFB_DID_BIT;
+        }
+        if(gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) {
+            pfb |= NFCIP_PFB_NAD_BIT;
+        }
+        if((gNfcip.isTxChaining) && (nfcip_PFBisIPDU(pfb))) {
+            pfb |= NFCIP_PFB_MI_BIT;
+        }
+
+        /* Store PFB for future handling */
+        gNfcip.lastPFB = pfb; /* store PFB sent */
+
+        if(!nfcip_PFBisSATN(pfb)) {
+            gNfcip.lastPFBnATN = pfb; /* store last PFB different then ATN */
+        }
+
+        /* Add NAD if it is to be supported */
+        if(gNfcip.cfg.nad != RFAL_NFCDEP_NAD_NO) {
+            *(--txBlock) = gNfcip.cfg.nad; /* NAD   */
+        }
+
+        /* Digital 1.0 - 14.8.1.1 & 14.8.1.1 Only add DID if not 0 */
+        if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+            *(--txBlock) = gNfcip.cfg.did; /* DID   */
+        }
+
+        *(--txBlock) = pfb; /* PFB */
+
+        /* NCI 1.0 - Check if Empty frames are allowed */
+        if((paylLen == 0U) && nfcipIsEmptyDEPDisabled(gNfcip.cfg.oper) && nfcip_PFBisIPDU(pfb)) {
+            return ERR_PARAM;
+        }
+        break;
+
+    /*******************************************************************************/
+    default:
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /* Prepend Header                                                              */
+    /*******************************************************************************/
+    *(--txBlock) = (uint8_t)cmd; /* CMD     */
+    *(--txBlock) = (uint8_t)(nfcipCmdIsReq(cmd) ? NFCIP_REQ : NFCIP_RES); /* CMDType */
+
+    txBufIt += paylLen + (uint16_t)((uint32_t)payloadBuf -
+                                    (uint32_t)txBlock); /* Calculate overall buffer size */
+
+    if(txBufIt > gNfcip.fsc) /* Check if msg length violates the maximum payload size FSC */
+    {
+        return ERR_NOTSUPP;
+    }
+
+    /*******************************************************************************/
+    return nfcipDataTx(txBlock, txBufIt, fwt);
+}
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*******************************************************************************/
+static void nfcipConfig(const rfalNfcDepConfigs* cfg) {
+    if(cfg == NULL) {
+        return;
+    }
+
+    ST_MEMCPY(&gNfcip.cfg, cfg, sizeof(rfalNfcDepConfigs)); /* Copy given config to local       */
+
+    gNfcip.cfg.to =
+        MIN(RFAL_NFCDEP_WT_TRG_MAX, gNfcip.cfg.to); /* Ensure proper WT value           */
+    gNfcip.cfg.did = nfcip_DIDMax(gNfcip.cfg.did); /* Ensure proper DID value          */
+    gNfcip.fsc = rfalNfcDepLR2FS(gNfcip.cfg.lr); /* Calculate FSC based on given LR  */
+
+    gNfcip.state =
+        ((gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) ? NFCIP_ST_TARG_WAIT_ATR :
+                                                        NFCIP_ST_INIT_IDLE);
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipRun(uint16_t* outActRxLen, bool* outIsChaining) {
+    ReturnCode ret;
+
+    ret = ERR_SYNTAX;
+
+    nfcipLogD(" NFCIP Run() state: %d \r\n", gNfcip.state);
+
+    switch(gNfcip.state) {
+    /*******************************************************************************/
+    case NFCIP_ST_IDLE:
+    case NFCIP_ST_INIT_DEP_IDLE:
+    case NFCIP_ST_TARG_DEP_IDLE:
+    case NFCIP_ST_TARG_DEP_SLEEP:
+        return ERR_NONE;
+
+    /*******************************************************************************/
+    case NFCIP_ST_INIT_DEP_TX:
+
+        nfcipLogD(" NFCIP(I) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen);
+        ret = nfcipTx(
+            NFCIP_CMD_DEP_REQ,
+            gNfcip.txBuf,
+            &gNfcip.txBuf[gNfcip.txBufPaylPos],
+            gNfcip.txBufLen,
+            nfcip_PFBIPDU(gNfcip.pni),
+            (gNfcip.cfg.fwt + gNfcip.cfg.dFwt));
+
+        switch(ret) {
+        case ERR_NONE:
+            gNfcip.state = NFCIP_ST_INIT_DEP_RX;
+            break;
+
+        case ERR_PARAM:
+        default:
+            gNfcip.state = NFCIP_ST_INIT_DEP_IDLE;
+            return ret;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    case NFCIP_ST_INIT_DEP_RX: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        ret = nfcipDataRx(false);
+
+        if(ret != ERR_BUSY) {
+            ret = nfcipInitiatorHandleDEP(ret, *gNfcip.rxRcvdLen, outActRxLen, outIsChaining);
+        }
+
+        break;
+
+    /*******************************************************************************/
+    case NFCIP_ST_TARG_DEP_RTOX:
+
+        if(!nfcipTimerisExpired(gNfcip.RTOXTimer)) /* Do nothing until RTOX timer has expired */
+        {
+            return ERR_BUSY;
+        }
+
+        /* If we cannot send a RTOX raise a Timeout error so that we do not   
+             * hold the field On forever in AP2P                                  */
+        if(nfcipIsRTOXReqDisabled(gNfcip.cfg.oper)) {
+            /* We should reEnable Rx, and measure time between our field Off to 
+                 * either report link loss or recover               #287          */
+            nfcipLogI(" NFCIP(T) RTOX not sent due to config, NOT reenabling Rx \r\n");
+            return ERR_TIMEOUT;
+        }
+
+        if(gNfcip.cntRTOXRetrys++ >
+           RFAL_NFCDEP_MAX_RTOX_RETRYS) /* Check maximum consecutive RTOX requests */
+        {
+            return ERR_PROTO;
+        }
+
+        nfcipLogI(" NFCIP(T) RTOX sent \r\n");
+
+        gNfcip.lastRTOX =
+            nfcip_RTOXTargMax(gNfcip.cfg.to); /* Calculate requested RTOX value, and send it */
+        EXIT_ON_ERR(ret, nfcipDEPControlMsg(nfcip_PFBSPDU_TO(), gNfcip.lastRTOX));
+
+        /* Set waiting for RTOX Ack Flag */
+        gNfcip.isWait4RTOX = true;
+
+        gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* Go back to Rx to process RTOX ack       */
+        return ERR_BUSY;
+
+    /*******************************************************************************/
+    case NFCIP_ST_TARG_DEP_TX:
+
+        nfcipLogD(" NFCIP(T) Tx PNI: %d txLen: %d \r\n", gNfcip.pni, gNfcip.txBufLen);
+        ret = nfcipTx(
+            NFCIP_CMD_DEP_RES,
+            gNfcip.txBuf,
+            &gNfcip.txBuf[gNfcip.txBufPaylPos],
+            gNfcip.txBufLen,
+            nfcip_PFBIPDU(gNfcip.pni),
+            NFCIP_NO_FWT);
+
+        /* Clear flags */
+        gNfcip.isTxPending = false;
+        gNfcip.isWait4RTOX = false;
+
+        /* Digital 1.0 14.12.3.4 Increment the current PNI after Tx */
+        gNfcip.pni = nfcip_PNIInc(gNfcip.pni);
+
+        switch(ret) {
+        case ERR_NONE:
+            gNfcip.state = NFCIP_ST_TARG_DEP_RX; /* All OK, goto Rx state          */
+            break;
+
+        case ERR_PARAM:
+        default:
+            gNfcip.state = NFCIP_ST_TARG_DEP_IDLE; /* Upon Tx error, goto IDLE state */
+            return ret;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    case NFCIP_ST_TARG_DEP_RX: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        if(gNfcip.isReqPending) /* if already has Data should be from a DEP from nfcipTargetHandleActivation()  */
+        {
+            nfcipLogD(" NFCIP(T) Skipping Rx Using DEP from Activation \r\n");
+
+            gNfcip.isReqPending = false;
+            ret = ERR_NONE;
+        } else {
+            ret = nfcipDataRx(false);
+        }
+
+        if(ret != ERR_BUSY) {
+            ret = nfcipTargetHandleRX(ret, outActRxLen, outIsChaining);
+        }
+
+        break;
+
+    /*******************************************************************************/
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+void rfalNfcDepSetDeactivatingCallback(rfalNfcDepDeactCallback pFunc) {
+    gNfcip.isDeactivating = pFunc;
+}
+
+/*******************************************************************************/
+void rfalNfcDepInitialize(void) {
+    nfcipLogD(" NFCIP Ini() \r\n");
+
+    gNfcip.state = NFCIP_ST_IDLE;
+    gNfcip.isDeactivating = NULL;
+
+    gNfcip.isTxPending = false;
+    gNfcip.isWait4RTOX = false;
+    gNfcip.isReqPending = false;
+
+    gNfcip.cfg.oper =
+        (RFAL_NFCDEP_OPER_FULL_MI_DIS | RFAL_NFCDEP_OPER_EMPTY_DEP_EN | RFAL_NFCDEP_OPER_ATN_EN |
+         RFAL_NFCDEP_OPER_RTOX_REQ_EN);
+
+    gNfcip.cfg.did = RFAL_NFCDEP_DID_NO;
+    gNfcip.cfg.nad = RFAL_NFCDEP_NAD_NO;
+
+    gNfcip.cfg.br = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+    gNfcip.cfg.bs = RFAL_NFCDEP_Bx_NO_HIGH_BR;
+
+    gNfcip.cfg.lr = RFAL_NFCDEP_LR_254;
+    gNfcip.fsc = rfalNfcDepLR2FS(gNfcip.cfg.lr);
+
+    gNfcip.cfg.gbLen = 0;
+
+    gNfcip.cfg.fwt = RFAL_NFCDEP_MAX_FWT;
+    gNfcip.cfg.dFwt = RFAL_NFCDEP_MAX_FWT;
+
+    gNfcip.pni = 0;
+
+    /* Destroy any ongoing RTOX timer*/
+    nfcipTimerDestroy(gNfcip.RTOXTimer);
+    gNfcip.RTOXTimer = 0U;
+
+    gNfcip.PDUTxPos = 0;
+    gNfcip.PDURxPos = 0;
+    gNfcip.PDUParam.rxLen = NULL;
+    gNfcip.PDUParam.rxBuf = NULL;
+    gNfcip.PDUParam.txBuf = NULL;
+
+    nfcipClearCounters();
+}
+
+/*******************************************************************************/
+static void nfcipSetDEPParams(const rfalNfcDepDEPParams* DEPParams) {
+    nfcipLogD(" NFCIP SetDEP() txLen: %d \r\n", DEPParams->txBufLen);
+
+    gNfcip.isTxChaining = DEPParams->txChaining;
+    gNfcip.txBuf = DEPParams->txBuf;
+    gNfcip.rxBuf = DEPParams->rxBuf;
+    gNfcip.txBufLen = DEPParams->txBufLen;
+    gNfcip.rxBufLen = DEPParams->rxBufLen;
+    gNfcip.txBufPaylPos = DEPParams->txBufPaylPos;
+    gNfcip.rxBufPaylPos = DEPParams->rxBufPaylPos;
+
+    if(DEPParams->did != RFAL_NFCDEP_DID_KEEP) {
+        gNfcip.cfg.did = nfcip_DIDMax(DEPParams->did);
+    }
+
+    gNfcip.cfg.fwt = DEPParams->fwt;
+    gNfcip.cfg.dFwt = DEPParams->dFwt;
+    gNfcip.fsc = DEPParams->fsc;
+
+    if(gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) {
+        /* If there's any data to be sent go for Tx */
+        if(DEPParams->txBufLen > 0U) {
+            /* Ensure that an RTOX Ack is not being expected at moment */
+            if(!gNfcip.isWait4RTOX) {
+                gNfcip.state = NFCIP_ST_TARG_DEP_TX;
+                return;
+            } else {
+                /* If RTOX Ack is expected, signal a pending Tx to be transmitted right after */
+                gNfcip.isTxPending = true;
+                nfcipLogW(" NFCIP(T) Waiting RTOX, queueing outgoing DEP Block \r\n");
+            }
+        }
+
+        /*Digital 1.0  14.12.4.1 In target mode the first PDU MUST be sent by the Initiator */
+        gNfcip.state = NFCIP_ST_TARG_DEP_RX;
+        return;
+    }
+
+    /* New data TxRx request clear previous error counters for consecutive TxRx without reseting communication/protocol layer*/
+    nfcipClearCounters();
+
+    gNfcip.state = NFCIP_ST_INIT_DEP_TX;
+}
+
+/*******************************************************************************/
+bool rfalNfcDepTargetRcvdATR(void) {
+    return (
+        (gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) && nfcipIsTarget(gNfcip.state) &&
+        (gNfcip.state > NFCIP_ST_TARG_WAIT_ATR));
+}
+
+/*******************************************************************************/
+bool rfalNfcDepIsAtrReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid3) {
+    uint8_t msgIt;
+
+    msgIt = 0;
+
+    if((bufLen < RFAL_NFCDEP_ATRREQ_MIN_LEN) || (bufLen > RFAL_NFCDEP_ATRREQ_MAX_LEN)) {
+        return false;
+    }
+
+    if(buf[msgIt++] != NFCIP_REQ) {
+        return false;
+    }
+
+    if(buf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_REQ) {
+        return false;
+    }
+
+    /* Output NFID3 if requested */
+    if(nfcid3 != NULL) {
+        ST_MEMCPY(nfcid3, &buf[RFAL_NFCDEP_ATR_REQ_NFCID3_POS], RFAL_NFCDEP_NFCID3_LEN);
+    }
+
+    return true;
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipTargetHandleActivation(rfalNfcDepDevice* nfcDepDev, uint8_t* outBRS) {
+    ReturnCode ret;
+    uint8_t msgIt;
+    uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_PSLRES_LEN];
+
+    /*******************************************************************************/
+    /*  Check if we are in correct state                                           */
+    /*******************************************************************************/
+    if(gNfcip.state != NFCIP_ST_TARG_WAIT_ACTV) {
+        return ERR_WRONG_STATE;
+    }
+
+    /*******************************************************************************/
+    /*  Check required parameters                                                  */
+    /*******************************************************************************/
+    if(outBRS == NULL) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /*  Wait and process incoming cmd (PSL / DEP)                                  */
+    /*******************************************************************************/
+    ret = nfcipDataRx(false);
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    msgIt = 0;
+    *outBRS = RFAL_NFCDEP_BRS_MAINTAIN; /* set out BRS to be maintained */
+
+    msgIt++; /* Skip LEN byte                */
+
+    if(gNfcip.rxBuf[msgIt++] != NFCIP_REQ) {
+        return ERR_PROTO;
+    }
+
+    if(gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_PSL_REQ) {
+        msgIt++;
+
+        if(gNfcip.rxBuf[msgIt++] != gNfcip.cfg.did) /* Checking DID                 */
+        {
+            return ERR_PROTO;
+        }
+
+        nfcipLogI(" NFCIP(T) PSL REQ rcvd \r\n");
+
+        *outBRS = gNfcip.rxBuf[msgIt++]; /* assign output BRS value      */
+
+        /* Store FSL(LR) and update current config */
+        gNfcip.cfg.lr = (gNfcip.rxBuf[msgIt++] & RFAL_NFCDEP_LR_VAL_MASK);
+        gNfcip.fsc = rfalNfcDepLR2FS(gNfcip.cfg.lr);
+
+        /*******************************************************************************/
+        /* Update NFC-DDE Device info */
+        if(nfcDepDev != NULL) {
+            /* Update Bitrate info */
+            /* PRQA S 4342 2 # MISRA 10.5 - Layout of enum rfalBitRate and definition of rfalNfcDepBRS2DSI guarantee no invalid enum values to be created */
+            nfcDepDev->info.DSI = (rfalBitRate)rfalNfcDepBRS2DSI(
+                *outBRS); /* DSI codes the bit rate from Initiator to Target */
+            nfcDepDev->info.DRI = (rfalBitRate)rfalNfcDepBRS2DRI(
+                *outBRS); /* DRI codes the bit rate from Target to Initiator */
+
+            /* Update Length Reduction and Frame Size */
+            nfcDepDev->info.LR = gNfcip.cfg.lr;
+            nfcDepDev->info.FS = gNfcip.fsc;
+
+            /* Update PPi byte */
+            nfcDepDev->activation.Initiator.ATR_REQ.PPi &= ~RFAL_NFCDEP_PP_LR_MASK;
+            nfcDepDev->activation.Initiator.ATR_REQ.PPi |= rfalNfcDepLR2PP(gNfcip.cfg.lr);
+        }
+
+        rfalSetBitRate(RFAL_BR_KEEP, gNfcip.nfcDepDev->info.DSI);
+
+        EXIT_ON_ERR(ret, nfcipTx(NFCIP_CMD_PSL_RES, txBuf, NULL, 0, 0, NFCIP_NO_FWT));
+    } else {
+        if(gNfcip.rxBuf[msgIt] == (uint8_t)NFCIP_CMD_DEP_REQ) {
+            msgIt++;
+
+            /*******************************************************************************/
+            /* Digital 1.0 14.12.3.1 PNI must be initialized to 0 */
+            if(nfcip_PBF_PNI(gNfcip.rxBuf[msgIt]) != 0U) {
+                return ERR_PROTO;
+            }
+
+            /*******************************************************************************/
+            /* Digital 1.0 14.8.2.1  check if DID is expected and match -> Protocol Error  */
+            if(nfcip_PFBhasDID(gNfcip.rxBuf[msgIt])) {
+                if(gNfcip.rxBuf[++msgIt] != gNfcip.cfg.did) {
+                    return ERR_PROTO;
+                }
+            } else if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) /* DID expected but not rcv */
+            {
+                return ERR_PROTO;
+            } else {
+                /* MISRA 15.7 - Empty else */
+            }
+        }
+
+        /* Signal Request pending to be digested on normal Handling (DEP_REQ, DSL_REQ, RLS_REQ) */
+        gNfcip.isReqPending = true;
+    }
+
+    gNfcip.state = NFCIP_ST_TARG_DEP_RX;
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalNfcDepATR(const rfalNfcDepAtrParam* param, rfalNfcDepAtrRes* atrRes, uint8_t* atrResLen) {
+    ReturnCode ret;
+    rfalNfcDepConfigs cfg;
+    uint16_t rxLen;
+    uint8_t msgIt;
+    uint8_t txBuf[RFAL_NFCDEP_ATRREQ_MAX_LEN];
+    uint8_t rxBuf[NFCIP_ATRRES_BUF_LEN];
+
+    if((param == NULL) || (atrRes == NULL) || (atrResLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /* Configure NFC-DEP layer                                                     */
+    /*******************************************************************************/
+
+    cfg.did = param->DID;
+    cfg.nad = param->NAD;
+    cfg.fwt = RFAL_NFCDEP_MAX_FWT;
+    cfg.dFwt = RFAL_NFCDEP_MAX_FWT;
+    cfg.br = param->BR;
+    cfg.bs = param->BS;
+    cfg.lr = param->LR;
+    cfg.to = RFAL_NFCDEP_WT_TRG_MAX; /* Not used in Initiator mode */
+
+    cfg.gbLen = param->GBLen;
+    if(cfg.gbLen > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(cfg.gb, param->GB, cfg.gbLen);
+    }
+
+    cfg.nfcidLen = param->nfcidLen;
+    if(cfg.nfcidLen > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(cfg.nfcid, param->nfcid, cfg.nfcidLen);
+    }
+
+    cfg.role = RFAL_NFCDEP_ROLE_INITIATOR;
+    cfg.oper = param->operParam;
+    cfg.commMode = param->commMode;
+
+    rfalNfcDepInitialize();
+    nfcipConfig(&cfg);
+
+    /*******************************************************************************/
+    /* Send ATR_REQ                                                                */
+    /*******************************************************************************/
+
+    EXIT_ON_ERR(
+        ret,
+        nfcipTxRx(
+            NFCIP_CMD_ATR_REQ,
+            txBuf,
+            nfcipRWTActivation(),
+            NULL,
+            0,
+            rxBuf,
+            NFCIP_ATRRES_BUF_LEN,
+            &rxLen));
+
+    /*******************************************************************************/
+    /* ATR sent, check response                                                    */
+    /*******************************************************************************/
+    msgIt = 0;
+    rxLen = ((uint16_t)rxBuf[msgIt++] - RFAL_NFCDEP_LEN_LEN); /* use LEN byte             */
+
+    if((rxLen < RFAL_NFCDEP_ATRRES_MIN_LEN) ||
+       (rxLen > RFAL_NFCDEP_ATRRES_MAX_LEN)) /* Checking length: ATR_RES */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[msgIt++] != NFCIP_RES) /* Checking if is a response*/
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_ATR_RES) /* Checking if is a ATR RES */
+    {
+        return ERR_PROTO;
+    }
+
+    ST_MEMCPY((uint8_t*)atrRes, (rxBuf + RFAL_NFCDEP_LEN_LEN), rxLen);
+    *atrResLen = (uint8_t)rxLen;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepPSL(uint8_t BRS, uint8_t FSL) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    uint8_t msgIt;
+    uint8_t txBuf[NFCIP_PSLREQ_LEN + NFCIP_PSLPAY_LEN];
+    uint8_t rxBuf[NFCIP_PSLRES_LEN];
+
+    msgIt = NFCIP_PSLREQ_LEN;
+
+    txBuf[msgIt++] = BRS;
+    txBuf[msgIt++] = FSL;
+
+    /*******************************************************************************/
+    /* Send PSL REQ and wait for response                                          */
+    /*******************************************************************************/
+    EXIT_ON_ERR(
+        ret,
+        nfcipTxRx(
+            NFCIP_CMD_PSL_REQ,
+            txBuf,
+            nfcipRWTActivation(),
+            &txBuf[NFCIP_PSLREQ_LEN],
+            (msgIt - NFCIP_PSLREQ_LEN),
+            rxBuf,
+            NFCIP_PSLRES_LEN,
+            &rxLen));
+
+    /*******************************************************************************/
+    /* PSL sent, check response                                                    */
+    /*******************************************************************************/
+    msgIt = 0;
+    rxLen = (uint16_t)(rxBuf[msgIt++]); /* use LEN byte                   */
+
+    if(rxLen < NFCIP_PSLRES_LEN) /* Checking length: LEN + RLS_RES */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[msgIt++] != NFCIP_RES) /* Checking if is a response      */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[msgIt++] != (uint8_t)NFCIP_CMD_PSL_RES) /* Checking if is a PSL RES       */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[msgIt++] != gNfcip.cfg.did) /* Checking DID                   */
+    {
+        return ERR_PROTO;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepDSL(void) {
+    ReturnCode ret;
+    uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_DSLREQ_LEN];
+    uint8_t rxBuf[NFCIP_DSLRES_LEN];
+    uint8_t rxMsgIt;
+    uint16_t rxLen = 0;
+
+    if(gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) {
+        return ERR_NONE; /* Target has no deselect procedure */
+    }
+
+    /* Repeating a DSL REQ is optional, not doing it */
+    EXIT_ON_ERR(
+        ret,
+        nfcipTxRx(
+            NFCIP_CMD_DSL_REQ,
+            txBuf,
+            nfcipRWTActivation(),
+            NULL,
+            0,
+            rxBuf,
+            (uint16_t)sizeof(rxBuf),
+            &rxLen));
+
+    /*******************************************************************************/
+    rxMsgIt = 0;
+
+    if(rxBuf[rxMsgIt++] < NFCIP_DSLRES_MIN) /* Checking length: LEN + DSL_RES */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[rxMsgIt++] != NFCIP_RES) /* Checking if is a response      */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_DSL_RES) /* Checking if is DSL RES          */
+    {
+        return ERR_PROTO;
+    }
+
+    if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+        if(rxBuf[rxMsgIt++] != gNfcip.cfg.did) {
+            return ERR_PROTO;
+        }
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepRLS(void) {
+    ReturnCode ret;
+    uint8_t txBuf[RFAL_NFCDEP_HEADER_PAD + NFCIP_RLSREQ_LEN];
+    uint8_t rxBuf[NFCIP_RLSRES_LEN];
+    uint8_t rxMsgIt;
+    uint16_t rxLen = 0;
+
+    if(gNfcip.cfg.role == RFAL_NFCDEP_ROLE_TARGET) /* Target has no release procedure */
+    {
+        return ERR_NONE;
+    }
+
+    /* Repeating a RLS REQ is optional, not doing it */
+    EXIT_ON_ERR(
+        ret,
+        nfcipTxRx(
+            NFCIP_CMD_RLS_REQ,
+            txBuf,
+            nfcipRWTActivation(),
+            NULL,
+            0,
+            rxBuf,
+            (uint16_t)sizeof(rxBuf),
+            &rxLen));
+
+    /*******************************************************************************/
+    rxMsgIt = 0;
+
+    if(rxBuf[rxMsgIt++] < NFCIP_RLSRES_MIN) /* Checking length: LEN + RLS_RES */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[rxMsgIt++] != NFCIP_RES) /* Checking if is a response      */
+    {
+        return ERR_PROTO;
+    }
+
+    if(rxBuf[rxMsgIt++] != (uint8_t)NFCIP_CMD_RLS_RES) /* Checking if is RLS RES         */
+    {
+        return ERR_PROTO;
+    }
+
+    if(gNfcip.cfg.did != RFAL_NFCDEP_DID_NO) {
+        if(rxBuf[rxMsgIt++] != gNfcip.cfg.did) {
+            return ERR_PROTO;
+        }
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepInitiatorHandleActivation(
+    rfalNfcDepAtrParam* param,
+    rfalBitRate desiredBR,
+    rfalNfcDepDevice* nfcDepDev) {
+    ReturnCode ret;
+    uint8_t maxRetyrs;
+    uint8_t PSL_BRS;
+    uint8_t PSL_FSL;
+    bool sendPSL;
+
+    if((param == NULL) || (nfcDepDev == NULL)) {
+        return ERR_PARAM;
+    }
+
+    param->NAD = RFAL_NFCDEP_NAD_NO; /* Digital 1.1  16.6.2.9  Initiator SHALL NOT use NAD */
+    maxRetyrs = NFCIP_ATR_RETRY_MAX;
+
+    /*******************************************************************************/
+    /* Send ATR REQ and wait for response                                          */
+    /*******************************************************************************/
+    do { /* Upon transmission error ATR REQ should be retried */
+
+        ret = rfalNfcDepATR(
+            param,
+            &nfcDepDev->activation.Target.ATR_RES,
+            &nfcDepDev->activation.Target.ATR_RESLen);
+
+        if(nfcipIsTransmissionError(ret)) {
+            continue;
+        }
+        break;
+    } while((maxRetyrs--) != 0U);
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /*******************************************************************************/
+    /* Compute NFC-DEP device with ATR_RES                                         */
+    /*******************************************************************************/
+    nfcDepDev->info.GBLen = (nfcDepDev->activation.Target.ATR_RESLen - RFAL_NFCDEP_ATRRES_MIN_LEN);
+    nfcDepDev->info.DID = nfcDepDev->activation.Target.ATR_RES.DID;
+    nfcDepDev->info.NAD =
+        RFAL_NFCDEP_NAD_NO; /* Digital 1.1  16.6.3.11 Initiator SHALL ignore b1 of PPt */
+    nfcDepDev->info.LR = rfalNfcDepPP2LR(nfcDepDev->activation.Target.ATR_RES.PPt);
+    nfcDepDev->info.FS = rfalNfcDepLR2FS(nfcDepDev->info.LR);
+    nfcDepDev->info.WT = (nfcDepDev->activation.Target.ATR_RES.TO & RFAL_NFCDEP_WT_MASK);
+    nfcDepDev->info.FWT = rfalNfcDepCalculateRWT(nfcDepDev->info.WT);
+    nfcDepDev->info.dFWT = RFAL_NFCDEP_WT_DELTA;
+
+    rfalGetBitRate(&nfcDepDev->info.DSI, &nfcDepDev->info.DRI);
+
+    /*******************************************************************************/
+    /* Check if a PSL needs to be sent                                                */
+    /*******************************************************************************/
+    sendPSL = false;
+    PSL_BRS = rfalNfcDepDx2BRS(
+        nfcDepDev->info.DSI); /* Set current bit rate divisor on both directions  */
+    PSL_FSL = nfcDepDev->info.LR; /* Set current Frame Size                           */
+
+    /* Activity 1.0  9.4.4.15 & 9.4.6.3   NFC-DEP Activation PSL
+    *  Activity 2.0  9.4.4.17 & 9.4.6.6   NFC-DEP Activation PSL
+    *     
+    *  PSL_REQ shall only be sent if desired bit rate is different from current (Activity 1.0)
+    *  PSL_REQ shall be sent to update LR or bit rate  (Activity 2.0)
+    * */
+
+#if 0 /* PSL due to LR is disabled, can be enabled if desired*/
+    /*******************************************************************************/
+    /* Check Frame Size                                                            */
+    /*******************************************************************************/
+    if( gNfcip.cfg.lr < nfcDepDev->info.LR )  /* If our Length reduction is smaller */   
+    {
+        sendPSL = true;
+        
+        nfcDepDev->info.LR   = MIN( nfcDepDev->info.LR, gNfcip.cfg.lr );
+        
+        gNfcip.cfg.lr = nfcDepDev->info.LR;                /* Update nfcip LR  to be used */
+        gNfcip.fsc    = rfalNfcDepLR2FS( gNfcip.cfg.lr );  /* Update nfcip FSC to be used */     
+        
+        PSL_FSL       = gNfcip.cfg.lr;                     /* Set LR to be sent           */
+        
+        nfcipLogI( " NFCIP(I) Frame Size differ, PSL new fsc: %d \r\n", gNfcip.fsc );
+    }
+#endif
+
+    /*******************************************************************************/
+    /* Check Baud rates                                                            */
+    /*******************************************************************************/
+    if((nfcDepDev->info.DSI != desiredBR) &&
+       (desiredBR != RFAL_BR_KEEP)) /* if desired BR is different    */
+    {
+        if(nfcipDxIsSupported(
+               (uint8_t)desiredBR,
+               nfcDepDev->activation.Target.ATR_RES.BRt,
+               nfcDepDev->activation.Target.ATR_RES
+                   .BSt)) /* if desired BR is supported     */ /* MISRA 13.5 */
+        {
+            sendPSL = true;
+            PSL_BRS = rfalNfcDepDx2BRS(desiredBR);
+
+            nfcipLogI(" NFCIP(I) BR differ, PSL BR: 0x%02X \r\n", PSL_BRS);
+        }
+    }
+
+    /*******************************************************************************/
+    if(sendPSL) {
+        /*******************************************************************************/
+        /* Send PSL REQ and wait for response                                          */
+        /*******************************************************************************/
+        EXIT_ON_ERR(ret, rfalNfcDepPSL(PSL_BRS, PSL_FSL));
+
+        /* Check if bit rate has been changed */
+        if(nfcDepDev->info.DSI != desiredBR) {
+            /* Check if device was in Passive NFC-A and went to higher bit rates, use NFC-F */
+            if((nfcDepDev->info.DSI == RFAL_BR_106) &&
+               (gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_PASSIVE)) {
+#if RFAL_FEATURE_NFCF
+                /* If Passive initialize NFC-F module */
+                rfalNfcfPollerInitialize(desiredBR);
+#else /* RFAL_FEATURE_NFCF */
+                return ERR_NOTSUPP;
+#endif /* RFAL_FEATURE_NFCF */
+            }
+
+            nfcDepDev->info.DRI = desiredBR; /* DSI Bit Rate coding from Initiator  to Target  */
+            nfcDepDev->info.DSI = desiredBR; /* DRI Bit Rate coding from Target to Initiator   */
+
+            rfalSetBitRate(nfcDepDev->info.DSI, nfcDepDev->info.DRI);
+        }
+
+        return ERR_NONE; /* PSL has been sent    */
+    }
+
+    return ERR_NONE; /* No PSL has been sent */
+}
+
+/*******************************************************************************/
+uint32_t rfalNfcDepCalculateRWT(uint8_t wt) {
+    /* Digital 1.0  14.6.3.8  &  Digital 1.1  16.6.3.9     */
+    /* Digital 1.1  16.6.3.9 treat all RFU values as WT=14 */
+    uint8_t responseWaitTime = MIN(RFAL_NFCDEP_WT_INI_MAX, wt);
+
+    return (uint32_t)rfalNfcDepWT2RWT(responseWaitTime);
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipDataTx(uint8_t* txBuf, uint16_t txBufLen, uint32_t fwt) {
+    return rfalTransceiveBlockingTx(
+        txBuf,
+        txBufLen,
+        gNfcip.rxBuf,
+        gNfcip.rxBufLen,
+        gNfcip.rxRcvdLen,
+        (RFAL_TXRX_FLAGS_DEFAULT | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_ON),
+        ((fwt == NFCIP_NO_FWT) ? RFAL_FWT_NONE : fwt));
+}
+
+/*******************************************************************************/
+static ReturnCode nfcipDataRx(bool blocking) {
+    ReturnCode ret;
+
+    /* Perform Rx either blocking or non-blocking */
+    if(blocking) {
+        ret = rfalTransceiveBlockingRx();
+    } else {
+        ret = rfalGetTransceiveStatus();
+    }
+
+    if(ret != ERR_BUSY) {
+        if(gNfcip.rxRcvdLen != NULL) {
+            (*gNfcip.rxRcvdLen) = rfalConvBitsToBytes(*gNfcip.rxRcvdLen);
+
+            if((ret == ERR_NONE) && (gNfcip.rxBuf != NULL)) {
+                /* Digital 1.1  16.4.1.3 - Length byte LEN SHALL have a value between 3 and 255 -> otherwise treat as Transmission Error *
+                 *                       - Ensure that actual received and frame length do match, otherwise treat as Transmission error  */
+                if((*gNfcip.rxRcvdLen != (uint16_t)*gNfcip.rxBuf) ||
+                   (*gNfcip.rxRcvdLen < RFAL_NFCDEP_LEN_MIN) ||
+                   (*gNfcip.rxRcvdLen > RFAL_NFCDEP_LEN_MAX)) {
+                    return ERR_FRAMING;
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepListenStartActivation(
+    const rfalNfcDepTargetParam* param,
+    const uint8_t* atrReq,
+    uint16_t atrReqLength,
+    rfalNfcDepListenActvParam rxParam) {
+    ReturnCode ret;
+    rfalNfcDepConfigs cfg;
+
+    if((param == NULL) || (atrReq == NULL) || (rxParam.rxLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /*  Check whether is a valid ATR_REQ Compute NFC-DEP device                    */
+    if(!rfalNfcDepIsAtrReq(atrReq, atrReqLength, NULL)) {
+        return ERR_PARAM;
+    }
+
+    rxParam.nfcDepDev->activation.Initiator.ATR_REQLen =
+        (uint8_t)atrReqLength; /* nfcipIsAtrReq() is already checking Min and Max buffer lengths */
+    if(atrReqLength > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(
+            (uint8_t*)&rxParam.nfcDepDev->activation.Initiator.ATR_REQ, atrReq, atrReqLength);
+    }
+
+    rxParam.nfcDepDev->info.GBLen = (uint8_t)(atrReqLength - RFAL_NFCDEP_ATRREQ_MIN_LEN);
+    rxParam.nfcDepDev->info.DID = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID;
+    rxParam.nfcDepDev->info.NAD =
+        RFAL_NFCDEP_NAD_NO; /* Digital 1.1  16.6.2.9  Initiator SHALL NOT use NAD */
+    rxParam.nfcDepDev->info.LR =
+        rfalNfcDepPP2LR(rxParam.nfcDepDev->activation.Initiator.ATR_REQ.PPi);
+    rxParam.nfcDepDev->info.FS = rfalNfcDepLR2FS(rxParam.nfcDepDev->info.LR);
+    rxParam.nfcDepDev->info.WT = 0;
+    rxParam.nfcDepDev->info.FWT = NFCIP_NO_FWT;
+    rxParam.nfcDepDev->info.dFWT = NFCIP_NO_FWT;
+
+    rfalGetBitRate(&rxParam.nfcDepDev->info.DSI, &rxParam.nfcDepDev->info.DRI);
+
+    /* Store Device Info location, updated upon a PSL  */
+    gNfcip.nfcDepDev = rxParam.nfcDepDev;
+
+    /*******************************************************************************/
+    cfg.did = rxParam.nfcDepDev->activation.Initiator.ATR_REQ.DID;
+    cfg.nad = RFAL_NFCDEP_NAD_NO;
+
+    cfg.fwt = RFAL_NFCDEP_MAX_FWT;
+    cfg.dFwt = RFAL_NFCDEP_MAX_FWT;
+
+    cfg.br = param->brt;
+    cfg.bs = param->bst;
+
+    cfg.lr = rfalNfcDepPP2LR(param->ppt);
+
+    cfg.gbLen = param->GBtLen;
+    if(cfg.gbLen > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(cfg.gb, param->GBt, cfg.gbLen);
+    }
+
+    cfg.nfcidLen = RFAL_NFCDEP_NFCID3_LEN;
+    ST_MEMCPY(cfg.nfcid, param->nfcid3, RFAL_NFCDEP_NFCID3_LEN);
+
+    cfg.to = param->to;
+
+    cfg.role = RFAL_NFCDEP_ROLE_TARGET;
+    cfg.oper = param->operParam;
+    cfg.commMode = param->commMode;
+
+    rfalNfcDepInitialize();
+    nfcipConfig(&cfg);
+
+    /*******************************************************************************/
+    /*  Reply with ATR RES to Initiator                                            */
+    /*******************************************************************************/
+    gNfcip.rxBuf = (uint8_t*)rxParam.rxBuf;
+    gNfcip.rxBufLen = sizeof(rfalNfcDepBufFormat);
+    gNfcip.rxRcvdLen = rxParam.rxLen;
+    gNfcip.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN;
+    gNfcip.isChaining = rxParam.isRxChaining;
+    gNfcip.txBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN;
+
+    EXIT_ON_ERR(ret, nfcipTx(NFCIP_CMD_ATR_RES, (uint8_t*)gNfcip.rxBuf, NULL, 0, 0, NFCIP_NO_FWT));
+
+    gNfcip.state = NFCIP_ST_TARG_WAIT_ACTV;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepListenGetActivationStatus(void) {
+    ReturnCode err;
+    uint8_t BRS;
+
+    BRS = RFAL_NFCDEP_BRS_MAINTAIN;
+
+    err = nfcipTargetHandleActivation(gNfcip.nfcDepDev, &BRS);
+
+    switch(err) {
+    case ERR_NONE:
+
+        if(BRS != RFAL_NFCDEP_BRS_MAINTAIN) {
+            /* DSI codes the bit rate from Initiator to Target */
+            /* DRI codes the bit rate from Target to Initiator */
+
+            if(gNfcip.cfg.commMode == RFAL_NFCDEP_COMM_ACTIVE) {
+                EXIT_ON_ERR(
+                    err,
+                    rfalSetMode(
+                        RFAL_MODE_LISTEN_ACTIVE_P2P,
+                        gNfcip.nfcDepDev->info.DRI,
+                        gNfcip.nfcDepDev->info.DSI));
+            } else {
+                EXIT_ON_ERR(
+                    err,
+                    rfalSetMode(
+                        ((RFAL_BR_106 == gNfcip.nfcDepDev->info.DRI) ? RFAL_MODE_LISTEN_NFCA :
+                                                                       RFAL_MODE_LISTEN_NFCF),
+                        gNfcip.nfcDepDev->info.DRI,
+                        gNfcip.nfcDepDev->info.DSI));
+            }
+        }
+        break;
+
+    case ERR_BUSY:
+        // do nothing
+        break;
+
+    case ERR_PROTO:
+    default:
+        // re-enable receiving of data
+        nfcDepReEnableRx(gNfcip.rxBuf, gNfcip.rxBufLen, gNfcip.rxRcvdLen);
+        break;
+    }
+
+    return err;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepStartTransceive(const rfalNfcDepTxRxParam* param) {
+    rfalNfcDepDEPParams nfcDepParams;
+
+    nfcDepParams.txBuf = (uint8_t*)param->txBuf;
+    nfcDepParams.txBufLen = param->txBufLen;
+    nfcDepParams.txChaining = param->isTxChaining;
+    nfcDepParams.txBufPaylPos =
+        RFAL_NFCDEP_DEPREQ_HEADER_LEN; /* position in txBuf where actual outgoing data is located */
+    nfcDepParams.did = RFAL_NFCDEP_DID_KEEP;
+    nfcDepParams.rxBufPaylPos = RFAL_NFCDEP_DEPREQ_HEADER_LEN;
+    nfcDepParams.rxBuf = (uint8_t*)param->rxBuf;
+    nfcDepParams.rxBufLen = sizeof(rfalNfcDepBufFormat);
+    nfcDepParams.fsc = param->FSx;
+    nfcDepParams.fwt = param->FWT;
+    nfcDepParams.dFwt = param->dFWT;
+
+    gNfcip.rxRcvdLen = param->rxLen;
+    gNfcip.isChaining = param->isRxChaining;
+
+    nfcipSetDEPParams(&nfcDepParams);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepGetTransceiveStatus(void) {
+    return nfcipRun(gNfcip.rxRcvdLen, gNfcip.isChaining);
+}
+
+/*******************************************************************************/
+static void rfalNfcDepPdu2BLockParam(
+    rfalNfcDepPduTxRxParam pduParam,
+    rfalNfcDepTxRxParam* blockParam,
+    uint16_t txPos,
+    uint16_t rxPos) {
+    uint16_t maxInfLen;
+
+    NO_WARNING(rxPos); /* Keep this param for future use */
+
+    blockParam->DID = pduParam.DID;
+    blockParam->FSx = pduParam.FSx;
+    blockParam->FWT = pduParam.FWT;
+    blockParam->dFWT = pduParam.dFWT;
+
+    /* Calculate max INF/Payload to be sent to other device */
+    maxInfLen = (blockParam->FSx - (RFAL_NFCDEP_HEADER + RFAL_NFCDEP_DEP_PFB_LEN));
+    maxInfLen += ((blockParam->DID != RFAL_NFCDEP_DID_NO) ? RFAL_NFCDEP_DID_LEN : 0U);
+
+    if((pduParam.txBufLen - txPos) > maxInfLen) {
+        blockParam->isTxChaining = true;
+        blockParam->txBufLen = maxInfLen;
+    } else {
+        blockParam->isTxChaining = false;
+        blockParam->txBufLen = (pduParam.txBufLen - txPos);
+    }
+
+    /* TxBuf is moved to the beginning for every Block */
+    blockParam->txBuf =
+        (rfalNfcDepBufFormat*)pduParam
+            .txBuf; /*  PRQA S 0310 # MISRA 11.3 - Intentional safe cast to avoiding large buffer duplication */
+    blockParam->rxBuf =
+        pduParam
+            .tmpBuf; /* Simply using the pdu buffer is not possible because of current ACK handling */
+    blockParam->isRxChaining = &gNfcip.isPDURxChaining;
+    blockParam->rxLen = pduParam.rxLen;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepStartPduTransceive(rfalNfcDepPduTxRxParam param) {
+    rfalNfcDepTxRxParam txRxParam;
+
+    /* Initialize and store APDU context */
+    gNfcip.PDUParam = param;
+    gNfcip.PDUTxPos = 0;
+    gNfcip.PDURxPos = 0;
+
+    /* Convert PDU TxRxParams to Block TxRxParams */
+    rfalNfcDepPdu2BLockParam(gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos);
+
+    return rfalNfcDepStartTransceive(&txRxParam);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcDepGetPduTransceiveStatus(void) {
+    ReturnCode ret;
+    rfalNfcDepTxRxParam txRxParam;
+
+    ret = rfalNfcDepGetTransceiveStatus();
+    switch(ret) {
+    /*******************************************************************************/
+    case ERR_NONE:
+
+        /* Check if we are still doing chaining on Tx */
+        if(gNfcip.isTxChaining) {
+            /* Add already Tx bytes */
+            gNfcip.PDUTxPos += gNfcip.txBufLen;
+
+            /* Convert APDU TxRxParams to I-Block TxRxParams */
+            rfalNfcDepPdu2BLockParam(
+                gNfcip.PDUParam, &txRxParam, gNfcip.PDUTxPos, gNfcip.PDURxPos);
+
+            if(txRxParam.txBufLen > 0U) /* MISRA 21.18 */
+            {
+                /* Move next Block to beginning of APDU Tx buffer */
+                ST_MEMCPY(
+                    gNfcip.PDUParam.txBuf->pdu,
+                    &gNfcip.PDUParam.txBuf->pdu[gNfcip.PDUTxPos],
+                    txRxParam.txBufLen);
+            }
+
+            EXIT_ON_ERR(ret, rfalNfcDepStartTransceive(&txRxParam));
+            return ERR_BUSY;
+        }
+
+        /* PDU TxRx is done */
+        /* fall through */
+
+    /*******************************************************************************/
+    case ERR_AGAIN: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* Check if no PDU transceive has been started before (data from rfalNfcDepListenStartActivation) */
+        if(gNfcip.PDUParam.rxLen == NULL) {
+            /* In Listen mode first chained packet cannot be retrieved via APDU interface */
+            if(ret == ERR_AGAIN) {
+                return ERR_NOTSUPP;
+            }
+
+            /* TxRx is complete and full data is already available */
+            return ERR_NONE;
+        }
+
+        if((*gNfcip.PDUParam.rxLen) > 0U) /* MISRA 21.18 */
+        {
+            /* Ensure that data in tmpBuf still fits into PDU buffer */
+            if((uint16_t)((uint16_t)gNfcip.PDURxPos + (*gNfcip.PDUParam.rxLen)) >
+               RFAL_FEATURE_NFC_DEP_PDU_MAX_LEN) {
+                return ERR_NOMEM;
+            }
+
+            /* Copy chained packet from tmp buffer to PDU buffer */
+            ST_MEMCPY(
+                &gNfcip.PDUParam.rxBuf->pdu[gNfcip.PDURxPos],
+                gNfcip.PDUParam.tmpBuf->inf,
+                *gNfcip.PDUParam.rxLen);
+            gNfcip.PDURxPos += *gNfcip.PDUParam.rxLen;
+        }
+
+        /* Update output param rxLen */
+        *gNfcip.PDUParam.rxLen = gNfcip.PDURxPos;
+
+        /* Wait for following Block or PDU TxRx is done */
+        return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);
+
+    /*******************************************************************************/
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFC_DEP */

+ 891 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfca.c

@@ -0,0 +1,891 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfca.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides several NFC-A convenience methods and definitions
+ *  
+ *  It provides a Poller (ISO14443A PCD) interface and as well as 
+ *  some NFC-A Listener (ISO14443A PICC) helpers.
+ *
+ *  The definitions and helpers methods provided by this module are only
+ *  up to ISO14443-3 layer
+ *  
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfca.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFCA
+#define RFAL_FEATURE_NFCA false /* NFC-A module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_NFCA
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCA_SLP_FWT \
+    rfalConvMsTo1fc(1) /*!< Check 1ms for any modulation  ISO14443-3 6.4.3   */
+#define RFAL_NFCA_SLP_CMD 0x50U /*!< SLP cmd (byte1)    Digital 1.1  6.9.1 & Table 20 */
+#define RFAL_NFCA_SLP_BYTE2 0x00U /*!< SLP byte2          Digital 1.1  6.9.1 & Table 20 */
+#define RFAL_NFCA_SLP_CMD_POS 0U /*!< SLP cmd position   Digital 1.1  6.9.1 & Table 20 */
+#define RFAL_NFCA_SLP_BYTE2_POS 1U /*!< SLP byte2 position Digital 1.1  6.9.1 & Table 20 */
+
+#define RFAL_NFCA_SDD_CT 0x88U /*!< Cascade Tag value Digital 1.1 6.7.2              */
+#define RFAL_NFCA_SDD_CT_LEN 1U /*!< Cascade Tag length                               */
+
+#define RFAL_NFCA_SLP_REQ_LEN 2U /*!< SLP_REQ length                                   */
+
+#define RFAL_NFCA_SEL_CMD_LEN 1U /*!< SEL_CMD length                                   */
+#define RFAL_NFCA_SEL_PAR_LEN 1U /*!< SEL_PAR length                                   */
+#define RFAL_NFCA_SEL_SELPAR \
+    rfalNfcaSelPar(7U, 0U) /*!< SEL_PAR on Select is always with 4 data/nfcid    */
+#define RFAL_NFCA_BCC_LEN 1U /*!< BCC length                                       */
+
+#define RFAL_NFCA_SDD_REQ_LEN \
+    (RFAL_NFCA_SEL_CMD_LEN + RFAL_NFCA_SEL_PAR_LEN) /*!< SDD_REQ length       */
+#define RFAL_NFCA_SDD_RES_LEN \
+    (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_BCC_LEN) /*!< SDD_RES length       */
+
+#define RFAL_NFCA_T_RETRANS 5U /*!< t RETRANSMISSION [3, 33]ms   EMVCo 2.6  A.5      */
+#define RFAL_NFCA_N_RETRANS 2U /*!< Number of retries            EMVCo 2.6  9.6.1.3  */
+
+/*! SDD_REQ (Select) Cascade Levels  */
+enum {
+    RFAL_NFCA_SEL_CASCADE_L1 = 0, /*!< SDD_REQ Cascade Level 1 */
+    RFAL_NFCA_SEL_CASCADE_L2 = 1, /*!< SDD_REQ Cascade Level 2 */
+    RFAL_NFCA_SEL_CASCADE_L3 = 2 /*!< SDD_REQ Cascade Level 3 */
+};
+
+/*! SDD_REQ (Select) request Cascade Level command   Digital 1.1 Table 15 */
+enum {
+    RFAL_NFCA_CMD_SEL_CL1 = 0x93, /*!< SDD_REQ command Cascade Level 1 */
+    RFAL_NFCA_CMD_SEL_CL2 = 0x95, /*!< SDD_REQ command Cascade Level 2 */
+    RFAL_NFCA_CMD_SEL_CL3 = 0x97, /*!< SDD_REQ command Cascade Level 3 */
+};
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+#define rfalNfcaSelPar(nBy, nbi)  \
+    (uint8_t)(                    \
+        (((nBy) << 4U) & 0xF0U) | \
+        ((nbi) & 0x0FU)) /*!< Calculates SEL_PAR with the bytes/bits to be sent */
+#define rfalNfcaCLn2SELCMD(cl)             \
+    (uint8_t)(                             \
+        (uint8_t)(RFAL_NFCA_CMD_SEL_CL1) + \
+        (2U * (cl))) /*!< Calculates SEL_CMD with the given cascade level   */
+#define rfalNfcaNfcidLen2CL(len) \
+    ((len) / 5U) /*!< Calculates cascade level by the NFCID length      */
+#define rfalNfcaRunBlocking(e, fn) \
+    do {                           \
+        (e) = (fn);                \
+        rfalWorker();              \
+    } while((e) == ERR_BUSY) /*!< Macro used for the blocking methods               */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Colission Resolution states */
+typedef enum {
+    RFAL_NFCA_CR_IDLE, /*!< IDLE state                      */
+    RFAL_NFCA_CR_CL, /*!< New Cascading Level state       */
+    RFAL_NFCA_CR_SDD, /*!< Perform anticollsion state      */
+    RFAL_NFCA_CR_SEL, /*!< Perform CL Selection state      */
+    RFAL_NFCA_CR_DONE /*!< Collision Resolution done state */
+} colResState;
+
+/*! Colission Resolution context */
+typedef struct {
+    uint8_t devLimit; /*!< Device limit to be used                                 */
+    rfalComplianceMode compMode; /*!< Compliancy mode to be used                              */
+    rfalNfcaListenDevice*
+        nfcaDevList; /*!< Location of the device list                             */
+    uint8_t* devCnt; /*!< Location of the device counter                          */
+    bool collPending; /*!< Collision pending flag                                  */
+
+    bool* collPend; /*!< Location of collision pending flag (Single CR)          */
+    rfalNfcaSelReq selReq; /*!< SelReqused during anticollision (Single CR)             */
+    rfalNfcaSelRes* selRes; /*!< Location to place of the SEL_RES(SAK) (Single CR)       */
+    uint8_t* nfcId1; /*!< Location to place the NFCID1 (Single CR)                */
+    uint8_t* nfcId1Len; /*!< Location to place the NFCID1 length (Single CR)         */
+    uint8_t cascadeLv; /*!< Current Cascading Level (Single CR)                     */
+    colResState state; /*!< Single Collision Resolution state (Single CR)           */
+    uint8_t bytesTxRx; /*!< TxRx bytes used during anticollision loop (Single CR)   */
+    uint8_t bitsTxRx; /*!< TxRx bits used during anticollision loop (Single CR)    */
+    uint16_t rxLen;
+    uint32_t tmrFDT; /*!< FDT timer used between SED_REQs  (Single CR)            */
+    uint8_t retries; /*!< Retries to be performed upon a timeout error (Single CR)*/
+    uint8_t backtrackCnt; /*!< Backtrack retries (Single CR)                           */
+    bool doBacktrack; /*!< Backtrack flag (Single CR)                              */
+} colResParams;
+
+/*! RFAL NFC-A instance */
+typedef struct {
+    colResParams CR; /*!< Collision Resolution context                            */
+} rfalNfca;
+
+/*! SLP_REQ (HLTA) format   Digital 1.1  6.9.1 & Table 20 */
+typedef struct {
+    uint8_t frame[RFAL_NFCA_SLP_REQ_LEN]; /*!< SLP:  0x50 0x00  */
+} rfalNfcaSlpReq;
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+static rfalNfca gNfca; /*!< RFAL NFC-A instance  */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen);
+static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
+    uint8_t devLimit,
+    bool* collPending,
+    rfalNfcaSelRes* selRes,
+    uint8_t* nfcId1,
+    uint8_t* nfcId1Len);
+static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void);
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTIONS
+ ******************************************************************************
+ */
+
+static uint8_t rfalNfcaCalculateBcc(const uint8_t* buf, uint8_t bufLen) {
+    uint8_t i;
+    uint8_t BCC;
+
+    BCC = 0;
+
+    /* BCC is XOR over first 4 bytes of the SDD_RES  Digital 1.1 6.7.2 */
+    for(i = 0; i < bufLen; i++) {
+        BCC ^= buf[i];
+    }
+
+    return BCC;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalNfcaPollerStartSingleCollisionResolution(
+    uint8_t devLimit,
+    bool* collPending,
+    rfalNfcaSelRes* selRes,
+    uint8_t* nfcId1,
+    uint8_t* nfcId1Len) {
+    /* Check parameters */
+    if((collPending == NULL) || (selRes == NULL) || (nfcId1 == NULL) || (nfcId1Len == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Initialize output parameters */
+    *collPending = false; /* Activity 1.1  9.3.4.6 */
+    *nfcId1Len = 0;
+    ST_MEMSET(nfcId1, 0x00, RFAL_NFCA_CASCADE_3_UID_LEN);
+
+    /* Save parameters */
+    gNfca.CR.devLimit = devLimit;
+    gNfca.CR.collPend = collPending;
+    gNfca.CR.selRes = selRes;
+    gNfca.CR.nfcId1 = nfcId1;
+    gNfca.CR.nfcId1Len = nfcId1Len;
+
+    platformTimerDestroy(gNfca.CR.tmrFDT);
+    gNfca.CR.tmrFDT = 0U;
+    gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
+    gNfca.CR.cascadeLv = (uint8_t)RFAL_NFCA_SEL_CASCADE_L1;
+    gNfca.CR.state = RFAL_NFCA_CR_CL;
+
+    gNfca.CR.doBacktrack = false;
+    gNfca.CR.backtrackCnt = 3U;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalNfcaPollerGetSingleCollisionResolutionStatus(void) {
+    ReturnCode ret;
+    uint8_t collBit = 1U; /* standards mandate or recommend collision bit to be set to One. */
+
+    /* Check if FDT timer is still running */
+    if(!platformTimerIsExpired(gNfca.CR.tmrFDT) && (gNfca.CR.tmrFDT != 0U)) {
+        return ERR_BUSY;
+    }
+
+    /*******************************************************************************/
+    /* Go through all Cascade Levels     Activity 1.1  9.3.4 */
+    if(gNfca.CR.cascadeLv > (uint8_t)RFAL_NFCA_SEL_CASCADE_L3) {
+        return ERR_INTERNAL;
+    }
+
+    switch(gNfca.CR.state) {
+    /*******************************************************************************/
+    case RFAL_NFCA_CR_CL:
+
+        /* Initialize the SDD_REQ to send for the new cascade level */
+        ST_MEMSET((uint8_t*)&gNfca.CR.selReq, 0x00, sizeof(rfalNfcaSelReq));
+
+        gNfca.CR.bytesTxRx = RFAL_NFCA_SDD_REQ_LEN;
+        gNfca.CR.bitsTxRx = 0U;
+        gNfca.CR.state = RFAL_NFCA_CR_SDD;
+
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_NFCA_CR_SDD: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* Calculate SEL_CMD and SEL_PAR with the bytes/bits to be sent */
+        gNfca.CR.selReq.selCmd = rfalNfcaCLn2SELCMD(gNfca.CR.cascadeLv);
+        gNfca.CR.selReq.selPar = rfalNfcaSelPar(gNfca.CR.bytesTxRx, gNfca.CR.bitsTxRx);
+
+        /* Send SDD_REQ (Anticollision frame) */
+        ret = rfalISO14443ATransceiveAnticollisionFrame(
+            (uint8_t*)&gNfca.CR.selReq,
+            &gNfca.CR.bytesTxRx,
+            &gNfca.CR.bitsTxRx,
+            &gNfca.CR.rxLen,
+            RFAL_NFCA_FDTMIN);
+
+        /* Retry upon timeout  EMVCo 2.6  9.6.1.3 */
+        if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
+            gNfca.CR.retries--;
+            platformTimerDestroy(gNfca.CR.tmrFDT);
+            gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
+            break;
+        }
+
+        /* Covert rxLen into bytes */
+        gNfca.CR.rxLen = rfalConvBitsToBytes(gNfca.CR.rxLen);
+
+        if((ret == ERR_TIMEOUT) && (gNfca.CR.backtrackCnt != 0U) && (!gNfca.CR.doBacktrack) &&
+           !((RFAL_NFCA_SDD_REQ_LEN == gNfca.CR.bytesTxRx) && (0U == gNfca.CR.bitsTxRx))) {
+            /* In multiple card scenarios it may always happen that some 
+                 * collisions of a weaker tag go unnoticed. If then a later 
+                 * collision is recognized and the strong tag has a 0 at the 
+                 * collision position then no tag will respond. Catch this 
+                 * corner case and then try with the bit being sent as zero. */
+            rfalNfcaSensRes sensRes;
+            ret = ERR_RF_COLLISION;
+            rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_REQA, &sensRes);
+            /* Algorithm below does a post-increment, decrement to go back to current position */
+            if(0U == gNfca.CR.bitsTxRx) {
+                gNfca.CR.bitsTxRx = 7;
+                gNfca.CR.bytesTxRx--;
+            } else {
+                gNfca.CR.bitsTxRx--;
+            }
+            collBit = (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] &
+                                (1U << gNfca.CR.bitsTxRx));
+            collBit = (uint8_t)((0U == collBit) ? 1U : 0U); // invert the collision bit
+            gNfca.CR.doBacktrack = true;
+            gNfca.CR.backtrackCnt--;
+        } else {
+            gNfca.CR.doBacktrack = false;
+        }
+
+        if(ret == ERR_RF_COLLISION) {
+            /* Check received length */
+            if((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
+               (RFAL_NFCA_SDD_RES_LEN + RFAL_NFCA_SDD_REQ_LEN)) {
+                return ERR_PROTO;
+            }
+
+            if(((gNfca.CR.bytesTxRx + ((gNfca.CR.bitsTxRx != 0U) ? 1U : 0U)) >
+                (RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN)) &&
+               (gNfca.CR.backtrackCnt != 0U)) { /* Collision in BCC: Anticollide only UID part */
+                gNfca.CR.backtrackCnt--;
+                gNfca.CR.bytesTxRx = RFAL_NFCA_CASCADE_1_UID_LEN + RFAL_NFCA_SDD_REQ_LEN - 1U;
+                gNfca.CR.bitsTxRx = 7;
+                collBit =
+                    (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] &
+                              (1U
+                               << gNfca.CR
+                                      .bitsTxRx)); /* Not a real collision, extract the actual bit for the subsequent code */
+            }
+
+            if((gNfca.CR.devLimit == 0U) && !(*gNfca.CR.collPend)) {
+                /* Activity 1.0 & 1.1  9.3.4.12: If CON_DEVICES_LIMIT has a value of 0, then 
+                     * NFC Forum Device is configured to perform collision detection only       */
+                *gNfca.CR.collPend = true;
+                return ERR_IGNORE;
+            }
+
+            *gNfca.CR.collPend = true;
+
+            /* Set and select the collision bit, with the number of bytes/bits successfully TxRx */
+            if(collBit != 0U) {
+                ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
+                    (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] |
+                              (1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
+            } else {
+                ((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] =
+                    (uint8_t)(((uint8_t*)&gNfca.CR.selReq)[gNfca.CR.bytesTxRx] &
+                              ~(1U << gNfca.CR.bitsTxRx)); /* MISRA 10.3 */
+            }
+
+            gNfca.CR.bitsTxRx++;
+
+            /* Check if number of bits form a byte */
+            if(gNfca.CR.bitsTxRx == RFAL_BITS_IN_BYTE) {
+                gNfca.CR.bitsTxRx = 0;
+                gNfca.CR.bytesTxRx++;
+            }
+            break;
+        }
+
+        /*******************************************************************************/
+        /* Check if Collision loop has failed */
+        if(ret != ERR_NONE) {
+            return ret;
+        }
+
+        /* If collisions are to be reported check whether the response is complete */
+        if((gNfca.CR.devLimit == 0U) && (gNfca.CR.rxLen != sizeof(rfalNfcaSddRes))) {
+            return ERR_PROTO;
+        }
+
+        /* Check if the received BCC match */
+        if(gNfca.CR.selReq.bcc !=
+           rfalNfcaCalculateBcc(gNfca.CR.selReq.nfcid1, RFAL_NFCA_CASCADE_1_UID_LEN)) {
+            return ERR_PROTO;
+        }
+
+        /*******************************************************************************/
+        /* Anticollision OK, Select this Cascade Level */
+        gNfca.CR.selReq.selPar = RFAL_NFCA_SEL_SELPAR;
+
+        gNfca.CR.retries = RFAL_NFCA_N_RETRANS;
+        gNfca.CR.state = RFAL_NFCA_CR_SEL;
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFCA_CR_SEL:
+
+        /* Send SEL_REQ (Select command) - Retry upon timeout  EMVCo 2.6  9.6.1.3 */
+        ret = rfalTransceiveBlockingTxRx(
+            (uint8_t*)&gNfca.CR.selReq,
+            sizeof(rfalNfcaSelReq),
+            (uint8_t*)gNfca.CR.selRes,
+            sizeof(rfalNfcaSelRes),
+            &gNfca.CR.rxLen,
+            RFAL_TXRX_FLAGS_DEFAULT,
+            RFAL_NFCA_FDTMIN);
+
+        /* Retry upon timeout  EMVCo 2.6  9.6.1.3 */
+        if((ret == ERR_TIMEOUT) && (gNfca.CR.devLimit == 0U) && (gNfca.CR.retries != 0U)) {
+            gNfca.CR.retries--;
+            platformTimerDestroy(gNfca.CR.tmrFDT);
+            gNfca.CR.tmrFDT = platformTimerCreate(RFAL_NFCA_T_RETRANS);
+            break;
+        }
+
+        if(ret != ERR_NONE) {
+            return ret;
+        }
+
+        /* Ensure proper response length */
+        if(gNfca.CR.rxLen != sizeof(rfalNfcaSelRes)) {
+            return ERR_PROTO;
+        }
+
+        /*******************************************************************************/
+        /* Check cascade byte, if cascade tag then go next cascade level */
+        if(*gNfca.CR.selReq.nfcid1 == RFAL_NFCA_SDD_CT) {
+            /* Cascade Tag present, store nfcid1 bytes (excluding cascade tag) and continue for next CL */
+            ST_MEMCPY(
+                &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
+                &((uint8_t*)&gNfca.CR.selReq.nfcid1)[RFAL_NFCA_SDD_CT_LEN],
+                (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
+            *gNfca.CR.nfcId1Len += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
+
+            /* Go to next cascade level */
+            gNfca.CR.state = RFAL_NFCA_CR_CL;
+            gNfca.CR.cascadeLv++;
+        } else {
+            /* UID Selection complete, Stop Cascade Level loop */
+            ST_MEMCPY(
+                &gNfca.CR.nfcId1[*gNfca.CR.nfcId1Len],
+                (uint8_t*)&gNfca.CR.selReq.nfcid1,
+                RFAL_NFCA_CASCADE_1_UID_LEN);
+            *gNfca.CR.nfcId1Len += RFAL_NFCA_CASCADE_1_UID_LEN;
+
+            gNfca.CR.state = RFAL_NFCA_CR_DONE;
+            break; /* Only flag operation complete on the next execution */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_NFCA_CR_DONE:
+        return ERR_NONE;
+
+    /*******************************************************************************/
+    default:
+        return ERR_WRONG_STATE;
+    }
+    return ERR_BUSY;
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerInitialize(void) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCA, RFAL_BR_106, RFAL_BR_106));
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+
+    rfalSetGT(RFAL_GT_NFCA);
+    rfalSetFDTListen(RFAL_FDT_LISTEN_NFCA_POLLER);
+    rfalSetFDTPoll(RFAL_FDT_POLL_NFCA_POLLER);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerCheckPresence(rfal14443AShortFrameCmd cmd, rfalNfcaSensRes* sensRes) {
+    ReturnCode ret;
+    uint16_t rcvLen;
+
+    /* Digital 1.1 6.10.1.3  For Commands ALL_REQ, SENS_REQ, SDD_REQ, and SEL_REQ, the NFC Forum Device      *
+     *              MUST treat receipt of a Listen Frame at a time after FDT(Listen, min) as a Timeour Error */
+
+    ret = rfalISO14443ATransceiveShortFrame(
+        cmd,
+        (uint8_t*)sensRes,
+        (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
+        &rcvLen,
+        RFAL_NFCA_FDTMIN);
+    if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_NOMEM) ||
+       (ret == ERR_FRAMING) || (ret == ERR_PAR)) {
+        ret = ERR_NONE;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalNfcaPollerTechnologyDetection(rfalComplianceMode compMode, rfalNfcaSensRes* sensRes) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalNfcaPollerCheckPresence(
+            ((compMode == RFAL_COMPLIANCE_MODE_EMV) ? RFAL_14443A_SHORTFRAME_CMD_WUPA :
+                                                      RFAL_14443A_SHORTFRAME_CMD_REQA),
+            sensRes));
+
+    /* Send SLP_REQ as  Activity 1.1  9.2.3.6 and EMVCo 2.6  9.2.1.3 */
+    if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
+        rfalNfcaPollerSleep();
+    }
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerSingleCollisionResolution(
+    uint8_t devLimit,
+    bool* collPending,
+    rfalNfcaSelRes* selRes,
+    uint8_t* nfcId1,
+    uint8_t* nfcId1Len) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalNfcaPollerStartSingleCollisionResolution(
+            devLimit, collPending, selRes, nfcId1, nfcId1Len));
+    rfalNfcaRunBlocking(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerStartFullCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt) {
+    ReturnCode ret;
+    rfalNfcaSensRes sensRes;
+    uint16_t rcvLen;
+
+    if((nfcaDevList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *devCnt = 0;
+    ret = ERR_NONE;
+
+    /*******************************************************************************/
+    /* Send ALL_REQ before Anticollision if a Sleep was sent before  Activity 1.1  9.3.4.1 and EMVco 2.6  9.3.2.1 */
+    if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
+        ret = rfalISO14443ATransceiveShortFrame(
+            RFAL_14443A_SHORTFRAME_CMD_WUPA,
+            (uint8_t*)&nfcaDevList->sensRes,
+            (uint8_t)rfalConvBytesToBits(sizeof(rfalNfcaSensRes)),
+            &rcvLen,
+            RFAL_NFCA_FDTMIN);
+        if(ret != ERR_NONE) {
+            if((compMode == RFAL_COMPLIANCE_MODE_EMV) ||
+               ((ret != ERR_RF_COLLISION) && (ret != ERR_CRC) && (ret != ERR_FRAMING) &&
+                (ret != ERR_PAR))) {
+                return ret;
+            }
+        }
+
+        /* Check proper SENS_RES/ATQA size */
+        if((ret == ERR_NONE) && (rfalConvBytesToBits(sizeof(rfalNfcaSensRes)) != rcvLen)) {
+            return ERR_PROTO;
+        }
+    }
+
+    /*******************************************************************************/
+    /* Store the SENS_RES from Technology Detection or from WUPA */
+    sensRes = nfcaDevList->sensRes;
+
+    if(devLimit > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMSET(nfcaDevList, 0x00, (sizeof(rfalNfcaListenDevice) * devLimit));
+    }
+
+    /* Restore the prev SENS_RES, assuming that the SENS_RES received is from first device
+     * When only one device is detected it's not woken up then we'll have no SENS_RES (ATQA) */
+    nfcaDevList->sensRes = sensRes;
+
+    /* Save parameters */
+    gNfca.CR.devCnt = devCnt;
+    gNfca.CR.devLimit = devLimit;
+    gNfca.CR.nfcaDevList = nfcaDevList;
+    gNfca.CR.compMode = compMode;
+
+#if RFAL_FEATURE_T1T
+    /*******************************************************************************/
+    /* Only check for T1T if previous SENS_RES was received without a transmission  *
+     * error. When collisions occur bits in the SENS_RES may look like a T1T        */
+    /* If T1T Anticollision is not supported  Activity 1.1  9.3.4.3 */
+    if(rfalNfcaIsSensResT1T(&nfcaDevList->sensRes) && (devLimit != 0U) && (ret == ERR_NONE) &&
+       (compMode != RFAL_COMPLIANCE_MODE_EMV)) {
+        /* RID_REQ shall be performed              Activity 1.1  9.3.4.24 */
+        rfalT1TPollerInitialize();
+        EXIT_ON_ERR(ret, rfalT1TPollerRid(&nfcaDevList->ridRes));
+
+        *devCnt = 1U;
+        nfcaDevList->isSleep = false;
+        nfcaDevList->type = RFAL_NFCA_T1T;
+        nfcaDevList->nfcId1Len = RFAL_NFCA_CASCADE_1_UID_LEN;
+        ST_MEMCPY(&nfcaDevList->nfcId1, &nfcaDevList->ridRes.uid, RFAL_NFCA_CASCADE_1_UID_LEN);
+
+        return ERR_NONE;
+    }
+#endif /* RFAL_FEATURE_T1T */
+
+    return rfalNfcaPollerStartSingleCollisionResolution(
+        devLimit,
+        &gNfca.CR.collPending,
+        &nfcaDevList->selRes,
+        (uint8_t*)&nfcaDevList->nfcId1,
+        &nfcaDevList->nfcId1Len);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerGetFullCollisionResolutionStatus(void) {
+    ReturnCode ret;
+    uint8_t newDevType;
+
+    if((gNfca.CR.nfcaDevList == NULL) || (gNfca.CR.devCnt == NULL)) {
+        return ERR_WRONG_STATE;
+    }
+
+    /*******************************************************************************/
+    /* Check whether a T1T has already been detected */
+    if(rfalNfcaIsSensResT1T(&gNfca.CR.nfcaDevList->sensRes) &&
+       (gNfca.CR.nfcaDevList->type == RFAL_NFCA_T1T)) {
+        /* T1T doesn't support Anticollision */
+        return ERR_NONE;
+    }
+
+    /*******************************************************************************/
+    EXIT_ON_ERR(ret, rfalNfcaPollerGetSingleCollisionResolutionStatus());
+
+    /* Assign Listen Device */
+    newDevType = ((uint8_t)gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes.sak) &
+                 RFAL_NFCA_SEL_RES_CONF_MASK; /* MISRA 10.8 */
+    /* PRQA S 4342 1 # MISRA 10.5 - Guaranteed that no invalid enum values are created: see guard_eq_RFAL_NFCA_T2T, .... */
+    gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].type = (rfalNfcaListenDeviceType)newDevType;
+    gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].isSleep = false;
+    (*gNfca.CR.devCnt)++;
+
+    /* If a collision was detected and device counter is lower than limit  Activity 1.1  9.3.4.21 */
+    if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
+        /* Put this device to Sleep  Activity 1.1  9.3.4.22 */
+        rfalNfcaPollerSleep();
+        gNfca.CR.nfcaDevList[(*gNfca.CR.devCnt - 1U)].isSleep = true;
+
+        /* Send a new SENS_REQ to check for other cards  Activity 1.1  9.3.4.23 */
+        ret = rfalNfcaPollerCheckPresence(
+            RFAL_14443A_SHORTFRAME_CMD_REQA, &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].sensRes);
+        if(ret == ERR_TIMEOUT) {
+            /* No more devices found, exit */
+            gNfca.CR.collPending = false;
+        } else {
+            /* Another device found, continue loop */
+            gNfca.CR.collPending = true;
+        }
+    } else {
+        /* Exit loop */
+        gNfca.CR.collPending = false;
+    }
+
+    /*******************************************************************************/
+    /* Check if collision resolution shall continue */
+    if((*gNfca.CR.devCnt < gNfca.CR.devLimit) && (gNfca.CR.collPending)) {
+        EXIT_ON_ERR(
+            ret,
+            rfalNfcaPollerStartSingleCollisionResolution(
+                gNfca.CR.devLimit,
+                &gNfca.CR.collPending,
+                &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].selRes,
+                (uint8_t*)&gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1,
+                &gNfca.CR.nfcaDevList[*gNfca.CR.devCnt].nfcId1Len));
+
+        return ERR_BUSY;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerFullCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret, rfalNfcaPollerStartFullCollisionResolution(compMode, devLimit, nfcaDevList, devCnt));
+    rfalNfcaRunBlocking(ret, rfalNfcaPollerGetFullCollisionResolutionStatus());
+
+    return ret;
+}
+
+ReturnCode rfalNfcaPollerSleepFullCollisionResolution(
+    uint8_t devLimit,
+    rfalNfcaListenDevice* nfcaDevList,
+    uint8_t* devCnt) {
+    bool firstRound;
+    uint8_t tmpDevCnt;
+    ReturnCode ret;
+
+    if((nfcaDevList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Only use ALL_REQ (WUPA) on the first round */
+    firstRound = true;
+    *devCnt = 0;
+
+    /* Perform collision resolution until no new device is found */
+    do {
+        tmpDevCnt = 0;
+        ret = rfalNfcaPollerFullCollisionResolution(
+            (firstRound ? RFAL_COMPLIANCE_MODE_NFC : RFAL_COMPLIANCE_MODE_ISO),
+            (devLimit - *devCnt),
+            &nfcaDevList[*devCnt],
+            &tmpDevCnt);
+
+        if((ret == ERR_NONE) && (tmpDevCnt > 0U)) {
+            *devCnt += tmpDevCnt;
+
+            /* Check whether to seacrh for more devices */
+            if(*devCnt < devLimit) {
+                /* Set last found device to sleep (all others are slept already) */
+                rfalNfcaPollerSleep();
+                nfcaDevList[((*devCnt) - 1U)].isSleep = true;
+
+                /* Check if any other device is present */
+                ret = rfalNfcaPollerCheckPresence(
+                    RFAL_14443A_SHORTFRAME_CMD_REQA, &nfcaDevList[*devCnt].sensRes);
+                if(ret == ERR_NONE) {
+                    firstRound = false;
+                    continue;
+                }
+            }
+        }
+        break;
+    } while(true);
+
+    return ((*devCnt > 0U) ? ERR_NONE : ret);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerSelect(const uint8_t* nfcid1, uint8_t nfcidLen, rfalNfcaSelRes* selRes) {
+    uint8_t i;
+    uint8_t cl;
+    uint8_t nfcidOffset;
+    uint16_t rxLen;
+    ReturnCode ret;
+    rfalNfcaSelReq selReq;
+
+    if((nfcid1 == NULL) || (nfcidLen > RFAL_NFCA_CASCADE_3_UID_LEN) || (selRes == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Calculate Cascate Level */
+    cl = rfalNfcaNfcidLen2CL(nfcidLen);
+    nfcidOffset = 0;
+
+    /*******************************************************************************/
+    /* Go through all Cascade Levels     Activity 1.1  9.4.4 */
+    for(i = RFAL_NFCA_SEL_CASCADE_L1; i <= cl; i++) {
+        /* Assign SEL_CMD according to the CLn and SEL_PAR*/
+        selReq.selCmd = rfalNfcaCLn2SELCMD(i);
+        selReq.selPar = RFAL_NFCA_SEL_SELPAR;
+
+        /* Compute NFCID/Data on the SEL_REQ command   Digital 1.1  Table 18 */
+        if(cl != i) {
+            *selReq.nfcid1 = RFAL_NFCA_SDD_CT;
+            ST_MEMCPY(
+                &selReq.nfcid1[RFAL_NFCA_SDD_CT_LEN],
+                &nfcid1[nfcidOffset],
+                (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN));
+            nfcidOffset += (RFAL_NFCA_CASCADE_1_UID_LEN - RFAL_NFCA_SDD_CT_LEN);
+        } else {
+            ST_MEMCPY(selReq.nfcid1, &nfcid1[nfcidOffset], RFAL_NFCA_CASCADE_1_UID_LEN);
+        }
+
+        /* Calculate nfcid's BCC */
+        selReq.bcc = rfalNfcaCalculateBcc((uint8_t*)&selReq.nfcid1, sizeof(selReq.nfcid1));
+
+        /*******************************************************************************/
+        /* Send SEL_REQ  */
+        EXIT_ON_ERR(
+            ret,
+            rfalTransceiveBlockingTxRx(
+                (uint8_t*)&selReq,
+                sizeof(rfalNfcaSelReq),
+                (uint8_t*)selRes,
+                sizeof(rfalNfcaSelRes),
+                &rxLen,
+                RFAL_TXRX_FLAGS_DEFAULT,
+                RFAL_NFCA_FDTMIN));
+
+        /* Ensure proper response length */
+        if(rxLen != sizeof(rfalNfcaSelRes)) {
+            return ERR_PROTO;
+        }
+    }
+
+    /* REMARK: Could check if NFCID1 is complete */
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcaPollerSleep(void) {
+    rfalNfcaSlpReq slpReq;
+    uint8_t rxBuf; /* dummy buffer, just to perform Rx */
+
+    slpReq.frame[RFAL_NFCA_SLP_CMD_POS] = RFAL_NFCA_SLP_CMD;
+    slpReq.frame[RFAL_NFCA_SLP_BYTE2_POS] = RFAL_NFCA_SLP_BYTE2;
+
+    rfalTransceiveBlockingTxRx(
+        (uint8_t*)&slpReq,
+        sizeof(rfalNfcaSlpReq),
+        &rxBuf,
+        sizeof(rxBuf),
+        NULL,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCA_SLP_FWT);
+
+    /* ISO14443-3 6.4.3  HLTA - If PICC responds with any modulation during 1 ms this response shall be interpreted as not acknowledge 
+       Digital 2.0  6.9.2.1 & EMVCo 3.0  5.6.2.1 - consider the HLTA command always acknowledged
+       No check to be compliant with NFC and EMVCo, and to improve interoprability (Kovio RFID Tag)
+    */
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+bool rfalNfcaListenerIsSleepReq(const uint8_t* buf, uint16_t bufLen) {
+    /* Check if length and payload match */
+    if((bufLen != sizeof(rfalNfcaSlpReq)) || (buf[RFAL_NFCA_SLP_CMD_POS] != RFAL_NFCA_SLP_CMD) ||
+       (buf[RFAL_NFCA_SLP_BYTE2_POS] != RFAL_NFCA_SLP_BYTE2)) {
+        return false;
+    }
+
+    return true;
+}
+
+/* If the guards here don't compile then the code above cannot work anymore. */
+extern uint8_t guard_eq_RFAL_NFCA_T2T
+    [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T2T) == (uint8_t)RFAL_NFCA_T2T) ? 1 : (-1)];
+extern uint8_t guard_eq_RFAL_NFCA_T4T
+    [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T) == (uint8_t)RFAL_NFCA_T4T) ? 1 : (-1)];
+extern uint8_t guard_eq_RFAL_NFCA_NFCDEP
+    [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_NFCDEP) == (uint8_t)RFAL_NFCA_NFCDEP) ?
+         1 :
+         (-1)];
+extern uint8_t guard_eq_RFAL_NFCA_T4T_NFCDEP
+    [((RFAL_NFCA_SEL_RES_CONF_MASK & (uint8_t)RFAL_NFCA_T4T_NFCDEP) ==
+      (uint8_t)RFAL_NFCA_T4T_NFCDEP) ?
+         1 :
+         (-1)];
+#endif /* RFAL_FEATURE_NFCA */

+ 519 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcb.c

@@ -0,0 +1,519 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcb.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-B (ISO14443B) helpers 
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfcb.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFCB
+#define RFAL_FEATURE_NFCB false /* NFC-B module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_NFCB
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED \
+    0x10U /*!< Bit mask for Extended SensB Response support in SENSB_REQ */
+#define RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU \
+    0x08U /*!< Bit mask for Protocol Type RFU in SENSB_RES               */
+#define RFAL_NFCB_SLOT_MARKER_SC_SHIFT \
+    4U /*!< Slot Code position on SLOT_MARKER APn                     */
+
+#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN \
+    1U /*!< SLOT_MARKER Slot Code minimum   Digital 1.1  Table 37     */
+#define RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX \
+    16U /*!< SLOT_MARKER Slot Code maximum   Digital 1.1  Table 37     */
+
+#define RFAL_NFCB_ACTIVATION_FWT \
+    (RFAL_NFCB_FWTSENSB + RFAL_NFCB_DTPOLL_20) /*!< FWT(SENSB) + dTbPoll  Digital 2.0  7.9.1.3  */
+
+/*! Advanced and Extended bit mask in Parameter of SENSB_REQ */
+#define RFAL_NFCB_SENSB_REQ_PARAM \
+    (RFAL_NFCB_SENSB_REQ_ADV_FEATURE | RFAL_NFCB_SENSB_REQ_EXT_SENSB_RES_SUPPORTED)
+
+/*! NFC-B commands definition */
+enum {
+    RFAL_NFCB_CMD_SENSB_REQ = 0x05, /*!< SENSB_REQ (REQB) & SLOT_MARKER  Digital 1.1 Table 24 */
+    RFAL_NFCB_CMD_SENSB_RES = 0x50, /*!< SENSB_RES (ATQB) & SLOT_MARKER  Digital 1.1 Table 27 */
+    RFAL_NFCB_CMD_SLPB_REQ = 0x50, /*!< SLPB_REQ (HLTB command)  Digital 1.1 Table 38        */
+    RFAL_NFCB_CMD_SLPB_RES = 0x00 /*!< SLPB_RES (HLTB Answer)   Digital 1.1 Table 39        */
+};
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+#define rfalNfcbNI2NumberOfSlots(ni) \
+    (uint8_t)(1U << (ni)) /*!< Converts the Number of slots Identifier to slot number */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! ALLB_REQ (WUPB) and SENSB_REQ (REQB) Command Format   Digital 1.1  7.6.1 */
+typedef struct {
+    uint8_t cmd; /*!< xxxxB_REQ: 05h       */
+    uint8_t AFI; /*!< NFC Identifier       */
+    uint8_t PARAM; /*!< Application Data     */
+} rfalNfcbSensbReq;
+
+/*! SLOT_MARKER Command format  Digital 1.1  7.7.1 */
+typedef struct {
+    uint8_t APn; /*!< Slot number 2..16 | 0101b */
+} rfalNfcbSlotMarker;
+
+/*! SLPB_REQ (HLTB) Command Format   Digital 1.1  7.8.1 */
+typedef struct {
+    uint8_t cmd; /*!< SLPB_REQ: 50h        */
+    uint8_t nfcid0[RFAL_NFCB_NFCID0_LEN]; /*!< NFC Identifier (PUPI)*/
+} rfalNfcbSlpbReq;
+
+/*! SLPB_RES (HLTB) Response Format   Digital 1.1  7.8.2 */
+typedef struct {
+    uint8_t cmd; /*!< SLPB_RES: 00h        */
+} rfalNfcbSlpbRes;
+
+/*! RFAL NFC-B instance */
+typedef struct {
+    uint8_t AFI; /*!< AFI to be used       */
+    uint8_t PARAM; /*!< PARAM to be used     */
+} rfalNfcb;
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static ReturnCode rfalNfcbCheckSensbRes(const rfalNfcbSensbRes* sensbRes, uint8_t sensbResLen);
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+static rfalNfcb gRfalNfcb; /*!< RFAL NFC-B Instance */
+
+/*
+******************************************************************************
+* LOCAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+static ReturnCode rfalNfcbCheckSensbRes(const rfalNfcbSensbRes* sensbRes, uint8_t sensbResLen) {
+    /* Check response length */
+    if(((sensbResLen != RFAL_NFCB_SENSB_RES_LEN) &&
+        (sensbResLen != RFAL_NFCB_SENSB_RES_EXT_LEN))) {
+        return ERR_PROTO;
+    }
+
+    /* Check SENSB_RES and Protocol Type   Digital 1.1 7.6.2.19 */
+    if(((sensbRes->protInfo.FsciProType & RFAL_NFCB_SENSB_RES_PROT_TYPE_RFU) != 0U) ||
+       (sensbRes->cmd != (uint8_t)RFAL_NFCB_CMD_SENSB_RES)) {
+        return ERR_PROTO;
+    }
+    return ERR_NONE;
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerInitialize(void) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCB, RFAL_BR_106, RFAL_BR_106));
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+
+    rfalSetGT(RFAL_GT_NFCB);
+    rfalSetFDTListen(RFAL_FDT_LISTEN_NFCB_POLLER);
+    rfalSetFDTPoll(RFAL_FDT_POLL_NFCB_POLLER);
+
+    gRfalNfcb.AFI = RFAL_NFCB_AFI;
+    gRfalNfcb.PARAM = RFAL_NFCB_PARAM;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerInitializeWithParams(uint8_t AFI, uint8_t PARAM) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalNfcbPollerInitialize());
+
+    gRfalNfcb.AFI = AFI;
+    gRfalNfcb.PARAM = (PARAM & RFAL_NFCB_SENSB_REQ_PARAM);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerCheckPresence(
+    rfalNfcbSensCmd cmd,
+    rfalNfcbSlots slots,
+    rfalNfcbSensbRes* sensbRes,
+    uint8_t* sensbResLen) {
+    uint16_t rxLen;
+    ReturnCode ret;
+    rfalNfcbSensbReq sensbReq;
+
+    /* Check if the command requested and given the slot number are valid */
+    if(((RFAL_NFCB_SENS_CMD_SENSB_REQ != cmd) && (RFAL_NFCB_SENS_CMD_ALLB_REQ != cmd)) ||
+       (slots > RFAL_NFCB_SLOT_NUM_16) || (sensbRes == NULL) || (sensbResLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *sensbResLen = 0;
+    ST_MEMSET(sensbRes, 0x00, sizeof(rfalNfcbSensbRes));
+
+    /* Compute SENSB_REQ */
+    sensbReq.cmd = RFAL_NFCB_CMD_SENSB_REQ;
+    sensbReq.AFI = gRfalNfcb.AFI;
+    sensbReq.PARAM =
+        (((uint8_t)gRfalNfcb.PARAM & RFAL_NFCB_SENSB_REQ_PARAM) | (uint8_t)cmd | (uint8_t)slots);
+
+    /* Send SENSB_REQ and disable AGC to detect collisions */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&sensbReq,
+        sizeof(rfalNfcbSensbReq),
+        (uint8_t*)sensbRes,
+        sizeof(rfalNfcbSensbRes),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCB_FWTSENSB);
+
+    *sensbResLen = (uint8_t)rxLen;
+
+    /*  Check if a transmission error was detected */
+    if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
+        /* Invalidate received frame as an error was detected (CollisionResolution checks if valid) */
+        *sensbResLen = 0;
+        return ERR_NONE;
+    }
+
+    if(ret == ERR_NONE) {
+        return rfalNfcbCheckSensbRes(sensbRes, *sensbResLen);
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerSleep(const uint8_t* nfcid0) {
+    uint16_t rxLen;
+    ReturnCode ret;
+    rfalNfcbSlpbReq slpbReq;
+    rfalNfcbSlpbRes slpbRes;
+
+    if(nfcid0 == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Compute SLPB_REQ */
+    slpbReq.cmd = RFAL_NFCB_CMD_SLPB_REQ;
+    ST_MEMCPY(slpbReq.nfcid0, nfcid0, RFAL_NFCB_NFCID0_LEN);
+
+    EXIT_ON_ERR(
+        ret,
+        rfalTransceiveBlockingTxRx(
+            (uint8_t*)&slpbReq,
+            sizeof(rfalNfcbSlpbReq),
+            (uint8_t*)&slpbRes,
+            sizeof(rfalNfcbSlpbRes),
+            &rxLen,
+            RFAL_TXRX_FLAGS_DEFAULT,
+            RFAL_NFCB_ACTIVATION_FWT));
+
+    /* Check SLPB_RES */
+    if((rxLen != sizeof(rfalNfcbSlpbRes)) || (slpbRes.cmd != (uint8_t)RFAL_NFCB_CMD_SLPB_RES)) {
+        return ERR_PROTO;
+    }
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalNfcbPollerSlotMarker(uint8_t slotCode, rfalNfcbSensbRes* sensbRes, uint8_t* sensbResLen) {
+    ReturnCode ret;
+    rfalNfcbSlotMarker slotMarker;
+    uint16_t rxLen;
+
+    /* Check parameters */
+    if((sensbRes == NULL) || (sensbResLen == NULL) ||
+       (slotCode < RFAL_NFCB_SLOTMARKER_SLOTCODE_MIN) ||
+       (slotCode > RFAL_NFCB_SLOTMARKER_SLOTCODE_MAX)) {
+        return ERR_PARAM;
+    }
+    /* Compose and send SLOT_MARKER with disabled AGC to detect collisions  */
+    slotMarker.APn =
+        ((slotCode << RFAL_NFCB_SLOT_MARKER_SC_SHIFT) | (uint8_t)RFAL_NFCB_CMD_SENSB_REQ);
+
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&slotMarker,
+        sizeof(rfalNfcbSlotMarker),
+        (uint8_t*)sensbRes,
+        sizeof(rfalNfcbSensbRes),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCB_ACTIVATION_FWT);
+
+    *sensbResLen = (uint8_t)rxLen;
+
+    /* Check if a transmission error was detected */
+    if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
+        return ERR_RF_COLLISION;
+    }
+
+    if(ret == ERR_NONE) {
+        return rfalNfcbCheckSensbRes(sensbRes, *sensbResLen);
+    }
+
+    return ret;
+}
+
+ReturnCode rfalNfcbPollerTechnologyDetection(
+    rfalComplianceMode compMode,
+    rfalNfcbSensbRes* sensbRes,
+    uint8_t* sensbResLen) {
+    NO_WARNING(compMode);
+
+    return rfalNfcbPollerCheckPresence(
+        RFAL_NFCB_SENS_CMD_SENSB_REQ, RFAL_NFCB_SLOT_NUM_1, sensbRes, sensbResLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcbListenDevice* nfcbDevList,
+    uint8_t* devCnt) {
+    bool colPending; /* dummy */
+    return rfalNfcbPollerSlottedCollisionResolution(
+        compMode,
+        devLimit,
+        RFAL_NFCB_SLOT_NUM_1,
+        RFAL_NFCB_SLOT_NUM_16,
+        nfcbDevList,
+        devCnt,
+        &colPending);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcbPollerSlottedCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcbSlots initSlots,
+    rfalNfcbSlots endSlots,
+    rfalNfcbListenDevice* nfcbDevList,
+    uint8_t* devCnt,
+    bool* colPending) {
+    ReturnCode ret;
+    uint8_t slotsNum;
+    uint8_t slotCode;
+    uint8_t curDevCnt;
+
+    /* Check parameters. In ISO | Activity 1.0 mode the initial slots must be 1 as continuation of Technology Detection */
+    if((nfcbDevList == NULL) || (devCnt == NULL) || (colPending == NULL) ||
+       (initSlots > RFAL_NFCB_SLOT_NUM_16) || (endSlots > RFAL_NFCB_SLOT_NUM_16) ||
+       ((compMode == RFAL_COMPLIANCE_MODE_ISO) && (initSlots != RFAL_NFCB_SLOT_NUM_1))) {
+        return ERR_PARAM;
+    }
+
+    /* Initialise as no error in case Activity 1.0 where the previous SENSB_RES from technology detection should be used */
+    ret = ERR_NONE;
+    *devCnt = 0;
+    curDevCnt = 0;
+    *colPending = false;
+
+    /* Send ALLB_REQ   Activity 1.1   9.3.5.2 and 9.3.5.3  (Symbol 1 and 2) */
+    if(compMode != RFAL_COMPLIANCE_MODE_ISO) {
+        ret = rfalNfcbPollerCheckPresence(
+            RFAL_NFCB_SENS_CMD_ALLB_REQ,
+            initSlots,
+            &nfcbDevList->sensbRes,
+            &nfcbDevList->sensbResLen);
+        if((ret != ERR_NONE) && (initSlots == RFAL_NFCB_SLOT_NUM_1)) {
+            return ret;
+        }
+    }
+
+    /* Check if there was a transmission error on WUPB  EMVCo 2.6  9.3.3.1 */
+    if((compMode == RFAL_COMPLIANCE_MODE_EMV) && (nfcbDevList->sensbResLen == 0U)) {
+        return ERR_FRAMING;
+    }
+
+    for(slotsNum = (uint8_t)initSlots; slotsNum <= (uint8_t)endSlots; slotsNum++) {
+        do {
+            /* Activity 1.1  9.3.5.23  -  Symbol 22 */
+            if((compMode == RFAL_COMPLIANCE_MODE_NFC) && (curDevCnt != 0U)) {
+                rfalNfcbPollerSleep(nfcbDevList[((*devCnt) - (uint8_t)1U)].sensbRes.nfcid0);
+                nfcbDevList[((*devCnt) - (uint8_t)1U)].isSleep = true;
+            }
+
+            /* Send SENSB_REQ with number of slots if not the first Activity 1.1  9.3.5.24  -  Symbol 23 */
+            if((slotsNum != (uint8_t)initSlots) || *colPending) {
+                /* PRQA S 4342 1 # MISRA 10.5 - Layout of rfalNfcbSlots and above loop guarantee that no invalid enum values are created. */
+                ret = rfalNfcbPollerCheckPresence(
+                    RFAL_NFCB_SENS_CMD_SENSB_REQ,
+                    (rfalNfcbSlots)slotsNum,
+                    &nfcbDevList[*devCnt].sensbRes,
+                    &nfcbDevList[*devCnt].sensbResLen);
+            }
+
+            /* Activity 1.1  9.3.5.6  -  Symbol 5 */
+            slotCode = 0;
+            curDevCnt = 0;
+            *colPending = false;
+
+            do {
+                /* Activity 1.1  9.3.5.26  -  Symbol 25 */
+                if(slotCode != 0U) {
+                    ret = rfalNfcbPollerSlotMarker(
+                        slotCode,
+                        &nfcbDevList[*devCnt].sensbRes,
+                        &nfcbDevList[*devCnt].sensbResLen);
+                }
+
+                /* Activity 1.1  9.3.5.7 and 9.3.5.8  -  Symbol 6 */
+                if(ret != ERR_TIMEOUT) {
+                    /* Activity 1.1  9.3.5.8  -  Symbol 7 */
+                    if((rfalNfcbCheckSensbRes(
+                            &nfcbDevList[*devCnt].sensbRes, nfcbDevList[*devCnt].sensbResLen) ==
+                        ERR_NONE) &&
+                       (ret == ERR_NONE)) {
+                        nfcbDevList[*devCnt].isSleep = false;
+
+                        if(compMode == RFAL_COMPLIANCE_MODE_EMV) {
+                            (*devCnt)++;
+                            return ret;
+                        } else if(compMode == RFAL_COMPLIANCE_MODE_ISO) {
+                            /* Activity 1.0  9.3.5.8  -  Symbol 7 */
+                            (*devCnt)++;
+                            curDevCnt++;
+
+                            /* Activity 1.0  9.3.5.10  -  Symbol 9 */
+                            if((*devCnt >= devLimit) ||
+                               (slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
+                                return ret;
+                            }
+
+                            /* Activity 1.0  9.3.5.11  -  Symbol 10 */
+                            rfalNfcbPollerSleep(nfcbDevList[*devCnt - 1U].sensbRes.nfcid0);
+                            nfcbDevList[*devCnt - 1U].isSleep = true;
+                        } else if(compMode == RFAL_COMPLIANCE_MODE_NFC) {
+                            /* Activity 1.1  9.3.5.10 and 9.3.5.11  -  Symbol 9 and Symbol 11*/
+                            if(curDevCnt != 0U) {
+                                rfalNfcbPollerSleep(
+                                    nfcbDevList[(*devCnt) - (uint8_t)1U].sensbRes.nfcid0);
+                                nfcbDevList[(*devCnt) - (uint8_t)1U].isSleep = true;
+                            }
+
+                            /* Activity 1.1  9.3.5.12  -  Symbol 11 */
+                            (*devCnt)++;
+                            curDevCnt++;
+
+                            /* Activity 1.1  9.3.5.6  -  Symbol 13 */
+                            if((*devCnt >= devLimit) ||
+                               (slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
+                                return ret;
+                            }
+                        } else {
+                            /* MISRA 15.7 - Empty else */
+                        }
+                    } else {
+                        /* If deviceLimit is set to 0 the NFC Forum Device is configured to perform collision detection only  Activity 1.0 and 1.1  9.3.5.5  - Symbol 4 */
+                        if((devLimit == 0U) && (slotsNum == (uint8_t)RFAL_NFCB_SLOT_NUM_1)) {
+                            return ERR_RF_COLLISION;
+                        }
+
+                        /* Activity 1.1  9.3.5.9  -  Symbol 8 */
+                        *colPending = true;
+                    }
+                }
+
+                /* Activity 1.1  9.3.5.15  -  Symbol 14 */
+                slotCode++;
+            } while(slotCode < rfalNfcbNI2NumberOfSlots(slotsNum));
+
+            /* Activity 1.1  9.3.5.17  -  Symbol 16 */
+            if(!(*colPending)) {
+                return ERR_NONE;
+            }
+
+            /* Activity 1.1  9.3.5.18  -  Symbol 17 */
+        } while(
+            curDevCnt !=
+            0U); /* If a collision is detected and card(s) were found on this loop keep the same number of available slots */
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+uint32_t rfalNfcbTR2ToFDT(uint8_t tr2Code) {
+    /*******************************************************************************/
+    /* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */
+    /*! TR2 Table according to Digital 1.1 Table 33 */
+    const uint16_t rfalNfcbTr2Table[] = {1792, 3328, 5376, 9472};
+    /*******************************************************************************/
+
+    return rfalNfcbTr2Table[(tr2Code & RFAL_NFCB_SENSB_RES_PROTO_TR2_MASK)];
+}
+
+#endif /* RFAL_FEATURE_NFCB */

+ 587 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcf.c

@@ -0,0 +1,587 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcf.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-F Poller (FeliCa PCD) device
+ *
+ *  The definitions and helpers methods provided by this module are 
+ *  aligned with NFC-F (FeliCa - JIS X6319-4)
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfcf.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFCF
+#define RFAL_FEATURE_NFCF false /* NFC-F module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_NFCF
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+#define RFAL_NFCF_SENSF_REQ_LEN_MIN \
+    5U /*!< SENSF_RES minimum length                              */
+
+#define RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN \
+    15U /*!< Minimum length for a Check Command         T3T  5.4.1 */
+#define RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN \
+    31U /*!< Minimum length for an Update Command       T3T  5.5.1 */
+
+#define RFAL_NFCF_CHECK_RES_MIN_LEN \
+    11U /*!< CHECK Response minimum length       T3T 1.0  Table 8  */
+#define RFAL_NFCF_UPDATE_RES_MIN_LEN \
+    11U /*!< UPDATE Response minimum length      T3T 1.0  Table 8  */
+
+#define RFAL_NFCF_CHECK_REQ_MAX_LEN \
+    86U /*!< Max length of a Check request        T3T 1.0  Table 7 */
+#define RFAL_NFCF_CHECK_REQ_MAX_SERV \
+    15U /*!< Max Services number on Check request T3T 1.0  5.4.1.5 */
+#define RFAL_NFCF_CHECK_REQ_MAX_BLOCK \
+    15U /*!< Max Blocks number on Check request  T3T 1.0  5.4.1.10 */
+#define RFAL_NFCF_UPDATE_REQ_MAX_SERV \
+    15U /*!< Max Services number Update request  T3T 1.0  5.4.1.5  */
+#define RFAL_NFCF_UPDATE_REQ_MAX_BLOCK \
+    13U /*!< Max Blocks number on Update request T3T 1.0  5.4.1.10 */
+
+/*! MRT Check | Uupdate = (Tt3t x ((A+1) + n (B+1)) x 4^E) + dRWTt3t    T3T  5.8
+    Max values used: A = 7 ; B = 7 ; E = 3 ; n = 15 (NFC Forum n = 15, JIS n = 32)
+*/
+#define RFAL_NFCF_MRT_CHECK_UPDATE ((4096 * (8 + (15 * 8)) * 64) + 16)
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+#define rfalNfcfSlots2CardNum(s) \
+    ((uint8_t)(s) + 1U) /*!< Converts Time Slot Number (TSN) into num of slots  */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Structure/Buffer to hold the SENSF_RES with LEN byte prepended                                 */
+typedef struct {
+    uint8_t LEN; /*!< NFC-F LEN byte                      */
+    rfalNfcfSensfRes SENSF_RES; /*!< SENSF_RES                           */
+} rfalNfcfSensfResBuf;
+
+/*! Greedy collection for NFCF GRE_POLL_F  Activity 1.0 Table 10                                   */
+typedef struct {
+    uint8_t pollFound; /*!< Number of devices found by the Poll */
+    uint8_t pollCollision; /*!< Number of collisions detected       */
+    rfalFeliCaPollRes POLL_F[RFAL_NFCF_POLL_MAXCARDS]; /*!< GRE_POLL_F   Activity 1.0 Table 10  */
+} rfalNfcfGreedyF;
+
+/*! NFC-F SENSF_REQ format  Digital 1.1  8.6.1                     */
+typedef struct {
+    uint8_t CMD; /*!< Command code: 00h  */
+    uint8_t SC[RFAL_NFCF_SENSF_SC_LEN]; /*!< System Code        */
+    uint8_t RC; /*!< Request Code       */
+    uint8_t TSN; /*!< Time Slot Number   */
+} rfalNfcfSensfReq;
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+static rfalNfcfGreedyF gRfalNfcfGreedyF; /*!< Activity's NFCF Greedy collection */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static void rfalNfcfComputeValidSENF(
+    rfalNfcfListenDevice* outDevInfo,
+    uint8_t* curDevIdx,
+    uint8_t devLimit,
+    bool overwrite,
+    bool* nfcDepFound);
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+/*******************************************************************************/
+static void rfalNfcfComputeValidSENF(
+    rfalNfcfListenDevice* outDevInfo,
+    uint8_t* curDevIdx,
+    uint8_t devLimit,
+    bool overwrite,
+    bool* nfcDepFound) {
+    uint8_t tmpIdx;
+    bool duplicate;
+    const rfalNfcfSensfResBuf* sensfBuf;
+    rfalNfcfSensfResBuf sensfCopy;
+
+    /*******************************************************************************/
+    /* Go through all responses check if valid and duplicates                      */
+    /*******************************************************************************/
+    while((gRfalNfcfGreedyF.pollFound > 0U) && ((*curDevIdx) < devLimit)) {
+        duplicate = false;
+        gRfalNfcfGreedyF.pollFound--;
+
+        /* MISRA 11.3 - Cannot point directly into different object type, use local copy */
+        ST_MEMCPY(
+            (uint8_t*)&sensfCopy,
+            (uint8_t*)&gRfalNfcfGreedyF.POLL_F[gRfalNfcfGreedyF.pollFound],
+            sizeof(rfalNfcfSensfResBuf));
+
+        /* Point to received SENSF_RES */
+        sensfBuf = &sensfCopy;
+
+        /* Check for devices that are already in device list */
+        for(tmpIdx = 0; tmpIdx < (*curDevIdx); tmpIdx++) {
+            if(ST_BYTECMP(
+                   sensfBuf->SENSF_RES.NFCID2,
+                   outDevInfo[tmpIdx].sensfRes.NFCID2,
+                   RFAL_NFCF_NFCID2_LEN) == 0) {
+                duplicate = true;
+                break;
+            }
+        }
+
+        /* If is a duplicate skip this (and not to overwrite)*/
+        if(duplicate && !overwrite) {
+            continue;
+        }
+
+        /* Check if response length is OK */
+        if(((sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) < RFAL_NFCF_SENSF_RES_LEN_MIN) ||
+           ((sensfBuf->LEN - RFAL_NFCF_HEADER_LEN) > RFAL_NFCF_SENSF_RES_LEN_MAX)) {
+            continue;
+        }
+
+        /* Check if the response is a SENSF_RES / Polling response */
+        if(sensfBuf->SENSF_RES.CMD != (uint8_t)RFAL_NFCF_CMD_POLLING_RES) {
+            continue;
+        }
+
+        /* Check if is an overwrite request or new device*/
+        if(duplicate && overwrite) {
+            /* overwrite deviceInfo/GRE_SENSF_RES with SENSF_RES */
+            outDevInfo[tmpIdx].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN);
+            ST_MEMCPY(
+                &outDevInfo[tmpIdx].sensfRes,
+                &sensfBuf->SENSF_RES,
+                outDevInfo[tmpIdx].sensfResLen);
+            continue;
+        } else {
+            /* fill deviceInfo/GRE_SENSF_RES with new SENSF_RES */
+            outDevInfo[(*curDevIdx)].sensfResLen = (sensfBuf->LEN - RFAL_NFCF_LENGTH_LEN);
+            ST_MEMCPY(
+                &outDevInfo[(*curDevIdx)].sensfRes,
+                &sensfBuf->SENSF_RES,
+                outDevInfo[(*curDevIdx)].sensfResLen);
+        }
+
+        /* Check if this device supports NFC-DEP and signal it (ACTIVITY 1.1   9.3.6.63) */
+        *nfcDepFound = rfalNfcfIsNfcDepSupported(&outDevInfo[(*curDevIdx)]);
+
+        (*curDevIdx)++;
+    }
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerInitialize(rfalBitRate bitRate) {
+    ReturnCode ret;
+
+    if((bitRate != RFAL_BR_212) && (bitRate != RFAL_BR_424)) {
+        return ERR_PARAM;
+    }
+
+    EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCF, bitRate, bitRate));
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+
+    rfalSetGT(RFAL_GT_NFCF);
+    rfalSetFDTListen(RFAL_FDT_LISTEN_NFCF_POLLER);
+    rfalSetFDTPoll(RFAL_FDT_POLL_NFCF_POLLER);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerPoll(
+    rfalFeliCaPollSlots slots,
+    uint16_t sysCode,
+    uint8_t reqCode,
+    rfalFeliCaPollRes* cardList,
+    uint8_t* devCnt,
+    uint8_t* collisions) {
+    return rfalFeliCaPoll(
+        slots, sysCode, reqCode, cardList, rfalNfcfSlots2CardNum(slots), devCnt, collisions);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerCheckPresence(void) {
+    gRfalNfcfGreedyF.pollFound = 0;
+    gRfalNfcfGreedyF.pollCollision = 0;
+
+    /* ACTIVITY 1.0 & 1.1 - 9.2.3.17 SENSF_REQ  must be with number of slots equal to 4
+     *                                SC must be 0xFFFF
+     *                                RC must be 0x00 (No system code info required) */
+    return rfalFeliCaPoll(
+        RFAL_FELICA_4_SLOTS,
+        RFAL_NFCF_SYSTEMCODE,
+        RFAL_FELICA_POLL_RC_NO_REQUEST,
+        gRfalNfcfGreedyF.POLL_F,
+        rfalNfcfSlots2CardNum(RFAL_FELICA_4_SLOTS),
+        &gRfalNfcfGreedyF.pollFound,
+        &gRfalNfcfGreedyF.pollCollision);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcfListenDevice* nfcfDevList,
+    uint8_t* devCnt) {
+    ReturnCode ret;
+    bool nfcDepFound;
+
+    if((nfcfDevList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *devCnt = 0;
+    nfcDepFound = false;
+
+    /*******************************************************************************************/
+    /* ACTIVITY 1.0 - 9.3.6.3 Copy valid SENSF_RES in GRE_POLL_F into GRE_SENSF_RES            */
+    /* ACTIVITY 1.0 - 9.3.6.6 The NFC Forum Device MUST remove all entries from GRE_SENSF_RES[]*/
+    /* ACTIVITY 1.1 - 9.3.63.59 Populate GRE_SENSF_RES with data from GRE_POLL_F               */
+    /*                                                                                         */
+    /* CON_DEVICES_LIMIT = 0 Just check if devices from Tech Detection exceeds -> always true  */
+    /* Allow the number of slots open on Technology Detection                                  */
+    /*******************************************************************************************/
+    rfalNfcfComputeValidSENF(
+        nfcfDevList,
+        devCnt,
+        ((devLimit == 0U) ? rfalNfcfSlots2CardNum(RFAL_FELICA_4_SLOTS) : devLimit),
+        false,
+        &nfcDepFound);
+
+    /*******************************************************************************/
+    /* ACTIVITY 1.0 - 9.3.6.4                                                      */
+    /* ACTIVITY 1.1 - 9.3.63.60 Check if devices found are lower than the limit    */
+    /* and send a SENSF_REQ if so                                                  */
+    /*******************************************************************************/
+    if(*devCnt < devLimit) {
+        /* ACTIVITY 1.0 - 9.3.6.5  Copy valid SENSF_RES and then to remove it
+         * ACTIVITY 1.1 - 9.3.6.65 Copy and filter duplicates                                           
+         * For now, due to some devices keep generating different nfcid2, we use 1.0  
+         * Phones detected: Samsung Galaxy Nexus,Samsung Galaxy S3,Samsung Nexus S */
+        *devCnt = 0;
+
+        ret = rfalNfcfPollerPoll(
+            RFAL_FELICA_16_SLOTS,
+            RFAL_NFCF_SYSTEMCODE,
+            RFAL_FELICA_POLL_RC_NO_REQUEST,
+            gRfalNfcfGreedyF.POLL_F,
+            &gRfalNfcfGreedyF.pollFound,
+            &gRfalNfcfGreedyF.pollCollision);
+        if(ret == ERR_NONE) {
+            rfalNfcfComputeValidSENF(nfcfDevList, devCnt, devLimit, false, &nfcDepFound);
+        }
+
+        /*******************************************************************************/
+        /* ACTIVITY 1.1 -  9.3.6.63 Check if any device supports NFC DEP               */
+        /*******************************************************************************/
+        if(nfcDepFound && (compMode == RFAL_COMPLIANCE_MODE_NFC)) {
+            ret = rfalNfcfPollerPoll(
+                RFAL_FELICA_16_SLOTS,
+                RFAL_NFCF_SYSTEMCODE,
+                RFAL_FELICA_POLL_RC_SYSTEM_CODE,
+                gRfalNfcfGreedyF.POLL_F,
+                &gRfalNfcfGreedyF.pollFound,
+                &gRfalNfcfGreedyF.pollCollision);
+            if(ret == ERR_NONE) {
+                rfalNfcfComputeValidSENF(nfcfDevList, devCnt, devLimit, true, &nfcDepFound);
+            }
+        }
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerCheck(
+    const uint8_t* nfcid2,
+    const rfalNfcfServBlockListParam* servBlock,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvdLen) {
+    uint8_t txBuf[RFAL_NFCF_CHECK_REQ_MAX_LEN];
+    uint8_t msgIt;
+    uint8_t i;
+    ReturnCode ret;
+    const uint8_t* checkRes;
+
+    /* Check parameters */
+    if((nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || (servBlock->numBlock == 0U) ||
+       (servBlock->numBlock > RFAL_NFCF_CHECK_REQ_MAX_BLOCK) || (servBlock->numServ == 0U) ||
+       (servBlock->numServ > RFAL_NFCF_CHECK_REQ_MAX_SERV) ||
+       (rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECK_RES_MIN_LEN))) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+
+    /*******************************************************************************/
+    /* Compose CHECK command/request                                               */
+
+    txBuf[msgIt++] = RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION; /* Command Code    */
+
+    ST_MEMCPY(&txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN); /* NFCID2          */
+    msgIt += RFAL_NFCF_NFCID2_LEN;
+
+    txBuf[msgIt++] = servBlock->numServ; /* NoS             */
+    for(i = 0; i < servBlock->numServ; i++) {
+        txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code    */
+        txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU);
+    }
+
+    txBuf[msgIt++] = servBlock->numBlock; /* NoB             */
+    for(i = 0; i < servBlock->numBlock; i++) {
+        txBuf[msgIt++] =
+            servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */
+        if((servBlock->blockList[i].conf & 0x80U) !=
+           0U) /* Check if 2 or 3 byte block list element       */
+        {
+            txBuf[msgIt++] =
+                (uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */
+        } else {
+            txBuf[msgIt++] =
+                (uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */
+            txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU);
+        }
+    }
+
+    /*******************************************************************************/
+    /* Transceive CHECK command/request                                            */
+    ret = rfalTransceiveBlockingTxRx(
+        txBuf,
+        msgIt,
+        rxBuf,
+        rxBufLen,
+        rcvdLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCF_MRT_CHECK_UPDATE);
+
+    if(ret == ERR_NONE) {
+        /* Skip LEN byte */
+        checkRes = (rxBuf + RFAL_NFCF_LENGTH_LEN);
+
+        /* Check response length */
+        if(*rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) {
+            ret = ERR_PROTO;
+        }
+        /* Check for a valid response */
+        else if(
+            (checkRes[RFAL_NFCF_CMD_POS] != (uint8_t)RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION_RES) ||
+            (checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ||
+            (checkRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS)) {
+            ret = ERR_REQUEST;
+        }
+        /* CHECK succesfull, remove header */
+        else {
+            (*rcvdLen) -= (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_NOB_POS);
+
+            if(*rcvdLen > 0U) {
+                ST_MEMMOVE(rxBuf, &checkRes[RFAL_NFCF_CHECKUPDATE_RES_NOB_POS], (*rcvdLen));
+            }
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcfPollerUpdate(
+    const uint8_t* nfcid2,
+    const rfalNfcfServBlockListParam* servBlock,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    const uint8_t* blockData,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen) {
+    uint8_t i;
+    uint16_t msgIt;
+    uint16_t rcvdLen;
+    uint16_t auxLen;
+    const uint8_t* updateRes;
+    ReturnCode ret;
+
+    /* Check parameters */
+    if((nfcid2 == NULL) || (rxBuf == NULL) || (servBlock == NULL) || (txBuf == NULL) ||
+       (servBlock->numBlock == 0U) || (servBlock->numBlock > RFAL_NFCF_UPDATE_REQ_MAX_BLOCK) ||
+       (servBlock->numServ == 0U) || (servBlock->numServ > RFAL_NFCF_UPDATE_REQ_MAX_SERV) ||
+       (rxBufLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_UPDATE_RES_MIN_LEN))) {
+        return ERR_PARAM;
+    }
+
+    /* Calculate required txBuffer lenth */
+    auxLen = (uint16_t)(RFAL_NFCF_CMD_LEN + RFAL_NFCF_NFCID2_LEN +
+                        (servBlock->numServ * sizeof(rfalNfcfServ)) +
+                        (servBlock->numBlock * sizeof(rfalNfcfBlockListElem)) +
+                        (uint16_t)((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN));
+
+    /* Check whether the provided buffer is sufficient for this request */
+    if(txBufLen < auxLen) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+
+    /*******************************************************************************/
+    /* Compose UPDATE command/request                                              */
+
+    txBuf[msgIt++] = RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION; /* Command Code    */
+
+    ST_MEMCPY(&txBuf[msgIt], nfcid2, RFAL_NFCF_NFCID2_LEN); /* NFCID2          */
+    msgIt += RFAL_NFCF_NFCID2_LEN;
+
+    txBuf[msgIt++] = servBlock->numServ; /* NoS             */
+    for(i = 0; i < servBlock->numServ; i++) {
+        txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 0U) & 0xFFU); /* Service Code    */
+        txBuf[msgIt++] = (uint8_t)((servBlock->servList[i] >> 8U) & 0xFFU);
+    }
+
+    txBuf[msgIt++] = servBlock->numBlock; /* NoB             */
+    for(i = 0; i < servBlock->numBlock; i++) {
+        txBuf[msgIt++] =
+            servBlock->blockList[i].conf; /* Block list element conf (Flag|Access|Service) */
+        if((servBlock->blockList[i].conf & 0x80U) !=
+           0U) /* Check if 2 or 3 byte block list element       */
+        {
+            txBuf[msgIt++] =
+                (uint8_t)(servBlock->blockList[i].blockNum & 0xFFU); /* 1byte Block Num */
+        } else {
+            txBuf[msgIt++] =
+                (uint8_t)((servBlock->blockList[i].blockNum >> 0U) & 0xFFU); /* 2byte Block Num */
+            txBuf[msgIt++] = (uint8_t)((servBlock->blockList[i].blockNum >> 8U) & 0xFFU);
+        }
+    }
+
+    auxLen = ((uint16_t)servBlock->numBlock * RFAL_NFCF_BLOCK_LEN);
+    ST_MEMCPY(&txBuf[msgIt], blockData, auxLen); /* Block Data      */
+    msgIt += auxLen;
+
+    /*******************************************************************************/
+    /* Transceive UPDATE command/request                                           */
+    ret = rfalTransceiveBlockingTxRx(
+        txBuf,
+        msgIt,
+        rxBuf,
+        rxBufLen,
+        &rcvdLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCF_MRT_CHECK_UPDATE);
+
+    if(ret == ERR_NONE) {
+        /* Skip LEN byte */
+        updateRes = (rxBuf + RFAL_NFCF_LENGTH_LEN);
+
+        /* Check response length */
+        if(rcvdLen < (RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CHECKUPDATE_RES_ST2_POS)) {
+            ret = ERR_PROTO;
+        }
+        /* Check for a valid response */
+        else if(
+            (updateRes[RFAL_NFCF_CMD_POS] !=
+             (uint8_t)RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION_RES) ||
+            (updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST1_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS) ||
+            (updateRes[RFAL_NFCF_CHECKUPDATE_RES_ST2_POS] != RFAL_NFCF_STATUS_FLAG_SUCCESS)) {
+            ret = ERR_REQUEST;
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+bool rfalNfcfListenerIsT3TReq(const uint8_t* buf, uint16_t bufLen, uint8_t* nfcid2) {
+    /* Check cmd byte */
+    switch(*buf) {
+    case RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION:
+        if(bufLen < RFAL_NFCF_READ_WO_ENCRYPTION_MIN_LEN) {
+            return false;
+        }
+        break;
+
+    case RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION:
+        if(bufLen < RFAL_NFCF_WRITE_WO_ENCRYPTION_MIN_LEN) {
+            return false;
+        }
+        break;
+
+    default:
+        return false;
+    }
+
+    /* Output NFID2 if requested */
+    if(nfcid2 != NULL) {
+        ST_MEMCPY(nfcid2, &buf[RFAL_NFCF_CMD_LEN], RFAL_NFCF_NFCID2_LEN);
+    }
+
+    return true;
+}
+
+#endif /* RFAL_FEATURE_NFCF */

+ 1059 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_nfcv.c

@@ -0,0 +1,1059 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_nfcv.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of NFC-V Poller (ISO15693) device
+ *
+ *  The definitions and helpers methods provided by this module are 
+ *  aligned with NFC-V (ISO15693)
+ *
+ *  The definitions and helpers methods provided by this module 
+ *  are aligned with NFC-V Digital 2.1
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_nfcv.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_NFCV
+#define RFAL_FEATURE_NFCV false /* NFC-V module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_NFCV
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_NFCV_INV_REQ_FLAG \
+    0x06U /*!< INVENTORY_REQ  INV_FLAG  Digital  2.1  9.6.1                      */
+#define RFAL_NFCV_MASKVAL_MAX_LEN \
+    8U /*!< Mask value max length: 64 bits  (UID length)                      */
+#define RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN \
+    64U /*!< Mask value max length in 1 Slot mode in bits  Digital 2.1 9.6.1.6 */
+#define RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN \
+    60U /*!< Mask value max length in 16 Slot mode in bits Digital 2.1 9.6.1.6 */
+#define RFAL_NFCV_MAX_SLOTS \
+    16U /*!< NFC-V max number of Slots                                         */
+#define RFAL_NFCV_INV_REQ_HEADER_LEN \
+    3U /*!< INVENTORY_REQ header length (INV_FLAG, CMD, MASK_LEN)             */
+#define RFAL_NFCV_INV_RES_LEN \
+    10U /*!< INVENTORY_RES length                                              */
+#define RFAL_NFCV_WR_MUL_REQ_HEADER_LEN \
+    4U /*!< Write Multiple header length (INV_FLAG, CMD, [UID], BNo, Bno)     */
+
+#define RFAL_NFCV_CMD_LEN \
+    1U /*!< Commandbyte length                                                */
+#define RFAL_NFCV_FLAG_POS \
+    0U /*!< Flag byte position                                                */
+#define RFAL_NFCV_FLAG_LEN \
+    1U /*!< Flag byte length                                                  */
+#define RFAL_NFCV_DATASTART_POS \
+    1U /*!< Position of start of data                                         */
+#define RFAL_NFCV_DSFI_LEN \
+    1U /*!< DSFID length                                                      */
+#define RFAL_NFCV_SLPREQ_REQ_FLAG \
+    0x22U /*!< SLPV_REQ request flags Digital 2.0 (Candidate) 9.7.1.1            */
+#define RFAL_NFCV_RES_FLAG_NOERROR \
+    0x00U /*!< RES_FLAG indicating no error (checked during activation)          */
+
+#define RFAL_NFCV_MAX_COLL_SUPPORTED \
+    16U /*!< Maximum number of collisions supported by the Anticollision loop  */
+
+#define RFAL_NFCV_FDT_MAX \
+    rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF and MAX2   Digital 2.1 B.5*/
+#define RFAL_NFCV_FDT_MAX1 \
+    4394U /*!< Read alike command FWT FDTV,LISTEN,MAX1  Digital 2.0 B.5          */
+
+/*! Time from special frame to EOF 
+ *                    ISO15693 2009 10.4.2                 : 20ms
+ *                    NFC Forum defines Digital 2.0  9.7.4 : FDTV,EOF = [10 ; 20]ms 
+ */
+#define RFAL_NFCV_FDT_EOF 20U
+
+/*! Time between slots - ISO 15693 defines t3min depending on modulation depth and data rate.
+ *  With only high-bitrate supported, AM modulation and a length of 12 bytes (96bits) for INV_RES we get:
+ *                    - ISO t3min = 96/26 ms + 300us = 4 ms
+ *                    - NFC Forum defines FDTV,INVENT_NORES = (4394 + 2048)/fc. Digital 2.0  B.5*/
+#define RFAL_NFCV_FDT_V_INVENT_NORES 4U
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*! Checks if a valid INVENTORY_RES is valid    Digital 2.2  9.6.2.1 & 9.6.2.3  */
+#define rfalNfcvCheckInvRes(f, l)                                               \
+    (((l) == rfalConvBytesToBits(RFAL_NFCV_INV_RES_LEN + RFAL_NFCV_CRC_LEN)) && \
+     ((f) == RFAL_NFCV_RES_FLAG_NOERROR))
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-V INVENTORY_REQ format   Digital 2.0 9.6.1 */
+typedef struct {
+    uint8_t INV_FLAG; /*!< Inventory Flags    */
+    uint8_t CMD; /*!< Command code: 01h  */
+    uint8_t MASK_LEN; /*!< Mask Value Length  */
+    uint8_t MASK_VALUE[RFAL_NFCV_MASKVAL_MAX_LEN]; /*!< Mask Value         */
+} rfalNfcvInventoryReq;
+
+/*! NFC-V SLP_REQ format   Digital 2.0 (Candidate) 9.7.1 */
+typedef struct {
+    uint8_t REQ_FLAG; /*!< Request Flags      */
+    uint8_t CMD; /*!< Command code: 02h  */
+    uint8_t UID[RFAL_NFCV_UID_LEN]; /*!< Mask Value         */
+} rfalNfcvSlpvReq;
+
+/*! Container for a collision found during Anticollision loop */
+typedef struct {
+    uint8_t maskLen;
+    uint8_t maskVal[RFAL_NFCV_MASKVAL_MAX_LEN];
+} rfalNfcvCollision;
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static ReturnCode rfalNfcvParseError(uint8_t err);
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* LOCAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+static ReturnCode rfalNfcvParseError(uint8_t err) {
+    switch(err) {
+    case RFAL_NFCV_ERROR_CMD_NOT_SUPPORTED:
+    case RFAL_NFCV_ERROR_OPTION_NOT_SUPPORTED:
+        return ERR_NOTSUPP;
+
+    case RFAL_NFCV_ERROR_CMD_NOT_RECOGNIZED:
+        return ERR_PROTO;
+
+    case RFAL_NFCV_ERROR_WRITE_FAILED:
+        return ERR_WRITE;
+
+    default:
+        return ERR_REQUEST;
+    }
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerInitialize(void) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCV, RFAL_BR_26p48, RFAL_BR_26p48));
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+
+    rfalSetGT(RFAL_GT_NFCV);
+    rfalSetFDTListen(RFAL_FDT_LISTEN_NFCV_POLLER);
+    rfalSetFDTPoll(RFAL_FDT_POLL_NFCV_POLLER);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerCheckPresence(rfalNfcvInventoryRes* invRes) {
+    ReturnCode ret;
+
+    /* INVENTORY_REQ with 1 slot and no Mask   Activity 2.0 (Candidate) 9.2.3.32 */
+    ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, invRes, NULL);
+
+    if((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_FRAMING) ||
+       (ret == ERR_PROTO)) {
+        ret = ERR_NONE;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerInventory(
+    rfalNfcvNumSlots nSlots,
+    uint8_t maskLen,
+    const uint8_t* maskVal,
+    rfalNfcvInventoryRes* invRes,
+    uint16_t* rcvdLen) {
+    ReturnCode ret;
+    rfalNfcvInventoryReq invReq;
+    uint16_t rxLen;
+
+    if(((maskVal == NULL) && (maskLen != 0U)) || (invRes == NULL)) {
+        return ERR_PARAM;
+    }
+
+    invReq.INV_FLAG = (RFAL_NFCV_INV_REQ_FLAG | (uint8_t)nSlots);
+    invReq.CMD = RFAL_NFCV_CMD_INVENTORY;
+    invReq.MASK_LEN = (uint8_t)MIN(
+        maskLen,
+        ((nSlots == RFAL_NFCV_NUM_SLOTS_1) ?
+             RFAL_NFCV_MASKVAL_MAX_1SLOT_LEN :
+             RFAL_NFCV_MASKVAL_MAX_16SLOT_LEN)); /* Digital 2.0  9.6.1.6 */
+
+    if((rfalConvBitsToBytes(invReq.MASK_LEN) > 0U) && (maskVal != NULL)) /* MISRA 21.18 & 1.3 */
+    {
+        ST_MEMCPY(invReq.MASK_VALUE, maskVal, rfalConvBitsToBytes(invReq.MASK_LEN));
+    }
+
+    ret = rfalISO15693TransceiveAnticollisionFrame(
+        (uint8_t*)&invReq,
+        (uint8_t)(RFAL_NFCV_INV_REQ_HEADER_LEN + rfalConvBitsToBytes(invReq.MASK_LEN)),
+        (uint8_t*)invRes,
+        sizeof(rfalNfcvInventoryRes),
+        &rxLen);
+
+    /* Check for optional output parameter */
+    if(rcvdLen != NULL) {
+        *rcvdLen = rxLen;
+    }
+
+    if(ret == ERR_NONE) {
+        /* Check for valid INVENTORY_RES   Digital 2.2  9.6.2.1 & 9.6.2.3 */
+        if(!rfalNfcvCheckInvRes(invRes->RES_FLAG, rxLen)) {
+            return ERR_PROTO;
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerCollisionResolution(
+    rfalComplianceMode compMode,
+    uint8_t devLimit,
+    rfalNfcvListenDevice* nfcvDevList,
+    uint8_t* devCnt) {
+    ReturnCode ret;
+    uint8_t slotNum;
+    uint16_t rcvdLen;
+    uint8_t colIt;
+    uint8_t colCnt;
+    uint8_t colPos;
+    bool colPending;
+    rfalNfcvCollision colFound[RFAL_NFCV_MAX_COLL_SUPPORTED];
+
+    if((nfcvDevList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Initialize parameters */
+    *devCnt = 0;
+    colIt = 0;
+    colCnt = 0;
+    colPending = false;
+    ST_MEMSET(colFound, 0x00, (sizeof(rfalNfcvCollision) * RFAL_NFCV_MAX_COLL_SUPPORTED));
+
+    if(devLimit > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMSET(nfcvDevList, 0x00, (sizeof(rfalNfcvListenDevice) * devLimit));
+    }
+
+    NO_WARNING(
+        colPending); /* colPending is not exposed externally, in future it might become exposed/ouput parameter */
+
+    if(compMode == RFAL_COMPLIANCE_MODE_NFC) {
+        /* Send INVENTORY_REQ with one slot   Activity 2.1  9.3.7.1  (Symbol 0)  */
+        ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &nfcvDevList->InvRes, NULL);
+
+        if(ret == ERR_TIMEOUT) /* Exit if no device found     Activity 2.1  9.3.7.2 (Symbol 1)  */
+        {
+            return ERR_NONE;
+        }
+        if(ret ==
+           ERR_NONE) /* Device found without transmission error/collision    Activity 2.1  9.3.7.3 (Symbol 2)  */
+        {
+            (*devCnt)++;
+            return ERR_NONE;
+        }
+
+        /* A Collision has been identified  Activity 2.1  9.3.7.4  (Symbol 3) */
+        colPending = true;
+        colCnt = 1;
+
+        /* Check if the Collision Resolution is set to perform only Collision detection   Activity 2.1  9.3.7.5 (Symbol 4)*/
+        if(devLimit == 0U) {
+            return ERR_RF_COLLISION;
+        }
+
+        platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
+
+        /*******************************************************************************/
+        /* Collisions pending, Anticollision loop must be executed                     */
+        /*******************************************************************************/
+    } else {
+        /* Advance to 16 slots below without mask. Will give a good chance to identify multiple cards */
+        colPending = true;
+        colCnt = 1;
+    }
+
+    /* Execute until all collisions are resolved Activity 2.1 9.3.7.18  (Symbol 17) */
+    do {
+        /* Activity 2.1  9.3.7.7  (Symbol 6 / 7) */
+        colPending = false;
+        slotNum = 0;
+
+        do {
+            if(slotNum == 0U) {
+                /* Send INVENTORY_REQ with 16 slots   Activity 2.1  9.3.7.9  (Symbol 8) */
+                ret = rfalNfcvPollerInventory(
+                    RFAL_NFCV_NUM_SLOTS_16,
+                    colFound[colIt].maskLen,
+                    colFound[colIt].maskVal,
+                    &nfcvDevList[(*devCnt)].InvRes,
+                    &rcvdLen);
+            } else {
+                ret = rfalISO15693TransceiveEOFAnticollision(
+                    (uint8_t*)&nfcvDevList[(*devCnt)].InvRes,
+                    sizeof(rfalNfcvInventoryRes),
+                    &rcvdLen);
+            }
+            slotNum++;
+
+            /*******************************************************************************/
+            if(ret != ERR_TIMEOUT) {
+                if(rcvdLen <
+                   rfalConvBytesToBits(
+                       RFAL_NFCV_INV_RES_LEN +
+                       RFAL_NFCV_CRC_LEN)) { /* If only a partial frame was received make sure the FDT_V_INVENT_NORES is fulfilled */
+                    platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
+                }
+
+                /* Check if response is a correct frame (no TxRx error)  Activity 2.1  9.3.7.11  (Symbol 10)*/
+                if((ret == ERR_NONE) || (ret == ERR_PROTO)) {
+                    /* Check if the device found is already on the list and its response is a valid INVENTORY_RES */
+                    if(rfalNfcvCheckInvRes(nfcvDevList[(*devCnt)].InvRes.RES_FLAG, rcvdLen)) {
+                        /* Activity 2.1  9.3.7.12  (Symbol 11) */
+                        (*devCnt)++;
+                    }
+                } else /* Treat everything else as collision */
+                {
+                    /* Activity 2.1  9.3.7.17  (Symbol 16) */
+                    colPending = true;
+
+                    /*******************************************************************************/
+                    /* Ensure that this collision still fits on the container */
+                    if(colCnt < RFAL_NFCV_MAX_COLL_SUPPORTED) {
+                        /* Store this collision on the container to be resolved later */
+                        /* Activity 2.1  9.3.7.17  (Symbol 16): add the collision information
+                         * (MASK_VAL + SN) to the list containing the collision information */
+                        ST_MEMCPY(
+                            colFound[colCnt].maskVal, colFound[colIt].maskVal, RFAL_NFCV_UID_LEN);
+                        colPos = colFound[colIt].maskLen;
+                        colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] &=
+                            (uint8_t)((1U << (colPos % RFAL_BITS_IN_BYTE)) - 1U);
+                        colFound[colCnt].maskVal[(colPos / RFAL_BITS_IN_BYTE)] |=
+                            (uint8_t)((slotNum - 1U) << (colPos % RFAL_BITS_IN_BYTE));
+                        colFound[colCnt].maskVal[((colPos / RFAL_BITS_IN_BYTE) + 1U)] =
+                            (uint8_t)((slotNum - 1U) >>
+                                      (RFAL_BITS_IN_BYTE - (colPos % RFAL_BITS_IN_BYTE)));
+
+                        colFound[colCnt].maskLen = (colFound[colIt].maskLen + 4U);
+
+                        colCnt++;
+                    }
+                }
+            } else {
+                /* Timeout */
+                platformDelay(RFAL_NFCV_FDT_V_INVENT_NORES);
+            }
+
+            /* Check if devices found have reached device limit   Activity 2.1  9.3.7.13  (Symbol 12) */
+            if(*devCnt >= devLimit) {
+                return ERR_NONE;
+            }
+
+        } while(slotNum < RFAL_NFCV_MAX_SLOTS); /* Slot loop             */
+        colIt++;
+    } while(colIt < colCnt); /* Collisions found loop */
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerSleepCollisionResolution(
+    uint8_t devLimit,
+    rfalNfcvListenDevice* nfcvDevList,
+    uint8_t* devCnt) {
+    uint8_t tmpDevCnt;
+    ReturnCode ret;
+    uint8_t i;
+
+    if((nfcvDevList == NULL) || (devCnt == NULL)) {
+        return ERR_PARAM;
+    }
+
+    *devCnt = 0;
+
+    do {
+        tmpDevCnt = 0;
+        ret = rfalNfcvPollerCollisionResolution(
+            RFAL_COMPLIANCE_MODE_ISO, (devLimit - *devCnt), &nfcvDevList[*devCnt], &tmpDevCnt);
+
+        for(i = *devCnt; i < (*devCnt + tmpDevCnt); i++) {
+            rfalNfcvPollerSleep(0x00, nfcvDevList[i].InvRes.UID);
+            nfcvDevList[i].isSleep = true;
+        }
+        *devCnt += tmpDevCnt;
+    } while((ret == ERR_NONE) && (tmpDevCnt > 0U) && (*devCnt < devLimit));
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerSleep(uint8_t flags, const uint8_t* uid) {
+    ReturnCode ret;
+    rfalNfcvSlpvReq slpReq;
+    uint8_t rxBuf; /* dummy buffer, just to perform Rx */
+
+    if(uid == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Compute SLPV_REQ */
+    slpReq.REQ_FLAG =
+        (flags |
+         (uint8_t)
+             RFAL_NFCV_REQ_FLAG_ADDRESS); /* Should be with UID according Digital 2.0 (Candidate) 9.7.1.1 */
+    slpReq.CMD = RFAL_NFCV_CMD_SLPV;
+    ST_MEMCPY(slpReq.UID, uid, RFAL_NFCV_UID_LEN);
+
+    /* NFC Forum device SHALL wait at least FDTVpp to consider the SLPV acknowledged (FDTVpp = FDTVpoll)  Digital 2.0 (Candidate)  9.7  9.8.2  */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&slpReq,
+        sizeof(rfalNfcvSlpvReq),
+        &rxBuf,
+        sizeof(rxBuf),
+        NULL,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCV_FDT_MAX1);
+    if(ret != ERR_TIMEOUT) {
+        return ret;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerSelect(uint8_t flags, const uint8_t* uid) {
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    if(uid == NULL) {
+        return ERR_PARAM;
+    }
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_SELECT,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        NULL,
+        0U,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t bn;
+
+    bn = blockNum;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        &bn,
+        sizeof(uint8_t),
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    /* Check for valid parameters */
+    if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
+        return ERR_PARAM;
+    }
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = blockNum; /* Set Block Number (8 bits)  */
+    ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
+    dataLen += blockLen;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerLockBlock(uint8_t flags, const uint8_t* uid, uint8_t blockNum) {
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+    uint8_t bn;
+
+    bn = blockNum;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_LOCK_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        &bn,
+        sizeof(uint8_t),
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = firstBlockNum; /* Set first Block Number       */
+    data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerWriteMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t blockLen,
+    const uint8_t* wrData,
+    uint16_t wrDataLen) {
+    ReturnCode ret;
+    uint16_t rcvLen;
+    uint16_t reqLen;
+    rfalNfcvGenericRes res;
+    uint16_t msgIt;
+
+    /* Calculate required buffer length */
+    reqLen = (uint16_t)((uid != NULL) ?
+                            (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
+                            (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
+
+    if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
+       ((((uint16_t)numOfBlocks) * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U) ||
+       (wrData == NULL)) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+
+    /* Compute Request Command */
+    txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
+    txBuf[msgIt++] = RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS;
+
+    /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
+    if(uid != NULL) {
+        txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
+        ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
+        msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
+    }
+
+    txBuf[msgIt++] = firstBlockNum;
+    txBuf[msgIt++] = (numOfBlocks - 1U);
+
+    if(wrDataLen > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
+        msgIt += wrDataLen;
+    }
+
+    /* Transceive Command */
+    ret = rfalTransceiveBlockingTxRx(
+        txBuf,
+        msgIt,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCV_FDT_MAX);
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /* Check if the response minimum length has been received */
+    if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
+        return ERR_PROTO;
+    }
+
+    /* Check if an error has been signalled */
+    if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
+        return rfalNfcvParseError(*res.data);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerExtendedReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)
+        blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
+    data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_EXTENDED_READ_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerExtendedWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    /* Check for valid parameters */
+    if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN)) {
+        return ERR_PARAM;
+    }
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)
+        blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
+    data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
+    ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write */
+    dataLen += blockLen;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalNfcvPollerExtendedLockSingleBlock(uint8_t flags, const uint8_t* uid, uint16_t blockNum) {
+    uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)
+        blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
+    data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerExtendedReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_EXTENDED_READ_MULTIPLE_BLOCK,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerExtendedWriteMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t blockLen,
+    const uint8_t* wrData,
+    uint16_t wrDataLen) {
+    ReturnCode ret;
+    uint16_t rcvLen;
+    uint16_t reqLen;
+    rfalNfcvGenericRes res;
+    uint16_t msgIt;
+    uint16_t nBlocks;
+
+    /* Calculate required buffer length */
+    reqLen =
+        ((uid != NULL) ? (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + RFAL_NFCV_UID_LEN + wrDataLen) :
+                         (RFAL_NFCV_WR_MUL_REQ_HEADER_LEN + wrDataLen));
+
+    if((reqLen > txBufLen) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) ||
+       (((uint16_t)numOfBlocks * (uint16_t)blockLen) != wrDataLen) || (numOfBlocks == 0U)) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+    nBlocks = (numOfBlocks - 1U);
+
+    /* Compute Request Command */
+    txBuf[msgIt++] = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
+    txBuf[msgIt++] = RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK;
+
+    /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
+    if(uid != NULL) {
+        txBuf[RFAL_NFCV_FLAG_POS] |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
+        ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
+        msgIt += (uint8_t)RFAL_NFCV_UID_LEN;
+    }
+
+    txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 0) & 0xFFU);
+    txBuf[msgIt++] = (uint8_t)((firstBlockNum >> 8) & 0xFFU);
+    txBuf[msgIt++] = (uint8_t)((nBlocks >> 0) & 0xFFU);
+    txBuf[msgIt++] = (uint8_t)((nBlocks >> 8) & 0xFFU);
+
+    if(wrDataLen > 0U) /* MISRA 21.18 */
+    {
+        ST_MEMCPY(&txBuf[msgIt], wrData, wrDataLen);
+        msgIt += wrDataLen;
+    }
+
+    /* Transceive Command */
+    ret = rfalTransceiveBlockingTxRx(
+        txBuf,
+        msgIt,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCV_FDT_MAX);
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /* Check if the response minimum length has been received */
+    if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
+        return ERR_PROTO;
+    }
+
+    /* Check if an error has been signalled */
+    if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
+        return rfalNfcvParseError(*res.data);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerGetSystemInformation(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_GET_SYS_INFO,
+        flags,
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        NULL,
+        0U,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerExtendedGetSystemInformation(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t requestField,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_EXTENDED_GET_SYS_INFO,
+        flags,
+        requestField,
+        uid,
+        NULL,
+        0U,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalNfcvPollerTransceiveReq(
+    uint8_t cmd,
+    uint8_t flags,
+    uint8_t param,
+    const uint8_t* uid,
+    const uint8_t* data,
+    uint16_t dataLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    ReturnCode ret;
+    rfalNfcvGenericReq req;
+    uint8_t msgIt;
+    rfalBitRate rxBR;
+    bool fastMode;
+
+    msgIt = 0;
+    fastMode = false;
+
+    /* Check for valid parameters */
+    if((rxBuf == NULL) || (rcvLen == NULL) || ((dataLen > 0U) && (data == NULL)) ||
+       (dataLen > ((uid != NULL) ? RFAL_NFCV_MAX_GEN_DATA_LEN :
+                                   (RFAL_NFCV_MAX_GEN_DATA_LEN - RFAL_NFCV_UID_LEN)))) {
+        return ERR_PARAM;
+    }
+
+    /* Check if the command is an ST's Fast command */
+    if((cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_MESSAGE) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION) ||
+       (cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION)) {
+        /* Store current Rx bit rate and move to fast mode */
+        rfalGetBitRate(NULL, &rxBR);
+        rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
+
+        fastMode = true;
+    }
+
+    /* Compute Request Command */
+    req.REQ_FLAG = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS)));
+    req.CMD = cmd;
+
+    /* Prepend parameter on ceratin proprietary requests: IC Manuf, Parameters */
+    if(param != RFAL_NFCV_PARAM_SKIP) {
+        req.payload.data[msgIt++] = param;
+    }
+
+    /* Check if Request is to be sent in Addressed mode. Select mode flag shall be set by user */
+    if(uid != NULL) {
+        req.REQ_FLAG |= (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS;
+        ST_MEMCPY(&req.payload.data[msgIt], uid, RFAL_NFCV_UID_LEN);
+        msgIt += RFAL_NFCV_UID_LEN;
+    }
+
+    if(dataLen > 0U) {
+        ST_MEMCPY(&req.payload.data[msgIt], data, dataLen);
+        msgIt += (uint8_t)dataLen;
+    }
+
+    /* Transceive Command */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&req,
+        (RFAL_NFCV_CMD_LEN + RFAL_NFCV_FLAG_LEN + (uint16_t)msgIt),
+        rxBuf,
+        rxBufLen,
+        rcvLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_NFCV_FDT_MAX);
+
+    /* If the Option Flag is set in certain commands an EOF needs to be sent after 20ms to retrieve the VICC response      ISO15693-3 2009  10.4.2 & 10.4.3 & 10.4.5 */
+    if(((flags & (uint8_t)RFAL_NFCV_REQ_FLAG_OPTION) != 0U) &&
+       ((cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK) ||
+        (cmd == (uint8_t)RFAL_NFCV_CMD_WRITE_MULTIPLE_BLOCKS) ||
+        (cmd == (uint8_t)RFAL_NFCV_CMD_LOCK_BLOCK) ||
+        (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_SINGLE_BLOCK) ||
+        (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_LOCK_SINGLE_BLOCK) ||
+        (cmd == (uint8_t)RFAL_NFCV_CMD_EXTENDED_WRITE_MULTIPLE_BLOCK))) {
+        ret = rfalISO15693TransceiveEOF(rxBuf, (uint8_t)rxBufLen, rcvLen);
+    }
+
+    /* Restore Rx BitRate */
+    if(fastMode) {
+        rfalSetBitRate(RFAL_BR_KEEP, rxBR);
+    }
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /* Check if the response minimum length has been received */
+    if((*rcvLen) < (uint8_t)RFAL_NFCV_FLAG_LEN) {
+        return ERR_PROTO;
+    }
+
+    /* Check if an error has been signalled */
+    if((rxBuf[RFAL_NFCV_FLAG_POS] & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
+        return rfalNfcvParseError(rxBuf[RFAL_NFCV_DATASTART_POS]);
+    }
+
+    return ERR_NONE;
+}
+
+#endif /* RFAL_FEATURE_NFCV */

+ 563 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_st25tb.c

@@ -0,0 +1,563 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *      www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_st25tb.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of ST25TB interface 
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_st25tb.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+#ifndef RFAL_FEATURE_ST25TB
+#define RFAL_FEATURE_ST25TB false /* ST25TB module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_ST25TB
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_ST25TB_CMD_LEN 1U /*!< ST25TB length of a command                       */
+#define RFAL_ST25TB_SLOTS 16U /*!< ST25TB number of slots                           */
+#define RFAL_ST25TB_SLOTNUM_MASK 0x0FU /*!< ST25TB Slot Number bit mask on SlotMarker        */
+#define RFAL_ST25TB_SLOTNUM_SHIFT 4U /*!< ST25TB Slot Number shift on SlotMarker           */
+
+#define RFAL_ST25TB_INITIATE_CMD1 0x06U /*!< ST25TB Initiate command byte1                    */
+#define RFAL_ST25TB_INITIATE_CMD2 0x00U /*!< ST25TB Initiate command byte2                    */
+#define RFAL_ST25TB_PCALL_CMD1 0x06U /*!< ST25TB Pcall16 command byte1                     */
+#define RFAL_ST25TB_PCALL_CMD2 0x04U /*!< ST25TB Pcall16 command byte2                     */
+#define RFAL_ST25TB_SELECT_CMD 0x0EU /*!< ST25TB Select command                            */
+#define RFAL_ST25TB_GET_UID_CMD 0x0BU /*!< ST25TB Get UID command                           */
+#define RFAL_ST25TB_COMPLETION_CMD 0x0FU /*!< ST25TB Completion command                        */
+#define RFAL_ST25TB_RESET_INV_CMD 0x0CU /*!< ST25TB Reset to Inventory command                */
+#define RFAL_ST25TB_READ_BLOCK_CMD 0x08U /*!< ST25TB Read Block command                        */
+#define RFAL_ST25TB_WRITE_BLOCK_CMD 0x09U /*!< ST25TB Write Block command                       */
+
+#define RFAL_ST25TB_T0 2157U /*!< ST25TB t0  159 us   ST25TB RF characteristics    */
+#define RFAL_ST25TB_T1 2048U /*!< ST25TB t1  151 us   ST25TB RF characteristics    */
+
+#define RFAL_ST25TB_FWT \
+    (RFAL_ST25TB_T0 + RFAL_ST25TB_T1) /*!< ST25TB FWT  = T0 + T1                            */
+#define RFAL_ST25TB_TW rfalConvMsTo1fc(7U) /*!< ST25TB TW : Programming time for write max 7ms   */
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Initiate Request */
+typedef struct {
+    uint8_t cmd1; /*!< Initiate Request cmd1: 0x06 */
+    uint8_t cmd2; /*!< Initiate Request cmd2: 0x00 */
+} rfalSt25tbInitiateReq;
+
+/*! Pcall16 Request */
+typedef struct {
+    uint8_t cmd1; /*!< Pcal16 Request cmd1: 0x06   */
+    uint8_t cmd2; /*!< Pcal16 Request cmd2: 0x04   */
+} rfalSt25tbPcallReq;
+
+/*! Select Request */
+typedef struct {
+    uint8_t cmd; /*!< Select Request cmd: 0x0E     */
+    uint8_t chipId; /*!< Chip ID                      */
+} rfalSt25tbSelectReq;
+
+/*! Read Block Request */
+typedef struct {
+    uint8_t cmd; /*!< Select Request cmd: 0x08     */
+    uint8_t address; /*!< Block address                */
+} rfalSt25tbReadBlockReq;
+
+/*! Write Block Request */
+typedef struct {
+    uint8_t cmd; /*!< Select Request cmd: 0x09     */
+    uint8_t address; /*!< Block address                */
+    rfalSt25tbBlock data; /*!< Block Data                   */
+} rfalSt25tbWriteBlockReq;
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+/*! 
+ *****************************************************************************
+ * \brief  ST25TB Poller Do Collision Resolution
+ *  
+ * This method performs ST25TB Collision resolution loop for each slot
+ *   
+ * \param[in]  devLimit      : device limit value, and size st25tbDevList
+ * \param[out] st25tbDevList : ST35TB listener device info
+ * \param[out] devCnt        : Devices found counter
+ * 
+ * \return colPending         : true if a collision was detected
+ *****************************************************************************
+ */
+static bool rfalSt25tbPollerDoCollisionResolution(
+    uint8_t devLimit,
+    rfalSt25tbListenDevice* st25tbDevList,
+    uint8_t* devCnt);
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+static bool rfalSt25tbPollerDoCollisionResolution(
+    uint8_t devLimit,
+    rfalSt25tbListenDevice* st25tbDevList,
+    uint8_t* devCnt) {
+    uint8_t i;
+    uint8_t chipId;
+    ReturnCode ret;
+    bool col;
+
+    col = false;
+
+    for(i = 0; i < RFAL_ST25TB_SLOTS; i++) {
+        platformDelay(1); /* Wait t2: Answer to new request delay  */
+
+        if(i == 0U) {
+            /* Step 2: Send Pcall16 */
+            ret = rfalSt25tbPollerPcall(&chipId);
+        } else {
+            /* Step 3-17: Send Pcall16 */
+            ret = rfalSt25tbPollerSlotMarker(i, &chipId);
+        }
+
+        if(ret == ERR_NONE) {
+            /* Found another device */
+            st25tbDevList[*devCnt].chipID = chipId;
+            st25tbDevList[*devCnt].isDeselected = false;
+
+            /* Select Device, retrieve its UID  */
+            ret = rfalSt25tbPollerSelect(chipId);
+
+            /* By Selecting this device, the previous gets Deselected */
+            if((*devCnt) > 0U) {
+                st25tbDevList[(*devCnt) - 1U].isDeselected = true;
+            }
+
+            if(ERR_NONE == ret) {
+                rfalSt25tbPollerGetUID(&st25tbDevList[*devCnt].UID);
+            }
+
+            if(ERR_NONE == ret) {
+                (*devCnt)++;
+            }
+        } else if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
+            col = true;
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+
+        if(*devCnt >= devLimit) {
+            break;
+        }
+    }
+    return col;
+}
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerInitialize(void) {
+    return rfalNfcbPollerInitialize();
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerCheckPresence(uint8_t* chipId) {
+    ReturnCode ret;
+    uint8_t chipIdRes;
+
+    chipIdRes = 0x00;
+
+    /* Send Initiate Request */
+    ret = rfalSt25tbPollerInitiate(&chipIdRes);
+
+    /*  Check if a transmission error was detected */
+    if((ret == ERR_CRC) || (ret == ERR_FRAMING)) {
+        return ERR_NONE;
+    }
+
+    /* Copy chip ID if requested */
+    if(chipId != NULL) {
+        *chipId = chipIdRes;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerInitiate(uint8_t* chipId) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    rfalSt25tbInitiateReq initiateReq;
+    uint8_t rxBuf
+        [RFAL_ST25TB_CHIP_ID_LEN +
+         RFAL_ST25TB_CRC_LEN]; /* In case we receive less data that CRC, RF layer will not remove the CRC from buffer */
+
+    /* Compute Initiate Request */
+    initiateReq.cmd1 = RFAL_ST25TB_INITIATE_CMD1;
+    initiateReq.cmd2 = RFAL_ST25TB_INITIATE_CMD2;
+
+    /* Send Initiate Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&initiateReq,
+        sizeof(rfalSt25tbInitiateReq),
+        (uint8_t*)rxBuf,
+        sizeof(rxBuf),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid Select Response   */
+    if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
+        return ERR_PROTO;
+    }
+
+    /* Copy chip ID if requested */
+    if(chipId != NULL) {
+        *chipId = *rxBuf;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerPcall(uint8_t* chipId) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    rfalSt25tbPcallReq pcallReq;
+
+    /* Compute Pcal16 Request */
+    pcallReq.cmd1 = RFAL_ST25TB_PCALL_CMD1;
+    pcallReq.cmd2 = RFAL_ST25TB_PCALL_CMD2;
+
+    /* Send Pcal16 Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&pcallReq,
+        sizeof(rfalSt25tbPcallReq),
+        (uint8_t*)chipId,
+        RFAL_ST25TB_CHIP_ID_LEN,
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid Select Response   */
+    if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
+        return ERR_PROTO;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerSlotMarker(uint8_t slotNum, uint8_t* chipIdRes) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    uint8_t slotMarker;
+
+    if((slotNum == 0U) || (slotNum > 15U)) {
+        return ERR_PARAM;
+    }
+
+    /* Compute SlotMarker */
+    slotMarker =
+        (((slotNum & RFAL_ST25TB_SLOTNUM_MASK) << RFAL_ST25TB_SLOTNUM_SHIFT) |
+         RFAL_ST25TB_PCALL_CMD1);
+
+    /* Send SlotMarker */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&slotMarker,
+        RFAL_ST25TB_CMD_LEN,
+        (uint8_t*)chipIdRes,
+        RFAL_ST25TB_CHIP_ID_LEN,
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid ChipID Response   */
+    if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_CHIP_ID_LEN)) {
+        return ERR_PROTO;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerSelect(uint8_t chipId) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    rfalSt25tbSelectReq selectReq;
+    uint8_t chipIdRes;
+
+    /* Compute Select Request */
+    selectReq.cmd = RFAL_ST25TB_SELECT_CMD;
+    selectReq.chipId = chipId;
+
+    /* Send Select Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&selectReq,
+        sizeof(rfalSt25tbSelectReq),
+        (uint8_t*)&chipIdRes,
+        RFAL_ST25TB_CHIP_ID_LEN,
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid Select Response   */
+    if((ret == ERR_NONE) && ((rxLen != RFAL_ST25TB_CHIP_ID_LEN) || (chipIdRes != chipId))) {
+        return ERR_PROTO;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerGetUID(rfalSt25tbUID* UID) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    uint8_t getUidReq;
+
+    /* Compute Get UID Request */
+    getUidReq = RFAL_ST25TB_GET_UID_CMD;
+
+    /* Send Select Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&getUidReq,
+        RFAL_ST25TB_CMD_LEN,
+        (uint8_t*)UID,
+        sizeof(rfalSt25tbUID),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid UID Response */
+    if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_UID_LEN)) {
+        return ERR_PROTO;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerCollisionResolution(
+    uint8_t devLimit,
+    rfalSt25tbListenDevice* st25tbDevList,
+    uint8_t* devCnt) {
+    uint8_t chipId;
+    ReturnCode ret;
+    bool detected; /* collision or device was detected */
+
+    if((st25tbDevList == NULL) || (devCnt == NULL) || (devLimit == 0U)) {
+        return ERR_PARAM;
+    }
+
+    *devCnt = 0;
+
+    /* Step 1: Send Initiate */
+    ret = rfalSt25tbPollerInitiate(&chipId);
+    if(ret == ERR_NONE) {
+        /* If only 1 answer is detected */
+        st25tbDevList[*devCnt].chipID = chipId;
+        st25tbDevList[*devCnt].isDeselected = false;
+
+        /* Retrieve its UID and keep it Selected*/
+        ret = rfalSt25tbPollerSelect(chipId);
+
+        if(ERR_NONE == ret) {
+            ret = rfalSt25tbPollerGetUID(&st25tbDevList[*devCnt].UID);
+        }
+
+        if(ERR_NONE == ret) {
+            (*devCnt)++;
+        }
+    }
+    /* Always proceed to Pcall16 anticollision as phase differences of tags can lead to no tag recognized, even if there is one */
+    if(*devCnt < devLimit) {
+        /* Multiple device responses */
+        do {
+            detected = rfalSt25tbPollerDoCollisionResolution(devLimit, st25tbDevList, devCnt);
+        } while((detected == true) && (*devCnt < devLimit));
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerReadBlock(uint8_t blockAddress, rfalSt25tbBlock* blockData) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    rfalSt25tbReadBlockReq readBlockReq;
+
+    /* Compute Read Block Request */
+    readBlockReq.cmd = RFAL_ST25TB_READ_BLOCK_CMD;
+    readBlockReq.address = blockAddress;
+
+    /* Send Read Block Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&readBlockReq,
+        sizeof(rfalSt25tbReadBlockReq),
+        (uint8_t*)blockData,
+        sizeof(rfalSt25tbBlock),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+
+    /* Check for valid UID Response */
+    if((ret == ERR_NONE) && (rxLen != RFAL_ST25TB_BLOCK_LEN)) {
+        return ERR_PROTO;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerWriteBlock(uint8_t blockAddress, const rfalSt25tbBlock* blockData) {
+    ReturnCode ret;
+    uint16_t rxLen;
+    rfalSt25tbWriteBlockReq writeBlockReq;
+    rfalSt25tbBlock tmpBlockData;
+
+    /* Compute Write Block Request */
+    writeBlockReq.cmd = RFAL_ST25TB_WRITE_BLOCK_CMD;
+    writeBlockReq.address = blockAddress;
+    ST_MEMCPY(&writeBlockReq.data, blockData, RFAL_ST25TB_BLOCK_LEN);
+
+    /* Send Write Block Request */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&writeBlockReq,
+        sizeof(rfalSt25tbWriteBlockReq),
+        tmpBlockData,
+        RFAL_ST25TB_BLOCK_LEN,
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        (RFAL_ST25TB_FWT + RFAL_ST25TB_TW));
+
+    /* Check if there was any error besides timeout */
+    if(ret != ERR_TIMEOUT) {
+        /* Check if an unexpected answer was received */
+        if(ret == ERR_NONE) {
+            return ERR_PROTO;
+        }
+
+        /* Check whether a transmission error occurred */
+        if((ret != ERR_CRC) && (ret != ERR_FRAMING) && (ret != ERR_NOMEM) &&
+           (ret != ERR_RF_COLLISION)) {
+            return ret;
+        }
+
+        /* If a transmission error occurred (maybe noise while committing data) wait maximum programming time and verify data afterwards */
+        rfalSetGT((RFAL_ST25TB_FWT + RFAL_ST25TB_TW));
+        rfalFieldOnAndStartGT();
+    }
+
+    ret = rfalSt25tbPollerReadBlock(blockAddress, &tmpBlockData);
+    if(ret == ERR_NONE) {
+        if(ST_BYTECMP(&tmpBlockData, blockData, RFAL_ST25TB_BLOCK_LEN) == 0) {
+            return ERR_NONE;
+        }
+        return ERR_PROTO;
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerCompletion(void) {
+    uint8_t completionReq;
+
+    /* Compute Completion Request */
+    completionReq = RFAL_ST25TB_COMPLETION_CMD;
+
+    /* Send Completion Request, no response is expected */
+    return rfalTransceiveBlockingTxRx(
+        (uint8_t*)&completionReq,
+        RFAL_ST25TB_CMD_LEN,
+        NULL,
+        0,
+        NULL,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+}
+
+/*******************************************************************************/
+ReturnCode rfalSt25tbPollerResetToInventory(void) {
+    uint8_t resetInvReq;
+
+    /* Compute Completion Request */
+    resetInvReq = RFAL_ST25TB_RESET_INV_CMD;
+
+    /* Send Completion Request, no response is expected */
+    return rfalTransceiveBlockingTxRx(
+        (uint8_t*)&resetInvReq,
+        RFAL_ST25TB_CMD_LEN,
+        NULL,
+        0,
+        NULL,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25TB_FWT);
+}
+
+#endif /* RFAL_FEATURE_ST25TB */

+ 818 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_st25xv.c

@@ -0,0 +1,818 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_st25xv.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief NFC-V ST25 NFC-V Tag specific features
+ *
+ *  This module provides support for ST's specific features available on
+ *  NFC-V (ISO15693) tag families: ST25D, ST25TV, M24LR
+ *
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_st25xv.h"
+#include "../include/rfal_nfcv.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_ST25xV
+#define RFAL_FEATURE_ST25xV false /* ST25xV module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_ST25xV
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_ST25xV_READ_CONFIG_LEN \
+    2U /*!< READ CONFIGURATION length                                         */
+#define RFAL_ST25xV_READ_MSG_LEN_LEN \
+    2U /*!< READ MESSAGE LENGTH length                                        */
+#define RFAL_ST25xV_CONF_POINTER_LEN \
+    1U /*!< READ/WRITE CONFIGURATION Pointer length                           */
+#define RFAL_ST25xV_CONF_REGISTER_LEN \
+    1U /*!< READ/WRITE CONFIGURATION Register length                          */
+#define RFAL_ST25xV_PWDNUM_LEN \
+    1U /*!< Password Number length                                            */
+#define RFAL_ST25xV_PWD_LEN \
+    8U /*!< Password length                                                   */
+#define RFAL_ST25xV_MBPOINTER_LEN \
+    1U /*!< Read Message MBPointer length                                     */
+#define RFAL_ST25xV_NUMBYTES_LEN \
+    1U /*!< Read Message Number of Bytes length                               */
+
+#define RFAL_ST25TV02K_TBOOT_RF \
+    1U /*!< RF Boot time (Minimum time from carrier generation to first data) */
+#define RFAL_ST25TV02K_TRF_OFF \
+    2U /*!< RF OFF time                                                       */
+
+#define RFAL_ST25xV_FDT_POLL_MAX \
+    rfalConvMsTo1fc(20) /*!< Maximum Wait time FDTV,EOF 20 ms    Digital 2.1  B.5 */
+#define RFAL_NFCV_FLAG_POS \
+    0U /*!< Flag byte position                                                */
+#define RFAL_NFCV_FLAG_LEN \
+    1U /*!< Flag byte length                                                  */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+static ReturnCode rfalST25xVPollerGenericReadConfiguration(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue);
+static ReturnCode rfalST25xVPollerGenericWriteConfiguration(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue);
+static ReturnCode rfalST25xVPollerGenericReadMessageLength(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* msgLen);
+static ReturnCode rfalST25xVPollerGenericReadMessage(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen);
+static ReturnCode rfalST25xVPollerGenericWriteMessage(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen);
+/*
+******************************************************************************
+* LOCAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+static ReturnCode rfalST25xVPollerGenericReadConfiguration(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue) {
+    ReturnCode ret;
+    uint8_t p;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    if(regValue == NULL) {
+        return ERR_PARAM;
+    }
+
+    p = pointer;
+
+    ret = rfalNfcvPollerTransceiveReq(
+        cmd,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        &p,
+        sizeof(uint8_t),
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+    if(ret == ERR_NONE) {
+        if(rcvLen < RFAL_ST25xV_READ_CONFIG_LEN) {
+            ret = ERR_PROTO;
+        } else {
+            *regValue = res.data[0];
+        }
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalST25xVPollerGenericWriteConfiguration(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue) {
+    uint8_t data[RFAL_ST25xV_CONF_POINTER_LEN + RFAL_ST25xV_CONF_REGISTER_LEN];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    dataLen = 0U;
+
+    data[dataLen++] = pointer;
+    data[dataLen++] = regValue;
+
+    return rfalNfcvPollerTransceiveReq(
+        cmd,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+static ReturnCode rfalST25xVPollerGenericReadMessageLength(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* msgLen) {
+    ReturnCode ret;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    if(msgLen == NULL) {
+        return ERR_PARAM;
+    }
+
+    ret = rfalNfcvPollerTransceiveReq(
+        cmd,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        NULL,
+        0,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+    if(ret == ERR_NONE) {
+        if(rcvLen < RFAL_ST25xV_READ_MSG_LEN_LEN) {
+            ret = ERR_PROTO;
+        } else {
+            *msgLen = res.data[0];
+        }
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalST25xVPollerGenericReadMessage(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[RFAL_ST25xV_MBPOINTER_LEN + RFAL_ST25xV_NUMBYTES_LEN];
+    uint8_t dataLen;
+
+    dataLen = 0;
+
+    /* Compute Request Data */
+    data[dataLen++] = mbPointer;
+    data[dataLen++] = numBytes;
+
+    return rfalNfcvPollerTransceiveReq(
+        cmd, flags, RFAL_NFCV_ST_IC_MFG_CODE, uid, data, dataLen, rxBuf, rxBufLen, rcvLen);
+}
+
+/*******************************************************************************/
+static ReturnCode rfalST25xVPollerGenericWriteMessage(
+    uint8_t cmd,
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen) {
+    ReturnCode ret;
+    uint8_t reqFlag;
+    uint16_t msgIt;
+    rfalBitRate rxBR;
+    bool fastMode;
+    rfalNfcvGenericRes res;
+    uint16_t rcvLen;
+
+    /* Calculate required Tx buf length:                    Mfg Code               UID                      MSGLen  MSGLen+1 */
+    msgIt = (uint16_t)(msgLen + sizeof(flags) + sizeof(cmd) + 1U +
+                       ((uid != NULL) ? RFAL_NFCV_UID_LEN : 0U) + 1U + 1U);
+    /* Note:  MSGlength parameter of the command is the number of Data bytes minus - 1 (00 for 1 byte of data, FFh for 256 bytes of data) */
+
+    /* Check for valid parameters */
+    if((txBuf == NULL) || (msgData == NULL) || (txBufLen < msgIt)) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+    fastMode = false;
+
+    /* Check if the command is an ST's Fast command */
+    if(cmd == (uint8_t)RFAL_NFCV_CMD_FAST_WRITE_MESSAGE) {
+        /* Store current Rx bit rate and move to fast mode */
+        rfalGetBitRate(NULL, &rxBR);
+        rfalSetBitRate(RFAL_BR_KEEP, RFAL_BR_52p97);
+
+        fastMode = true;
+    }
+
+    /* Compute Request Command */
+    reqFlag = (uint8_t)(flags & (~((uint32_t)RFAL_NFCV_REQ_FLAG_ADDRESS) &
+                                 ~((uint32_t)RFAL_NFCV_REQ_FLAG_SELECT)));
+    reqFlag |=
+        ((uid != NULL) ? (uint8_t)RFAL_NFCV_REQ_FLAG_ADDRESS : (uint8_t)RFAL_NFCV_REQ_FLAG_SELECT);
+
+    txBuf[msgIt++] = reqFlag;
+    txBuf[msgIt++] = cmd;
+    txBuf[msgIt++] = RFAL_NFCV_ST_IC_MFG_CODE;
+
+    if(uid != NULL) {
+        ST_MEMCPY(&txBuf[msgIt], uid, RFAL_NFCV_UID_LEN);
+        msgIt += RFAL_NFCV_UID_LEN;
+    }
+    txBuf[msgIt++] = msgLen;
+    ST_MEMCPY(
+        &txBuf[msgIt],
+        msgData,
+        (uint16_t)(msgLen + (uint16_t)1U)); /* Message Data contains (MSGLength + 1) bytes */
+    msgIt += (uint16_t)(msgLen + (uint16_t)1U);
+
+    /* Transceive Command */
+    ret = rfalTransceiveBlockingTxRx(
+        txBuf,
+        msgIt,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_ST25xV_FDT_POLL_MAX);
+
+    /* Restore Rx BitRate */
+    if(fastMode) {
+        rfalSetBitRate(RFAL_BR_KEEP, rxBR);
+    }
+
+    if(ret != ERR_NONE) {
+        return ret;
+    }
+
+    /* Check if the response minimum length has been received */
+    if(rcvLen < (uint8_t)RFAL_NFCV_FLAG_LEN) {
+        return ERR_PROTO;
+    }
+
+    /* Check if an error has been signalled */
+    if((res.RES_FLAG & (uint8_t)RFAL_NFCV_RES_FLAG_ERROR) != 0U) {
+        return ERR_PROTO;
+    }
+
+    return ERR_NONE;
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerM24LRReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN];
+    uint8_t dataLen;
+
+    dataLen = 0;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
+    data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_READ_SINGLE_BLOCK,
+        (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerM24LRWriteSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    const uint8_t* wrData,
+    uint8_t blockLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_MAX_BLOCK_LEN)];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    /* Check for valid parameters */
+    if((blockLen == 0U) || (blockLen > (uint8_t)RFAL_NFCV_MAX_BLOCK_LEN) || (wrData == NULL)) {
+        return ERR_PARAM;
+    }
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
+    data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
+    ST_MEMCPY(&data[dataLen], wrData, blockLen); /* Append Block data to write       */
+    dataLen += blockLen;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_WRITE_SINGLE_BLOCK,
+        (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerM24LRReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */
+    data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
+    data[dataLen++] = numOfBlocks; /* Set number of blocks to read         */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_READ_MULTIPLE_BLOCKS,
+        (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
+        RFAL_NFCV_PARAM_SKIP,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t bn;
+
+    bn = blockNum;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        &bn,
+        sizeof(uint8_t),
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerM24LRFastReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[RFAL_NFCV_BLOCKNUM_M24LR_LEN];
+    uint8_t dataLen;
+
+    dataLen = 0;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)blockNum; /* Set M24LR Block Number (16 bits) LSB */
+    data[dataLen++] = (uint8_t)(blockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_READ_SINGLE_BLOCK,
+        (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerM24LRFastReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_M24LR_LEN + RFAL_NFCV_BLOCKNUM_M24LR_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)firstBlockNum; /* Set M24LR Block Number (16 bits) LSB */
+    data[dataLen++] = (uint8_t)(firstBlockNum >> 8U); /* Set M24LR Block Number (16 bits) MSB */
+    data[dataLen++] = numOfBlocks; /* Set number of blocks to read         */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS,
+        (flags | (uint8_t)RFAL_NFCV_REQ_FLAG_PROTOCOL_EXT),
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t firstBlockNum,
+    uint8_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_LEN + RFAL_NFCV_BLOCKNUM_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = firstBlockNum; /* Set first Block Number       */
+    data[dataLen++] = numOfBlocks; /* Set number of blocks to read */
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_READ_MULTIPLE_BLOCKS,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastExtendedReadSingleBlock(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t blockNum,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[RFAL_NFCV_BLOCKNUM_EXTENDED_LEN];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)
+        blockNum; /* TS T5T 1.0 BNo is considered as a multi-byte field. TS T5T 1.0 5.1.1.13 multi-byte field follows [DIGITAL]. [DIGITAL] 9.3.1 A multiple byte field is transmitted LSB first. */
+    data[dataLen++] = (uint8_t)((blockNum >> 8U) & 0xFFU);
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_EXTENDED_READ_SINGLE_BLOCK,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastExtReadMultipleBlocks(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint16_t firstBlockNum,
+    uint16_t numOfBlocks,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    uint8_t data[(RFAL_NFCV_BLOCKNUM_EXTENDED_LEN + RFAL_NFCV_BLOCKNUM_EXTENDED_LEN)];
+    uint8_t dataLen;
+
+    dataLen = 0U;
+
+    /* Compute Request Data */
+    data[dataLen++] = (uint8_t)((firstBlockNum >> 0U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((firstBlockNum >> 8U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((numOfBlocks >> 0U) & 0xFFU);
+    data[dataLen++] = (uint8_t)((numOfBlocks >> 8U) & 0xFFU);
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_FAST_EXTENDED_READ_MULTIPLE_BLOCKS,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerReadConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue) {
+    return rfalST25xVPollerGenericReadConfiguration(
+        RFAL_NFCV_CMD_READ_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerWriteConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue) {
+    return rfalST25xVPollerGenericWriteConfiguration(
+        RFAL_NFCV_CMD_WRITE_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerReadDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue) {
+    return rfalST25xVPollerGenericReadConfiguration(
+        RFAL_NFCV_CMD_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerWriteDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue) {
+    return rfalST25xVPollerGenericWriteConfiguration(
+        RFAL_NFCV_CMD_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastReadDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t* regValue) {
+    return rfalST25xVPollerGenericReadConfiguration(
+        RFAL_NFCV_CMD_FAST_READ_DYN_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastWriteDynamicConfiguration(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pointer,
+    uint8_t regValue) {
+    return rfalST25xVPollerGenericWriteConfiguration(
+        RFAL_NFCV_CMD_FAST_WRITE_DYN_CONFIGURATION, flags, uid, pointer, regValue);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerPresentPassword(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t pwdNum,
+    const uint8_t* pwd,
+    uint8_t pwdLen) {
+    uint8_t data[RFAL_ST25xV_PWDNUM_LEN + RFAL_ST25xV_PWD_LEN];
+    uint8_t dataLen;
+    uint16_t rcvLen;
+    rfalNfcvGenericRes res;
+
+    if((pwdLen > RFAL_ST25xV_PWD_LEN) || (pwd == NULL)) {
+        return ERR_PARAM;
+    }
+
+    dataLen = 0U;
+    data[dataLen++] = pwdNum;
+    if(pwdLen > 0U) {
+        ST_MEMCPY(&data[dataLen], pwd, pwdLen);
+    }
+    dataLen += pwdLen;
+
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_PRESENT_PASSWORD,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        data,
+        dataLen,
+        (uint8_t*)&res,
+        sizeof(rfalNfcvGenericRes),
+        &rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerGetRandomNumber(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    rfalFieldOff();
+    platformDelay(RFAL_ST25TV02K_TRF_OFF);
+    rfalNfcvPollerInitialize();
+    rfalFieldOnAndStartGT();
+    platformDelay(RFAL_ST25TV02K_TBOOT_RF);
+    return rfalNfcvPollerTransceiveReq(
+        RFAL_NFCV_CMD_GET_RANDOM_NUMBER,
+        flags,
+        RFAL_NFCV_ST_IC_MFG_CODE,
+        uid,
+        NULL,
+        0U,
+        rxBuf,
+        rxBufLen,
+        rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerWriteMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen) {
+    return rfalST25xVPollerGenericWriteMessage(
+        RFAL_NFCV_CMD_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastWriteMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t msgLen,
+    const uint8_t* msgData,
+    uint8_t* txBuf,
+    uint16_t txBufLen) {
+    return rfalST25xVPollerGenericWriteMessage(
+        RFAL_NFCV_CMD_FAST_WRITE_MESSAGE, flags, uid, msgLen, msgData, txBuf, txBufLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerReadMessageLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen) {
+    return rfalST25xVPollerGenericReadMessageLength(
+        RFAL_NFCV_CMD_READ_MESSAGE_LENGTH, flags, uid, msgLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastReadMsgLength(uint8_t flags, const uint8_t* uid, uint8_t* msgLen) {
+    return rfalST25xVPollerGenericReadMessageLength(
+        RFAL_NFCV_CMD_FAST_READ_MESSAGE_LENGTH, flags, uid, msgLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerReadMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    return rfalST25xVPollerGenericReadMessage(
+        RFAL_NFCV_CMD_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalST25xVPollerFastReadMessage(
+    uint8_t flags,
+    const uint8_t* uid,
+    uint8_t mbPointer,
+    uint8_t numBytes,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rcvLen) {
+    return rfalST25xVPollerGenericReadMessage(
+        RFAL_NFCV_CMD_FAST_READ_MESSAGE, flags, uid, mbPointer, numBytes, rxBuf, rxBufLen, rcvLen);
+}
+
+#endif /* RFAL_FEATURE_ST25xV */

+ 233 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t1t.c

@@ -0,0 +1,233 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t1t.c
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides NFC-A T1T convenience methods and definitions
+ *  
+ *  This module provides an interface to perform as a NFC-A Reader/Writer
+ *  to handle a Type 1 Tag T1T (Topaz) 
+ *  
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_t1t.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_T1T
+#define RFAL_FEATURE_T1T false /* T1T module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_T1T
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+
+#define RFAL_T1T_DRD_READ \
+    (1236U * 2U) /*!< DRD for Reads with n=9         => 1236/fc  ~= 91 us   T1T 1.2  4.4.2 */
+#define RFAL_T1T_DRD_WRITE \
+    36052U /*!< DRD for Write with n=281       => 36052/fc ~= 2659 us T1T 1.2  4.4.2 */
+#define RFAL_T1T_DRD_WRITE_E \
+    70996U /*!< DRD for Write/Erase with n=554 => 70996/fc ~= 5236 us T1T 1.2  4.4.2 */
+
+#define RFAL_T1T_RID_RES_HR0_VAL \
+    0x10U /*!< HR0 indicating NDEF support  Digital 2.0 (Candidate) 11.6.2.1        */
+#define RFAL_T1T_RID_RES_HR0_MASK \
+    0xF0U /*!< HR0 most significant nibble mask                                     */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-A T1T (Topaz) RID_REQ  Digital 1.1  10.6.1 & Table 49 */
+typedef struct {
+    uint8_t cmd; /*!< T1T cmd: RID              */
+    uint8_t add; /*!< ADD: undefined value      */
+    uint8_t data; /*!< DATA: undefined value     */
+    uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID-echo: undefined value */
+} rfalT1TRidReq;
+
+/*! NFC-A T1T (Topaz) RALL_REQ   T1T 1.2  Table 4 */
+typedef struct {
+    uint8_t cmd; /*!< T1T cmd: RALL             */
+    uint8_t add1; /*!< ADD: 0x00                 */
+    uint8_t add0; /*!< ADD: 0x00                 */
+    uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID                       */
+} rfalT1TRallReq;
+
+/*! NFC-A T1T (Topaz) WRITE_REQ   T1T 1.2  Table 4 */
+typedef struct {
+    uint8_t cmd; /*!< T1T cmd: RALL             */
+    uint8_t add; /*!< ADD                       */
+    uint8_t data; /*!< DAT                       */
+    uint8_t uid[RFAL_T1T_UID_LEN]; /*!< UID                       */
+} rfalT1TWriteReq;
+
+/*! NFC-A T1T (Topaz) WRITE_RES   T1T 1.2  Table 4 */
+typedef struct {
+    uint8_t add; /*!< ADD                       */
+    uint8_t data; /*!< DAT                       */
+} rfalT1TWriteRes;
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+ReturnCode rfalT1TPollerInitialize(void) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(ret, rfalSetMode(RFAL_MODE_POLL_NFCA_T1T, RFAL_BR_106, RFAL_BR_106));
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_NFC);
+
+    rfalSetGT(
+        RFAL_GT_NONE); /* T1T should only be initialized after NFC-A mode, therefore the GT has been fulfilled */
+    rfalSetFDTListen(
+        RFAL_FDT_LISTEN_NFCA_POLLER); /* T1T uses NFC-A FDT Listen with n=9   Digital 1.1  10.7.2                             */
+    rfalSetFDTPoll(RFAL_FDT_POLL_NFCA_T1T_POLLER);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalT1TPollerRid(rfalT1TRidRes* ridRes) {
+    ReturnCode ret;
+    rfalT1TRidReq ridReq;
+    uint16_t rcvdLen;
+
+    if(ridRes == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Compute RID command and set Undefined Values to 0x00    Digital 1.1 10.6.1 */
+    ST_MEMSET(&ridReq, 0x00, sizeof(rfalT1TRidReq));
+    ridReq.cmd = (uint8_t)RFAL_T1T_CMD_RID;
+
+    EXIT_ON_ERR(
+        ret,
+        rfalTransceiveBlockingTxRx(
+            (uint8_t*)&ridReq,
+            sizeof(rfalT1TRidReq),
+            (uint8_t*)ridRes,
+            sizeof(rfalT1TRidRes),
+            &rcvdLen,
+            RFAL_TXRX_FLAGS_DEFAULT,
+            RFAL_T1T_DRD_READ));
+
+    /* Check expected RID response length and the HR0   Digital 2.0 (Candidate) 11.6.2.1 */
+    if((rcvdLen != sizeof(rfalT1TRidRes)) ||
+       ((ridRes->hr0 & RFAL_T1T_RID_RES_HR0_MASK) != RFAL_T1T_RID_RES_HR0_VAL)) {
+        return ERR_PROTO;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalT1TPollerRall(const uint8_t* uid, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxRcvdLen) {
+    rfalT1TRallReq rallReq;
+
+    if((rxBuf == NULL) || (uid == NULL) || (rxRcvdLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /* Compute RALL command and set Add to 0x00 */
+    ST_MEMSET(&rallReq, 0x00, sizeof(rfalT1TRallReq));
+    rallReq.cmd = (uint8_t)RFAL_T1T_CMD_RALL;
+    ST_MEMCPY(rallReq.uid, uid, RFAL_T1T_UID_LEN);
+
+    return rfalTransceiveBlockingTxRx(
+        (uint8_t*)&rallReq,
+        sizeof(rfalT1TRallReq),
+        (uint8_t*)rxBuf,
+        rxBufLen,
+        rxRcvdLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_T1T_DRD_READ);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT1TPollerWrite(const uint8_t* uid, uint8_t address, uint8_t data) {
+    rfalT1TWriteReq writeReq;
+    rfalT1TWriteRes writeRes;
+    uint16_t rxRcvdLen;
+    ReturnCode err;
+
+    if(uid == NULL) {
+        return ERR_PARAM;
+    }
+
+    writeReq.cmd = (uint8_t)RFAL_T1T_CMD_WRITE_E;
+    writeReq.add = address;
+    writeReq.data = data;
+    ST_MEMCPY(writeReq.uid, uid, RFAL_T1T_UID_LEN);
+
+    err = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&writeReq,
+        sizeof(rfalT1TWriteReq),
+        (uint8_t*)&writeRes,
+        sizeof(rfalT1TWriteRes),
+        &rxRcvdLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_T1T_DRD_WRITE_E);
+
+    if(err == ERR_NONE) {
+        if((writeReq.add != writeRes.add) || (writeReq.data != writeRes.data) ||
+           (rxRcvdLen != sizeof(rfalT1TWriteRes))) {
+            return ERR_PROTO;
+        }
+    }
+    return err;
+}
+
+#endif /* RFAL_FEATURE_T1T */

+ 253 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t2t.c

@@ -0,0 +1,253 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t2t.c
+ *
+ *  \author 
+ *
+ *  \brief Provides NFC-A T2T convenience methods and definitions
+ *  
+ *  This module provides an interface to perform as a NFC-A Reader/Writer
+ *  to handle a Type 2 Tag T2T 
+ *  
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_t2t.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_T2T
+#define RFAL_FEATURE_T2T false /* T2T module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_T2T
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+#define RFAL_FDT_POLL_READ_MAX \
+    rfalConvMsTo1fc(           \
+        5U) /*!< Maximum Wait time for Read command as defined in TS T2T 1.0 table 18   */
+#define RFAL_FDT_POLL_WRITE_MAX \
+    rfalConvMsTo1fc(            \
+        10U) /*!< Maximum Wait time for Write command as defined in TS T2T 1.0 table 18  */
+#define RFAL_FDT_POLL_SL_MAX \
+    rfalConvMsTo1fc(         \
+        1U) /*!< Maximum Wait time for Sector Select as defined in TS T2T 1.0 table 18  */
+#define RFAL_T2T_ACK_NACK_LEN \
+    1U /*!< Len of NACK in bytes (4 bits)                                          */
+#define RFAL_T2T_ACK \
+    0x0AU /*!< ACK value                                                              */
+#define RFAL_T2T_ACK_MASK \
+    0x0FU /*!< ACK value                                                              */
+
+#define RFAL_T2T_SECTOR_SELECT_P1_BYTE2 \
+    0xFFU /*!< Sector Select Packet 1 byte 2                                          */
+#define RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN \
+    3U /*!< Sector Select RFU length                                               */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! NFC-A T2T command set    T2T 1.0 5.1 */
+typedef enum {
+    RFAL_T2T_CMD_READ = 0x30, /*!< T2T Read                                */
+    RFAL_T2T_CMD_WRITE = 0xA2, /*!< T2T Write                               */
+    RFAL_T2T_CMD_SECTOR_SELECT = 0xC2 /*!< T2T Sector Select                       */
+} rfalT2Tcmds;
+
+/*! NFC-A T2T READ     T2T 1.0 5.2 and table 11 */
+typedef struct {
+    uint8_t code; /*!< Command code                            */
+    uint8_t blNo; /*!< Block number                            */
+} rfalT2TReadReq;
+
+/*! NFC-A T2T WRITE    T2T 1.0 5.3 and table 12 */
+typedef struct {
+    uint8_t code; /*!< Command code                            */
+    uint8_t blNo; /*!< Block number                            */
+    uint8_t data[RFAL_T2T_WRITE_DATA_LEN]; /*!< Data                                    */
+} rfalT2TWriteReq;
+
+/*! NFC-A T2T SECTOR SELECT Packet 1   T2T 1.0 5.4 and table 13 */
+typedef struct {
+    uint8_t code; /*!< Command code                            */
+    uint8_t byte2; /*!< Sector Select Packet 1 byte 2           */
+} rfalT2TSectorSelectP1Req;
+
+/*! NFC-A T2T SECTOR SELECT Packet 2   T2T 1.0 5.4 and table 13 */
+typedef struct {
+    uint8_t secNo; /*!< Block number                   */
+    uint8_t rfu[RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN]; /*!< Sector Select Packet RFU       */
+} rfalT2TSectorSelectP2Req;
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+
+ReturnCode
+    rfalT2TPollerRead(uint8_t blockNum, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rcvLen) {
+    ReturnCode ret;
+    rfalT2TReadReq req;
+
+    if((rxBuf == NULL) || (rcvLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    req.code = (uint8_t)RFAL_T2T_CMD_READ;
+    req.blNo = blockNum;
+
+    /* Transceive Command */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&req,
+        sizeof(rfalT2TReadReq),
+        rxBuf,
+        rxBufLen,
+        rcvLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_FDT_POLL_READ_MAX);
+
+    /* T2T 1.0 5.2.1.7 The Reader/Writer SHALL treat a NACK in response to a READ Command as a Protocol Error */
+    if((ret == ERR_INCOMPLETE_BYTE) && (*rcvLen == RFAL_T2T_ACK_NACK_LEN) &&
+       ((*rxBuf & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK)) {
+        return ERR_PROTO;
+    }
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalT2TPollerWrite(uint8_t blockNum, const uint8_t* wrData) {
+    ReturnCode ret;
+    rfalT2TWriteReq req;
+    uint8_t res;
+    uint16_t rxLen;
+
+    req.code = (uint8_t)RFAL_T2T_CMD_WRITE;
+    req.blNo = blockNum;
+    ST_MEMCPY(req.data, wrData, RFAL_T2T_WRITE_DATA_LEN);
+
+    /* Transceive WRITE Command */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&req,
+        sizeof(rfalT2TWriteReq),
+        &res,
+        sizeof(uint8_t),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_FDT_POLL_READ_MAX);
+
+    /* Check for a valid ACK */
+    if((ret == ERR_INCOMPLETE_BYTE) || (ret == ERR_NONE)) {
+        ret = ERR_PROTO;
+
+        if((rxLen == RFAL_T2T_ACK_NACK_LEN) && ((res & RFAL_T2T_ACK_MASK) == RFAL_T2T_ACK)) {
+            ret = ERR_NONE;
+        }
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalT2TPollerSectorSelect(uint8_t sectorNum) {
+    rfalT2TSectorSelectP1Req p1Req;
+    rfalT2TSectorSelectP2Req p2Req;
+    ReturnCode ret;
+    uint8_t res;
+    uint16_t rxLen;
+
+    /* Compute SECTOR SELECT Packet 1  */
+    p1Req.code = (uint8_t)RFAL_T2T_CMD_SECTOR_SELECT;
+    p1Req.byte2 = RFAL_T2T_SECTOR_SELECT_P1_BYTE2;
+
+    /* Transceive SECTOR SELECT Packet 1 */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&p1Req,
+        sizeof(rfalT2TSectorSelectP1Req),
+        &res,
+        sizeof(uint8_t),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_FDT_POLL_SL_MAX);
+
+    /* Check and report any transmission error */
+    if((ret != ERR_INCOMPLETE_BYTE) && (ret != ERR_NONE)) {
+        return ret;
+    }
+
+    /* Ensure that an ACK was received */
+    if((ret != ERR_INCOMPLETE_BYTE) || (rxLen != RFAL_T2T_ACK_NACK_LEN) ||
+       ((res & RFAL_T2T_ACK_MASK) != RFAL_T2T_ACK)) {
+        return ERR_PROTO;
+    }
+
+    /* Compute SECTOR SELECT Packet 2  */
+    p2Req.secNo = sectorNum;
+    ST_MEMSET(&p2Req.rfu, 0x00, RFAL_T2T_SECTOR_SELECT_P2_RFU_LEN);
+
+    /* Transceive SECTOR SELECT Packet 2 */
+    ret = rfalTransceiveBlockingTxRx(
+        (uint8_t*)&p2Req,
+        sizeof(rfalT2TSectorSelectP2Req),
+        &res,
+        sizeof(uint8_t),
+        &rxLen,
+        RFAL_TXRX_FLAGS_DEFAULT,
+        RFAL_FDT_POLL_SL_MAX);
+
+    /* T2T 1.0 5.4.1.14 The Reader/Writer SHALL treat any response received before the end of PATT2T,SL,MAX as a Protocol Error */
+    if((ret == ERR_NONE) || (ret == ERR_INCOMPLETE_BYTE)) {
+        return ERR_PROTO;
+    }
+
+    /* T2T 1.0 5.4.1.13 The Reader/Writer SHALL treat the transmission of the SECTOR SELECT Command Packet 2 as being successful when it receives no response until PATT2T,SL,MAX. */
+    if(ret == ERR_TIMEOUT) {
+        return ERR_NONE;
+    }
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_T2T */

+ 397 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/rfal_t4t.c

@@ -0,0 +1,397 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision:
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_t4t.h
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Provides convenience methods and definitions for T4T (ISO7816-4)
+ *  
+ *  This module provides an interface to exchange T4T APDUs according to 
+ *  NFC Forum T4T and ISO7816-4
+ *  
+ *  This implementation was based on the following specs:
+ *    - ISO/IEC 7816-4  3rd Edition 2013-04-15
+ *    - NFC Forum T4T Technical Specification 1.0 2017-08-28
+ *  
+ */
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../include/rfal_t4t.h"
+#include "../utils.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCH
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_T4T
+#define RFAL_FEATURE_T4T false /* T4T module configuration missing. Disabled by default */
+#endif
+
+#if RFAL_FEATURE_T4T
+
+/*
+ ******************************************************************************
+ * GLOBAL DEFINES
+ ******************************************************************************
+ */
+#define RFAL_T4T_OFFSET_DO 0x54U /*!< Tag value for offset BER-TLV data object          */
+#define RFAL_T4T_LENGTH_DO 0x03U /*!< Len value for offset BER-TLV data object          */
+#define RFAL_T4T_DATA_DO 0x53U /*!< Tag value for data BER-TLV data object            */
+
+#define RFAL_T4T_MAX_LC 255U /*!< Maximum Lc value for short Lc coding              */
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*
+ ******************************************************************************
+ * LOCAL VARIABLES
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * GLOBAL FUNCTIONS
+ ******************************************************************************
+ */
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeCAPDU(const rfalT4tCApduParam* apduParam) {
+    uint8_t hdrLen;
+    uint16_t msgIt;
+
+    if((apduParam == NULL) || (apduParam->cApduBuf == NULL) || (apduParam->cApduLen == NULL)) {
+        return ERR_PARAM;
+    }
+
+    msgIt = 0;
+    *(apduParam->cApduLen) = 0;
+
+    /*******************************************************************************/
+    /* Compute Command-APDU  according to the format   T4T 1.0 5.1.2 & ISO7816-4 2013 Table 1 */
+
+    /* Check if Data is present */
+    if(apduParam->LcFlag) {
+        if(apduParam->Lc == 0U) {
+            /* Extended field coding not supported */
+            return ERR_PARAM;
+        }
+
+        /* Check whether requested Lc fits */
+#pragma GCC diagnostic ignored "-Wtype-limits"
+        if((uint16_t)apduParam->Lc >
+           (uint16_t)(RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN - RFAL_T4T_LE_LEN)) {
+            return ERR_PARAM; /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset  */
+        }
+
+        /* Calculate the header length a place the data/body where it should be */
+        hdrLen = RFAL_T4T_MAX_CAPDU_PROLOGUE_LEN + RFAL_T4T_LC_LEN;
+
+        /* make sure not to exceed buffer size */
+        if(((uint16_t)hdrLen + (uint16_t)apduParam->Lc +
+            (apduParam->LeFlag ? RFAL_T4T_LC_LEN : 0U)) > RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN) {
+            return ERR_NOMEM; /*  PRQA S  2880 # MISRA 2.1 - Unreachable code due to configuration option being set/unset */
+        }
+        ST_MEMMOVE(&apduParam->cApduBuf->apdu[hdrLen], apduParam->cApduBuf->apdu, apduParam->Lc);
+    }
+
+    /* Prepend the ADPDU's header */
+    apduParam->cApduBuf->apdu[msgIt++] = apduParam->CLA;
+    apduParam->cApduBuf->apdu[msgIt++] = apduParam->INS;
+    apduParam->cApduBuf->apdu[msgIt++] = apduParam->P1;
+    apduParam->cApduBuf->apdu[msgIt++] = apduParam->P2;
+
+    /* Check if Data field length is to be added */
+    if(apduParam->LcFlag) {
+        apduParam->cApduBuf->apdu[msgIt++] = apduParam->Lc;
+        msgIt += apduParam->Lc;
+    }
+
+    /* Check if Expected Response Length is to be added */
+    if(apduParam->LeFlag) {
+        apduParam->cApduBuf->apdu[msgIt++] = apduParam->Le;
+    }
+
+    *(apduParam->cApduLen) = msgIt;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerParseRAPDU(rfalT4tRApduParam* apduParam) {
+    if((apduParam == NULL) || (apduParam->rApduBuf == NULL)) {
+        return ERR_PARAM;
+    }
+
+    if(apduParam->rcvdLen < RFAL_T4T_MAX_RAPDU_SW1SW2_LEN) {
+        return ERR_PROTO;
+    }
+
+    apduParam->rApduBodyLen = (apduParam->rcvdLen - (uint16_t)RFAL_T4T_MAX_RAPDU_SW1SW2_LEN);
+    apduParam->statusWord = GETU16((&apduParam->rApduBuf->apdu[apduParam->rApduBodyLen]));
+
+    /* Check SW1 SW2    T4T 1.0 5.1.3 NOTE */
+    if(apduParam->statusWord == RFAL_T4T_ISO7816_STATUS_COMPLETE) {
+        return ERR_NONE;
+    }
+
+    return ERR_REQUEST;
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeSelectAppl(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* aid,
+    uint8_t aidLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+
+    /* CLA INS P1  P2   Lc  Data   Le  */
+    /* 00h A4h 00h 00h  07h AID    00h */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
+    cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_DF_NAME;
+    cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
+               RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
+    cAPDU.Lc = aidLen;
+    cAPDU.Le = 0x00;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = true;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    if(aidLen > 0U) {
+        ST_MEMCPY(cAPDU.cApduBuf->apdu, aid, aidLen);
+    }
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeSelectFile(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* fid,
+    uint8_t fidLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+
+    /* CLA INS P1  P2   Lc  Data   Le  */
+    /* 00h A4h 00h 0Ch  02h FID    -   */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
+    cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
+    cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
+               RFAL_T4T_ISO7816_P2_SELECT_NO_RESPONSE_DATA;
+    cAPDU.Lc = fidLen;
+    cAPDU.Le = 0x00;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = false;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    if(fidLen > 0U) {
+        ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
+    }
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeSelectFileV1Mapping(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    const uint8_t* fid,
+    uint8_t fidLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+
+    /* CLA INS P1  P2   Lc  Data   Le  */
+    /* 00h A4h 00h 00h  02h FID    -   */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_SELECT;
+    cAPDU.P1 = RFAL_T4T_ISO7816_P1_SELECT_BY_FILEID;
+    cAPDU.P2 = RFAL_T4T_ISO7816_P2_SELECT_FIRST_OR_ONLY_OCCURENCE |
+               RFAL_T4T_ISO7816_P2_SELECT_RETURN_FCI_TEMPLATE;
+    cAPDU.Lc = fidLen;
+    cAPDU.Le = 0x00;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = false;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    if(fidLen > 0U) {
+        ST_MEMCPY(cAPDU.cApduBuf->apdu, fid, fidLen);
+    }
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeReadData(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint16_t offset,
+    uint8_t expLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+
+    /* CLA INS P1  P2   Lc  Data   Le  */
+    /* 00h B0h [Offset] -   -      len */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY;
+    cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
+    cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
+    cAPDU.Le = expLen;
+    cAPDU.LcFlag = false;
+    cAPDU.LeFlag = true;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeReadDataODO(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint32_t offset,
+    uint8_t expLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+    uint8_t dataIt;
+
+    /* CLA INS P1  P2  Lc  Data         Le */
+    /* 00h B1h 00h 00h Lc  54 03 xxyyzz len */
+    /*                          [Offset]    */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_READBINARY_ODO;
+    cAPDU.P1 = 0x00U;
+    cAPDU.P2 = 0x00U;
+    cAPDU.Le = expLen;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = true;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    dataIt = 0U;
+    cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
+    cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
+    cAPDU.Lc = dataIt;
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeWriteData(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint16_t offset,
+    const uint8_t* data,
+    uint8_t dataLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+
+    /* CLA INS P1  P2   Lc  Data   Le  */
+    /* 00h D6h [Offset] len Data   -   */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY;
+    cAPDU.P1 = (uint8_t)((offset >> 8U) & 0xFFU);
+    cAPDU.P2 = (uint8_t)((offset >> 0U) & 0xFFU);
+    cAPDU.Lc = dataLen;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = false;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    if(dataLen > 0U) {
+        ST_MEMCPY(cAPDU.cApduBuf->apdu, data, dataLen);
+    }
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+/*******************************************************************************/
+ReturnCode rfalT4TPollerComposeWriteDataODO(
+    rfalIsoDepApduBufFormat* cApduBuf,
+    uint32_t offset,
+    const uint8_t* data,
+    uint8_t dataLen,
+    uint16_t* cApduLen) {
+    rfalT4tCApduParam cAPDU;
+    uint8_t dataIt;
+
+    /* CLA INS P1  P2   Lc  Data                     Le  */
+    /* 00h D7h 00h 00h  len 54 03 xxyyzz 53 Ld data  -   */
+    /*                           [offset]     [data]     */
+    cAPDU.CLA = RFAL_T4T_CLA;
+    cAPDU.INS = (uint8_t)RFAL_T4T_INS_UPDATEBINARY_ODO;
+    cAPDU.P1 = 0x00U;
+    cAPDU.P2 = 0x00U;
+    cAPDU.LcFlag = true;
+    cAPDU.LeFlag = false;
+    cAPDU.cApduBuf = cApduBuf;
+    cAPDU.cApduLen = cApduLen;
+
+    dataIt = 0U;
+    cApduBuf->apdu[dataIt++] = RFAL_T4T_OFFSET_DO;
+    cApduBuf->apdu[dataIt++] = RFAL_T4T_LENGTH_DO;
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 16U);
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset >> 8U);
+    cApduBuf->apdu[dataIt++] = (uint8_t)(offset);
+    cApduBuf->apdu[dataIt++] = RFAL_T4T_DATA_DO;
+    cApduBuf->apdu[dataIt++] = dataLen;
+
+    if((((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_T4T_MAX_LC) ||
+       (((uint32_t)dataLen + (uint32_t)dataIt) >= RFAL_FEATURE_ISO_DEP_APDU_MAX_LEN)) {
+        return (ERR_NOMEM);
+    }
+
+    if(dataLen > 0U) {
+        ST_MEMCPY(&cAPDU.cApduBuf->apdu[dataIt], data, dataLen);
+    }
+    dataIt += dataLen;
+    cAPDU.Lc = dataIt;
+
+    return rfalT4TPollerComposeCAPDU(&cAPDU);
+}
+
+#endif /* RFAL_FEATURE_T4T */

+ 1487 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_analogConfigTbl.h

@@ -0,0 +1,1487 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file rfal_analogConfig.h
+ *
+ *  \author bkam
+ *
+ *  \brief ST25R3916 Analog Configuration Settings
+ *  
+ */
+
+#ifndef ST25R3916_ANALOGCONFIG_H
+#define ST25R3916_ANALOGCONFIG_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../../include/rfal_analogConfig.h"
+#include "st25r3916_com.h"
+
+/*
+ ******************************************************************************
+ * DEFINES
+ ******************************************************************************
+ */
+
+/*
+ ******************************************************************************
+ * GLOBAL MACROS
+ ******************************************************************************
+ */
+
+/*! Macro for Configuration Setting with only one register-mask-value set: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1] */
+#define MODE_ENTRY_1_REG(MODE, R0, M0, V0)                           \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 1, \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0)
+
+/*! Macro for Configuration Setting with only two register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1] */
+#define MODE_ENTRY_2_REG(MODE, R0, M0, V0, R1, M1, V1)                                          \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 2,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1)
+
+/*! Macro for Configuration Setting with only three register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_3_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2)                              \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 3,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2)
+
+/*! Macro for Configuration Setting with only four register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_4_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3)                  \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 4,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3)
+
+/*! Macro for Configuration Setting with only five register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_5_REG(MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4)      \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 5,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4)
+
+/*! Macro for Configuration Setting with only six register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_6_REG(                                                                       \
+    MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5)               \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 6,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5)
+
+/*! Macro for Configuration Setting with only seven register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_7_REG(                                                                       \
+    MODE, R0, M0, V0, R1, M1, V1, R2, M2, V2, R3, M3, V3, R4, M4, V4, R5, M5, V5, R6, M6, V6)   \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 7,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6)
+
+/*! Macro for Configuration Setting with only eight register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_8_REG(                                                                       \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7)                                                                                         \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 8,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7)
+
+/*! Macro for Configuration Setting with only nine register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_9_REG(                                                                       \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7,                                                                                         \
+    R8,                                                                                         \
+    M8,                                                                                         \
+    V8)                                                                                         \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 9,                            \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8)
+
+/*! Macro for Configuration Setting with only ten register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_10_REG(                                                                      \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7,                                                                                         \
+    R8,                                                                                         \
+    M8,                                                                                         \
+    V8,                                                                                         \
+    R9,                                                                                         \
+    M9,                                                                                         \
+    V9)                                                                                         \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 10,                           \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9)
+
+/*! Macro for Configuration Setting with eleven register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_11_REG(                                                                      \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7,                                                                                         \
+    R8,                                                                                         \
+    M8,                                                                                         \
+    V8,                                                                                         \
+    R9,                                                                                         \
+    M9,                                                                                         \
+    V9,                                                                                         \
+    R10,                                                                                        \
+    M10,                                                                                        \
+    V10)                                                                                        \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 11,                           \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10)
+
+/*! Macro for Configuration Setting with twelve register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_12_REG(                                                                      \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7,                                                                                         \
+    R8,                                                                                         \
+    M8,                                                                                         \
+    V8,                                                                                         \
+    R9,                                                                                         \
+    M9,                                                                                         \
+    V9,                                                                                         \
+    R10,                                                                                        \
+    M10,                                                                                        \
+    V10,                                                                                        \
+    R11,                                                                                        \
+    M11,                                                                                        \
+    V11)                                                                                        \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 12,                           \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8U), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11)
+
+/*! Macro for Configuration Setting with thirteen register-mask-value sets: 
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_13_REG(                                                                      \
+    MODE,                                                                                       \
+    R0,                                                                                         \
+    M0,                                                                                         \
+    V0,                                                                                         \
+    R1,                                                                                         \
+    M1,                                                                                         \
+    V1,                                                                                         \
+    R2,                                                                                         \
+    M2,                                                                                         \
+    V2,                                                                                         \
+    R3,                                                                                         \
+    M3,                                                                                         \
+    V3,                                                                                         \
+    R4,                                                                                         \
+    M4,                                                                                         \
+    V4,                                                                                         \
+    R5,                                                                                         \
+    M5,                                                                                         \
+    V5,                                                                                         \
+    R6,                                                                                         \
+    M6,                                                                                         \
+    V6,                                                                                         \
+    R7,                                                                                         \
+    M7,                                                                                         \
+    V7,                                                                                         \
+    R8,                                                                                         \
+    M8,                                                                                         \
+    V8,                                                                                         \
+    R9,                                                                                         \
+    M9,                                                                                         \
+    V9,                                                                                         \
+    R10,                                                                                        \
+    M10,                                                                                        \
+    V10,                                                                                        \
+    R11,                                                                                        \
+    M11,                                                                                        \
+    V11,                                                                                        \
+    R12,                                                                                        \
+    M12,                                                                                        \
+    V12)                                                                                        \
+    (uint8_t)((uint16_t)(MODE) >> 8U), (uint8_t)((MODE) & 0xFFU), 13,                           \
+        (uint8_t)((uint16_t)(R0) >> 8U), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8U), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8U), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8U), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8U), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8U), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8U), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8U), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8U), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8U), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8U), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8U), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11), (uint8_t)((uint16_t)(R12) >> 8U),                       \
+        (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12)
+
+/*! Macro for Configuration Setting with fourteen register-mask-value sets:
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_14_REG(                                                                     \
+    MODE,                                                                                      \
+    R0,                                                                                        \
+    M0,                                                                                        \
+    V0,                                                                                        \
+    R1,                                                                                        \
+    M1,                                                                                        \
+    V1,                                                                                        \
+    R2,                                                                                        \
+    M2,                                                                                        \
+    V2,                                                                                        \
+    R3,                                                                                        \
+    M3,                                                                                        \
+    V3,                                                                                        \
+    R4,                                                                                        \
+    M4,                                                                                        \
+    V4,                                                                                        \
+    R5,                                                                                        \
+    M5,                                                                                        \
+    V5,                                                                                        \
+    R6,                                                                                        \
+    M6,                                                                                        \
+    V6,                                                                                        \
+    R7,                                                                                        \
+    M7,                                                                                        \
+    V7,                                                                                        \
+    R8,                                                                                        \
+    M8,                                                                                        \
+    V8,                                                                                        \
+    R9,                                                                                        \
+    M9,                                                                                        \
+    V9,                                                                                        \
+    R10,                                                                                       \
+    M10,                                                                                       \
+    V10,                                                                                       \
+    R11,                                                                                       \
+    M11,                                                                                       \
+    V11,                                                                                       \
+    R12,                                                                                       \
+    M12,                                                                                       \
+    V12,                                                                                       \
+    R13,                                                                                       \
+    M13,                                                                                       \
+    V13,                                                                                       \
+    R14,                                                                                       \
+    M14,                                                                                       \
+    V14,                                                                                       \
+    R15,                                                                                       \
+    M15,                                                                                       \
+    V15)                                                                                       \
+    (uint8_t)((uint16_t)(MODE) >> 8), (uint8_t)((MODE) & 0xFFU), 14,                           \
+        (uint8_t)((uint16_t)(R0) >> 8), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11), (uint8_t)((uint16_t)(R12) >> 8),                       \
+        (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12),                              \
+        (uint8_t)((uint16_t)(R13) >> 8), (uint8_t)((R13) & 0xFFU), (uint8_t)(M13), (uint8_t)(V13)
+
+/*! Macro for Configuration Setting with fifteen register-mask-value sets:
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_15_REG(                                                                     \
+    MODE,                                                                                      \
+    R0,                                                                                        \
+    M0,                                                                                        \
+    V0,                                                                                        \
+    R1,                                                                                        \
+    M1,                                                                                        \
+    V1,                                                                                        \
+    R2,                                                                                        \
+    M2,                                                                                        \
+    V2,                                                                                        \
+    R3,                                                                                        \
+    M3,                                                                                        \
+    V3,                                                                                        \
+    R4,                                                                                        \
+    M4,                                                                                        \
+    V4,                                                                                        \
+    R5,                                                                                        \
+    M5,                                                                                        \
+    V5,                                                                                        \
+    R6,                                                                                        \
+    M6,                                                                                        \
+    V6,                                                                                        \
+    R7,                                                                                        \
+    M7,                                                                                        \
+    V7,                                                                                        \
+    R8,                                                                                        \
+    M8,                                                                                        \
+    V8,                                                                                        \
+    R9,                                                                                        \
+    M9,                                                                                        \
+    V9,                                                                                        \
+    R10,                                                                                       \
+    M10,                                                                                       \
+    V10,                                                                                       \
+    R11,                                                                                       \
+    M11,                                                                                       \
+    V11,                                                                                       \
+    R12,                                                                                       \
+    M12,                                                                                       \
+    V12,                                                                                       \
+    R13,                                                                                       \
+    M13,                                                                                       \
+    V13,                                                                                       \
+    R14,                                                                                       \
+    M14,                                                                                       \
+    V14,                                                                                       \
+    R15,                                                                                       \
+    M15,                                                                                       \
+    V15)                                                                                       \
+    (uint8_t)((uint16_t)(MODE) >> 8), (uint8_t)((MODE) & 0xFFU), 15,                           \
+        (uint8_t)((uint16_t)(R0) >> 8), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11), (uint8_t)((uint16_t)(R12) >> 8),                       \
+        (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12),                              \
+        (uint8_t)((uint16_t)(R13) >> 8), (uint8_t)((R13) & 0xFFU), (uint8_t)(M13),             \
+        (uint8_t)(V13), (uint8_t)((uint16_t)(R14) >> 8), (uint8_t)((R14) & 0xFFU),             \
+        (uint8_t)(M14), (uint8_t)(V14)
+
+/*! Macro for Configuration Setting with sixteen register-mask-value sets:
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_16_REG(                                                                     \
+    MODE,                                                                                      \
+    R0,                                                                                        \
+    M0,                                                                                        \
+    V0,                                                                                        \
+    R1,                                                                                        \
+    M1,                                                                                        \
+    V1,                                                                                        \
+    R2,                                                                                        \
+    M2,                                                                                        \
+    V2,                                                                                        \
+    R3,                                                                                        \
+    M3,                                                                                        \
+    V3,                                                                                        \
+    R4,                                                                                        \
+    M4,                                                                                        \
+    V4,                                                                                        \
+    R5,                                                                                        \
+    M5,                                                                                        \
+    V5,                                                                                        \
+    R6,                                                                                        \
+    M6,                                                                                        \
+    V6,                                                                                        \
+    R7,                                                                                        \
+    M7,                                                                                        \
+    V7,                                                                                        \
+    R8,                                                                                        \
+    M8,                                                                                        \
+    V8,                                                                                        \
+    R9,                                                                                        \
+    M9,                                                                                        \
+    V9,                                                                                        \
+    R10,                                                                                       \
+    M10,                                                                                       \
+    V10,                                                                                       \
+    R11,                                                                                       \
+    M11,                                                                                       \
+    V11,                                                                                       \
+    R12,                                                                                       \
+    M12,                                                                                       \
+    V12,                                                                                       \
+    R13,                                                                                       \
+    M13,                                                                                       \
+    V13,                                                                                       \
+    R14,                                                                                       \
+    M14,                                                                                       \
+    V14,                                                                                       \
+    R15,                                                                                       \
+    M15,                                                                                       \
+    V15)                                                                                       \
+    (uint8_t)((uint16_t)(MODE) >> 8), (uint8_t)((MODE) & 0xFFU), 16,                           \
+        (uint8_t)((uint16_t)(R0) >> 8), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11), (uint8_t)((uint16_t)(R12) >> 8),                       \
+        (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12),                              \
+        (uint8_t)((uint16_t)(R13) >> 8), (uint8_t)((R13) & 0xFFU), (uint8_t)(M13),             \
+        (uint8_t)(V13), (uint8_t)((uint16_t)(R14) >> 8), (uint8_t)((R14) & 0xFFU),             \
+        (uint8_t)(M14), (uint8_t)(V14), (uint8_t)((uint16_t)(R15) >> 8),                       \
+        (uint8_t)((R15) & 0xFFU), (uint8_t)(M15), (uint8_t)(V15)
+
+/*! Macro for Configuration Setting with seventeen register-mask-value sets:
+ *  - Configuration ID[2], Number of Register sets to follow[1], Register[2], Mask[1], Value[1], Register[2], Mask[1], Value[1], Register[2]... */
+#define MODE_ENTRY_17_REG(                                                                     \
+    MODE,                                                                                      \
+    R0,                                                                                        \
+    M0,                                                                                        \
+    V0,                                                                                        \
+    R1,                                                                                        \
+    M1,                                                                                        \
+    V1,                                                                                        \
+    R2,                                                                                        \
+    M2,                                                                                        \
+    V2,                                                                                        \
+    R3,                                                                                        \
+    M3,                                                                                        \
+    V3,                                                                                        \
+    R4,                                                                                        \
+    M4,                                                                                        \
+    V4,                                                                                        \
+    R5,                                                                                        \
+    M5,                                                                                        \
+    V5,                                                                                        \
+    R6,                                                                                        \
+    M6,                                                                                        \
+    V6,                                                                                        \
+    R7,                                                                                        \
+    M7,                                                                                        \
+    V7,                                                                                        \
+    R8,                                                                                        \
+    M8,                                                                                        \
+    V8,                                                                                        \
+    R9,                                                                                        \
+    M9,                                                                                        \
+    V9,                                                                                        \
+    R10,                                                                                       \
+    M10,                                                                                       \
+    V10,                                                                                       \
+    R11,                                                                                       \
+    M11,                                                                                       \
+    V11,                                                                                       \
+    R12,                                                                                       \
+    M12,                                                                                       \
+    V12,                                                                                       \
+    R13,                                                                                       \
+    M13,                                                                                       \
+    V13,                                                                                       \
+    R14,                                                                                       \
+    M14,                                                                                       \
+    V14,                                                                                       \
+    R15,                                                                                       \
+    M15,                                                                                       \
+    V15,                                                                                       \
+    R16,                                                                                       \
+    M16,                                                                                       \
+    V16)                                                                                       \
+    (uint8_t)((uint16_t)(MODE) >> 8), (uint8_t)((MODE) & 0xFFU), 17,                           \
+        (uint8_t)((uint16_t)(R0) >> 8), (uint8_t)((R0) & 0xFFU), (uint8_t)(M0), (uint8_t)(V0), \
+        (uint8_t)((uint16_t)(R1) >> 8), (uint8_t)((R1) & 0xFFU), (uint8_t)(M1), (uint8_t)(V1), \
+        (uint8_t)((uint16_t)(R2) >> 8), (uint8_t)((R2) & 0xFFU), (uint8_t)(M2), (uint8_t)(V2), \
+        (uint8_t)((uint16_t)(R3) >> 8), (uint8_t)((R3) & 0xFFU), (uint8_t)(M3), (uint8_t)(V3), \
+        (uint8_t)((uint16_t)(R4) >> 8), (uint8_t)((R4) & 0xFFU), (uint8_t)(M4), (uint8_t)(V4), \
+        (uint8_t)((uint16_t)(R5) >> 8), (uint8_t)((R5) & 0xFFU), (uint8_t)(M5), (uint8_t)(V5), \
+        (uint8_t)((uint16_t)(R6) >> 8), (uint8_t)((R6) & 0xFFU), (uint8_t)(M6), (uint8_t)(V6), \
+        (uint8_t)((uint16_t)(R7) >> 8), (uint8_t)((R7) & 0xFFU), (uint8_t)(M7), (uint8_t)(V7), \
+        (uint8_t)((uint16_t)(R8) >> 8), (uint8_t)((R8) & 0xFFU), (uint8_t)(M8), (uint8_t)(V8), \
+        (uint8_t)((uint16_t)(R9) >> 8), (uint8_t)((R9) & 0xFFU), (uint8_t)(M9), (uint8_t)(V9), \
+        (uint8_t)((uint16_t)(R10) >> 8), (uint8_t)((R10) & 0xFFU), (uint8_t)(M10),             \
+        (uint8_t)(V10), (uint8_t)((uint16_t)(R11) >> 8), (uint8_t)((R11) & 0xFFU),             \
+        (uint8_t)(M11), (uint8_t)(V11), (uint8_t)((uint16_t)(R12) >> 8),                       \
+        (uint8_t)((R12) & 0xFFU), (uint8_t)(M12), (uint8_t)(V12),                              \
+        (uint8_t)((uint16_t)(R13) >> 8), (uint8_t)((R13) & 0xFFU), (uint8_t)(M13),             \
+        (uint8_t)(V13), (uint8_t)((uint16_t)(R14) >> 8), (uint8_t)((R14) & 0xFFU),             \
+        (uint8_t)(M14), (uint8_t)(V14), (uint8_t)((uint16_t)(R15) >> 8),                       \
+        (uint8_t)((R15) & 0xFFU), (uint8_t)(M15), (uint8_t)(V15),                              \
+        (uint8_t)((uint16_t)(R16) >> 8), (uint8_t)((R16) & 0xFFU), (uint8_t)(M16), (uint8_t)(V16)
+/*
+ ******************************************************************************
+ * GLOBAL DATA TYPES
+ ******************************************************************************
+ */
+/*  PRQA S 3406 1 # MISRA 8.6 - Externally generated table included by the library */ /*  PRQA S 1514 1 # MISRA 8.9 - Externally generated table included by the library */
+const uint8_t rfalAnalogConfigDefaultSettings[] = {
+
+    /****** Default Analog Configuration for Chip-Specific Reset ******/
+    MODE_ENTRY_17_REG(
+        (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT),
+        ST25R3916_REG_IO_CONF1,
+        (ST25R3916_REG_IO_CONF1_out_cl_mask | ST25R3916_REG_IO_CONF1_lf_clk_off),
+        0x07 /* Disable MCU_CLK */
+        ,
+        ST25R3916_REG_IO_CONF2,
+        (ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2),
+        0x18 /* SPI Pull downs */
+        ,
+        ST25R3916_REG_IO_CONF2,
+        ST25R3916_REG_IO_CONF2_aat_en,
+        ST25R3916_REG_IO_CONF2_aat_en /* Enable AAT */
+        ,
+        ST25R3916_REG_TX_DRIVER,
+        ST25R3916_REG_TX_DRIVER_d_res_mask,
+        0x00 /* Set RFO resistance Active Tx */
+        ,
+        ST25R3916_REG_RES_AM_MOD,
+        0xFF,
+        0x80 /* Use minimum non-overlap */
+        ,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV /* Lower activation threshold (higher than deactivation)*/
+        ,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask,
+        ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV /* Lower activation threshold (higher than deactivation)*/
+        ,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV /* Lower deactivation threshold */
+        ,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask,
+        ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV /* Lower deactivation threshold */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        ST25R3916_REG_AUX_MOD_lm_ext,
+        0x00 /* Disable External Load Modulation */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        ST25R3916_REG_AUX_MOD_lm_dri,
+        ST25R3916_REG_AUX_MOD_lm_dri /* Use internal Load Modulation */
+        ,
+        ST25R3916_REG_PASSIVE_TARGET,
+        ST25R3916_REG_PASSIVE_TARGET_fdel_mask,
+        (5U
+         << ST25R3916_REG_PASSIVE_TARGET_fdel_shift) /* Adjust the FDT to be aligned with the bitgrid  */
+        ,
+        ST25R3916_REG_PT_MOD,
+        (ST25R3916_REG_PT_MOD_ptm_res_mask | ST25R3916_REG_PT_MOD_pt_res_mask),
+        0x5f /* Reduce RFO resistance in Modulated state */
+        ,
+        ST25R3916_REG_EMD_SUP_CONF,
+        ST25R3916_REG_EMD_SUP_CONF_rx_start_emv,
+        ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on /* Enable start on first 4 bits */
+        ,
+        ST25R3916_REG_ANT_TUNE_A,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        ST25R3916_REG_ANT_TUNE_B,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        0x84U,
+        0x10,
+        0x10 /* Avoid chip internal overheat protection */
+        )
+
+    /****** Default Analog Configuration for Chip-Specific Poll Common ******/
+    ,
+    MODE_ENTRY_9_REG(
+        (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        ,
+        ST25R3916_REG_TX_DRIVER,
+        ST25R3916_REG_TX_DRIVER_am_mod_mask,
+        ST25R3916_REG_TX_DRIVER_am_mod_12percent /* Set Modulation index */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
+        0x00 /* Use AM via regulator */
+        ,
+        ST25R3916_REG_ANT_TUNE_A,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        ST25R3916_REG_ANT_TUNE_B,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx Common ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 106 ******/
+    ,
+    MODE_ENTRY_5_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_ook /* Use OOK */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Overshoot Protection */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Overshoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 106 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_106 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x08,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x2D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x51,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 212 ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
+        0x88 /* Use Resistive AM */
+        ,
+        ST25R3916_REG_RES_AM_MOD,
+        ST25R3916_REG_RES_AM_MOD_md_res_mask,
+        0x7F /* Set Resistive modulation */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 212 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_212 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x02,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x14,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 424 ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
+        0x88 /* Use Resistive AM */
+        ,
+        ST25R3916_REG_RES_AM_MOD,
+        ST25R3916_REG_RES_AM_MOD_md_res_mask,
+        0x7F /* Set Resistive modulation */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 424 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_424 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x42,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x54,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-A Tx 848 ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        ,
+        ST25R3916_REG_TX_DRIVER,
+        ST25R3916_REG_TX_DRIVER_am_mod_mask,
+        ST25R3916_REG_TX_DRIVER_am_mod_40percent /* Set Modulation index */
+        ,
+        ST25R3916_REG_AUX_MOD,
+        (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am),
+        0x00 /* Use AM via regulator */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll NFC-A Rx 848 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | RFAL_ANALOG_CONFIG_BITRATE_848 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x42,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x44,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-A Anticolision setting ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL),
+        ST25R3916_REG_CORR_CONF1,
+        ST25R3916_REG_CORR_CONF1_corr_s6,
+        0x00 /* Set collision detection level different from data */
+        )
+
+#ifdef RFAL_USE_COHE
+    /****** Default Analog Configuration for Poll NFC-B Rx Common ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_coherent /* Use Coherent Receiver */
+        )
+#else
+    /****** Default Analog Configuration for Poll NFC-B Rx Common ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
+        )
+#endif /*RFAL_USE_COHE*/
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 106 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_106 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x04,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x1B,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 212 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_212 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x02,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x14,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 424 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_424 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x42,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x54,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+
+    /****** Default Analog Configuration for Poll NFC-B Rx 848 ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB | RFAL_ANALOG_CONFIG_BITRATE_848 |
+         RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x42,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x44,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+#ifdef RFAL_USE_COHE
+
+    /****** Default Analog Configuration for Poll NFC-F Rx Common ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_coherent /* Use Pulse Receiver */
+        ,
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x54,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+#else
+    /****** Default Analog Configuration for Poll NFC-F Rx Common ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
+        ,
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x3D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x54,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x00)
+#endif /*RFAL_USE_COHE*/
+
+        ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | RFAL_ANALOG_CONFIG_BITRATE_1OF4 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_ook /* Use OOK */
+        )
+
+#ifdef RFAL_USE_COHE
+    /****** Default Analog Configuration for Poll NFC-V Rx Common ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_coherent /* Use Pulse Receiver */
+        ,
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x2D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x01)
+#else
+    /****** Default Analog Configuration for Poll NFC-V Rx Common ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_AUX,
+        ST25R3916_REG_AUX_dis_corr,
+        ST25R3916_REG_AUX_dis_corr_correlator /* Use Correlator Receiver */
+        ,
+        ST25R3916_REG_RX_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_RX_CONF2,
+        0xFF,
+        0x2D,
+        ST25R3916_REG_RX_CONF3,
+        0xFF,
+        0x00,
+        ST25R3916_REG_RX_CONF4,
+        0xFF,
+        0x00,
+        ST25R3916_REG_CORR_CONF1,
+        0xFF,
+        0x13,
+        ST25R3916_REG_CORR_CONF2,
+        0xFF,
+        0x01)
+#endif /*RFAL_USE_COHE*/
+
+    /****** Default Analog Configuration for Poll AP2P Tx 106 ******/
+    ,
+    MODE_ENTRY_5_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_106 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_ook /* Use OOK modulation */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Poll AP2P Tx 212 ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_212 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        )
+
+    /****** Default Analog Configuration for Poll AP2P Tx 424 ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P | RFAL_ANALOG_CONFIG_BITRATE_424 |
+         RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        )
+
+    /****** Default Analog Configuration for Chip-Specific Listen On ******/
+    ,
+    MODE_ENTRY_6_REG(
+        (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON),
+        ST25R3916_REG_ANT_TUNE_A,
+        0xFF,
+        0x00 /* Set Antenna Tuning (Listener): ANTL */
+        ,
+        ST25R3916_REG_ANT_TUNE_B,
+        0xFF,
+        0xff /* Set Antenna Tuning (Listener): ANTL */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Listen AP2P Tx Common ******/
+    ,
+    MODE_ENTRY_7_REG(
+        (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_ANT_TUNE_A,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        ST25R3916_REG_ANT_TUNE_B,
+        0xFF,
+        0x82 /* Set Antenna Tuning (Poller): ANTL */
+        ,
+        ST25R3916_REG_TX_DRIVER,
+        ST25R3916_REG_TX_DRIVER_am_mod_mask,
+        ST25R3916_REG_TX_DRIVER_am_mod_12percent /* Set Modulation index */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x00 /* Disable Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Listen AP2P Rx Common ******/
+    ,
+    MODE_ENTRY_3_REG(
+        (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX),
+        ST25R3916_REG_RX_CONF1,
+        ST25R3916_REG_RX_CONF1_lp_mask,
+        ST25R3916_REG_RX_CONF1_lp_1200khz /* Set Rx filter configuration */
+        ,
+        ST25R3916_REG_RX_CONF1,
+        ST25R3916_REG_RX_CONF1_hz_mask,
+        ST25R3916_REG_RX_CONF1_hz_12_200khz /* Set Rx filter configuration */
+        ,
+        ST25R3916_REG_RX_CONF2,
+        ST25R3916_REG_RX_CONF2_amd_sel,
+        ST25R3916_REG_RX_CONF2_amd_sel_mixer /* AM demodulator: mixer */
+        )
+
+    /****** Default Analog Configuration for Listen AP2P Tx 106 ******/
+    ,
+    MODE_ENTRY_5_REG(
+        (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+         RFAL_ANALOG_CONFIG_BITRATE_106 | RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_ook /* Use OOK modulation */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_OVERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Overshoot Protection  */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF1,
+        0xFF,
+        0x40 /* Set default Undershoot Protection */
+        ,
+        ST25R3916_REG_UNDERSHOOT_CONF2,
+        0xFF,
+        0x03 /* Set default Undershoot Protection */
+        )
+
+    /****** Default Analog Configuration for Listen AP2P Tx 212 ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+         RFAL_ANALOG_CONFIG_BITRATE_212 | RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        )
+
+    /****** Default Analog Configuration for Listen AP2P Tx 424 ******/
+    ,
+    MODE_ENTRY_1_REG(
+        (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+         RFAL_ANALOG_CONFIG_BITRATE_424 | RFAL_ANALOG_CONFIG_TX),
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_tr_am,
+        ST25R3916_REG_MODE_tr_am_am /* Use AM modulation */
+        )
+
+};
+
+#endif /* ST25R3916_ANALOGCONFIG_H */

+ 68 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_dpoTbl.h

@@ -0,0 +1,68 @@
+
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      $Revision: $
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Martin Zechleitner 
+ *
+ *  \brief RF Dynamic Power Table default values
+ */
+
+#ifndef ST25R3916_DPO_H
+#define ST25R3916_DPO_H
+
+/*
+ ******************************************************************************
+ * INCLUDES
+ ******************************************************************************
+ */
+#include "../../include/rfal_dpo.h"
+
+/*
+ ******************************************************************************
+ * GLOBAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! Default DPO table */
+const uint8_t rfalDpoDefaultSettings[] = {
+    0x00,
+    255,
+    200,
+    0x01,
+    210,
+    150,
+    0x02,
+    160,
+    100,
+    0x03,
+    110,
+    50,
+};
+
+#endif /* ST25R3916_DPO_H */

+ 109 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_features.h

@@ -0,0 +1,109 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio 
+ *
+ *  \brief RFAL Features/Capabilities Definition for ST25R3916
+ */
+
+#ifndef RFAL_FEATURES_H
+#define RFAL_FEATURES_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../../platform.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+#define RFAL_SUPPORT_MODE_POLL_NFCA true /*!< RFAL Poll NFCA mode support switch    */
+#define RFAL_SUPPORT_MODE_POLL_NFCB true /*!< RFAL Poll NFCB mode support switch    */
+#define RFAL_SUPPORT_MODE_POLL_NFCF true /*!< RFAL Poll NFCF mode support switch    */
+#define RFAL_SUPPORT_MODE_POLL_NFCV true /*!< RFAL Poll NFCV mode support switch    */
+#define RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P true /*!< RFAL Poll AP2P mode support switch    */
+#define RFAL_SUPPORT_MODE_LISTEN_NFCA true /*!< RFAL Listen NFCA mode support switch  */
+#define RFAL_SUPPORT_MODE_LISTEN_NFCB false /*!< RFAL Listen NFCB mode support switch  */
+#define RFAL_SUPPORT_MODE_LISTEN_NFCF true /*!< RFAL Listen NFCF mode support switch  */
+#define RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P true /*!< RFAL Listen AP2P mode support switch  */
+
+/*******************************************************************************/
+/*! RFAL supported Card Emulation (CE)        */
+#define RFAL_SUPPORT_CE                                                \
+    (RFAL_SUPPORT_MODE_LISTEN_NFCA || RFAL_SUPPORT_MODE_LISTEN_NFCB || \
+     RFAL_SUPPORT_MODE_LISTEN_NFCF)
+
+/*! RFAL supported Reader/Writer (RW)         */
+#define RFAL_SUPPORT_RW                                                                           \
+    (RFAL_SUPPORT_MODE_POLL_NFCA || RFAL_SUPPORT_MODE_POLL_NFCB || RFAL_SUPPORT_MODE_POLL_NFCF || \
+     RFAL_SUPPORT_MODE_POLL_NFCV)
+
+/*! RFAL support for Active P2P (AP2P)        */
+#define RFAL_SUPPORT_AP2P \
+    (RFAL_SUPPORT_MODE_POLL_ACTIVE_P2P || RFAL_SUPPORT_MODE_LISTEN_ACTIVE_P2P)
+
+/*******************************************************************************/
+#define RFAL_SUPPORT_BR_RW_106 true /*!< RFAL RW  106 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_212 true /*!< RFAL RW  212 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_424 true /*!< RFAL RW  424 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_848 true /*!< RFAL RW  848 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_1695 false /*!< RFAL RW 1695 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_3390 false /*!< RFAL RW 3390 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_6780 false /*!< RFAL RW 6780 Bit Rate support switch   */
+#define RFAL_SUPPORT_BR_RW_13560 false /*!< RFAL RW 6780 Bit Rate support switch   */
+
+/*******************************************************************************/
+#define RFAL_SUPPORT_BR_AP2P_106 true /*!< RFAL AP2P  106 Bit Rate support switch */
+#define RFAL_SUPPORT_BR_AP2P_212 true /*!< RFAL AP2P  212 Bit Rate support switch */
+#define RFAL_SUPPORT_BR_AP2P_424 true /*!< RFAL AP2P  424 Bit Rate support switch */
+#define RFAL_SUPPORT_BR_AP2P_848 false /*!< RFAL AP2P  848 Bit Rate support switch */
+
+/*******************************************************************************/
+#define RFAL_SUPPORT_BR_CE_A_106 true /*!< RFAL CE A 106 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_A_212 false /*!< RFAL CE A 212 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_A_424 false /*!< RFAL CE A 424 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_A_848 false /*!< RFAL CE A 848 Bit Rate support switch  */
+
+/*******************************************************************************/
+#define RFAL_SUPPORT_BR_CE_B_106 false /*!< RFAL CE B 106 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_B_212 false /*!< RFAL CE B 212 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_B_424 false /*!< RFAL CE B 424 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_B_848 false /*!< RFAL CE B 848 Bit Rate support switch  */
+
+/*******************************************************************************/
+#define RFAL_SUPPORT_BR_CE_F_212 true /*!< RFAL CE F 212 Bit Rate support switch  */
+#define RFAL_SUPPORT_BR_CE_F_424 true /*!< RFAL CE F 424 Bit Rate support switch  */
+
+#endif /* RFAL_FEATURES_H */

+ 4857 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c

@@ -0,0 +1,4857 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio 
+ *
+ *  \brief RF Abstraction Layer (RFAL)
+ *  
+ *  RFAL implementation for ST25R3916
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "../../include/rfal_chip.h"
+#include "../../utils.h"
+#include "st25r3916.h"
+#include "st25r3916_com.h"
+#include "st25r3916_irq.h"
+#include "../../include/rfal_analogConfig.h"
+#include "../../include/rfal_iso15693_2.h"
+#include "../../include/rfal_crc.h"
+
+/*
+ ******************************************************************************
+ * ENABLE SWITCHES
+ ******************************************************************************
+ */
+
+#ifndef RFAL_FEATURE_LISTEN_MODE
+#define RFAL_FEATURE_LISTEN_MODE false /* Listen Mode configuration missing. Disabled by default */
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+#ifndef RFAL_FEATURE_WAKEUP_MODE
+#define RFAL_FEATURE_WAKEUP_MODE \
+    false /* Wake-Up mode configuration missing. Disabled by default */
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+#ifndef RFAL_FEATURE_LOWPOWER_MODE
+#define RFAL_FEATURE_LOWPOWER_MODE \
+    false /* Low Power mode configuration missing. Disabled by default */
+#endif /* RFAL_FEATURE_LOWPOWER_MODE */
+
+/*
+******************************************************************************
+* GLOBAL TYPES
+******************************************************************************
+*/
+
+/*! Struct that holds all involved on a Transceive including the context passed by the caller     */
+typedef struct {
+    rfalTransceiveState state; /*!< Current transceive state                            */
+    rfalTransceiveState lastState; /*!< Last transceive state (debug purposes)              */
+    ReturnCode status; /*!< Current status/error of the transceive              */
+
+    rfalTransceiveContext ctx; /*!< The transceive context given by the caller          */
+} rfalTxRx;
+
+/*! Struct that holds all context for the Listen Mode                                             */
+typedef struct {
+    rfalLmState state; /*!< Current Listen Mode state                           */
+    uint32_t mdMask; /*!< Listen Mode mask used                               */
+    uint32_t mdReg; /*!< Listen Mode register value used                     */
+    uint32_t mdIrqs; /*!< Listen Mode IRQs used                               */
+    rfalBitRate brDetected; /*!< Last bit rate detected                              */
+
+    uint8_t* rxBuf; /*!< Location to store incoming data in Listen Mode      */
+    uint16_t rxBufLen; /*!< Length of rxBuf                                     */
+    uint16_t* rxLen; /*!< Pointer to write the data length placed into rxBuf  */
+    bool dataFlag; /*!< Listen Mode current Data Flag                       */
+    bool iniFlag; /*!< Listen Mode initialized Flag  (FeliCa slots)        */
+} rfalLm;
+
+/*! Struct that holds all context for the Wake-Up Mode                                             */
+typedef struct {
+    rfalWumState state; /*!< Current Wake-Up Mode state                           */
+    rfalWakeUpConfig cfg; /*!< Current Wake-Up Mode context                         */
+} rfalWum;
+
+/*! Struct that holds all context for the Low Power Mode                                             */
+typedef struct {
+    bool isRunning;
+} rfalLpm;
+
+/*! Struct that holds the timings GT and FDTs                           */
+typedef struct {
+    uint32_t GT; /*!< GT in 1/fc                */
+    uint32_t FDTListen; /*!< FDTListen in 1/fc         */
+    uint32_t FDTPoll; /*!< FDTPoll in 1/fc           */
+    uint8_t nTRFW; /*!< n*TRFW used during RF CA  */
+} rfalTimings;
+
+/*! Struct that holds the software timers                               */
+typedef struct {
+    uint32_t GT; /*!< RFAL's GT timer           */
+    uint32_t RXE; /*!< Timer between RXS and RXE */
+    uint32_t txRx; /*!< Transceive sanity timer   */
+} rfalTimers;
+
+/*! Struct that holds the RFAL's callbacks                              */
+typedef struct {
+    rfalPreTxRxCallback preTxRx; /*!< RFAL's Pre TxRx callback  */
+    rfalPostTxRxCallback postTxRx; /*!< RFAL's Post TxRx callback */
+    RfalStateChangedCallback state_changed_cb;
+    void* ctx;
+} rfalCallbacks;
+
+/*! Struct that holds counters to control the FIFO on Tx and Rx                                                                          */
+typedef struct {
+    uint16_t
+        expWL; /*!< The amount of bytes expected to be Tx when a WL interrupt occurs                          */
+    uint16_t
+        bytesTotal; /*!< Total bytes to be transmitted OR the total bytes received                                  */
+    uint16_t
+        bytesWritten; /*!< Amount of bytes already written on FIFO (Tx) OR read (RX) from FIFO and written on rxBuffer*/
+    uint8_t status
+        [ST25R3916_FIFO_STATUS_LEN]; /*!< FIFO Status Registers                                              */
+} rfalFIFO;
+
+/*! Struct that holds RFAL's configuration settings                                                      */
+typedef struct {
+    uint8_t obsvModeTx; /*!< RFAL's config of the ST25R3916's observation mode while Tx */
+    uint8_t obsvModeRx; /*!< RFAL's config of the ST25R3916's observation mode while Rx */
+    rfalEHandling eHandling; /*!< RFAL's error handling config/mode                          */
+} rfalConfigs;
+
+/*! Struct that holds NFC-F data - Used only inside rfalFelicaPoll() (static to avoid adding it into stack) */
+typedef struct {
+    rfalFeliCaPollRes
+        pollResponses[RFAL_FELICA_POLL_MAX_SLOTS]; /* FeliCa Poll response container for 16 slots */
+} rfalNfcfWorkingData;
+
+/*! Struct that holds NFC-V current context
+ *
+ * This buffer has to be big enough for coping with maximum response size (hamming coded)
+ *    - inventory requests responses: 14*2+2 bytes 
+ *    - read single block responses: (32+4)*2+2 bytes
+ *    - read multiple block could be very long... -> not supported
+ *    - current implementation expects it be written in one bulk into FIFO
+ *    - needs to be above FIFO water level of ST25R3916 (200)
+ *    - the coding function needs to be able to 
+ *      put more than FIFO water level bytes into it (n*64+1)>200                                                          */
+typedef struct {
+    uint8_t codingBuffer[(
+        (2 + 255 + 3) * 2)]; /*!< Coding buffer,   length MUST be above 257: [257; ...]    */
+    uint16_t
+        nfcvOffset; /*!< Offset needed for ISO15693 coding function                             */
+    rfalTransceiveContext
+        origCtx; /*!< context provided by user                                               */
+    uint16_t
+        ignoreBits; /*!< Number of bits at the beginning of a frame to be ignored when decoding */
+} rfalNfcvWorkingData;
+
+/*! RFAL instance  */
+typedef struct {
+    rfalState state; /*!< RFAL's current state                          */
+    rfalMode mode; /*!< RFAL's current mode                           */
+    rfalBitRate txBR; /*!< RFAL's current Tx Bit Rate                    */
+    rfalBitRate rxBR; /*!< RFAL's current Rx Bit Rate                    */
+    bool field; /*!< Current field state (On / Off)                */
+
+    rfalConfigs conf; /*!< RFAL's configuration settings                 */
+    rfalTimings timings; /*!< RFAL's timing setting                         */
+    rfalTxRx TxRx; /*!< RFAL's transceive management                  */
+    rfalFIFO fifo; /*!< RFAL's FIFO management                        */
+    rfalTimers tmr; /*!< RFAL's Software timers                        */
+    rfalCallbacks callbacks; /*!< RFAL's callbacks                              */
+
+#if RFAL_FEATURE_LISTEN_MODE
+    rfalLm Lm; /*!< RFAL's listen mode management                 */
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+#if RFAL_FEATURE_WAKEUP_MODE
+    rfalWum wum; /*!< RFAL's Wake-up mode management                */
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+#if RFAL_FEATURE_LOWPOWER_MODE
+    rfalLpm lpm; /*!< RFAL's Low power mode management              */
+#endif /* RFAL_FEATURE_LOWPOWER_MODE */
+
+#if RFAL_FEATURE_NFCF
+    rfalNfcfWorkingData nfcfData; /*!< RFAL's working data when supporting NFC-F     */
+#endif /* RFAL_FEATURE_NFCF */
+
+#if RFAL_FEATURE_NFCV
+    rfalNfcvWorkingData nfcvData; /*!< RFAL's working data when performing NFC-V     */
+#endif /* RFAL_FEATURE_NFCV */
+
+} rfal;
+
+/*! Felica's command set */
+typedef enum {
+    FELICA_CMD_POLLING =
+        0x00, /*!< Felica Poll/REQC command (aka SENSF_REQ) to identify a card    */
+    FELICA_CMD_POLLING_RES =
+        0x01, /*!< Felica Poll/REQC command (aka SENSF_RES) response              */
+    FELICA_CMD_REQUEST_SERVICE =
+        0x02, /*!< verify the existence of Area and Service                       */
+    FELICA_CMD_REQUEST_RESPONSE =
+        0x04, /*!< verify the existence of a card                                 */
+    FELICA_CMD_READ_WITHOUT_ENCRYPTION =
+        0x06, /*!< read Block Data from a Service that requires no authentication */
+    FELICA_CMD_WRITE_WITHOUT_ENCRYPTION =
+        0x08, /*!< write Block Data to a Service that requires no authentication  */
+    FELICA_CMD_REQUEST_SYSTEM_CODE =
+        0x0C, /*!< acquire the System Code registered to a card                   */
+    FELICA_CMD_AUTHENTICATION1 =
+        0x10, /*!< authenticate a card                                            */
+    FELICA_CMD_AUTHENTICATION2 =
+        0x12, /*!< allow a card to authenticate a Reader/Writer                   */
+    FELICA_CMD_READ = 0x14, /*!< read Block Data from a Service that requires authentication    */
+    FELICA_CMD_WRITE = 0x16, /*!< write Block Data to a Service that requires authentication     */
+} t_rfalFeliCaCmd;
+
+/*! Union representing all PTMem sections */
+typedef union { /*  PRQA S 0750 # MISRA 19.2 - Both members are of the same type, just different names.  Thus no problem can occur. */
+    uint8_t PTMem_A
+        [ST25R3916_PTM_A_LEN]; /*!< PT_Memory area allocated for NFC-A configuration               */
+    uint8_t PTMem_F
+        [ST25R3916_PTM_F_LEN]; /*!< PT_Memory area allocated for NFC-F configuration               */
+    uint8_t
+        TSN[ST25R3916_PTM_TSN_LEN]; /*!< PT_Memory area allocated for TSN - Random numbers              */
+} t_rfalPTMem;
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+#define RFAL_FIFO_IN_WL \
+    200U /*!< Number of bytes in the FIFO when WL interrupt occurs while Tx                   */
+#define RFAL_FIFO_OUT_WL    \
+    (ST25R3916_FIFO_DEPTH - \
+     RFAL_FIFO_IN_WL) /*!< Number of bytes sent/out of the FIFO when WL interrupt occurs while Tx          */
+
+#define RFAL_FIFO_STATUS_REG1 \
+    0U /*!< Location of FIFO status register 1 in local copy                                */
+#define RFAL_FIFO_STATUS_REG2 \
+    1U /*!< Location of FIFO status register 2 in local copy                                */
+#define RFAL_FIFO_STATUS_INVALID \
+    0xFFU /*!< Value indicating that the local FIFO status in invalid|cleared                  */
+
+#define RFAL_ST25R3916_GPT_MAX_1FC \
+    rfalConv8fcTo1fc(              \
+        0xFFFFU) /*!< Max GPT steps in 1fc (0xFFFF steps of 8/fc    => 0xFFFF * 590ns  = 38,7ms)      */
+#define RFAL_ST25R3916_NRT_MAX_1FC \
+    rfalConv4096fcTo1fc(           \
+        0xFFFFU) /*!< Max NRT steps in 1fc (0xFFFF steps of 4096/fc => 0xFFFF * 302us  = 19.8s )      */
+#define RFAL_ST25R3916_NRT_DISABLED \
+    0U /*!< NRT Disabled: All 0 No-response timer is not started, wait forever              */
+#define RFAL_ST25R3916_MRT_MAX_1FC \
+    rfalConv64fcTo1fc(             \
+        0x00FFU) /*!< Max MRT steps in 1fc (0x00FF steps of 64/fc   => 0x00FF * 4.72us = 1.2ms )      */
+#define RFAL_ST25R3916_MRT_MIN_1FC \
+    rfalConv64fcTo1fc(             \
+        0x0004U) /*!< Min MRT steps in 1fc ( 0<=mrt<=4 ; 4 (64/fc)  => 0x0004 * 4.72us = 18.88us )    */
+#define RFAL_ST25R3916_GT_MAX_1FC \
+    rfalConvMsTo1fc(              \
+        6000U) /*!< Max GT value allowed in 1/fc (SFGI=14 => SFGT + dSFGT = 5.4s)                   */
+#define RFAL_ST25R3916_GT_MIN_1FC \
+    rfalConvMsTo1fc(              \
+        RFAL_ST25R3916_SW_TMR_MIN_1MS) /*!< Min GT value allowed in 1/fc                                                    */
+#define RFAL_ST25R3916_SW_TMR_MIN_1MS \
+    1U /*!< Min value of a SW timer in ms                                                   */
+
+#define RFAL_OBSMODE_DISABLE \
+    0x00U /*!< Observation Mode disabled                                                       */
+
+#define RFAL_RX_INCOMPLETE_MAXLEN \
+    (uint8_t)1U /*!< Threshold value where incoming rx may be considered as incomplete               */
+#define RFAL_EMVCO_RX_MAXLEN \
+    (uint8_t)4U /*!< Maximum value where EMVCo to apply special error handling                       */
+
+#define RFAL_NORXE_TOUT \
+    50U /*!< Timeout to be used on a potential missing RXE - Silicon ST25R3916 Errata #TBD   */
+
+#define RFAL_ISO14443A_SDD_RES_LEN \
+    5U /*!< SDD_RES | Anticollision (UID CLn) length  -  rfalNfcaSddRes                     */
+#define RFAL_ISO14443A_CRC_INTVAL \
+    0x6363 /*!< ISO14443 CRC Initial Value|Register                                             */
+
+#define RFAL_FELICA_POLL_DELAY_TIME \
+    512U /*!<  FeliCa Poll Processing time is 2.417 ms ~512*64/fc Digital 1.1 A4              */
+#define RFAL_FELICA_POLL_SLOT_TIME \
+    256U /*!<  FeliCa Poll Time Slot duration is 1.208 ms ~256*64/fc Digital 1.1 A4           */
+
+#define RFAL_LM_SENSF_RD0_POS \
+    17U /*!<  FeliCa SENSF_RES Request Data RD0 position                                     */
+#define RFAL_LM_SENSF_RD1_POS \
+    18U /*!<  FeliCa SENSF_RES Request Data RD1 position                                     */
+
+#define RFAL_LM_NFCID_INCOMPLETE \
+    0x04U /*!<  NFCA NFCID not complete bit in SEL_RES (SAK)                                   */
+
+#define RFAL_ISO15693_IGNORE_BITS \
+    rfalConvBytesToBits(          \
+        2U) /*!< Ignore collisions before the UID (RES_FLAG + DSFID)                             */
+#define RFAL_ISO15693_INV_RES_LEN \
+    12U /*!< ISO15693 Inventory response length with CRC (bytes)                             */
+#define RFAL_ISO15693_INV_RES_DUR \
+    4U /*!< ISO15693 Inventory response duration @ 26 kbps (ms)                             */
+
+#define RFAL_WU_MIN_WEIGHT_VAL \
+    4U /*!< ST25R3916 minimum Wake-up weight value                                         */
+
+/*******************************************************************************/
+
+#define RFAL_LM_GT   \
+    rfalConvUsTo1fc( \
+        100U) /*!< Listen Mode Guard Time enforced (GT - Passive; TIRFG - Active)                  */
+#define RFAL_FDT_POLL_ADJUSTMENT \
+    rfalConvUsTo1fc(             \
+        80U) /*!< FDT Poll adjustment: Time between the expiration of GPT to the actual Tx        */
+#define RFAL_FDT_LISTEN_MRT_ADJUSTMENT \
+    64U /*!< MRT jitter adjustment: timeout will be between [ tout ; tout + 64 cycles ]      */
+#define RFAL_AP2P_FIELDOFF_TRFW \
+    rfalConv8fcTo1fc(           \
+        64U) /*!< Time after TXE and Field Off in AP2P Trfw: 37.76us -> 64  (8/fc)                */
+
+#ifndef RFAL_ST25R3916_AAT_SETTLE
+#define RFAL_ST25R3916_AAT_SETTLE \
+    5U /*!< Time in ms required for AAT pins and Osc to settle after en bit set */
+#endif /* RFAL_ST25R3916_AAT_SETTLE */
+
+/*! FWT adjustment: 
+ *    64 : NRT jitter between TXE and NRT start      */
+#define RFAL_FWT_ADJUSTMENT 64U
+
+/*! FWT ISO14443A adjustment:  
+ *   512  : 4bit length
+ *    64  : Half a bit duration due to ST25R3916 Coherent receiver (1/fc)         */
+#define RFAL_FWT_A_ADJUSTMENT (512U + 64U)
+
+/*! FWT ISO14443B adjustment:  
+ *    SOF (14etu) + 1Byte (10etu) + 1etu (IRQ comes 1etu after first byte) - 3etu (ST25R3916 sends TXE 3etu after) */
+#define RFAL_FWT_B_ADJUSTMENT ((14U + 10U + 1U - 3U) * 128U)
+
+/*! FWT FeliCa 212 adjustment:  
+ *    1024 : Length of the two Sync bytes at 212kbps */
+#define RFAL_FWT_F_212_ADJUSTMENT 1024U
+
+/*! FWT FeliCa 424 adjustment:  
+ *    512 : Length of the two Sync bytes at 424kbps  */
+#define RFAL_FWT_F_424_ADJUSTMENT 512U
+
+/*! Time between our field Off and other peer field On : Tadt + (n x Trfw)
+ * Ecma 340 11.1.2 - Tadt: [56.64 , 188.72] us ;  n: [0 , 3]  ; Trfw = 37.76 us        
+ * Should be: 189 + (3*38) = 303us ; we'll use a more relaxed setting: 605 us    */
+#define RFAL_AP2P_FIELDON_TADTTRFW rfalConvUsTo1fc(605U)
+
+/*! FDT Listen adjustment for ISO14443A   EMVCo 2.6  4.8.1.3  ;  Digital 1.1  6.10
+ *
+ *  276: Time from the rising pulse of the pause of the logic '1' (i.e. the time point to measure the deaftime from), 
+ *       to the actual end of the EOF sequence (the point where the MRT starts). Please note that the ST25R391x uses the 
+ *       ISO14443-2 definition where the EOF consists of logic '0' followed by sequence Y. 
+ *  -64: Further adjustment for receiver to be ready just before first bit
+ */
+#define RFAL_FDT_LISTEN_A_ADJUSTMENT (276U - 64U)
+
+/*! FDT Listen adjustment for ISO14443B   EMVCo 2.6  4.8.1.6  ;  Digital 1.1  7.9
+ *
+ *  340: Time from the rising edge of the EoS to the starting point of the MRT timer (sometime after the final high 
+ *       part of the EoS is completed)
+ */
+#define RFAL_FDT_LISTEN_B_ADJUSTMENT 340U
+
+/*! FDT Listen adjustment for ISO15693
+ * ISO15693 2000  8.4  t1 MIN = 4192/fc
+ * ISO15693 2009  9.1  t1 MIN = 4320/fc
+ * Digital 2.1 B.5 FDTV,LISTEN,MIN  = 4310/fc
+ * Set FDT Listen one step earlier than on the more recent spec versions for greater interoperability
+ */
+#define RFAL_FDT_LISTEN_V_ADJUSTMENT 64U
+
+/*! FDT Poll adjustment for ISO14443B Correlator - sst 5 etu */
+#define RFAL_FDT_LISTEN_B_ADJT_CORR 128U
+
+/*! FDT Poll adjustment for ISO14443B Correlator sst window - 5 etu */
+#define RFAL_FDT_LISTEN_B_ADJT_CORR_SST 20U
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*! Calculates Transceive Sanity Timer. It accounts for the slowest bit rate and the longest data format
+ *    1s for transmission and reception of a 4K message at 106kpbs (~425ms each direction)
+ *       plus TxRx preparation and FIFO load over Serial Interface                                      */
+#define rfalCalcSanityTmr(fwt) (uint16_t)(1000U + rfalConv1fcToMs((fwt)))
+
+#define rfalGennTRFW(n) \
+    (((n) + 1U) &       \
+     ST25R3916_REG_AUX_nfc_n_mask) /*!< Generates the next n*TRRW used for RFCA       */
+
+#define rfalCalcNumBytes(nBits) \
+    (((uint32_t)(nBits) + 7U) / \
+     8U) /*!< Returns the number of bytes required to fit given the number of bits */
+
+#define rfalTimerStart(timer, time_ms)                      \
+    do {                                                    \
+        platformTimerDestroy(timer);                        \
+        (timer) = platformTimerCreate((uint16_t)(time_ms)); \
+    } while(0) /*!< Configures and starts timer         */
+#define rfalTimerisExpired(timer) \
+    platformTimerIsExpired(       \
+        timer) /*!< Checks if timer has expired                                         */
+#define rfalTimerDestroy(timer) \
+    platformTimerDestroy(       \
+        timer) /*!< Destroys timer                                                      */
+
+#define rfalST25R3916ObsModeDisable() \
+    st25r3916WriteTestRegister(       \
+        0x01U,                        \
+        (0x40U)) /*!< Disable ST25R3916 Observation mode                                   */
+#define rfalST25R3916ObsModeTx() \
+    st25r3916WriteTestRegister(  \
+        0x01U,                   \
+        (0x40U |                 \
+         gRFAL.conf              \
+             .obsvModeTx)) /*!< Enable Tx Observation mode                                           */
+#define rfalST25R3916ObsModeRx() \
+    st25r3916WriteTestRegister(  \
+        0x01U,                   \
+        (0x40U |                 \
+         gRFAL.conf              \
+             .obsvModeRx)) /*!< Enable Rx Observation mode                                           */
+
+#define rfalCheckDisableObsMode()      \
+    if(gRFAL.conf.obsvModeRx != 0U) {  \
+        rfalST25R3916ObsModeDisable(); \
+    } /*!< Checks if the observation mode is enabled, and applies on ST25R3916  */
+#define rfalCheckEnableObsModeTx()    \
+    if(gRFAL.conf.obsvModeTx != 0U) { \
+        rfalST25R3916ObsModeTx();     \
+    } /*!< Checks if the observation mode is enabled, and applies on ST25R3916  */
+#define rfalCheckEnableObsModeRx()    \
+    if(gRFAL.conf.obsvModeRx != 0U) { \
+        rfalST25R3916ObsModeRx();     \
+    } /*!< Checks if the observation mode is enabled, and applies on ST25R3916  */
+
+#define rfalGetIncmplBits(FIFOStatus2) \
+    (((FIFOStatus2) >> 1) &            \
+     0x07U) /*!< Returns the number of bits from fifo status                  */
+#define rfalIsIncompleteByteError(error) \
+    (((error) >= ERR_INCOMPLETE_BYTE) && \
+     ((error) <=                         \
+      ERR_INCOMPLETE_BYTE_07)) /*!< Checks if given error is a Incomplete error                  */
+
+#define rfalAdjACBR(b)                            \
+    (((uint16_t)(b) >= (uint16_t)RFAL_BR_52p97) ? \
+         (uint16_t)(b) :                          \
+         ((uint16_t)(b) +                         \
+          1U)) /*!< Adjusts ST25R391x Bit rate to Analog Configuration              */
+#define rfalConvBR2ACBR(b)                                      \
+    (((rfalAdjACBR((b))) << RFAL_ANALOG_CONFIG_BITRATE_SHIFT) & \
+     RFAL_ANALOG_CONFIG_BITRATE_MASK) /*!< Converts ST25R391x Bit rate to Analog Configuration bit rate id */
+
+#define rfalConvTDFormat(v) \
+    ((uint16_t)(v) << 8U) /*!< Converts a uint8_t to the format used in SW Tag Detection */
+
+/*
+ ******************************************************************************
+ * LOCAL VARIABLES
+ ******************************************************************************
+ */
+
+static rfal gRFAL; /*!< RFAL module instance               */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+static void rfalTransceiveTx(void);
+static void rfalTransceiveRx(void);
+static ReturnCode rfalTransceiveRunBlockingTx(void);
+static void rfalPrepareTransceive(void);
+static void rfalCleanupTransceive(void);
+static void rfalErrorHandling(void);
+
+static ReturnCode rfalRunTransceiveWorker(void);
+#if RFAL_FEATURE_LISTEN_MODE
+static ReturnCode rfalRunListenModeWorker(void);
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+#if RFAL_FEATURE_WAKEUP_MODE
+static void rfalRunWakeUpModeWorker(void);
+static uint16_t rfalWakeUpModeFilter(uint16_t curRef, uint16_t curVal, uint8_t weight);
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+static void rfalFIFOStatusUpdate(void);
+static void rfalFIFOStatusClear(void);
+static bool rfalFIFOStatusIsMissingPar(void);
+static bool rfalFIFOStatusIsIncompleteByte(void);
+static uint16_t rfalFIFOStatusGetNumBytes(void);
+static uint8_t rfalFIFOGetNumIncompleteBits(void);
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode rfalInitialize(void) {
+    ReturnCode err;
+
+    EXIT_ON_ERR(err, st25r3916Initialize());
+
+    st25r3916ClearInterrupts();
+
+    /* Disable any previous observation mode */
+    rfalST25R3916ObsModeDisable();
+
+    /*******************************************************************************/
+    /* Apply RF Chip generic initialization */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_INIT));
+
+    // TODO:
+    // I don't want to mess with config table ("Default Analog Configuration for Chip-Specific Reset", rfal_analogConfigTbl.h)
+    // so with every rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_CHIP_INIT)) currently we need to clear pulldown bits
+    // luckily for us this is done only here
+
+    // disable pulldowns
+    st25r3916ClrRegisterBits(
+        ST25R3916_REG_IO_CONF2,
+        (ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2));
+
+    /*******************************************************************************/
+    /* Enable External Field Detector as: Automatics */
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_OP_CONTROL,
+        ST25R3916_REG_OP_CONTROL_en_fd_mask,
+        ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
+
+    /* Clear FIFO status local copy */
+    rfalFIFOStatusClear();
+
+    /*******************************************************************************/
+    gRFAL.state = RFAL_STATE_INIT;
+    gRFAL.mode = RFAL_MODE_NONE;
+    gRFAL.field = false;
+
+    /* Set RFAL default configs */
+    gRFAL.conf.obsvModeRx = RFAL_OBSMODE_DISABLE;
+    gRFAL.conf.obsvModeTx = RFAL_OBSMODE_DISABLE;
+    gRFAL.conf.eHandling = RFAL_ERRORHANDLING_NONE;
+
+    /* Transceive set to IDLE */
+    gRFAL.TxRx.lastState = RFAL_TXRX_STATE_IDLE;
+    gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE;
+
+    /* Disable all timings */
+    gRFAL.timings.FDTListen = RFAL_TIMING_NONE;
+    gRFAL.timings.FDTPoll = RFAL_TIMING_NONE;
+    gRFAL.timings.GT = RFAL_TIMING_NONE;
+    gRFAL.timings.nTRFW = 0U;
+
+    /* Destroy any previous pending timers */
+    rfalTimerDestroy(gRFAL.tmr.GT);
+    rfalTimerDestroy(gRFAL.tmr.txRx);
+    rfalTimerDestroy(gRFAL.tmr.RXE);
+    gRFAL.tmr.GT = RFAL_TIMING_NONE;
+    gRFAL.tmr.txRx = RFAL_TIMING_NONE;
+    gRFAL.tmr.RXE = RFAL_TIMING_NONE;
+
+    gRFAL.callbacks.preTxRx = NULL;
+    gRFAL.callbacks.postTxRx = NULL;
+    gRFAL.callbacks.state_changed_cb = NULL;
+    gRFAL.callbacks.ctx = NULL;
+
+#if RFAL_FEATURE_NFCV
+    /* Initialize NFC-V Data */
+    gRFAL.nfcvData.ignoreBits = 0;
+#endif /* RFAL_FEATURE_NFCV */
+
+#if RFAL_FEATURE_LISTEN_MODE
+    /* Initialize Listen Mode */
+    gRFAL.Lm.state = RFAL_LM_STATE_NOT_INIT;
+    gRFAL.Lm.brDetected = RFAL_BR_KEEP;
+    gRFAL.Lm.iniFlag = false;
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+#if RFAL_FEATURE_WAKEUP_MODE
+    /* Initialize Wake-Up Mode */
+    gRFAL.wum.state = RFAL_WUM_STATE_NOT_INIT;
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+#if RFAL_FEATURE_LOWPOWER_MODE
+    /* Initialize Low Power Mode */
+    gRFAL.lpm.isRunning = false;
+#endif /* RFAL_FEATURE_LOWPOWER_MODE */
+
+    /*******************************************************************************/
+    /* Perform Automatic Calibration (if configured to do so).                     *
+     * Registers set by rfalSetAnalogConfig will tell rfalCalibrate what to perform*/
+    rfalCalibrate();
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalCalibrate(void) {
+    uint16_t resValue;
+
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state == RFAL_STATE_IDLE) {
+        return ERR_WRONG_STATE;
+    }
+
+    /*******************************************************************************/
+    /* Perform ST25R3916 regulators and antenna calibration                        */
+    /*******************************************************************************/
+
+    /* Automatic regulator adjustment only performed if not set manually on Analog Configs */
+    if(st25r3916CheckReg(
+           ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s, 0x00)) {
+        /* Adjust the regulators so that Antenna Calibrate has better Regulator values */
+        st25r3916AdjustRegulators(&resValue);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalAdjustRegulators(uint16_t* result) {
+    return st25r3916AdjustRegulators(result);
+}
+
+/*******************************************************************************/
+void rfalSetUpperLayerCallback(rfalUpperLayerCallback pFunc) {
+    st25r3916IRQCallbackSet(pFunc);
+}
+
+/*******************************************************************************/
+void rfalSetPreTxRxCallback(rfalPreTxRxCallback pFunc) {
+    gRFAL.callbacks.preTxRx = pFunc;
+}
+
+/*******************************************************************************/
+void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc) {
+    gRFAL.callbacks.postTxRx = pFunc;
+}
+
+void rfal_set_state_changed_callback(RfalStateChangedCallback callback) {
+    gRFAL.callbacks.state_changed_cb = callback;
+}
+
+void rfal_set_callback_context(void* context) {
+    gRFAL.callbacks.ctx = context;
+}
+
+/*******************************************************************************/
+ReturnCode rfalDeinitialize(void) {
+    /* Deinitialize chip */
+    st25r3916Deinitialize();
+
+    /* Set Analog configurations for deinitialization */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_DEINIT));
+
+    gRFAL.state = RFAL_STATE_IDLE;
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+void rfalSetObsvMode(uint8_t txMode, uint8_t rxMode) {
+    gRFAL.conf.obsvModeTx = txMode;
+    gRFAL.conf.obsvModeRx = rxMode;
+}
+
+/*******************************************************************************/
+void rfalGetObsvMode(uint8_t* txMode, uint8_t* rxMode) {
+    if(txMode != NULL) {
+        *txMode = gRFAL.conf.obsvModeTx;
+    }
+
+    if(rxMode != NULL) {
+        *rxMode = gRFAL.conf.obsvModeRx;
+    }
+}
+
+/*******************************************************************************/
+void rfalDisableObsvMode(void) {
+    gRFAL.conf.obsvModeTx = RFAL_OBSMODE_DISABLE;
+    gRFAL.conf.obsvModeRx = RFAL_OBSMODE_DISABLE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSetMode(rfalMode mode, rfalBitRate txBR, rfalBitRate rxBR) {
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state == RFAL_STATE_IDLE) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check allowed bit rate value */
+    if((txBR == RFAL_BR_KEEP) || (rxBR == RFAL_BR_KEEP)) {
+        return ERR_PARAM;
+    }
+
+    switch(mode) {
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCA:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable ISO14443A mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443a);
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCA_T1T:
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable Topaz mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_topaz);
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCB:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable ISO14443B mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443b);
+
+        /* Set the EGT, SOF, EOF and EOF */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_1,
+            (ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask |
+             ST25R3916_REG_ISO14443B_1_eof),
+            ((0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu |
+             ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu));
+
+        /* Set the minimum TR1, SOF, EOF and EOF12 */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_2,
+            (ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof |
+             ST25R3916_REG_ISO14443B_2_no_eof),
+            (ST25R3916_REG_ISO14443B_2_tr1_80fs80fs));
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_B_PRIME:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable ISO14443B mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443b);
+
+        /* Set the EGT, SOF, EOF and EOF */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_1,
+            (ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask |
+             ST25R3916_REG_ISO14443B_1_eof),
+            ((0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu |
+             ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu));
+
+        /* Set the minimum TR1, EOF and EOF12 */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_2,
+            (ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof |
+             ST25R3916_REG_ISO14443B_2_no_eof),
+            (ST25R3916_REG_ISO14443B_2_tr1_80fs80fs | ST25R3916_REG_ISO14443B_2_no_sof));
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_B_CTS:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable ISO14443B mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443b);
+
+        /* Set the EGT, SOF, EOF and EOF */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_1,
+            (ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask |
+             ST25R3916_REG_ISO14443B_1_eof),
+            ((0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu |
+             ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu));
+
+        /* Set the minimum TR1, clear SOF, EOF and EOF12 */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_ISO14443B_2,
+            (ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof |
+             ST25R3916_REG_ISO14443B_2_no_eof),
+            (ST25R3916_REG_ISO14443B_2_tr1_80fs80fs | ST25R3916_REG_ISO14443B_2_no_sof |
+             ST25R3916_REG_ISO14443B_2_no_eof));
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCF:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable FeliCa mode */
+        st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_felica);
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCV:
+    case RFAL_MODE_POLL_PICOPASS:
+
+#if !RFAL_FEATURE_NFCV
+        return ERR_DISABLED;
+#else
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+#endif /* RFAL_FEATURE_NFCV */
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_ACTIVE_P2P:
+
+        /* Set NFCIP1 active communication Initiator mode and Automatic Response RF Collision Avoidance to always after EOF */
+        st25r3916WriteRegister(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_nfc |
+             ST25R3916_REG_MODE_nfc_ar_eof));
+
+        /* External Field Detector enabled as Automatics on rfalInitialize() */
+
+        /* Set NRT to start at end of TX (own) field */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL,
+            ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc,
+            ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off);
+
+        /* Set GPT to start after end of TX, as GPT is used in active communication mode to timeout the field switching off */
+        /* The field is turned off 37.76us after the end of the transmission  Trfw                                          */
+        st25r3916SetStartGPTimer(
+            (uint16_t)rfalConv1fcTo8fc(RFAL_AP2P_FIELDOFF_TRFW),
+            ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc);
+
+        /* Set PPon2 timer with the max time between our field Off and other peer field On : Tadt + (n x Trfw)    */
+        st25r3916WriteRegister(
+            ST25R3916_REG_PPON2, (uint8_t)rfalConv1fcTo64fc(RFAL_AP2P_FIELDON_TADTTRFW));
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_ACTIVE_P2P:
+
+        /* Set NFCIP1 active communication Target mode and Automatic Response RF Collision Avoidance to always after EOF */
+        st25r3916WriteRegister(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om_targ_nfcip |
+             ST25R3916_REG_MODE_nfc_ar_eof));
+
+        /* Set TARFG: 0 (75us+0ms=75us), as Target no Guard time needed */
+        st25r3916WriteRegister(ST25R3916_REG_FIELD_ON_GT, 0U);
+
+        /* External Field Detector enabled as Automatics on rfalInitialize() */
+
+        /* Set NRT to start at end of TX (own) field */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL,
+            ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc,
+            ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off);
+
+        /* Set GPT to start after end of TX, as GPT is used in active communication mode to timeout the field switching off */
+        /* The field is turned off 37.76us after the end of the transmission  Trfw                                          */
+        st25r3916SetStartGPTimer(
+            (uint16_t)rfalConv1fcTo8fc(RFAL_AP2P_FIELDOFF_TRFW),
+            ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc);
+
+        /* Set PPon2 timer with the max time between our field Off and other peer field On : Tadt + (n x Trfw)    */
+        st25r3916WriteRegister(
+            ST25R3916_REG_PPON2, (uint8_t)rfalConv1fcTo64fc(RFAL_AP2P_FIELDON_TADTTRFW));
+
+        /* Set Analog configurations for this mode and bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCA:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable Passive Target NFC-A mode, disable any Collision Avoidance */
+        st25r3916WriteRegister(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_targ_nfca |
+             ST25R3916_REG_MODE_nfc_ar_off));
+
+        /* Set Analog configurations for this mode */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCF:
+
+        /* Disable wake up mode, if set */
+        st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+
+        /* Enable Passive Target NFC-F mode, disable any Collision Avoidance */
+        st25r3916WriteRegister(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_targ_nfcf |
+             ST25R3916_REG_MODE_nfc_ar_off));
+
+        /* Set Analog configurations for this mode */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF |
+             RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCB:
+        return ERR_NOTSUPP;
+
+    /*******************************************************************************/
+    default:
+        return ERR_NOT_IMPLEMENTED;
+    }
+
+    /* Set state as STATE_MODE_SET only if not initialized yet (PSL) */
+    gRFAL.state = ((gRFAL.state < RFAL_STATE_MODE_SET) ? RFAL_STATE_MODE_SET : gRFAL.state);
+    gRFAL.mode = mode;
+
+    /* Apply the given bit rate */
+    return rfalSetBitRate(txBR, rxBR);
+}
+
+/*******************************************************************************/
+rfalMode rfalGetMode(void) {
+    return gRFAL.mode;
+}
+
+/*******************************************************************************/
+ReturnCode rfalSetBitRate(rfalBitRate txBR, rfalBitRate rxBR) {
+    ReturnCode ret;
+
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state == RFAL_STATE_IDLE) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Store the new Bit Rates */
+    gRFAL.txBR = ((txBR == RFAL_BR_KEEP) ? gRFAL.txBR : txBR);
+    gRFAL.rxBR = ((rxBR == RFAL_BR_KEEP) ? gRFAL.rxBR : rxBR);
+
+    /* Update the bitrate reg if not in NFCV mode (streaming) */
+    if((RFAL_MODE_POLL_NFCV != gRFAL.mode) && (RFAL_MODE_POLL_PICOPASS != gRFAL.mode)) {
+        /* Set bit rate register */
+        EXIT_ON_ERR(ret, st25r3916SetBitrate((uint8_t)gRFAL.txBR, (uint8_t)gRFAL.rxBR));
+    }
+
+    switch(gRFAL.mode) {
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCA:
+    case RFAL_MODE_POLL_NFCA_T1T:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCB:
+    case RFAL_MODE_POLL_B_PRIME:
+    case RFAL_MODE_POLL_B_CTS:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCB |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCF:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCF |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_NFCV:
+    case RFAL_MODE_POLL_PICOPASS:
+
+#if !RFAL_FEATURE_NFCV
+        return ERR_DISABLED;
+#else
+
+        if(((gRFAL.rxBR != RFAL_BR_26p48) && (gRFAL.rxBR != RFAL_BR_52p97)) ||
+           ((gRFAL.txBR != RFAL_BR_1p66) && (gRFAL.txBR != RFAL_BR_26p48))) {
+            return ERR_PARAM;
+        }
+
+        {
+            const struct iso15693StreamConfig* isoStreamConfig;
+            struct st25r3916StreamConfig streamConf;
+            iso15693PhyConfig_t config;
+
+            config.coding =
+                ((gRFAL.txBR == RFAL_BR_1p66) ? ISO15693_VCD_CODING_1_256 :
+                                                ISO15693_VCD_CODING_1_4);
+            switch(gRFAL.rxBR) {
+            case RFAL_BR_52p97:
+                config.speedMode = 1;
+                break;
+            default:
+                config.speedMode = 0;
+                break;
+            }
+
+            iso15693PhyConfigure(&config, &isoStreamConfig);
+
+            /* MISRA 11.3 - Cannot point directly into different object type, copy to local var */
+            streamConf.din = isoStreamConfig->din;
+            streamConf.dout = isoStreamConfig->dout;
+            streamConf.report_period_length = isoStreamConfig->report_period_length;
+            streamConf.useBPSK = isoStreamConfig->useBPSK;
+            st25r3916StreamConfigure(&streamConf);
+        }
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+#endif /* RFAL_FEATURE_NFCV */
+
+    /*******************************************************************************/
+    case RFAL_MODE_POLL_ACTIVE_P2P:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_POLL_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_AP2P |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_ACTIVE_P2P:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_AP2P |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCA:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCA |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCF:
+
+        /* Set Analog configurations for this bit rate */
+        rfalSetAnalogConfig(
+            (RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_COMMON));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF |
+                                 rfalConvBR2ACBR(gRFAL.txBR) | RFAL_ANALOG_CONFIG_TX));
+        rfalSetAnalogConfig(
+            (rfalAnalogConfigId)(RFAL_ANALOG_CONFIG_LISTEN | RFAL_ANALOG_CONFIG_TECH_NFCF |
+                                 rfalConvBR2ACBR(gRFAL.rxBR) | RFAL_ANALOG_CONFIG_RX));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_MODE_LISTEN_NFCB:
+    case RFAL_MODE_NONE:
+        return ERR_WRONG_STATE;
+
+    /*******************************************************************************/
+    default:
+        return ERR_NOT_IMPLEMENTED;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalGetBitRate(rfalBitRate* txBR, rfalBitRate* rxBR) {
+    if((gRFAL.state == RFAL_STATE_IDLE) || (gRFAL.mode == RFAL_MODE_NONE)) {
+        return ERR_WRONG_STATE;
+    }
+
+    if(txBR != NULL) {
+        *txBR = gRFAL.txBR;
+    }
+
+    if(rxBR != NULL) {
+        *rxBR = gRFAL.rxBR;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+void rfalSetErrorHandling(rfalEHandling eHandling) {
+    switch(eHandling) {
+    case RFAL_ERRORHANDLING_NFC:
+    case RFAL_ERRORHANDLING_NONE:
+        st25r3916ClrRegisterBits(ST25R3916_REG_EMD_SUP_CONF, ST25R3916_REG_EMD_SUP_CONF_emd_emv);
+        break;
+
+    case RFAL_ERRORHANDLING_EMVCO:
+        /* MISRA 16.4: no empty default statement (in case RFAL_SW_EMD is defined) */
+#ifndef RFAL_SW_EMD
+        st25r3916ModifyRegister(
+            ST25R3916_REG_EMD_SUP_CONF,
+            (ST25R3916_REG_EMD_SUP_CONF_emd_emv | ST25R3916_REG_EMD_SUP_CONF_emd_thld_mask),
+            (ST25R3916_REG_EMD_SUP_CONF_emd_emv_on | RFAL_EMVCO_RX_MAXLEN));
+#endif /* RFAL_SW_EMD */
+        break;
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+
+    gRFAL.conf.eHandling = eHandling;
+}
+
+/*******************************************************************************/
+rfalEHandling rfalGetErrorHandling(void) {
+    return gRFAL.conf.eHandling;
+}
+
+/*******************************************************************************/
+void rfalSetFDTPoll(uint32_t FDTPoll) {
+    gRFAL.timings.FDTPoll = MIN(FDTPoll, RFAL_ST25R3916_GPT_MAX_1FC);
+}
+
+/*******************************************************************************/
+uint32_t rfalGetFDTPoll(void) {
+    return gRFAL.timings.FDTPoll;
+}
+
+/*******************************************************************************/
+void rfalSetFDTListen(uint32_t FDTListen) {
+    gRFAL.timings.FDTListen = MIN(FDTListen, RFAL_ST25R3916_MRT_MAX_1FC);
+}
+
+/*******************************************************************************/
+uint32_t rfalGetFDTListen(void) {
+    return gRFAL.timings.FDTListen;
+}
+
+/*******************************************************************************/
+void rfalSetGT(uint32_t GT) {
+    gRFAL.timings.GT = MIN(GT, RFAL_ST25R3916_GT_MAX_1FC);
+}
+
+/*******************************************************************************/
+uint32_t rfalGetGT(void) {
+    return gRFAL.timings.GT;
+}
+
+/*******************************************************************************/
+bool rfalIsGTExpired(void) {
+    if(gRFAL.tmr.GT != RFAL_TIMING_NONE) {
+        if(!rfalTimerisExpired(gRFAL.tmr.GT)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/*******************************************************************************/
+ReturnCode rfalFieldOnAndStartGT(void) {
+    ReturnCode ret;
+
+    /* Check if RFAL has been initialized (Oscillator should be running) and also
+     * if a direct register access has been performed and left the Oscillator Off */
+    if(!st25r3916IsOscOn() || (gRFAL.state < RFAL_STATE_INIT)) {
+        return ERR_WRONG_STATE;
+    }
+
+    ret = ERR_NONE;
+
+    /* Set Analog configurations for Field On event */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_ON));
+
+    /*******************************************************************************/
+    /* Perform collision avoidance and turn field On if not already On */
+    if(!st25r3916IsTxEnabled() || !gRFAL.field) {
+        /* Set TARFG: 0 (75us+0ms=75us), GT is fulfilled using a SW timer */
+        st25r3916WriteRegister(ST25R3916_REG_FIELD_ON_GT, 0U);
+
+        /* Use Thresholds set by AnalogConfig */
+        ret = st25r3916PerformCollisionAvoidance(
+            ST25R3916_CMD_INITIAL_RF_COLLISION,
+            ST25R3916_THRESHOLD_DO_NOT_SET,
+            ST25R3916_THRESHOLD_DO_NOT_SET,
+            gRFAL.timings.nTRFW);
+
+        /* n * TRFW timing shall vary  Activity 2.1  3.3.1.1 */
+        gRFAL.timings.nTRFW = rfalGennTRFW(gRFAL.timings.nTRFW);
+
+        gRFAL.field = st25r3916IsTxEnabled(); //(ret == ERR_NONE);
+
+        /* Only turn on Receiver and Transmitter if field was successfully turned On */
+        if(gRFAL.field) {
+            st25r3916TxRxOn(); /* Enable Tx and Rx (Tx is already On)*/
+        }
+    }
+
+    /*******************************************************************************/
+    /* Start GT timer in case the GT value is set */
+    if((gRFAL.timings.GT != RFAL_TIMING_NONE)) {
+        /* Ensure that a SW timer doesn't have a lower value then the minimum  */
+        rfalTimerStart(
+            gRFAL.tmr.GT, rfalConv1fcToMs(MAX((gRFAL.timings.GT), RFAL_ST25R3916_GT_MIN_1FC)));
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalFieldOff(void) {
+    /* Check whether a TxRx is not yet finished */
+    if(gRFAL.TxRx.state != RFAL_TXRX_STATE_IDLE) {
+        rfalCleanupTransceive();
+    }
+
+    /* Disable Tx and Rx */
+    st25r3916TxRxOff();
+
+    /* Set Analog configurations for Field Off event */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_FIELD_OFF));
+    gRFAL.field = false;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalStartTransceive(const rfalTransceiveContext* ctx) {
+    uint32_t FxTAdj; /* FWT or FDT adjustment calculation */
+
+    /* Check for valid parameters */
+    if(ctx == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Ensure that RFAL is already Initialized and the mode has been set */
+    if((gRFAL.state >= RFAL_STATE_MODE_SET) /*&& (gRFAL.TxRx.state == RFAL_TXRX_STATE_INIT )*/) {
+        /*******************************************************************************/
+        /* Check whether the field is already On, otherwise no TXE will be received  */
+        if(!st25r3916IsTxEnabled() &&
+           (!rfalIsModePassiveListen(gRFAL.mode) && (ctx->txBuf != NULL))) {
+            return ERR_WRONG_STATE;
+        }
+
+        gRFAL.TxRx.ctx = *ctx;
+
+        /*******************************************************************************/
+        if(gRFAL.timings.FDTListen != RFAL_TIMING_NONE) {
+            /* Calculate MRT adjustment accordingly to the current mode */
+            FxTAdj = RFAL_FDT_LISTEN_MRT_ADJUSTMENT;
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCA) {
+                FxTAdj += (uint32_t)RFAL_FDT_LISTEN_A_ADJUSTMENT;
+            }
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCA_T1T) {
+                FxTAdj += (uint32_t)RFAL_FDT_LISTEN_A_ADJUSTMENT;
+            }
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCB) {
+                FxTAdj += (uint32_t)RFAL_FDT_LISTEN_B_ADJUSTMENT;
+            }
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCV) {
+                FxTAdj += (uint32_t)RFAL_FDT_LISTEN_V_ADJUSTMENT;
+            }
+
+            /* Ensure that MRT is using 64/fc steps */
+            st25r3916ClrRegisterBits(
+                ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step);
+
+            /* If Correlator is being used further adjustment is required for NFCB */
+            if((st25r3916CheckReg(ST25R3916_REG_AUX, ST25R3916_REG_AUX_dis_corr, 0x00U)) &&
+               (gRFAL.mode == RFAL_MODE_POLL_NFCB)) {
+                FxTAdj += (uint32_t)
+                    RFAL_FDT_LISTEN_B_ADJT_CORR; /* Reduce FDT(Listen)                   */
+                st25r3916SetRegisterBits(
+                    ST25R3916_REG_CORR_CONF1,
+                    ST25R3916_REG_CORR_CONF1_corr_s3); /* Ensure BPSK start to 33 pilot pulses */
+                st25r3916ChangeRegisterBits(
+                    ST25R3916_REG_SUBC_START_TIME,
+                    ST25R3916_REG_SUBC_START_TIME_sst_mask,
+                    RFAL_FDT_LISTEN_B_ADJT_CORR_SST); /* Set sst                              */
+            }
+
+            /* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */
+            st25r3916WriteRegister(
+                ST25R3916_REG_MASK_RX_TIMER,
+                (uint8_t)rfalConv1fcTo64fc(
+                    (FxTAdj > gRFAL.timings.FDTListen) ? RFAL_ST25R3916_MRT_MIN_1FC :
+                                                         (gRFAL.timings.FDTListen - FxTAdj)));
+        }
+
+        /*******************************************************************************/
+        /* FDT Poll will be loaded in rfalPrepareTransceive() once the previous was expired */
+
+        /*******************************************************************************/
+        if((gRFAL.TxRx.ctx.fwt != RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != 0U)) {
+            /* Ensure proper timing configuration */
+            if(gRFAL.timings.FDTListen >= gRFAL.TxRx.ctx.fwt) {
+                return ERR_PARAM;
+            }
+
+            FxTAdj = RFAL_FWT_ADJUSTMENT;
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCA) {
+                FxTAdj += (uint32_t)RFAL_FWT_A_ADJUSTMENT;
+            }
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCA_T1T) {
+                FxTAdj += (uint32_t)RFAL_FWT_A_ADJUSTMENT;
+            }
+            if(gRFAL.mode == RFAL_MODE_POLL_NFCB) {
+                FxTAdj += (uint32_t)RFAL_FWT_B_ADJUSTMENT;
+            }
+            if((gRFAL.mode == RFAL_MODE_POLL_NFCF) || (gRFAL.mode == RFAL_MODE_POLL_ACTIVE_P2P)) {
+                FxTAdj += (uint32_t)((gRFAL.txBR == RFAL_BR_212) ? RFAL_FWT_F_212_ADJUSTMENT :
+                                                                   RFAL_FWT_F_424_ADJUSTMENT);
+            }
+
+            /* Ensure that the given FWT doesn't exceed NRT maximum */
+            gRFAL.TxRx.ctx.fwt = MIN((gRFAL.TxRx.ctx.fwt + FxTAdj), RFAL_ST25R3916_NRT_MAX_1FC);
+
+            /* Set FWT in the NRT */
+            st25r3916SetNoResponseTime(rfalConv1fcTo64fc(gRFAL.TxRx.ctx.fwt));
+        } else {
+            /* Disable NRT, no NRE will be triggered, therefore wait endlessly for Rx */
+            st25r3916SetNoResponseTime(RFAL_ST25R3916_NRT_DISABLED);
+        }
+
+        gRFAL.state = RFAL_STATE_TXRX;
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_IDLE;
+        gRFAL.TxRx.status = ERR_BUSY;
+
+#if RFAL_FEATURE_NFCV
+        /*******************************************************************************/
+        if((RFAL_MODE_POLL_NFCV == gRFAL.mode) ||
+           (RFAL_MODE_POLL_PICOPASS ==
+            gRFAL.mode)) { /* Exchange receive buffer with internal buffer */
+            gRFAL.nfcvData.origCtx = gRFAL.TxRx.ctx;
+
+            gRFAL.TxRx.ctx.rxBuf =
+                ((gRFAL.nfcvData.origCtx.rxBuf != NULL) ? gRFAL.nfcvData.codingBuffer : NULL);
+            gRFAL.TxRx.ctx.rxBufLen =
+                (uint16_t)rfalConvBytesToBits(sizeof(gRFAL.nfcvData.codingBuffer));
+            gRFAL.TxRx.ctx.flags =
+                (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF |
+                (uint32_t)(gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF) |
+                (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE;
+
+            /* In NFCV a TxRx with a valid txBuf and txBufSize==0 indicates to send an EOF */
+            /* Skip logic below that would go directly into receive                        */
+            if(gRFAL.TxRx.ctx.txBuf != NULL) {
+                return ERR_NONE;
+            }
+        }
+#endif /* RFAL_FEATURE_NFCV */
+
+        /*******************************************************************************/
+        /* Check if the Transceive start performing Tx or goes directly to Rx          */
+        if((gRFAL.TxRx.ctx.txBuf == NULL) || (gRFAL.TxRx.ctx.txBufLen == 0U)) {
+            /* Clear FIFO, Clear and Enable the Interrupts */
+            rfalPrepareTransceive();
+
+            /* In AP2P check the field status */
+            if(rfalIsModeActiveComm(gRFAL.mode)) {
+                /* Disable our field upon a Rx reEnable, and start PPON2 manually */
+                st25r3916TxOff();
+                st25r3916ExecuteCommand(ST25R3916_CMD_START_PPON2_TIMER);
+            }
+
+            /* No Tx done, enable the Receiver */
+            st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+            /* Start NRT manually, if FWT = 0 (wait endlessly for Rx) chip will ignore anyhow */
+            st25r3916ExecuteCommand(ST25R3916_CMD_START_NO_RESPONSE_TIMER);
+
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE;
+        }
+
+        return ERR_NONE;
+    }
+
+    return ERR_WRONG_STATE;
+}
+
+/*******************************************************************************/
+bool rfalIsTransceiveInTx(void) {
+    return (
+        (gRFAL.TxRx.state >= RFAL_TXRX_STATE_TX_IDLE) &&
+        (gRFAL.TxRx.state < RFAL_TXRX_STATE_RX_IDLE));
+}
+
+/*******************************************************************************/
+bool rfalIsTransceiveInRx(void) {
+    return (gRFAL.TxRx.state >= RFAL_TXRX_STATE_RX_IDLE);
+}
+
+/*******************************************************************************/
+ReturnCode rfalTransceiveBlockingTx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    ReturnCode ret;
+    rfalTransceiveContext ctx;
+
+    rfalCreateByteFlagsTxRxContext(ctx, txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt);
+    EXIT_ON_ERR(ret, rfalStartTransceive(&ctx));
+
+    return rfalTransceiveRunBlockingTx();
+}
+
+ReturnCode rfalTransceiveBitsBlockingTx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    ReturnCode ret;
+    rfalTransceiveContext ctx = {
+        .rxBuf = rxBuf,
+        .rxBufLen = rxBufLen,
+        .rxRcvdLen = actLen,
+        .txBuf = txBuf,
+        .txBufLen = txBufLen,
+        .flags = flags,
+        .fwt = fwt,
+    };
+
+    EXIT_ON_ERR(ret, rfalStartTransceive(&ctx));
+
+    return rfalTransceiveRunBlockingTx();
+}
+
+/*******************************************************************************/
+static ReturnCode rfalTransceiveRunBlockingTx(void) {
+    ReturnCode ret;
+
+    do {
+        rfalWorker();
+        ret = rfalGetTransceiveStatus();
+    } while(rfalIsTransceiveInTx() && (ret == ERR_BUSY));
+
+    if(rfalIsTransceiveInRx()) {
+        return ERR_NONE;
+    }
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalTransceiveBlockingRx(void) {
+    ReturnCode ret;
+
+    do {
+        rfalWorker();
+        ret = rfalGetTransceiveStatus();
+    } while(rfalIsTransceiveInRx() && (ret == ERR_BUSY));
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalTransceiveBlockingTxRx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret, rfalTransceiveBlockingTx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt));
+    ret = rfalTransceiveBlockingRx();
+
+    /* Convert received bits to bytes */
+    if(actLen != NULL) {
+        *actLen = rfalConvBitsToBytes(*actLen);
+    }
+
+    return ret;
+}
+
+ReturnCode rfalTransceiveBitsBlockingTxRx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    ReturnCode ret;
+
+    EXIT_ON_ERR(
+        ret, rfalTransceiveBitsBlockingTx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt));
+    ret = rfalTransceiveBlockingRx();
+
+    return ret;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalRunTransceiveWorker(void) {
+    if(gRFAL.state == RFAL_STATE_TXRX) {
+        /*******************************************************************************/
+        /* Check Transceive Sanity Timer has expired */
+        if(gRFAL.tmr.txRx != RFAL_TIMING_NONE) {
+            if(rfalTimerisExpired(gRFAL.tmr.txRx)) {
+                /* If sanity timer has expired abort ongoing transceive and signal error */
+                gRFAL.TxRx.status = ERR_IO;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            }
+        }
+
+        /*******************************************************************************/
+        /* Run Tx or Rx state machines */
+        if(rfalIsTransceiveInTx()) {
+            rfalTransceiveTx();
+            return rfalGetTransceiveStatus();
+        }
+        if(rfalIsTransceiveInRx()) {
+            rfalTransceiveRx();
+            return rfalGetTransceiveStatus();
+        }
+    }
+    return ERR_WRONG_STATE;
+}
+
+/*******************************************************************************/
+rfalTransceiveState rfalGetTransceiveState(void) {
+    return gRFAL.TxRx.state;
+}
+
+/*******************************************************************************/
+ReturnCode rfalGetTransceiveStatus(void) {
+    return ((gRFAL.TxRx.state == RFAL_TXRX_STATE_IDLE) ? gRFAL.TxRx.status : ERR_BUSY);
+}
+
+/*******************************************************************************/
+ReturnCode rfalGetTransceiveRSSI(uint16_t* rssi) {
+    uint16_t amRSSI;
+    uint16_t pmRSSI;
+    bool isSumMode;
+
+    if(rssi == NULL) {
+        return ERR_PARAM;
+    }
+
+    st25r3916GetRSSI(&amRSSI, &pmRSSI);
+
+    /* Check if Correlator Summation mode is being used */
+    isSumMode =
+        (st25r3916CheckReg(
+             ST25R3916_REG_CORR_CONF1,
+             ST25R3916_REG_CORR_CONF1_corr_s4,
+             ST25R3916_REG_CORR_CONF1_corr_s4) ?
+             st25r3916CheckReg(ST25R3916_REG_AUX, ST25R3916_REG_AUX_dis_corr, 0x00) :
+             false);
+    if(isSumMode) {
+        /*******************************************************************************/
+        /* Using SQRT from math.h and float. If due to compiler, resources or performance 
+         * issue this cannot be used, other approaches can be foreseen with less accuracy:
+         *    Use a simpler sqrt algorithm 
+         *    *rssi = MAX( amRSSI, pmRSSI );
+         *    *rssi = ( (amRSSI + pmRSSI) / 2);
+         */
+        *rssi = (uint16_t)sqrt(
+            ((double)amRSSI * (double)amRSSI) +
+            ((double)pmRSSI *
+             (double)
+                 pmRSSI)); /*  PRQA S 5209 # MISRA 4.9 - External function (sqrt()) requires double */
+    } else {
+        /* Check which channel was used */
+        *rssi =
+            (st25r3916CheckReg(
+                 ST25R3916_REG_AUX_DISPLAY,
+                 ST25R3916_REG_AUX_DISPLAY_a_cha,
+                 ST25R3916_REG_AUX_DISPLAY_a_cha) ?
+                 pmRSSI :
+                 amRSSI);
+    }
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+void rfalWorker(void) {
+    platformProtectWorker(); /* Protect RFAL Worker/Task/Process */
+
+    switch(gRFAL.state) {
+    case RFAL_STATE_TXRX:
+        rfalRunTransceiveWorker();
+        break;
+
+#if RFAL_FEATURE_LISTEN_MODE
+    case RFAL_STATE_LM:
+        rfalRunListenModeWorker();
+        break;
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+#if RFAL_FEATURE_WAKEUP_MODE
+    case RFAL_STATE_WUM:
+        rfalRunWakeUpModeWorker();
+        break;
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+    /* Nothing to be done */
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+
+    platformUnprotectWorker(); /* Unprotect RFAL Worker/Task/Process */
+}
+
+/*******************************************************************************/
+static void rfalErrorHandling(void) {
+    uint16_t fifoBytesToRead;
+
+    fifoBytesToRead = rfalFIFOStatusGetNumBytes();
+
+#ifdef RFAL_SW_EMD
+    /*******************************************************************************/
+    /* EMVCo                                                                       */
+    /*******************************************************************************/
+    if(gRFAL.conf.eHandling == RFAL_ERRORHANDLING_EMVCO) {
+        bool rxHasIncParError;
+
+        /*******************************************************************************/
+        /* EMD Handling - NFC Forum Digital 1.1  4.1.1.1 ; EMVCo v2.5  4.9.2           */
+        /* ReEnable the receiver on frames with a length < 4 bytes, upon:              */
+        /*   - Collision or Framing error detected                                     */
+        /*   - Residual bits are detected (hard framing error)                         */
+        /*   - Parity error                                                            */
+        /*   - CRC error                                                               */
+        /*******************************************************************************/
+
+        /* Check if reception has incomplete bytes or parity error */
+        rxHasIncParError =
+            (rfalFIFOStatusIsIncompleteByte() ? true :
+                                                rfalFIFOStatusIsMissingPar()); /* MISRA 13.5 */
+
+        /* In case there are residual bits decrement FIFO bytes */
+        /* Ensure FIFO contains some byte as the FIFO might be empty upon Framing errors */
+        if((fifoBytesToRead > 0U) && rxHasIncParError) {
+            fifoBytesToRead--;
+        }
+
+        if(((gRFAL.fifo.bytesTotal + fifoBytesToRead) < RFAL_EMVCO_RX_MAXLEN) &&
+           ((gRFAL.TxRx.status == ERR_RF_COLLISION) || (gRFAL.TxRx.status == ERR_FRAMING) ||
+            (gRFAL.TxRx.status == ERR_PAR) || (gRFAL.TxRx.status == ERR_CRC) ||
+            rxHasIncParError)) {
+            /* Ignore this reception, ReEnable receiver which also clears the FIFO */
+            st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+            /* Ensure that the NRT has not expired meanwhile */
+            if(st25r3916CheckReg(
+                   ST25R3916_REG_NFCIP1_BIT_RATE, ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on, 0x00)) {
+                if(st25r3916CheckReg(
+                       ST25R3916_REG_AUX_DISPLAY, ST25R3916_REG_AUX_DISPLAY_rx_act, 0x00)) {
+                    /* Abort reception */
+                    st25r3916ExecuteCommand(ST25R3916_CMD_MASK_RECEIVE_DATA);
+                    gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+                    return;
+                }
+            }
+
+            rfalFIFOStatusClear();
+            gRFAL.fifo.bytesTotal = 0;
+            gRFAL.TxRx.status = ERR_BUSY;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS;
+        }
+        return;
+    }
+#endif
+
+    /*******************************************************************************/
+    /* ISO14443A Mode                                                              */
+    /*******************************************************************************/
+    if(gRFAL.mode == RFAL_MODE_POLL_NFCA) {
+        /*******************************************************************************/
+        /* If we received a frame with a incomplete byte we`ll raise a specific error  *
+         * ( support for T2T 4 bit ACK / NAK, MIFARE and Kovio )                       */
+        /*******************************************************************************/
+        if((gRFAL.TxRx.status == ERR_PAR) || (gRFAL.TxRx.status == ERR_CRC)) {
+            if(rfalFIFOStatusIsIncompleteByte()) {
+                st25r3916ReadFifo((uint8_t*)(gRFAL.TxRx.ctx.rxBuf), fifoBytesToRead);
+                if((gRFAL.TxRx.ctx.rxRcvdLen) != NULL) {
+                    *gRFAL.TxRx.ctx.rxRcvdLen = rfalFIFOGetNumIncompleteBits();
+                }
+
+                gRFAL.TxRx.status = ERR_INCOMPLETE_BYTE;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            }
+        }
+    }
+}
+
+/*******************************************************************************/
+static void rfalCleanupTransceive(void) {
+    /*******************************************************************************/
+    /* Transceive flags                                                            */
+    /*******************************************************************************/
+
+    /* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity*/
+    st25r3916ClrRegisterBits(
+        ST25R3916_REG_ISO14443A_NFC,
+        (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par |
+         ST25R3916_REG_ISO14443A_NFC_nfc_f0));
+
+    /* Restore AGC enabled */
+    st25r3916SetRegisterBits(ST25R3916_REG_RX_CONF2, ST25R3916_REG_RX_CONF2_agc_en);
+
+    /*******************************************************************************/
+
+    /*******************************************************************************/
+    /* Transceive timers                                                           */
+    /*******************************************************************************/
+    rfalTimerDestroy(gRFAL.tmr.txRx);
+    rfalTimerDestroy(gRFAL.tmr.RXE);
+    gRFAL.tmr.txRx = RFAL_TIMING_NONE;
+    gRFAL.tmr.RXE = RFAL_TIMING_NONE;
+    /*******************************************************************************/
+
+    /*******************************************************************************/
+    /* Execute Post Transceive Callback                                            */
+    /*******************************************************************************/
+    if(gRFAL.callbacks.postTxRx != NULL) {
+        gRFAL.callbacks.postTxRx(gRFAL.callbacks.ctx);
+    }
+    /*******************************************************************************/
+}
+
+/*******************************************************************************/
+static void rfalPrepareTransceive(void) {
+    uint32_t maskInterrupts;
+    uint8_t reg;
+
+    /* If we are in RW or AP2P mode */
+    if(!rfalIsModePassiveListen(gRFAL.mode)) {
+        /* Reset receive logic with STOP command */
+        st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+
+        /* Reset Rx Gain */
+        st25r3916ExecuteCommand(ST25R3916_CMD_RESET_RXGAIN);
+    } else {
+        /* In Passive Listen Mode do not use STOP as it stops FDT timer */
+        st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+    }
+
+    /*******************************************************************************/
+    /* FDT Poll                                                                    */
+    /*******************************************************************************/
+    if(rfalIsModePassiveComm(gRFAL.mode)) /* Passive Comms */
+    {
+        /* In Passive communications General Purpose Timer is used to measure FDT Poll */
+        if(gRFAL.timings.FDTPoll != RFAL_TIMING_NONE) {
+            /* Configure GPT to start at RX end */
+            st25r3916SetStartGPTimer(
+                (uint16_t)rfalConv1fcTo8fc(MIN(
+                    gRFAL.timings.FDTPoll, (gRFAL.timings.FDTPoll - RFAL_FDT_POLL_ADJUSTMENT))),
+                ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx);
+        }
+    }
+
+    /*******************************************************************************/
+    /* Execute Pre Transceive Callback                                             */
+    /*******************************************************************************/
+    if(gRFAL.callbacks.preTxRx != NULL) {
+        gRFAL.callbacks.preTxRx(gRFAL.callbacks.ctx);
+    }
+    /*******************************************************************************/
+
+    maskInterrupts =
+        (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS |
+         ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC |
+         ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE);
+
+    /*******************************************************************************/
+    /* Transceive flags                                                            */
+    /*******************************************************************************/
+
+    reg =
+        (ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off |
+         ST25R3916_REG_ISO14443A_NFC_nfc_f0_off);
+
+    /* Check if NFCIP1 mode is to be enabled */
+    if((gRFAL.TxRx.ctx.flags & (uint8_t)RFAL_TXRX_FLAGS_NFCIP1_ON) != 0U) {
+        reg |= ST25R3916_REG_ISO14443A_NFC_nfc_f0;
+    }
+
+    /* Check if Parity check is to be skipped and to keep the parity + CRC bits in FIFO */
+    if((gRFAL.TxRx.ctx.flags & (uint8_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP) != 0U) {
+        reg |= ST25R3916_REG_ISO14443A_NFC_no_rx_par;
+    }
+
+    /* Check if automatic Parity bits is to be disabled */
+    if((gRFAL.TxRx.ctx.flags & (uint8_t)RFAL_TXRX_FLAGS_PAR_TX_NONE) != 0U) {
+        reg |= ST25R3916_REG_ISO14443A_NFC_no_tx_par;
+    }
+
+    /* Apply current TxRx flags on ISO14443A and NFC 106kb/s Settings Register */
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_ISO14443A_NFC,
+        (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par |
+         ST25R3916_REG_ISO14443A_NFC_nfc_f0),
+        reg);
+
+    /* Check if AGC is to be disabled */
+    if((gRFAL.TxRx.ctx.flags & (uint8_t)RFAL_TXRX_FLAGS_AGC_OFF) != 0U) {
+        st25r3916ClrRegisterBits(ST25R3916_REG_RX_CONF2, ST25R3916_REG_RX_CONF2_agc_en);
+    } else {
+        st25r3916SetRegisterBits(ST25R3916_REG_RX_CONF2, ST25R3916_REG_RX_CONF2_agc_en);
+    }
+    /*******************************************************************************/
+
+    /*******************************************************************************/
+    /* EMVCo NRT mode                                                              */
+    /*******************************************************************************/
+    if(gRFAL.conf.eHandling == RFAL_ERRORHANDLING_EMVCO) {
+        st25r3916SetRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv);
+        maskInterrupts |= ST25R3916_IRQ_MASK_RX_REST;
+    } else {
+        st25r3916ClrRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv);
+    }
+    /*******************************************************************************/
+
+    /* In Passive Listen mode additionally enable External Field interrupts  */
+    if(rfalIsModePassiveListen(gRFAL.mode)) {
+        maskInterrupts |=
+            (ST25R3916_IRQ_MASK_EOF |
+             ST25R3916_IRQ_MASK_WU_F); /* Enable external Field interrupts to detect Link Loss and SENF_REQ auto responses */
+    }
+
+    /* In Active comms enable also External Field interrupts and set RF Collision Avoindance */
+    if(rfalIsModeActiveComm(gRFAL.mode)) {
+        maskInterrupts |=
+            (ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_PPON2 |
+             ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_CAC);
+
+        /* Set n=0 for subsequent RF Collision Avoidance */
+        st25r3916ChangeRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, 0);
+    }
+
+    /*******************************************************************************/
+    /* Start transceive Sanity Timer if a FWT is used */
+    if((gRFAL.TxRx.ctx.fwt != RFAL_FWT_NONE) && (gRFAL.TxRx.ctx.fwt != 0U)) {
+        rfalTimerStart(gRFAL.tmr.txRx, rfalCalcSanityTmr(gRFAL.TxRx.ctx.fwt));
+    }
+    /*******************************************************************************/
+
+    /*******************************************************************************/
+    /* Clear and enable these interrupts */
+    st25r3916GetInterrupt(maskInterrupts);
+    st25r3916EnableInterrupts(maskInterrupts);
+
+    /* Clear FIFO status local copy */
+    rfalFIFOStatusClear();
+}
+
+/*******************************************************************************/
+static void rfalTransceiveTx(void) {
+    volatile uint32_t irqs;
+    uint16_t tmp;
+    ReturnCode ret;
+
+    /* Suppress warning in case NFC-V feature is disabled */
+    ret = ERR_NONE;
+    NO_WARNING(ret);
+
+    irqs = ST25R3916_IRQ_MASK_NONE;
+
+    if(gRFAL.TxRx.state != gRFAL.TxRx.lastState) {
+        /* rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); */
+        gRFAL.TxRx.lastState = gRFAL.TxRx.state;
+    }
+
+    switch(gRFAL.TxRx.state) {
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_IDLE:
+
+        /* Nothing to do */
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_WAIT_GT;
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_WAIT_GT: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        if(!rfalIsGTExpired()) {
+            break;
+        }
+
+        rfalTimerDestroy(gRFAL.tmr.GT);
+        gRFAL.tmr.GT = RFAL_TIMING_NONE;
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_WAIT_FDT;
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_WAIT_FDT: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* Only in Passive communications GPT is used to measure FDT Poll */
+        if(rfalIsModePassiveComm(gRFAL.mode)) {
+            if(st25r3916IsGPTRunning()) {
+                break;
+            }
+        }
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_TRANSMIT;
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_TRANSMIT: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* Clear FIFO, Clear and Enable the Interrupts */
+        rfalPrepareTransceive();
+
+        /* ST25R3916 has a fixed FIFO water level */
+        gRFAL.fifo.expWL = RFAL_FIFO_OUT_WL;
+
+#if RFAL_FEATURE_NFCV
+        /*******************************************************************************/
+        /* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits    */
+        if((RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode)) {
+#if 0
+                /* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */
+                st25r3916WriteFifo(gRFAL.TxRx.ctx.txBuf, rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen));
+                st25r3916ExecuteCommand( ST25R3916_CMD_CLEAR_FIFO );
+#endif
+            /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
+            gRFAL.nfcvData.nfcvOffset = 0;
+            ret = iso15693VCDCode(
+                gRFAL.TxRx.ctx.txBuf,
+                rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen),
+                (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U) ?
+                     false :
+                     true),
+                (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL) !=
+                  0U) ?
+                     false :
+                     true),
+                (RFAL_MODE_POLL_PICOPASS == gRFAL.mode),
+                &gRFAL.fifo.bytesTotal,
+                &gRFAL.nfcvData.nfcvOffset,
+                gRFAL.nfcvData.codingBuffer,
+                MIN((uint16_t)ST25R3916_FIFO_DEPTH, (uint16_t)sizeof(gRFAL.nfcvData.codingBuffer)),
+                &gRFAL.fifo.bytesWritten);
+
+            if((ret != ERR_NONE) && (ret != ERR_AGAIN)) {
+                gRFAL.TxRx.status = ret;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+                break;
+            }
+            /* Set the number of full bytes and bits to be transmitted */
+            st25r3916SetNumTxBits((uint16_t)rfalConvBytesToBits(gRFAL.fifo.bytesTotal));
+
+            /* Load FIFO with coded bytes */
+            st25r3916WriteFifo(gRFAL.nfcvData.codingBuffer, gRFAL.fifo.bytesWritten);
+
+        }
+        /*******************************************************************************/
+        else
+#endif /* RFAL_FEATURE_NFCV */
+        {
+            /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
+            gRFAL.fifo.bytesTotal = (uint16_t)rfalCalcNumBytes(gRFAL.TxRx.ctx.txBufLen);
+
+            /* Set the number of full bytes and bits to be transmitted */
+            st25r3916SetNumTxBits(gRFAL.TxRx.ctx.txBufLen);
+
+            /* Load FIFO with total length or FIFO's maximum */
+            gRFAL.fifo.bytesWritten = MIN(gRFAL.fifo.bytesTotal, ST25R3916_FIFO_DEPTH);
+            st25r3916WriteFifo(gRFAL.TxRx.ctx.txBuf, gRFAL.fifo.bytesWritten);
+        }
+
+        /*Check if Observation Mode is enabled and set it on ST25R391x */
+        rfalCheckEnableObsModeTx();
+
+        /*******************************************************************************/
+        /* If we're in Passive Listen mode ensure that the external field is still On  */
+        if(rfalIsModePassiveListen(gRFAL.mode)) {
+            if(!rfalIsExtFieldOn()) {
+                gRFAL.TxRx.status = ERR_LINK_LOSS;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+                break;
+            }
+        }
+
+        /*******************************************************************************/
+        /* Trigger/Start transmission                                                  */
+        if((gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U) {
+            st25r3916ExecuteCommand(ST25R3916_CMD_TRANSMIT_WITHOUT_CRC);
+        } else {
+            st25r3916ExecuteCommand(ST25R3916_CMD_TRANSMIT_WITH_CRC);
+        }
+
+        /* Check if a WL level is expected or TXE should come */
+        gRFAL.TxRx.state =
+            ((gRFAL.fifo.bytesWritten < gRFAL.fifo.bytesTotal) ? RFAL_TXRX_STATE_TX_WAIT_WL :
+                                                                 RFAL_TXRX_STATE_TX_WAIT_TXE);
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_WAIT_WL:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if(((irqs & ST25R3916_IRQ_MASK_FWL) != 0U) && ((irqs & ST25R3916_IRQ_MASK_TXE) == 0U)) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_RELOAD_FIFO;
+        } else {
+            gRFAL.TxRx.status = ERR_IO;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+            break;
+        }
+
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_RELOAD_FIFO: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+#if RFAL_FEATURE_NFCV
+        /*******************************************************************************/
+        /* In NFC-V streaming mode, the FIFO needs to be loaded with the coded bits    */
+        if((RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode)) {
+            uint16_t maxLen;
+
+            /* Load FIFO with the remaining length or maximum available (which fit on the coding buffer) */
+            maxLen =
+                (uint16_t)MIN((gRFAL.fifo.bytesTotal - gRFAL.fifo.bytesWritten), gRFAL.fifo.expWL);
+            maxLen = (uint16_t)MIN(maxLen, sizeof(gRFAL.nfcvData.codingBuffer));
+            tmp = 0;
+
+            /* Calculate the bytes needed to be Written into FIFO (a incomplete byte will be added as 1byte) */
+            ret = iso15693VCDCode(
+                gRFAL.TxRx.ctx.txBuf,
+                rfalConvBitsToBytes(gRFAL.TxRx.ctx.txBufLen),
+                (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL) != 0U) ?
+                     false :
+                     true),
+                (((gRFAL.nfcvData.origCtx.flags & (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL) !=
+                  0U) ?
+                     false :
+                     true),
+                (RFAL_MODE_POLL_PICOPASS == gRFAL.mode),
+                &gRFAL.fifo.bytesTotal,
+                &gRFAL.nfcvData.nfcvOffset,
+                gRFAL.nfcvData.codingBuffer,
+                maxLen,
+                &tmp);
+
+            if((ret != ERR_NONE) && (ret != ERR_AGAIN)) {
+                gRFAL.TxRx.status = ret;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+                break;
+            }
+
+            /* Load FIFO with coded bytes */
+            st25r3916WriteFifo(gRFAL.nfcvData.codingBuffer, tmp);
+        }
+        /*******************************************************************************/
+        else
+#endif /* RFAL_FEATURE_NFCV */
+        {
+            /* Load FIFO with the remaining length or maximum available */
+            tmp = MIN(
+                (gRFAL.fifo.bytesTotal - gRFAL.fifo.bytesWritten),
+                gRFAL.fifo.expWL); /* tmp holds the number of bytes written on this iteration */
+            st25r3916WriteFifo(&gRFAL.TxRx.ctx.txBuf[gRFAL.fifo.bytesWritten], tmp);
+        }
+
+        /* Update total written bytes to FIFO */
+        gRFAL.fifo.bytesWritten += tmp;
+
+        /* Check if a WL level is expected or TXE should come */
+        gRFAL.TxRx.state =
+            ((gRFAL.fifo.bytesWritten < gRFAL.fifo.bytesTotal) ? RFAL_TXRX_STATE_TX_WAIT_WL :
+                                                                 RFAL_TXRX_STATE_TX_WAIT_TXE);
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_WAIT_TXE:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_TXE) != 0U) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_DONE;
+        } else if((irqs & ST25R3916_IRQ_MASK_FWL) != 0U) {
+            break; /* Ignore ST25R3916 FIFO WL if total TxLen is already on the FIFO */
+        } else {
+            gRFAL.TxRx.status = ERR_IO;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+            break;
+        }
+
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_DONE: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /* If no rxBuf is provided do not wait/expect Rx */
+        if(gRFAL.TxRx.ctx.rxBuf == NULL) {
+            /*Check if Observation Mode was enabled and disable it on ST25R391x */
+            rfalCheckDisableObsMode();
+
+            /* Clean up Transceive */
+            rfalCleanupTransceive();
+
+            gRFAL.TxRx.status = ERR_NONE;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE;
+            break;
+        }
+
+        rfalCheckEnableObsModeRx();
+
+        /* Goto Rx */
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE;
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_TX_FAIL:
+
+        /* Error should be assigned by previous state */
+        if(gRFAL.TxRx.status == ERR_BUSY) {
+            gRFAL.TxRx.status = ERR_SYSTEM;
+        }
+
+        /*Check if Observation Mode was enabled and disable it on ST25R391x */
+        rfalCheckDisableObsMode();
+
+        /* Clean up Transceive */
+        rfalCleanupTransceive();
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE;
+        break;
+
+    /*******************************************************************************/
+    default:
+        gRFAL.TxRx.status = ERR_SYSTEM;
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_TX_FAIL;
+        break;
+    }
+}
+
+/*******************************************************************************/
+static void rfalTransceiveRx(void) {
+    volatile uint32_t irqs;
+    uint16_t tmp;
+    uint16_t aux;
+
+    irqs = ST25R3916_IRQ_MASK_NONE;
+
+    if(gRFAL.TxRx.state != gRFAL.TxRx.lastState) {
+        /* rfalLogD( "RFAL: lastSt: %d curSt: %d \r\n", gRFAL.TxRx.lastState, gRFAL.TxRx.state ); */
+        gRFAL.TxRx.lastState = gRFAL.TxRx.state;
+    }
+
+    switch(gRFAL.TxRx.state) {
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_IDLE:
+
+        /* Clear rx counters */
+        gRFAL.fifo.bytesWritten = 0; /* Total bytes written on RxBuffer         */
+        gRFAL.fifo.bytesTotal = 0; /* Total bytes in FIFO will now be from Rx */
+        if(gRFAL.TxRx.ctx.rxRcvdLen != NULL) {
+            *gRFAL.TxRx.ctx.rxRcvdLen = 0;
+        }
+
+        gRFAL.TxRx.state =
+            (rfalIsModeActiveComm(gRFAL.mode) ? RFAL_TXRX_STATE_RX_WAIT_EON :
+                                                RFAL_TXRX_STATE_RX_WAIT_RXS);
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_WAIT_RXS:
+
+        /*******************************************************************************/
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_EOF));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        /* Only raise Timeout if NRE is detected with no Rx Start (NRT EMV mode) */
+        if(((irqs & ST25R3916_IRQ_MASK_NRE) != 0U) && ((irqs & ST25R3916_IRQ_MASK_RXS) == 0U)) {
+            gRFAL.TxRx.status = ERR_TIMEOUT;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        }
+
+        /* Only raise Link Loss if EOF is detected with no Rx Start */
+        if(((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) && ((irqs & ST25R3916_IRQ_MASK_RXS) == 0U)) {
+            /* In AP2P a Field On has already occurred - treat this as timeout | mute */
+            gRFAL.TxRx.status = (rfalIsModeActiveComm(gRFAL.mode) ? ERR_TIMEOUT : ERR_LINK_LOSS);
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_RXS) != 0U) {
+            /*******************************************************************************/
+            /* REMARK: Silicon workaround ST25R3916 Errata #TBD                            */
+            /* Rarely on corrupted frames I_rxs gets signaled but I_rxe is not signaled    */
+            /* Use a SW timer to handle an eventual missing RXE                            */
+            rfalTimerStart(gRFAL.tmr.RXE, RFAL_NORXE_TOUT);
+            /*******************************************************************************/
+
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXE;
+        } else {
+            gRFAL.TxRx.status = ERR_IO;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        }
+
+        /* remove NRE that might appear together (NRT EMV mode), and remove RXS, but keep EOF if present for next state */
+        irqs &= ~(ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NRE);
+
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_WAIT_RXE: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /*******************************************************************************/
+        /* REMARK: Silicon workaround ST25R3916 Errata #TBD                            */
+        /* ST25R396 may indicate RXS without RXE afterwards, this happens rarely on    */
+        /* corrupted frames.                                                           */
+        /* SW timer is used to timeout upon a missing RXE                              */
+        if(rfalTimerisExpired(gRFAL.tmr.RXE)) {
+            gRFAL.TxRx.status = ERR_FRAMING;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        }
+        /*******************************************************************************/
+
+        irqs |= st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_EOF |
+             ST25R3916_IRQ_MASK_RX_REST | ST25R3916_IRQ_MASK_WU_F));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_RX_REST) != 0U) {
+            /* RX_REST indicates that Receiver has been reset due to EMD, therefore a RXS + RXE should *
+                 * follow if a good reception is followed within the valid initial timeout                   */
+
+            /* Check whether NRT has expired already, if so signal a timeout */
+            if(st25r3916GetInterrupt(ST25R3916_IRQ_MASK_NRE) != 0U) {
+                gRFAL.TxRx.status = ERR_TIMEOUT;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+                break;
+            }
+            if(st25r3916CheckReg(
+                   ST25R3916_REG_NFCIP1_BIT_RATE,
+                   ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on,
+                   0)) /* MISRA 13.5 */
+            {
+                gRFAL.TxRx.status = ERR_TIMEOUT;
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+                break;
+            }
+
+            /* Discard any previous RXS */
+            st25r3916GetInterrupt(ST25R3916_IRQ_MASK_RXS);
+
+            /* Check whether a following reception has already started */
+            if(st25r3916CheckReg(
+                   ST25R3916_REG_AUX_DISPLAY,
+                   ST25R3916_REG_AUX_DISPLAY_rx_act,
+                   ST25R3916_REG_AUX_DISPLAY_rx_act)) {
+                gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXE;
+                break;
+            }
+
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS;
+            break;
+        }
+
+        if(((irqs & ST25R3916_IRQ_MASK_FWL) != 0U) && ((irqs & ST25R3916_IRQ_MASK_RXE) == 0U)) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_FIFO;
+            break;
+        }
+
+        /* Automatic responses allowed during TxRx only for the SENSF_REQ */
+        if((irqs & ST25R3916_IRQ_MASK_WU_F) != 0U) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS;
+            break;
+        }
+
+        /* After RXE retrieve and check for any error irqs */
+        irqs |= st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_ERR1 |
+             ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_COL));
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_ERR_CHECK;
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_ERR_CHECK: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        if((irqs & ST25R3916_IRQ_MASK_ERR1) != 0U) {
+            gRFAL.TxRx.status = ERR_FRAMING;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+
+            /* Check if there's a specific error handling for this */
+            rfalErrorHandling();
+            break;
+        }
+        /* Discard Soft Framing errors in AP2P and CE */
+        else if(rfalIsModePassivePoll(gRFAL.mode) && ((irqs & ST25R3916_IRQ_MASK_ERR2) != 0U)) {
+            gRFAL.TxRx.status = ERR_FRAMING;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+
+            /* Check if there's a specific error handling for this */
+            rfalErrorHandling();
+            break;
+        } else if((irqs & ST25R3916_IRQ_MASK_PAR) != 0U) {
+            gRFAL.TxRx.status = ERR_PAR;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+
+            /* Check if there's a specific error handling for this */
+            rfalErrorHandling();
+            break;
+        } else if((irqs & ST25R3916_IRQ_MASK_CRC) != 0U) {
+            gRFAL.TxRx.status = ERR_CRC;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+
+            /* Check if there's a specific error handling for this */
+            rfalErrorHandling();
+            break;
+        } else if((irqs & ST25R3916_IRQ_MASK_COL) != 0U) {
+            gRFAL.TxRx.status = ERR_RF_COLLISION;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+
+            /* Check if there's a specific error handling for this */
+            rfalErrorHandling();
+            break;
+        } else if(rfalIsModePassiveListen(gRFAL.mode) && ((irqs & ST25R3916_IRQ_MASK_EOF) != 0U)) {
+            gRFAL.TxRx.status = ERR_LINK_LOSS;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        } else if((irqs & ST25R3916_IRQ_MASK_RXE) != 0U) {
+            /* Reception ended without any error indication,                  *
+                 * check FIFO status for malformed or incomplete frames           */
+
+            /* Check if the reception ends with an incomplete byte (residual bits) */
+            if(rfalFIFOStatusIsIncompleteByte()) {
+                gRFAL.TxRx.status = ERR_INCOMPLETE_BYTE;
+            }
+            /* Check if the reception ends missing parity bit */
+            else if(rfalFIFOStatusIsMissingPar()) {
+                gRFAL.TxRx.status = ERR_FRAMING;
+            } else {
+                /* MISRA 15.7 - Empty else */
+            }
+
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_READ_DATA;
+        } else {
+            gRFAL.TxRx.status = ERR_IO;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        }
+
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_READ_DATA: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        tmp = rfalFIFOStatusGetNumBytes();
+
+        /*******************************************************************************/
+        /* Check if CRC should not be placed in rxBuf                                  */
+        if(((gRFAL.TxRx.ctx.flags & (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP) == 0U)) {
+            /* if received frame was bigger than CRC */
+            if((uint16_t)(gRFAL.fifo.bytesTotal + tmp) > 0U) {
+                /* By default CRC will not be placed into the rxBuffer */
+                if((tmp > RFAL_CRC_LEN)) {
+                    tmp -= RFAL_CRC_LEN;
+                }
+                /* If the CRC was already placed into rxBuffer (due to WL interrupt where CRC was already in FIFO Read)
+                     * cannot remove it from rxBuf. Can only remove it from rxBufLen not indicate the presence of CRC    */
+                else if(gRFAL.fifo.bytesTotal > RFAL_CRC_LEN) {
+                    gRFAL.fifo.bytesTotal -= RFAL_CRC_LEN;
+                } else {
+                    /* MISRA 15.7 - Empty else */
+                }
+            }
+        }
+
+        gRFAL.fifo.bytesTotal += tmp; /* add to total bytes counter */
+
+        /*******************************************************************************/
+        /* Check if remaining bytes fit on the rxBuf available                         */
+        if(gRFAL.fifo.bytesTotal > rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen)) {
+            tmp =
+                (uint16_t)(rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) - gRFAL.fifo.bytesWritten);
+
+            /* Transmission errors have precedence over buffer error */
+            if(gRFAL.TxRx.status == ERR_BUSY) {
+                gRFAL.TxRx.status = ERR_NOMEM;
+            }
+        }
+
+        /*******************************************************************************/
+        /* Retrieve remaining bytes from FIFO to rxBuf, and assign total length rcvd   */
+        st25r3916ReadFifo(&gRFAL.TxRx.ctx.rxBuf[gRFAL.fifo.bytesWritten], tmp);
+        if(gRFAL.TxRx.ctx.rxRcvdLen != NULL) {
+            (*gRFAL.TxRx.ctx.rxRcvdLen) = (uint16_t)rfalConvBytesToBits(gRFAL.fifo.bytesTotal);
+            if(rfalFIFOStatusIsIncompleteByte()) {
+                (*gRFAL.TxRx.ctx.rxRcvdLen) -=
+                    (RFAL_BITS_IN_BYTE - rfalFIFOGetNumIncompleteBits());
+            }
+        }
+
+#if RFAL_FEATURE_NFCV
+        /*******************************************************************************/
+        /* Decode sub bit stream into payload bits for NFCV, if no error found so far  */
+        if(((RFAL_MODE_POLL_NFCV == gRFAL.mode) || (RFAL_MODE_POLL_PICOPASS == gRFAL.mode)) &&
+           (gRFAL.TxRx.status == ERR_BUSY)) {
+            ReturnCode ret;
+            uint16_t offset = 0; /* REMARK offset not currently used */
+
+            ret = iso15693VICCDecode(
+                gRFAL.TxRx.ctx.rxBuf,
+                gRFAL.fifo.bytesTotal,
+                gRFAL.nfcvData.origCtx.rxBuf,
+                rfalConvBitsToBytes(gRFAL.nfcvData.origCtx.rxBufLen),
+                &offset,
+                gRFAL.nfcvData.origCtx.rxRcvdLen,
+                gRFAL.nfcvData.ignoreBits,
+                (RFAL_MODE_POLL_PICOPASS == gRFAL.mode));
+
+            if(((ERR_NONE == ret) || (ERR_CRC == ret)) &&
+               (((uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP & gRFAL.nfcvData.origCtx.flags) == 0U) &&
+               ((*gRFAL.nfcvData.origCtx.rxRcvdLen % RFAL_BITS_IN_BYTE) == 0U) &&
+               (*gRFAL.nfcvData.origCtx.rxRcvdLen >= rfalConvBytesToBits(RFAL_CRC_LEN))) {
+                *gRFAL.nfcvData.origCtx.rxRcvdLen -=
+                    (uint16_t)rfalConvBytesToBits(RFAL_CRC_LEN); /* Remove CRC */
+            }
+#if 0
+                /* Debugging code: output the payload bits by writing into the FIFO and subsequent clearing */
+                st25r3916WriteFifo(gRFAL.nfcvData.origCtx.rxBuf, rfalConvBitsToBytes( *gRFAL.nfcvData.origCtx.rxRcvdLen));
+                st25r3916ExecuteCommand( ST25R3916_CMD_CLEAR_FIFO );
+#endif
+
+            /* Restore original ctx */
+            gRFAL.TxRx.ctx = gRFAL.nfcvData.origCtx;
+            gRFAL.TxRx.status = ((ret != ERR_NONE) ? ret : ERR_BUSY);
+        }
+#endif /* RFAL_FEATURE_NFCV */
+
+        /*******************************************************************************/
+        /* If an error as been marked/detected don't fall into to RX_DONE  */
+        if(gRFAL.TxRx.status != ERR_BUSY) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+            break;
+        }
+
+        if(rfalIsModeActiveComm(gRFAL.mode)) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_EOF;
+            break;
+        }
+
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_DONE;
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_DONE: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        /*Check if Observation Mode was enabled and disable it on ST25R391x */
+        rfalCheckDisableObsMode();
+
+        /* Clean up Transceive */
+        rfalCleanupTransceive();
+
+        gRFAL.TxRx.status = ERR_NONE;
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE;
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_READ_FIFO:
+
+        /*******************************************************************************/
+        /* REMARK: Silicon workaround ST25R3916 Errata #TBD                            */
+        /* Rarely on corrupted frames I_rxs gets signaled but I_rxe is not signaled    */
+        /* Use a SW timer to handle an eventual missing RXE                            */
+        rfalTimerStart(gRFAL.tmr.RXE, RFAL_NORXE_TOUT);
+        /*******************************************************************************/
+
+        tmp = rfalFIFOStatusGetNumBytes();
+        gRFAL.fifo.bytesTotal += tmp;
+
+        /*******************************************************************************/
+        /* Calculate the amount of bytes that still fits in rxBuf                      */
+        aux =
+            ((gRFAL.fifo.bytesTotal > rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen)) ?
+                 (rfalConvBitsToBytes(gRFAL.TxRx.ctx.rxBufLen) - gRFAL.fifo.bytesWritten) :
+                 tmp);
+
+        /*******************************************************************************/
+        /* Retrieve incoming bytes from FIFO to rxBuf, and store already read amount   */
+        st25r3916ReadFifo(&gRFAL.TxRx.ctx.rxBuf[gRFAL.fifo.bytesWritten], aux);
+        gRFAL.fifo.bytesWritten += aux;
+
+        /*******************************************************************************/
+        /* If the bytes already read were not the full FIFO WL, dump the remaining     *
+             * FIFO so that ST25R391x can continue with reception                          */
+        if(aux < tmp) {
+            st25r3916ReadFifo(NULL, (tmp - aux));
+        }
+
+        rfalFIFOStatusClear();
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXE;
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_FAIL:
+
+        /*Check if Observation Mode was enabled and disable it on ST25R391x */
+        rfalCheckDisableObsMode();
+
+        /* Clean up Transceive */
+        rfalCleanupTransceive();
+
+        /* Error should be assigned by previous state */
+        if(gRFAL.TxRx.status == ERR_BUSY) {
+            gRFAL.TxRx.status = ERR_SYSTEM;
+        }
+
+        /*rfalLogD( "RFAL: curSt: %d  Error: %d \r\n", gRFAL.TxRx.state, gRFAL.TxRx.status );*/
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_IDLE;
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_WAIT_EON:
+
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_PPON2));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_EON) != 0U) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_WAIT_RXS;
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_NRE) != 0U) {
+            gRFAL.TxRx.status = ERR_TIMEOUT;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        }
+        if((irqs & ST25R3916_IRQ_MASK_PPON2) != 0U) {
+            gRFAL.TxRx.status = ERR_LINK_LOSS;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_TXRX_STATE_RX_WAIT_EOF:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_CAC));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_CAT) != 0U) {
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_DONE;
+        } else if((irqs & ST25R3916_IRQ_MASK_CAC) != 0U) {
+            gRFAL.TxRx.status = ERR_RF_COLLISION;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        } else {
+            gRFAL.TxRx.status = ERR_IO;
+            gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        }
+        break;
+
+    /*******************************************************************************/
+    default:
+        gRFAL.TxRx.status = ERR_SYSTEM;
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_FAIL;
+        break;
+    }
+}
+
+/*******************************************************************************/
+static void rfalFIFOStatusUpdate(void) {
+    if(gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] == RFAL_FIFO_STATUS_INVALID) {
+        st25r3916ReadMultipleRegisters(
+            ST25R3916_REG_FIFO_STATUS1, gRFAL.fifo.status, ST25R3916_FIFO_STATUS_LEN);
+    }
+}
+
+/*******************************************************************************/
+static void rfalFIFOStatusClear(void) {
+    gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] = RFAL_FIFO_STATUS_INVALID;
+}
+
+/*******************************************************************************/
+static uint16_t rfalFIFOStatusGetNumBytes(void) {
+    uint16_t result;
+
+    rfalFIFOStatusUpdate();
+
+    result =
+        ((((uint16_t)gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] &
+           ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
+          ST25R3916_REG_FIFO_STATUS2_fifo_b_shift)
+         << RFAL_BITS_IN_BYTE);
+    result |= (((uint16_t)gRFAL.fifo.status[RFAL_FIFO_STATUS_REG1]) & 0x00FFU);
+    return result;
+}
+
+/*******************************************************************************/
+static bool rfalFIFOStatusIsIncompleteByte(void) {
+    rfalFIFOStatusUpdate();
+    return (
+        (gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) !=
+        0U);
+}
+
+/*******************************************************************************/
+static bool rfalFIFOStatusIsMissingPar(void) {
+    rfalFIFOStatusUpdate();
+    return ((gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & ST25R3916_REG_FIFO_STATUS2_np_lb) != 0U);
+}
+
+/*******************************************************************************/
+static uint8_t rfalFIFOGetNumIncompleteBits(void) {
+    rfalFIFOStatusUpdate();
+    return (
+        (gRFAL.fifo.status[RFAL_FIFO_STATUS_REG2] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
+        ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
+}
+
+#if RFAL_FEATURE_NFCA
+
+/*******************************************************************************/
+ReturnCode rfalISO14443ATransceiveShortFrame(
+    rfal14443AShortFrameCmd txCmd,
+    uint8_t* rxBuf,
+    uint8_t rxBufLen,
+    uint16_t* rxRcvdLen,
+    uint32_t fwt) {
+    ReturnCode ret;
+    uint8_t directCmd;
+
+    /* Check if RFAL is properly initialized */
+    if(!st25r3916IsTxEnabled() || (gRFAL.state < RFAL_STATE_MODE_SET) ||
+       ((gRFAL.mode != RFAL_MODE_POLL_NFCA) && (gRFAL.mode != RFAL_MODE_POLL_NFCA_T1T))) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check for valid parameters */
+    if((rxBuf == NULL) || (rxRcvdLen == NULL) || (fwt == RFAL_FWT_NONE)) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /* Select the Direct Command to be performed                                   */
+    switch(txCmd) {
+    case RFAL_14443A_SHORTFRAME_CMD_WUPA:
+        directCmd = ST25R3916_CMD_TRANSMIT_WUPA;
+        break;
+
+    case RFAL_14443A_SHORTFRAME_CMD_REQA:
+        directCmd = ST25R3916_CMD_TRANSMIT_REQA;
+        break;
+
+    default:
+        return ERR_PARAM;
+    }
+
+    /* Disable CRC while receiving since ATQA has no CRC included */
+    st25r3916SetRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
+
+    /*******************************************************************************/
+    /* Wait for GT and FDT */
+    while(!rfalIsGTExpired()) { /* MISRA 15.6: mandatory brackets */
+    };
+    while(st25r3916IsGPTRunning()) { /* MISRA 15.6: mandatory brackets */
+    };
+
+    rfalTimerDestroy(gRFAL.tmr.GT);
+    gRFAL.tmr.GT = RFAL_TIMING_NONE;
+
+    /*******************************************************************************/
+    /* Prepare for Transceive, Receive only (bypass Tx states) */
+    gRFAL.TxRx.ctx.flags =
+        ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP);
+    gRFAL.TxRx.ctx.rxBuf = rxBuf;
+    gRFAL.TxRx.ctx.rxBufLen = rxBufLen;
+    gRFAL.TxRx.ctx.rxRcvdLen = rxRcvdLen;
+    gRFAL.TxRx.ctx.fwt = fwt;
+
+    /*******************************************************************************/
+    /* Load NRT with FWT */
+    st25r3916SetNoResponseTime(rfalConv1fcTo64fc(
+        MIN((fwt + RFAL_FWT_ADJUSTMENT + RFAL_FWT_A_ADJUSTMENT), RFAL_ST25R3916_NRT_MAX_1FC)));
+
+    if(gRFAL.timings.FDTListen != RFAL_TIMING_NONE) {
+        /* Ensure that MRT is using 64/fc steps */
+        st25r3916ClrRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step);
+
+        /* Set Minimum FDT(Listen) in which PICC is not allowed to send a response */
+        st25r3916WriteRegister(
+            ST25R3916_REG_MASK_RX_TIMER,
+            (uint8_t)rfalConv1fcTo64fc(
+                ((RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT) >
+                 gRFAL.timings.FDTListen) ?
+                    RFAL_ST25R3916_MRT_MIN_1FC :
+                    (gRFAL.timings.FDTListen -
+                     (RFAL_FDT_LISTEN_MRT_ADJUSTMENT + RFAL_FDT_LISTEN_A_ADJUSTMENT))));
+    }
+
+    /* In Passive communications General Purpose Timer is used to measure FDT Poll */
+    if(gRFAL.timings.FDTPoll != RFAL_TIMING_NONE) {
+        /* Configure GPT to start at RX end */
+        st25r3916SetStartGPTimer(
+            (uint16_t)rfalConv1fcTo8fc(
+                MIN(gRFAL.timings.FDTPoll, (gRFAL.timings.FDTPoll - RFAL_FDT_POLL_ADJUSTMENT))),
+            ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx);
+    }
+
+    /*******************************************************************************/
+    rfalPrepareTransceive();
+
+    /* Also enable bit collision interrupt */
+    st25r3916GetInterrupt(ST25R3916_IRQ_MASK_COL);
+    st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_COL);
+
+    /*Check if Observation Mode is enabled and set it on ST25R391x */
+    rfalCheckEnableObsModeTx();
+
+    /*******************************************************************************/
+    /* Clear nbtx bits before sending WUPA/REQA - otherwise ST25R3916 will report parity error, Note2 of the register */
+    st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES2, 0);
+
+    /* Send either WUPA or REQA. All affected tags will backscatter ATQA and change to READY state */
+    st25r3916ExecuteCommand(directCmd);
+
+    /* Wait for TXE */
+    if(st25r3916WaitForInterruptsTimed(
+           ST25R3916_IRQ_MASK_TXE,
+           (uint16_t)MAX(rfalConv1fcToMs(fwt), RFAL_ST25R3916_SW_TMR_MIN_1MS)) == 0U) {
+        ret = ERR_IO;
+    } else {
+        /*Check if Observation Mode is enabled and set it on ST25R391x */
+        rfalCheckEnableObsModeRx();
+
+        /* Jump into a transceive Rx state for reception (bypass Tx states) */
+        gRFAL.state = RFAL_STATE_TXRX;
+        gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE;
+        gRFAL.TxRx.status = ERR_BUSY;
+
+        /* Execute Transceive Rx blocking */
+        ret = rfalTransceiveBlockingRx();
+    }
+
+    /* Disable Collision interrupt */
+    st25r3916DisableInterrupts((ST25R3916_IRQ_MASK_COL));
+
+    /* ReEnable CRC on Rx */
+    st25r3916ClrRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalISO14443ATransceiveAnticollisionFrame(
+    uint8_t* buf,
+    uint8_t* bytesToSend,
+    uint8_t* bitsToSend,
+    uint16_t* rxLength,
+    uint32_t fwt) {
+    ReturnCode ret;
+    rfalTransceiveContext ctx;
+    uint8_t collByte;
+    uint8_t collData;
+
+    /* Check if RFAL is properly initialized */
+    if((gRFAL.state < RFAL_STATE_MODE_SET) || (gRFAL.mode != RFAL_MODE_POLL_NFCA)) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Check for valid parameters */
+    if((buf == NULL) || (bytesToSend == NULL) || (bitsToSend == NULL) || (rxLength == NULL)) {
+        return ERR_PARAM;
+    }
+
+    /*******************************************************************************/
+    /* Set specific Analog Config for Anticolission if needed */
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL));
+
+    /*******************************************************************************/
+    /* Enable anti collision to recognise collision in first byte of SENS_REQ */
+    st25r3916SetRegisterBits(ST25R3916_REG_ISO14443A_NFC, ST25R3916_REG_ISO14443A_NFC_antcl);
+
+    /* Disable CRC while receiving */
+    st25r3916SetRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
+
+    /*******************************************************************************/
+    /* Prepare for Transceive                                                      */
+    ctx.flags = ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP);
+    ctx.txBuf = buf;
+    ctx.txBufLen = (uint16_t)(rfalConvBytesToBits(*bytesToSend) + *bitsToSend);
+    ctx.rxBuf = &buf[*bytesToSend];
+    ctx.rxBufLen = (uint16_t)rfalConvBytesToBits(RFAL_ISO14443A_SDD_RES_LEN);
+    ctx.rxRcvdLen = rxLength;
+    ctx.fwt = fwt;
+
+    /* Disable Automatic Gain Control (AGC) for better detection of collisions if using Coherent Receiver */
+    ctx.flags |=
+        (st25r3916CheckReg(
+             ST25R3916_REG_AUX, ST25R3916_REG_AUX_dis_corr, ST25R3916_REG_AUX_dis_corr) ?
+             (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF :
+             0x00U);
+
+    rfalStartTransceive(&ctx);
+
+    /* Additionally enable bit collision interrupt */
+    st25r3916GetInterrupt(ST25R3916_IRQ_MASK_COL);
+    st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_COL);
+
+    /*******************************************************************************/
+    collByte = 0;
+
+    /* save the collision byte */
+    if((*bitsToSend) > 0U) {
+        buf[(*bytesToSend)] <<= (RFAL_BITS_IN_BYTE - (*bitsToSend));
+        buf[(*bytesToSend)] >>= (RFAL_BITS_IN_BYTE - (*bitsToSend));
+        collByte = buf[(*bytesToSend)];
+    }
+
+    /*******************************************************************************/
+    /* Run Transceive blocking */
+    ret = rfalTransceiveRunBlockingTx();
+    if(ret == ERR_NONE) {
+        ret = rfalTransceiveBlockingRx();
+
+        /*******************************************************************************/
+        if((*bitsToSend) > 0U) {
+            buf[(*bytesToSend)] >>= (*bitsToSend);
+            buf[(*bytesToSend)] <<= (*bitsToSend);
+            buf[(*bytesToSend)] |= collByte;
+        }
+
+        if((ERR_RF_COLLISION == ret)) {
+            /* read out collision register */
+            st25r3916ReadRegister(ST25R3916_REG_COLLISION_STATUS, &collData);
+
+            (*bytesToSend) =
+                ((collData >> ST25R3916_REG_COLLISION_STATUS_c_byte_shift) &
+                 0x0FU); // 4-bits Byte information
+            (*bitsToSend) =
+                ((collData >> ST25R3916_REG_COLLISION_STATUS_c_bit_shift) &
+                 0x07U); // 3-bits bit information
+        }
+    }
+
+    /*******************************************************************************/
+    /* Disable Collision interrupt */
+    st25r3916DisableInterrupts((ST25R3916_IRQ_MASK_COL));
+
+    /* Disable anti collision again */
+    st25r3916ClrRegisterBits(ST25R3916_REG_ISO14443A_NFC, ST25R3916_REG_ISO14443A_NFC_antcl);
+
+    /* ReEnable CRC on Rx */
+    st25r3916ClrRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
+    /*******************************************************************************/
+
+    /* Restore common Analog configurations for this mode */
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR(gRFAL.txBR) |
+         RFAL_ANALOG_CONFIG_TX));
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCA | rfalConvBR2ACBR(gRFAL.rxBR) |
+         RFAL_ANALOG_CONFIG_RX));
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFCA */
+
+#if RFAL_FEATURE_NFCV
+
+/*******************************************************************************/
+ReturnCode rfalISO15693TransceiveAnticollisionFrame(
+    uint8_t* txBuf,
+    uint8_t txBufLen,
+    uint8_t* rxBuf,
+    uint8_t rxBufLen,
+    uint16_t* actLen) {
+    ReturnCode ret;
+    rfalTransceiveContext ctx;
+
+    /* Check if RFAL is properly initialized */
+    if((gRFAL.state < RFAL_STATE_MODE_SET) || (gRFAL.mode != RFAL_MODE_POLL_NFCV)) {
+        return ERR_WRONG_STATE;
+    }
+
+    /*******************************************************************************/
+    /* Set specific Analog Config for Anticolission if needed */
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV |
+         RFAL_ANALOG_CONFIG_BITRATE_COMMON | RFAL_ANALOG_CONFIG_ANTICOL));
+
+    /* Ignoring collisions before the UID (RES_FLAG + DSFID) */
+    gRFAL.nfcvData.ignoreBits = (uint16_t)RFAL_ISO15693_IGNORE_BITS;
+
+    /*******************************************************************************/
+    /* Prepare for Transceive  */
+    ctx.flags =
+        ((txBufLen == 0U) ? (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL :
+                            (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO) |
+        (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_AGC_OFF |
+        ((txBufLen == 0U) ?
+             (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_MANUAL :
+             (uint32_t)
+                 RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO); /* Disable Automatic Gain Control (AGC) for better detection of collision */
+    ctx.txBuf = txBuf;
+    ctx.txBufLen = (uint16_t)rfalConvBytesToBits(txBufLen);
+    ctx.rxBuf = rxBuf;
+    ctx.rxBufLen = (uint16_t)rfalConvBytesToBits(rxBufLen);
+    ctx.rxRcvdLen = actLen;
+    ctx.fwt = rfalConv64fcTo1fc(ISO15693_FWT);
+
+    rfalStartTransceive(&ctx);
+
+    /*******************************************************************************/
+    /* Run Transceive blocking */
+    ret = rfalTransceiveRunBlockingTx();
+    if(ret == ERR_NONE) {
+        ret = rfalTransceiveBlockingRx();
+    }
+
+    /* Check if a Transmission error and received data is less then expected */
+    if(((ret == ERR_RF_COLLISION) || (ret == ERR_CRC) || (ret == ERR_FRAMING)) &&
+       (rfalConvBitsToBytes(*ctx.rxRcvdLen) < RFAL_ISO15693_INV_RES_LEN)) {
+        /* If INVENTORY_RES is shorter than expected, tag is still modulating *
+         * Ensure that response is complete before next frame                 */
+        platformDelay((uint8_t)((RFAL_ISO15693_INV_RES_LEN - rfalConvBitsToBytes(*ctx.rxRcvdLen)) /
+                                ((RFAL_ISO15693_INV_RES_LEN / RFAL_ISO15693_INV_RES_DUR) + 1U)));
+    }
+
+    /* Restore common Analog configurations for this mode */
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR(gRFAL.txBR) |
+         RFAL_ANALOG_CONFIG_TX));
+    rfalSetAnalogConfig(
+        (RFAL_ANALOG_CONFIG_POLL | RFAL_ANALOG_CONFIG_TECH_NFCV | rfalConvBR2ACBR(gRFAL.rxBR) |
+         RFAL_ANALOG_CONFIG_RX));
+
+    gRFAL.nfcvData.ignoreBits = 0;
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalISO15693TransceiveEOFAnticollision(uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* actLen) {
+    uint8_t dummy;
+
+    return rfalISO15693TransceiveAnticollisionFrame(&dummy, 0, rxBuf, rxBufLen, actLen);
+}
+
+/*******************************************************************************/
+ReturnCode rfalISO15693TransceiveEOF(uint8_t* rxBuf, uint8_t rxBufLen, uint16_t* actLen) {
+    ReturnCode ret;
+    uint8_t dummy;
+
+    /* Check if RFAL is properly initialized */
+    if((gRFAL.state < RFAL_STATE_MODE_SET) || (gRFAL.mode != RFAL_MODE_POLL_NFCV)) {
+        return ERR_WRONG_STATE;
+    }
+
+    /*******************************************************************************/
+    /* Run Transceive blocking */
+    ret = rfalTransceiveBlockingTxRx(
+        &dummy,
+        0,
+        rxBuf,
+        rxBufLen,
+        actLen,
+        ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+         (uint32_t)RFAL_TXRX_FLAGS_AGC_ON),
+        rfalConv64fcTo1fc(ISO15693_FWT));
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_NFCV */
+
+#if RFAL_FEATURE_NFCF
+
+/*******************************************************************************/
+ReturnCode rfalFeliCaPoll(
+    rfalFeliCaPollSlots slots,
+    uint16_t sysCode,
+    uint8_t reqCode,
+    rfalFeliCaPollRes* pollResList,
+    uint8_t pollResListSize,
+    uint8_t* devicesDetected,
+    uint8_t* collisionsDetected) {
+    ReturnCode ret;
+    uint8_t frame
+        [RFAL_FELICA_POLL_REQ_LEN - RFAL_FELICA_LEN_LEN]; // LEN is added by ST25R391x automatically
+    uint16_t actLen;
+    uint8_t frameIdx;
+    uint8_t devDetected;
+    uint8_t colDetected;
+    rfalEHandling curHandling;
+    uint8_t nbSlots;
+
+    /* Check if RFAL is properly initialized */
+    if((gRFAL.state < RFAL_STATE_MODE_SET) || (gRFAL.mode != RFAL_MODE_POLL_NFCF)) {
+        return ERR_WRONG_STATE;
+    }
+
+    frameIdx = 0;
+    colDetected = 0;
+    devDetected = 0;
+    nbSlots = (uint8_t)slots;
+
+    /*******************************************************************************/
+    /* Compute SENSF_REQ frame */
+    frame[frameIdx++] = (uint8_t)FELICA_CMD_POLLING; /* CMD: SENF_REQ                       */
+    frame[frameIdx++] = (uint8_t)(sysCode >> 8); /* System Code (SC)                    */
+    frame[frameIdx++] = (uint8_t)(sysCode & 0xFFU); /* System Code (SC)                    */
+    frame[frameIdx++] = reqCode; /* Communication Parameter Request (RC)*/
+    frame[frameIdx++] = nbSlots; /* TimeSlot (TSN)                      */
+
+    /*******************************************************************************/
+    /* NRT should not stop on reception - Use EMVCo mode to run NRT in nrt_emv     *
+     * ERRORHANDLING_EMVCO has no special handling for NFC-F mode                  */
+    curHandling = gRFAL.conf.eHandling;
+    rfalSetErrorHandling(RFAL_ERRORHANDLING_EMVCO);
+
+    /*******************************************************************************/
+    /* Run transceive blocking, 
+     * Calculate Total Response Time in(64/fc): 
+     *                       512 PICC process time + (n * 256 Time Slot duration)  */
+    ret = rfalTransceiveBlockingTx(
+        frame,
+        (uint16_t)frameIdx,
+        (uint8_t*)gRFAL.nfcfData.pollResponses,
+        RFAL_FELICA_POLL_RES_LEN,
+        &actLen,
+        (RFAL_TXRX_FLAGS_DEFAULT),
+        rfalConv64fcTo1fc(
+            RFAL_FELICA_POLL_DELAY_TIME +
+            (RFAL_FELICA_POLL_SLOT_TIME * ((uint32_t)nbSlots + 1U))));
+
+    /*******************************************************************************/
+    /* If Tx OK, Wait for all responses, store them as soon as they appear         */
+    if(ret == ERR_NONE) {
+        bool timeout;
+
+        do {
+            ret = rfalTransceiveBlockingRx();
+            if(ret == ERR_TIMEOUT) {
+                /* Upon timeout the full Poll Delay + (Slot time)*(nbSlots) has expired */
+                timeout = true;
+            } else {
+                /* Reception done, reEnabled Rx for following Slot */
+                st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+                st25r3916ExecuteCommand(ST25R3916_CMD_RESET_RXGAIN);
+
+                /* If the reception was OK, new device found */
+                if(ret == ERR_NONE) {
+                    devDetected++;
+
+                    /* Overwrite the Transceive context for the next reception */
+                    gRFAL.TxRx.ctx.rxBuf = (uint8_t*)gRFAL.nfcfData.pollResponses[devDetected];
+                }
+                /* If the reception was not OK, mark as collision */
+                else {
+                    colDetected++;
+                }
+
+                /* Check whether NRT has expired meanwhile  */
+                timeout = st25r3916CheckReg(
+                    ST25R3916_REG_NFCIP1_BIT_RATE, ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on, 0x00);
+                if(!timeout) {
+                    /* Jump again into transceive Rx state for the following reception */
+                    gRFAL.TxRx.status = ERR_BUSY;
+                    gRFAL.state = RFAL_STATE_TXRX;
+                    gRFAL.TxRx.state = RFAL_TXRX_STATE_RX_IDLE;
+                }
+            }
+        } while(((nbSlots--) != 0U) && !timeout);
+    }
+
+    /*******************************************************************************/
+    /* Restore NRT to normal mode - back to previous error handling */
+    rfalSetErrorHandling(curHandling);
+
+    /*******************************************************************************/
+    /* Assign output parameters if requested                                       */
+
+    if((pollResList != NULL) && (pollResListSize > 0U) && (devDetected > 0U)) {
+        ST_MEMCPY(
+            pollResList,
+            gRFAL.nfcfData.pollResponses,
+            (RFAL_FELICA_POLL_RES_LEN * (uint32_t)MIN(pollResListSize, devDetected)));
+    }
+
+    if(devicesDetected != NULL) {
+        *devicesDetected = devDetected;
+    }
+
+    if(collisionsDetected != NULL) {
+        *collisionsDetected = colDetected;
+    }
+
+    return (((colDetected != 0U) || (devDetected != 0U)) ? ERR_NONE : ret);
+}
+
+#endif /* RFAL_FEATURE_NFCF */
+
+/*****************************************************************************
+ *  Listen Mode                                                              *  
+ *****************************************************************************/
+
+/*******************************************************************************/
+bool rfalIsExtFieldOn(void) {
+    return st25r3916IsExtFieldOn();
+}
+
+#if RFAL_FEATURE_LISTEN_MODE
+
+/*******************************************************************************/
+ReturnCode rfalListenStart(
+    uint32_t lmMask,
+    const rfalLmConfPA* confA,
+    const rfalLmConfPB* confB,
+    const rfalLmConfPF* confF,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* rxLen) {
+    t_rfalPTMem
+        PTMem; /*  PRQA S 0759 # MISRA 19.2 - Allocating Union where members are of the same type, just different names.  Thus no problem can occur. */
+    uint8_t* pPTMem;
+    uint8_t autoResp;
+
+    /* Check if RFAL is initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    gRFAL.Lm.state = RFAL_LM_STATE_NOT_INIT;
+    gRFAL.Lm.mdIrqs = ST25R3916_IRQ_MASK_NONE;
+    gRFAL.Lm.mdReg =
+        (ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_nfc | ST25R3916_REG_MODE_nfc_ar_off);
+
+    /* By default disable all automatic responses */
+    autoResp =
+        (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_rfu |
+         ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p);
+
+    /*******************************************************************************/
+    if((lmMask & RFAL_LM_MASK_NFCA) != 0U) {
+        /* Check if the conf has been provided */
+        if(confA == NULL) {
+            return ERR_PARAM;
+        }
+
+        pPTMem = (uint8_t*)PTMem.PTMem_A;
+
+        /*******************************************************************************/
+        /* Check and set supported NFCID Length */
+        switch(confA->nfcidLen) {
+        case RFAL_LM_NFCID_LEN_04:
+            st25r3916ChangeRegisterBits(
+                ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_4bytes);
+            break;
+
+        case RFAL_LM_NFCID_LEN_07:
+            st25r3916ChangeRegisterBits(
+                ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_7bytes);
+            break;
+
+        default:
+            return ERR_PARAM;
+        }
+
+        /*******************************************************************************/
+        /* Set NFCID */
+        ST_MEMCPY(pPTMem, confA->nfcid, RFAL_NFCID1_TRIPLE_LEN);
+        pPTMem = &pPTMem[RFAL_NFCID1_TRIPLE_LEN]; /* MISRA 18.4 */
+
+        /* Set SENS_RES */
+        ST_MEMCPY(pPTMem, confA->SENS_RES, RFAL_LM_SENS_RES_LEN);
+        pPTMem = &pPTMem[RFAL_LM_SENS_RES_LEN]; /* MISRA 18.4 */
+
+        /* Set SEL_RES */
+        *pPTMem++ =
+            ((confA->nfcidLen == RFAL_LM_NFCID_LEN_04) ?
+                 (confA->SEL_RES & ~RFAL_LM_NFCID_INCOMPLETE) :
+                 (confA->SEL_RES | RFAL_LM_NFCID_INCOMPLETE));
+        *pPTMem++ = (confA->SEL_RES & ~RFAL_LM_NFCID_INCOMPLETE);
+        *pPTMem++ = (confA->SEL_RES & ~RFAL_LM_NFCID_INCOMPLETE);
+
+        /* Write into PTMem-A */
+        st25r3916WritePTMem(PTMem.PTMem_A, ST25R3916_PTM_A_LEN);
+
+        /*******************************************************************************/
+        /* Enable automatic responses for A */
+        autoResp &= ~ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a;
+
+        /* Set Target mode, Bit Rate detection and Listen Mode for NFC-F */
+        gRFAL.Lm.mdReg |=
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0 |
+             ST25R3916_REG_MODE_nfc_ar_off);
+
+        gRFAL.Lm.mdIrqs |=
+            (ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RXE_PTA);
+    }
+
+    /*******************************************************************************/
+    if((lmMask & RFAL_LM_MASK_NFCB) != 0U) {
+        /* Check if the conf has been provided */
+        if(confB == NULL) {
+            return ERR_PARAM;
+        }
+
+        return ERR_NOTSUPP;
+    }
+
+    /*******************************************************************************/
+    if((lmMask & RFAL_LM_MASK_NFCF) != 0U) {
+        pPTMem = (uint8_t*)PTMem.PTMem_F;
+
+        /* Check if the conf has been provided */
+        if(confF == NULL) {
+            return ERR_PARAM;
+        }
+
+        /*******************************************************************************/
+        /* Set System Code */
+        ST_MEMCPY(pPTMem, confF->SC, RFAL_LM_SENSF_SC_LEN);
+        pPTMem = &pPTMem[RFAL_LM_SENSF_SC_LEN]; /* MISRA 18.4 */
+
+        /* Set SENSF_RES */
+        ST_MEMCPY(pPTMem, confF->SENSF_RES, RFAL_LM_SENSF_RES_LEN);
+
+        /* Set RD bytes to 0x00 as ST25R3916 cannot support advances features */
+        pPTMem[RFAL_LM_SENSF_RD0_POS] =
+            0x00; /* NFC Forum Digital 1.1 Table 46: 0x00                   */
+        pPTMem[RFAL_LM_SENSF_RD1_POS] =
+            0x00; /* NFC Forum Digital 1.1 Table 47: No automatic bit rates */
+
+        pPTMem = &pPTMem[RFAL_LM_SENS_RES_LEN]; /* MISRA 18.4 */
+
+        /* Write into PTMem-F */
+        st25r3916WritePTMemF(PTMem.PTMem_F, ST25R3916_PTM_F_LEN);
+
+        /*******************************************************************************/
+        /* Write 24 TSN "Random" Numbers at first initialization and let it rollover   */
+        if(!gRFAL.Lm.iniFlag) {
+            pPTMem = (uint8_t*)PTMem.TSN;
+
+            *pPTMem++ = 0x12;
+            *pPTMem++ = 0x34;
+            *pPTMem++ = 0x56;
+            *pPTMem++ = 0x78;
+            *pPTMem++ = 0x9A;
+            *pPTMem++ = 0xBC;
+            *pPTMem++ = 0xDF;
+            *pPTMem++ = 0x21;
+            *pPTMem++ = 0x43;
+            *pPTMem++ = 0x65;
+            *pPTMem++ = 0x87;
+            *pPTMem++ = 0xA9;
+
+            /* Write into PTMem-TSN */
+            st25r3916WritePTMemTSN(PTMem.TSN, ST25R3916_PTM_TSN_LEN);
+        }
+
+        /*******************************************************************************/
+        /* Enable automatic responses for F */
+        autoResp &= ~(ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r);
+
+        /* Set Target mode, Bit Rate detection and Listen Mode for NFC-F */
+        gRFAL.Lm.mdReg |=
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 |
+             ST25R3916_REG_MODE_nfc_ar_off);
+
+        /* In CE NFC-F any data without error will be passed to FIFO, to support CUP */
+        gRFAL.Lm.mdIrqs |=
+            (ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_RXE);
+    }
+
+    /*******************************************************************************/
+    if((lmMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U) {
+        /* Enable Reception of P2P frames */
+        autoResp &= ~(ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p);
+
+        /* Set Target mode, Bit Rate detection and Automatic Response RF Collision Avoidance */
+        gRFAL.Lm.mdReg |=
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 |
+             ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_auto_rx);
+
+        /* n * TRFW timing shall vary  Activity 2.1  3.4.1.1 */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, gRFAL.timings.nTRFW);
+        gRFAL.timings.nTRFW = rfalGennTRFW(gRFAL.timings.nTRFW);
+
+        gRFAL.Lm.mdIrqs |= (ST25R3916_IRQ_MASK_RXE);
+    }
+
+    /* Check if one of the modes were selected */
+    if((gRFAL.Lm.mdReg & ST25R3916_REG_MODE_targ) == ST25R3916_REG_MODE_targ_targ) {
+        gRFAL.state = RFAL_STATE_LM;
+        gRFAL.Lm.mdMask = lmMask;
+
+        gRFAL.Lm.rxBuf = rxBuf;
+        gRFAL.Lm.rxBufLen = rxBufLen;
+        gRFAL.Lm.rxLen = rxLen;
+        *gRFAL.Lm.rxLen = 0;
+        gRFAL.Lm.dataFlag = false;
+        gRFAL.Lm.iniFlag = true;
+
+        /* Apply the Automatic Responses configuration */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_PASSIVE_TARGET,
+            (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_rfu |
+             ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p),
+            autoResp);
+
+        /* Disable GPT trigger source */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL,
+            ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask,
+            ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
+
+        /* On Bit Rate Detection Mode ST25R391x will filter incoming frames during MRT time starting on External Field On event, use 512/fc steps */
+        st25r3916SetRegisterBits(
+            ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_512);
+        st25r3916WriteRegister(
+            ST25R3916_REG_MASK_RX_TIMER, (uint8_t)rfalConv1fcTo512fc(RFAL_LM_GT));
+
+        /* Restore default settings on NFCIP1 mode, Receiving parity + CRC bits and manual Tx Parity*/
+        st25r3916ClrRegisterBits(
+            ST25R3916_REG_ISO14443A_NFC,
+            (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par |
+             ST25R3916_REG_ISO14443A_NFC_nfc_f0));
+
+        /* External Field Detector enabled as Automatics on rfalInitialize() */
+
+        /* Set Analog configurations for generic Listen mode */
+        /* Not on SetState(POWER OFF) as otherwise would be applied on every Field Event */
+        rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_ON));
+
+        /* Initialize as POWER_OFF and set proper mode in RF Chip */
+        rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+    } else {
+        return ERR_REQUEST; /* Listen Start called but no mode was enabled */
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+static ReturnCode rfalRunListenModeWorker(void) {
+    volatile uint32_t irqs;
+    uint8_t tmp;
+
+    if(gRFAL.state != RFAL_STATE_LM) {
+        return ERR_WRONG_STATE;
+    }
+
+    switch(gRFAL.Lm.state) {
+    /*******************************************************************************/
+    case RFAL_LM_STATE_POWER_OFF:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EON));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_EON) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_IDLE);
+        } else {
+            break;
+        }
+        /* fall through */
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_IDLE: /*  PRQA S 2003 # MISRA 16.3 - Intentional fall through */
+
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE |
+             ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_RXE_PTA));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_NFCT) != 0U) {
+            /* Retrieve detected bitrate */
+            uint8_t newBr;
+            st25r3916ReadRegister(ST25R3916_REG_NFCIP1_BIT_RATE, &newBr);
+            newBr >>= ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift;
+
+            if(newBr > ST25R3916_REG_BIT_RATE_rxrate_424) {
+                newBr = ST25R3916_REG_BIT_RATE_rxrate_424;
+            }
+
+            gRFAL.Lm.brDetected =
+                (rfalBitRate)(newBr); /* PRQA S 4342 # MISRA 10.5 - Guaranteed that no invalid enum values may be created. See also equalityGuard_RFAL_BR_106 ff.*/
+        }
+
+        if(((irqs & ST25R3916_IRQ_MASK_WU_F) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            rfalListenSetState(RFAL_LM_STATE_READY_F);
+        } else if(((irqs & ST25R3916_IRQ_MASK_RXE) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            irqs = st25r3916GetInterrupt(
+                (ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF |
+                 ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_ERR2 |
+                 ST25R3916_IRQ_MASK_ERR1));
+
+            if(((irqs & ST25R3916_IRQ_MASK_CRC) != 0U) ||
+               ((irqs & ST25R3916_IRQ_MASK_PAR) != 0U) ||
+               ((irqs & ST25R3916_IRQ_MASK_ERR1) != 0U)) {
+                st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+                st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+                st25r3916TxOff();
+                break; /* A bad reception occurred, remain in same state */
+            }
+
+            /* Retrieve received data */
+            *gRFAL.Lm.rxLen = st25r3916GetNumFIFOBytes();
+            st25r3916ReadFifo(
+                gRFAL.Lm.rxBuf, MIN(*gRFAL.Lm.rxLen, rfalConvBitsToBytes(gRFAL.Lm.rxBufLen)));
+
+            /*******************************************************************************/
+            /* REMARK: Silicon workaround ST25R3916 Errata #TBD                            */
+            /* In bitrate detection mode CRC is now checked for NFC-A frames               */
+            if((*gRFAL.Lm.rxLen > RFAL_CRC_LEN) && (gRFAL.Lm.brDetected == RFAL_BR_106)) {
+                if(rfalCrcCalculateCcitt(
+                       RFAL_ISO14443A_CRC_INTVAL, gRFAL.Lm.rxBuf, *gRFAL.Lm.rxLen) != 0U) {
+                    st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+                    st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+                    st25r3916TxOff();
+                    break; /* A bad reception occurred, remain in same state */
+                }
+            }
+            /*******************************************************************************/
+
+            /* Check if the data we got has at least the CRC and remove it, otherwise leave at 0 */
+            *gRFAL.Lm.rxLen -= ((*gRFAL.Lm.rxLen > RFAL_CRC_LEN) ? RFAL_CRC_LEN : *gRFAL.Lm.rxLen);
+            *gRFAL.Lm.rxLen = (uint16_t)rfalConvBytesToBits(*gRFAL.Lm.rxLen);
+            gRFAL.Lm.dataFlag = true;
+
+            /*Check if Observation Mode was enabled and disable it on ST25R391x */
+            rfalCheckDisableObsMode();
+        } else if(
+            ((irqs & ST25R3916_IRQ_MASK_RXE_PTA) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            if(((gRFAL.Lm.mdMask & RFAL_LM_MASK_NFCA) != 0U) &&
+               (gRFAL.Lm.brDetected == RFAL_BR_106)) {
+                st25r3916ReadRegister(ST25R3916_REG_PASSIVE_TARGET_STATUS, &tmp);
+                if(tmp > ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_idle) {
+                    rfalListenSetState(RFAL_LM_STATE_READY_A);
+                }
+            }
+        } else if(((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) && (!gRFAL.Lm.dataFlag)) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_READY_F:
+
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WU_F) != 0U) {
+            break;
+        } else if((irqs & ST25R3916_IRQ_MASK_RXE) != 0U) {
+            /* Retrieve the error flags/irqs */
+            irqs |= st25r3916GetInterrupt(
+                (ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_ERR1));
+
+            if(((irqs & ST25R3916_IRQ_MASK_CRC) != 0U) ||
+               ((irqs & ST25R3916_IRQ_MASK_ERR1) != 0U)) {
+                st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+                st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+                break; /* A bad reception occurred, remain in same state */
+            }
+
+            /* Retrieve received data */
+            *gRFAL.Lm.rxLen = st25r3916GetNumFIFOBytes();
+            st25r3916ReadFifo(
+                gRFAL.Lm.rxBuf, MIN(*gRFAL.Lm.rxLen, rfalConvBitsToBytes(gRFAL.Lm.rxBufLen)));
+
+            /* Check if the data we got has at least the CRC and remove it, otherwise leave at 0 */
+            *gRFAL.Lm.rxLen -= ((*gRFAL.Lm.rxLen > RFAL_CRC_LEN) ? RFAL_CRC_LEN : *gRFAL.Lm.rxLen);
+            *gRFAL.Lm.rxLen = (uint16_t)rfalConvBytesToBits(*gRFAL.Lm.rxLen);
+            gRFAL.Lm.dataFlag = true;
+        } else if((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_READY_A:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WU_A) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_ACTIVE_A);
+        } else if((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_ACTIVE_A:
+    case RFAL_LM_STATE_ACTIVE_Ax:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_EOF));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_RXE) != 0U) {
+            /* Retrieve the error flags/irqs */
+            irqs |= st25r3916GetInterrupt(
+                (ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 |
+                 ST25R3916_IRQ_MASK_ERR1));
+            *gRFAL.Lm.rxLen = st25r3916GetNumFIFOBytes();
+
+            if(((irqs & ST25R3916_IRQ_MASK_CRC) != 0U) ||
+               ((irqs & ST25R3916_IRQ_MASK_ERR1) != 0U) ||
+               ((irqs & ST25R3916_IRQ_MASK_PAR) != 0U) || (*gRFAL.Lm.rxLen <= RFAL_CRC_LEN)) {
+                /* Clear rx context and FIFO */
+                *gRFAL.Lm.rxLen = 0;
+                st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+                st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+                /* Check if we should go to IDLE or Sleep */
+                if(gRFAL.Lm.state == RFAL_LM_STATE_ACTIVE_Ax) {
+                    rfalListenSleepStart(
+                        RFAL_LM_STATE_SLEEP_A, gRFAL.Lm.rxBuf, gRFAL.Lm.rxBufLen, gRFAL.Lm.rxLen);
+                } else {
+                    rfalListenSetState(RFAL_LM_STATE_IDLE);
+                }
+
+                st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_RXE);
+                break;
+            }
+
+            /* Remove CRC from length */
+            *gRFAL.Lm.rxLen -= RFAL_CRC_LEN;
+
+            /* Retrieve received data */
+            st25r3916ReadFifo(
+                gRFAL.Lm.rxBuf, MIN(*gRFAL.Lm.rxLen, rfalConvBitsToBytes(gRFAL.Lm.rxBufLen)));
+            *gRFAL.Lm.rxLen = (uint16_t)rfalConvBytesToBits(*gRFAL.Lm.rxLen);
+            gRFAL.Lm.dataFlag = true;
+        } else if((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_SLEEP_A:
+    case RFAL_LM_STATE_SLEEP_B:
+    case RFAL_LM_STATE_SLEEP_AF:
+
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RXE |
+             ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_RXE_PTA));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_NFCT) != 0U) {
+            uint8_t newBr;
+            /* Retrieve detected bitrate */
+            st25r3916ReadRegister(ST25R3916_REG_NFCIP1_BIT_RATE, &newBr);
+            newBr >>= ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift;
+
+            if(newBr > ST25R3916_REG_BIT_RATE_rxrate_424) {
+                newBr = ST25R3916_REG_BIT_RATE_rxrate_424;
+            }
+
+            gRFAL.Lm.brDetected =
+                (rfalBitRate)(newBr); /* PRQA S 4342 # MISRA 10.5 - Guaranteed that no invalid enum values may be created. See also equalityGuard_RFAL_BR_106 ff.*/
+        }
+
+        if(((irqs & ST25R3916_IRQ_MASK_WU_F) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            rfalListenSetState(RFAL_LM_STATE_READY_F);
+        } else if(((irqs & ST25R3916_IRQ_MASK_RXE) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            /* Clear rx context and FIFO */
+            *gRFAL.Lm.rxLen = 0;
+            st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+            st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+            /* REMARK: In order to support CUP or proprietary frames, handling could be added here */
+        } else if(
+            ((irqs & ST25R3916_IRQ_MASK_RXE_PTA) != 0U) && (gRFAL.Lm.brDetected != RFAL_BR_KEEP)) {
+            if(((gRFAL.Lm.mdMask & RFAL_LM_MASK_NFCA) != 0U) &&
+               (gRFAL.Lm.brDetected == RFAL_BR_106)) {
+                st25r3916ReadRegister(ST25R3916_REG_PASSIVE_TARGET_STATUS, &tmp);
+                if(tmp > ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_halt) {
+                    rfalListenSetState(RFAL_LM_STATE_READY_Ax);
+                }
+            }
+        } else if((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_READY_Ax:
+
+        irqs = st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WU_A_X) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_ACTIVE_Ax);
+        } else if((irqs & ST25R3916_IRQ_MASK_EOF) != 0U) {
+            rfalListenSetState(RFAL_LM_STATE_POWER_OFF);
+        } else {
+            /* MISRA 15.7 - Empty else */
+        }
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_CARDEMU_4A:
+    case RFAL_LM_STATE_CARDEMU_4B:
+    case RFAL_LM_STATE_CARDEMU_3:
+    case RFAL_LM_STATE_TARGET_F:
+    case RFAL_LM_STATE_TARGET_A:
+        break;
+
+    /*******************************************************************************/
+    default:
+        return ERR_WRONG_STATE;
+    }
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalListenStop(void) {
+    /* Check if RFAL is initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    gRFAL.Lm.state = RFAL_LM_STATE_NOT_INIT;
+
+    /*Check if Observation Mode was enabled and disable it on ST25R391x */
+    rfalCheckDisableObsMode();
+
+    /* Re-Enable the Oscillator if not running */
+    st25r3916OscOn();
+
+    /* Disable Receiver and Transmitter */
+    rfalFieldOff();
+
+    /* Disable all automatic responses */
+    st25r3916SetRegisterBits(
+        ST25R3916_REG_PASSIVE_TARGET,
+        (ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_rfu |
+         ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p));
+
+    /* As there's no Off mode, set default value: ISO14443A with automatic RF Collision Avoidance Off */
+    st25r3916WriteRegister(
+        ST25R3916_REG_MODE,
+        (ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_tr_am_ook |
+         ST25R3916_REG_MODE_nfc_ar_off));
+
+    st25r3916DisableInterrupts(
+        (ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_WU_A |
+         ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RFU2 | ST25R3916_IRQ_MASK_OSC));
+    st25r3916GetInterrupt(
+        (ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_WU_A |
+         ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_RFU2));
+
+    /* Set Analog configurations for Listen Off event */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LISTEN_OFF));
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode
+    rfalListenSleepStart(rfalLmState sleepSt, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* rxLen) {
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    switch(sleepSt) {
+    /*******************************************************************************/
+    case RFAL_LM_STATE_SLEEP_A:
+
+        /* Enable automatic responses for A */
+        st25r3916ClrRegisterBits(
+            ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a));
+
+        /* Reset NFCA target */
+        st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP);
+
+        /* Set Target mode, Bit Rate detection and Listen Mode for NFC-A */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask |
+             ST25R3916_REG_MODE_nfc_ar_mask),
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0 |
+             ST25R3916_REG_MODE_nfc_ar_off));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_SLEEP_AF:
+
+        /* Enable automatic responses for A + F */
+        st25r3916ClrRegisterBits(
+            ST25R3916_REG_PASSIVE_TARGET,
+            (ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r | ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a));
+
+        /* Reset NFCA target state */
+        st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP);
+
+        /* Set Target mode, Bit Rate detection, Listen Mode for NFC-A and NFC-F */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_MODE,
+            (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask |
+             ST25R3916_REG_MODE_nfc_ar_mask),
+            (ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om2 |
+             ST25R3916_REG_MODE_om0 | ST25R3916_REG_MODE_nfc_ar_off));
+        break;
+
+    /*******************************************************************************/
+    case RFAL_LM_STATE_SLEEP_B:
+        /* REMARK: Support for CE-B would be added here  */
+        return ERR_NOT_IMPLEMENTED;
+
+    /*******************************************************************************/
+    default:
+        return ERR_PARAM;
+    }
+
+    /* Ensure that the  NFCIP1 mode is disabled */
+    st25r3916ClrRegisterBits(ST25R3916_REG_ISO14443A_NFC, ST25R3916_REG_ISO14443A_NFC_nfc_f0);
+
+    st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+    /* Clear and enable required IRQs */
+    st25r3916ClearAndEnableInterrupts(
+        (ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_CRC |
+         ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_PAR |
+         ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | gRFAL.Lm.mdIrqs));
+
+    /* Check whether the field was turn off right after the Sleep request */
+    if(!rfalIsExtFieldOn()) {
+        /*rfalLogD( "RFAL: curState: %02X newState: %02X \r\n", gRFAL.Lm.state, RFAL_LM_STATE_NOT_INIT );*/
+
+        rfalListenStop();
+        return ERR_LINK_LOSS;
+    }
+
+    /*rfalLogD( "RFAL: curState: %02X newState: %02X \r\n", gRFAL.Lm.state, sleepSt );*/
+
+    /* Set the new Sleep State*/
+    gRFAL.Lm.state = sleepSt;
+    gRFAL.state = RFAL_STATE_LM;
+
+    gRFAL.Lm.rxBuf = rxBuf;
+    gRFAL.Lm.rxBufLen = rxBufLen;
+    gRFAL.Lm.rxLen = rxLen;
+    *gRFAL.Lm.rxLen = 0;
+    gRFAL.Lm.dataFlag = false;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+rfalLmState rfalListenGetState(bool* dataFlag, rfalBitRate* lastBR) {
+    /* Allow state retrieval even if gRFAL.state != RFAL_STATE_LM so  *
+     * that this Lm state can be used by caller after activation      */
+
+    if(lastBR != NULL) {
+        *lastBR = gRFAL.Lm.brDetected;
+    }
+
+    if(dataFlag != NULL) {
+        *dataFlag = gRFAL.Lm.dataFlag;
+    }
+
+    return gRFAL.Lm.state;
+}
+
+/*******************************************************************************/
+ReturnCode rfalListenSetState(rfalLmState newSt) {
+    ReturnCode ret;
+    rfalLmState newState;
+    bool reSetState;
+
+    /* Check if RFAL is initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* SetState clears the Data flag */
+    gRFAL.Lm.dataFlag = false;
+    newState = newSt;
+    ret = ERR_NONE;
+
+    do {
+        reSetState = false;
+
+        /*******************************************************************************/
+        switch(newState) {
+        /*******************************************************************************/
+        case RFAL_LM_STATE_POWER_OFF:
+
+            /* Enable the receiver and reset logic */
+            st25r3916SetRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_rx_en);
+            st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+
+            if((gRFAL.Lm.mdMask & RFAL_LM_MASK_NFCA) != 0U) {
+                /* Enable automatic responses for A */
+                st25r3916ClrRegisterBits(
+                    ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a);
+
+                /* Prepares the NFCIP-1 Passive target logic to wait in the Sense/Idle state */
+                st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SENSE);
+            }
+
+            if((gRFAL.Lm.mdMask & RFAL_LM_MASK_NFCF) != 0U) {
+                /* Enable automatic responses for F */
+                st25r3916ClrRegisterBits(
+                    ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r));
+            }
+
+            if((gRFAL.Lm.mdMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U) {
+                /* Ensure automatic response RF Collision Avoidance is back to only after Rx */
+                st25r3916ChangeRegisterBits(
+                    ST25R3916_REG_MODE,
+                    ST25R3916_REG_MODE_nfc_ar_mask,
+                    ST25R3916_REG_MODE_nfc_ar_auto_rx);
+
+                /* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */
+                st25r3916TxOff();
+            }
+
+            /*******************************************************************************/
+            /* Ensure that the  NFCIP1 mode is disabled */
+            st25r3916ClrRegisterBits(
+                ST25R3916_REG_ISO14443A_NFC, ST25R3916_REG_ISO14443A_NFC_nfc_f0);
+
+            /*******************************************************************************/
+            /* Clear and enable required IRQs */
+            st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
+
+            st25r3916ClearAndEnableInterrupts(
+                (ST25R3916_IRQ_MASK_NFCT | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_CRC |
+                 ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_OSC | ST25R3916_IRQ_MASK_ERR2 |
+                 ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF |
+                 gRFAL.Lm.mdIrqs));
+
+            /*******************************************************************************/
+            /* Clear the bitRate previously detected */
+            gRFAL.Lm.brDetected = RFAL_BR_KEEP;
+
+            /*******************************************************************************/
+            /* Apply the initial mode */
+            st25r3916ChangeRegisterBits(
+                ST25R3916_REG_MODE,
+                (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask |
+                 ST25R3916_REG_MODE_nfc_ar_mask),
+                (uint8_t)gRFAL.Lm.mdReg);
+
+            /*******************************************************************************/
+            /* Check if external Field is already On */
+            if(rfalIsExtFieldOn()) {
+                reSetState = true;
+                newState = RFAL_LM_STATE_IDLE; /* Set IDLE state */
+            }
+#if 1 /* Perform bit rate detection in Low power mode */
+            else {
+                st25r3916ClrRegisterBits(
+                    ST25R3916_REG_OP_CONTROL,
+                    (ST25R3916_REG_OP_CONTROL_tx_en | ST25R3916_REG_OP_CONTROL_rx_en |
+                     ST25R3916_REG_OP_CONTROL_en));
+            }
+#endif
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_IDLE:
+
+            /*******************************************************************************/
+            /* Check if device is coming from Low Power bit rate detection */
+            if(!st25r3916CheckReg(
+                   ST25R3916_REG_OP_CONTROL,
+                   ST25R3916_REG_OP_CONTROL_en,
+                   ST25R3916_REG_OP_CONTROL_en)) {
+                /* Exit Low Power mode and confirm the temporarily enable */
+                st25r3916SetRegisterBits(
+                    ST25R3916_REG_OP_CONTROL,
+                    (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en));
+
+                if(!st25r3916CheckReg(
+                       ST25R3916_REG_AUX_DISPLAY,
+                       ST25R3916_REG_AUX_DISPLAY_osc_ok,
+                       ST25R3916_REG_AUX_DISPLAY_osc_ok)) {
+                    /* Wait for Oscillator ready */
+                    if(st25r3916WaitForInterruptsTimed(
+                           ST25R3916_IRQ_MASK_OSC, ST25R3916_TOUT_OSC_STABLE) == 0U) {
+                        ret = ERR_IO;
+                        break;
+                    }
+                }
+            } else {
+                st25r3916GetInterrupt(ST25R3916_IRQ_MASK_OSC);
+            }
+
+            /*******************************************************************************/
+            /* In Active P2P the Initiator may:  Turn its field On;  LM goes into IDLE state;
+                 *      Initiator sends an unexpected frame raising a Protocol error; Initiator 
+                 *      turns its field Off and ST25R3916 performs the automatic RF Collision 
+                 *      Avoidance keeping our field On; upon a Protocol error upper layer sets 
+                 *      again the state to IDLE to clear dataFlag and wait for next data.
+                 *      
+                 * Ensure that when upper layer calls SetState(IDLE), it restores initial 
+                 * configuration and that check whether an external Field is still present     */
+            if((gRFAL.Lm.mdMask & RFAL_LM_MASK_ACTIVE_P2P) != 0U) {
+                /* Ensure nfc_ar is reset and back to only after Rx */
+                st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+                st25r3916ChangeRegisterBits(
+                    ST25R3916_REG_MODE,
+                    ST25R3916_REG_MODE_nfc_ar_mask,
+                    ST25R3916_REG_MODE_nfc_ar_auto_rx);
+
+                /* Ensure that our field is Off, as automatic response RF Collision Avoidance may have been triggered */
+                st25r3916TxOff();
+
+                /* If external Field is no longer detected go back to POWER_OFF */
+                if(!st25r3916IsExtFieldOn()) {
+                    reSetState = true;
+                    newState = RFAL_LM_STATE_POWER_OFF; /* Set POWER_OFF state */
+                }
+            }
+            /*******************************************************************************/
+
+            /* If we are in ACTIVE_A, reEnable Listen for A before going to IDLE, otherwise do nothing */
+            if(gRFAL.Lm.state == RFAL_LM_STATE_ACTIVE_A) {
+                /* Enable automatic responses for A and Reset NFCA target state */
+                st25r3916ClrRegisterBits(
+                    ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a));
+                st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SENSE);
+            }
+
+            /* ReEnable the receiver */
+            st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+            st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+            /*******************************************************************************/
+            /*Check if Observation Mode is enabled and set it on ST25R391x */
+            rfalCheckEnableObsModeRx();
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_READY_F:
+
+            /*******************************************************************************/
+            /* If we're coming from BitRate detection mode, the Bit Rate Definition reg 
+                 * still has the last bit rate used.
+                 * If a frame is received between setting the mode to Listen NFCA and 
+                 * setting Bit Rate Definition reg, it will raise a framing error.
+                 * Set the bitrate immediately, and then the normal SetMode procedure          */
+            st25r3916SetBitrate((uint8_t)gRFAL.Lm.brDetected, (uint8_t)gRFAL.Lm.brDetected);
+            /*******************************************************************************/
+
+            /* Disable automatic responses for NFC-A */
+            st25r3916SetRegisterBits(
+                ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a));
+
+            /* Set Mode NFC-F only */
+            ret = rfalSetMode(RFAL_MODE_LISTEN_NFCF, gRFAL.Lm.brDetected, gRFAL.Lm.brDetected);
+            gRFAL.state = RFAL_STATE_LM; /* Keep in Listen Mode */
+
+            /* ReEnable the receiver */
+            st25r3916ExecuteCommand(ST25R3916_CMD_CLEAR_FIFO);
+            st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+            /* Clear any previous transmission errors (if Reader polled for other/unsupported technologies) */
+            st25r3916GetInterrupt(
+                (ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 |
+                 ST25R3916_IRQ_MASK_ERR1));
+
+            st25r3916EnableInterrupts(
+                ST25R3916_IRQ_MASK_RXE); /* Start looking for any incoming data */
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_CARDEMU_3:
+
+            /* Set Listen NFCF mode  */
+            ret = rfalSetMode(RFAL_MODE_LISTEN_NFCF, gRFAL.Lm.brDetected, gRFAL.Lm.brDetected);
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_READY_Ax:
+        case RFAL_LM_STATE_READY_A:
+
+            /*******************************************************************************/
+            /* If we're coming from BitRate detection mode, the Bit Rate Definition reg 
+                 * still has the last bit rate used.
+                 * If a frame is received between setting the mode to Listen NFCA and 
+                 * setting Bit Rate Definition reg, it will raise a framing error.
+                 * Set the bitrate immediately, and then the normal SetMode procedure          */
+            st25r3916SetBitrate((uint8_t)gRFAL.Lm.brDetected, (uint8_t)gRFAL.Lm.brDetected);
+            /*******************************************************************************/
+
+            /* Disable automatic responses for NFC-F */
+            st25r3916SetRegisterBits(
+                ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r));
+
+            /* Set Mode NFC-A only */
+            ret = rfalSetMode(RFAL_MODE_LISTEN_NFCA, gRFAL.Lm.brDetected, gRFAL.Lm.brDetected);
+
+            gRFAL.state = RFAL_STATE_LM; /* Keep in Listen Mode */
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_ACTIVE_Ax:
+        case RFAL_LM_STATE_ACTIVE_A:
+
+            /* Disable automatic responses for A */
+            st25r3916SetRegisterBits(
+                ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a));
+
+            /* Clear any previous transmission errors (if Reader polled for other/unsupported technologies) */
+            st25r3916GetInterrupt(
+                (ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR2 |
+                 ST25R3916_IRQ_MASK_ERR1));
+
+            st25r3916EnableInterrupts(
+                ST25R3916_IRQ_MASK_RXE); /* Start looking for any incoming data */
+            break;
+
+        case RFAL_LM_STATE_TARGET_F:
+            /* Disable Automatic response SENSF_REQ */
+            st25r3916SetRegisterBits(
+                ST25R3916_REG_PASSIVE_TARGET, (ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r));
+            break;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_SLEEP_A:
+        case RFAL_LM_STATE_SLEEP_B:
+        case RFAL_LM_STATE_SLEEP_AF:
+            /* These sleep states have to be set by the rfalListenSleepStart() method */
+            return ERR_REQUEST;
+
+        /*******************************************************************************/
+        case RFAL_LM_STATE_CARDEMU_4A:
+        case RFAL_LM_STATE_CARDEMU_4B:
+        case RFAL_LM_STATE_TARGET_A:
+            /* States not handled by the LM, just keep state context */
+            break;
+
+        /*******************************************************************************/
+        default:
+            return ERR_WRONG_STATE;
+        }
+    } while(reSetState);
+
+    gRFAL.Lm.state = newState;
+
+    // Call callback on state change
+    if(gRFAL.callbacks.state_changed_cb) {
+        gRFAL.callbacks.state_changed_cb(gRFAL.callbacks.ctx);
+    }
+
+    return ret;
+}
+
+#endif /* RFAL_FEATURE_LISTEN_MODE */
+
+/*******************************************************************************
+ *  Wake-Up Mode                                                               *
+ *******************************************************************************/
+
+#if RFAL_FEATURE_WAKEUP_MODE
+
+/*******************************************************************************/
+ReturnCode rfalWakeUpModeStart(const rfalWakeUpConfig* config) {
+    uint8_t aux;
+    uint8_t reg;
+    uint32_t irqs;
+
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* The Wake-Up procedure is explained in detail in Application Note: AN4985 */
+
+    if(config == NULL) {
+        gRFAL.wum.cfg.period = RFAL_WUM_PERIOD_200MS;
+        gRFAL.wum.cfg.irqTout = false;
+        gRFAL.wum.cfg.indAmp.enabled = true;
+        gRFAL.wum.cfg.indPha.enabled = false;
+        gRFAL.wum.cfg.cap.enabled = false;
+        gRFAL.wum.cfg.indAmp.delta = 2U;
+        gRFAL.wum.cfg.indAmp.reference = RFAL_WUM_REFERENCE_AUTO;
+        gRFAL.wum.cfg.indAmp.autoAvg = false;
+
+        /*******************************************************************************/
+        /* Check if AAT is enabled and if so make use of the SW Tag Detection          */
+        if(st25r3916CheckReg(
+               ST25R3916_REG_IO_CONF2,
+               ST25R3916_REG_IO_CONF2_aat_en,
+               ST25R3916_REG_IO_CONF2_aat_en)) {
+            gRFAL.wum.cfg.swTagDetect = true;
+            gRFAL.wum.cfg.indAmp.autoAvg = true;
+            gRFAL.wum.cfg.indAmp.aaWeight = RFAL_WUM_AA_WEIGHT_16;
+        }
+    } else {
+        gRFAL.wum.cfg = *config;
+    }
+
+    /* Check for valid configuration */
+    if((!gRFAL.wum.cfg.cap.enabled && !gRFAL.wum.cfg.indAmp.enabled &&
+        !gRFAL.wum.cfg.indPha.enabled) ||
+       (gRFAL.wum.cfg.cap.enabled &&
+        (gRFAL.wum.cfg.indAmp.enabled || gRFAL.wum.cfg.indPha.enabled)) ||
+       (gRFAL.wum.cfg.cap.enabled && gRFAL.wum.cfg.swTagDetect) ||
+       ((gRFAL.wum.cfg.indAmp.reference > RFAL_WUM_REFERENCE_AUTO) ||
+        (gRFAL.wum.cfg.indPha.reference > RFAL_WUM_REFERENCE_AUTO) ||
+        (gRFAL.wum.cfg.cap.reference > RFAL_WUM_REFERENCE_AUTO))) {
+        return ERR_PARAM;
+    }
+
+    irqs = ST25R3916_IRQ_MASK_NONE;
+
+    /* Disable Tx, Rx, External Field Detector and set default ISO14443A mode */
+    st25r3916TxRxOff();
+    st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en_fd_mask);
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_MODE,
+        (ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om_mask),
+        (ST25R3916_REG_MODE_targ_init | ST25R3916_REG_MODE_om_iso14443a));
+
+    /* Set Analog configurations for Wake-up On event */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON));
+
+    /*******************************************************************************/
+    /* Prepare Wake-Up Timer Control Register */
+    reg = (uint8_t)(((uint8_t)gRFAL.wum.cfg.period & 0x0FU)
+                    << ST25R3916_REG_WUP_TIMER_CONTROL_wut_shift);
+    reg |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.period < (uint8_t)RFAL_WUM_PERIOD_100MS) ?
+                         ST25R3916_REG_WUP_TIMER_CONTROL_wur :
+                         0x00U);
+
+    if(gRFAL.wum.cfg.irqTout || gRFAL.wum.cfg.swTagDetect) {
+        reg |= ST25R3916_REG_WUP_TIMER_CONTROL_wto;
+        irqs |= ST25R3916_IRQ_MASK_WT;
+    }
+
+    /* Check if HW Wake-up is to be used or SW Tag detection */
+    if(gRFAL.wum.cfg.swTagDetect) {
+        gRFAL.wum.cfg.indAmp.reference = 0U;
+        gRFAL.wum.cfg.indPha.reference = 0U;
+        gRFAL.wum.cfg.cap.reference = 0U;
+    } else {
+        /*******************************************************************************/
+        /* Check if Inductive Amplitude is to be performed */
+        if(gRFAL.wum.cfg.indAmp.enabled) {
+            aux = (uint8_t)((gRFAL.wum.cfg.indAmp.delta)
+                            << ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_shift);
+            aux |= (uint8_t)(gRFAL.wum.cfg.indAmp.aaInclMeas ?
+                                 ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aam :
+                                 0x00U);
+            aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.indAmp.aaWeight
+                              << ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_shift) &
+                             ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_mask);
+            aux |= (uint8_t)(gRFAL.wum.cfg.indAmp.autoAvg ?
+                                 ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_ae :
+                                 0x00U);
+
+            st25r3916WriteRegister(ST25R3916_REG_AMPLITUDE_MEASURE_CONF, aux);
+
+            /* Only need to set the reference if not using Auto Average */
+            if(!gRFAL.wum.cfg.indAmp.autoAvg) {
+                if(gRFAL.wum.cfg.indAmp.reference == RFAL_WUM_REFERENCE_AUTO) {
+                    st25r3916MeasureAmplitude(&aux);
+                    gRFAL.wum.cfg.indAmp.reference = aux;
+                }
+                st25r3916WriteRegister(
+                    ST25R3916_REG_AMPLITUDE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.indAmp.reference);
+            }
+
+            reg |= ST25R3916_REG_WUP_TIMER_CONTROL_wam;
+            irqs |= ST25R3916_IRQ_MASK_WAM;
+        }
+
+        /*******************************************************************************/
+        /* Check if Inductive Phase is to be performed */
+        if(gRFAL.wum.cfg.indPha.enabled) {
+            aux = (uint8_t)((gRFAL.wum.cfg.indPha.delta)
+                            << ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_shift);
+            aux |= (uint8_t)(gRFAL.wum.cfg.indPha.aaInclMeas ?
+                                 ST25R3916_REG_PHASE_MEASURE_CONF_pm_aam :
+                                 0x00U);
+            aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.indPha.aaWeight
+                              << ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_shift) &
+                             ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_mask);
+            aux |= (uint8_t)(gRFAL.wum.cfg.indPha.autoAvg ?
+                                 ST25R3916_REG_PHASE_MEASURE_CONF_pm_ae :
+                                 0x00U);
+
+            st25r3916WriteRegister(ST25R3916_REG_PHASE_MEASURE_CONF, aux);
+
+            /* Only need to set the reference if not using Auto Average */
+            if(!gRFAL.wum.cfg.indPha.autoAvg) {
+                if(gRFAL.wum.cfg.indPha.reference == RFAL_WUM_REFERENCE_AUTO) {
+                    st25r3916MeasurePhase(&aux);
+                    gRFAL.wum.cfg.indPha.reference = aux;
+                }
+                st25r3916WriteRegister(
+                    ST25R3916_REG_PHASE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.indPha.reference);
+            }
+
+            reg |= ST25R3916_REG_WUP_TIMER_CONTROL_wph;
+            irqs |= ST25R3916_IRQ_MASK_WPH;
+        }
+
+        /*******************************************************************************/
+        /* Check if Capacitive is to be performed */
+        if(gRFAL.wum.cfg.cap.enabled) {
+            /*******************************************************************************/
+            /* Perform Capacitive sensor calibration */
+
+            /* Disable Oscillator and Field */
+            st25r3916ClrRegisterBits(
+                ST25R3916_REG_OP_CONTROL,
+                (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_tx_en));
+
+            /* Sensor gain should be configured on Analog Config: RFAL_ANALOG_CONFIG_CHIP_WAKEUP_ON */
+
+            /* Perform calibration procedure */
+            st25r3916CalibrateCapacitiveSensor(NULL);
+
+            /*******************************************************************************/
+            aux = (uint8_t)((gRFAL.wum.cfg.cap.delta)
+                            << ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_shift);
+            aux |= (uint8_t)(gRFAL.wum.cfg.cap.aaInclMeas ?
+                                 ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aam :
+                                 0x00U);
+            aux |= (uint8_t)(((uint8_t)gRFAL.wum.cfg.cap.aaWeight
+                              << ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_shift) &
+                             ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_mask);
+            aux |= (uint8_t)(gRFAL.wum.cfg.cap.autoAvg ?
+                                 ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_ae :
+                                 0x00U);
+
+            st25r3916WriteRegister(ST25R3916_REG_CAPACITANCE_MEASURE_CONF, aux);
+
+            /* Only need to set the reference if not using Auto Average */
+            if(!gRFAL.wum.cfg.cap.autoAvg || gRFAL.wum.cfg.swTagDetect) {
+                if(gRFAL.wum.cfg.indPha.reference == RFAL_WUM_REFERENCE_AUTO) {
+                    st25r3916MeasureCapacitance(&aux);
+                    gRFAL.wum.cfg.cap.reference = aux;
+                }
+                st25r3916WriteRegister(
+                    ST25R3916_REG_CAPACITANCE_MEASURE_REF, (uint8_t)gRFAL.wum.cfg.cap.reference);
+            }
+
+            reg |= ST25R3916_REG_WUP_TIMER_CONTROL_wcap;
+            irqs |= ST25R3916_IRQ_MASK_WCAP;
+        }
+    }
+
+    /* Disable and clear all interrupts except Wake-Up IRQs */
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
+    st25r3916GetInterrupt(irqs);
+    st25r3916EnableInterrupts(irqs);
+
+    /* Enable Low Power Wake-Up Mode (Disable: Oscilattor, Tx, Rx and External Field Detector) */
+    st25r3916WriteRegister(ST25R3916_REG_WUP_TIMER_CONTROL, reg);
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_OP_CONTROL,
+        (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
+         ST25R3916_REG_OP_CONTROL_tx_en | ST25R3916_REG_OP_CONTROL_en_fd_mask |
+         ST25R3916_REG_OP_CONTROL_wu),
+        ST25R3916_REG_OP_CONTROL_wu);
+
+    gRFAL.wum.state = RFAL_WUM_STATE_ENABLED;
+    gRFAL.state = RFAL_STATE_WUM;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+bool rfalWakeUpModeHasWoke(void) {
+    return (gRFAL.wum.state >= RFAL_WUM_STATE_ENABLED_WOKE);
+}
+
+/*******************************************************************************/
+static uint16_t rfalWakeUpModeFilter(uint16_t curRef, uint16_t curVal, uint8_t weight) {
+    uint16_t newRef;
+
+    /* Perform the averaging|filter as describded in ST25R3916 DS */
+
+    /* Avoid signed arithmetics by splitting in two cases */
+    if(curVal > curRef) {
+        newRef = curRef + ((curVal - curRef) / weight);
+
+        /* In order for the reference to converge to final value   *
+         * increment once the diff is smaller that the weight      */
+        if((curVal != curRef) && (curRef == newRef)) {
+            newRef &= 0xFF00U;
+            newRef += 0x0100U;
+        }
+    } else {
+        newRef = curRef - ((curRef - curVal) / weight);
+
+        /* In order for the reference to converge to final value   *
+         * decrement once the diff is smaller that the weight      */
+        if((curVal != curRef) && (curRef == newRef)) {
+            newRef &= 0xFF00U;
+        }
+    }
+
+    return newRef;
+}
+
+/*******************************************************************************/
+static void rfalRunWakeUpModeWorker(void) {
+    uint32_t irqs;
+    uint8_t reg;
+    uint16_t value;
+    uint16_t delta;
+
+    if(gRFAL.state != RFAL_STATE_WUM) {
+        return;
+    }
+
+    switch(gRFAL.wum.state) {
+    case RFAL_WUM_STATE_ENABLED:
+    case RFAL_WUM_STATE_ENABLED_WOKE:
+
+        irqs = st25r3916GetInterrupt(
+            (ST25R3916_IRQ_MASK_WT | ST25R3916_IRQ_MASK_WAM | ST25R3916_IRQ_MASK_WPH |
+             ST25R3916_IRQ_MASK_WCAP));
+        if(irqs == ST25R3916_IRQ_MASK_NONE) {
+            break; /* No interrupt to process */
+        }
+
+        /*******************************************************************************/
+        /* Check and mark which measurement(s) cause interrupt */
+        if((irqs & ST25R3916_IRQ_MASK_WAM) != 0U) {
+            st25r3916ReadRegister(ST25R3916_REG_AMPLITUDE_MEASURE_RESULT, &reg);
+            gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WPH) != 0U) {
+            st25r3916ReadRegister(ST25R3916_REG_PHASE_MEASURE_RESULT, &reg);
+            gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WCAP) != 0U) {
+            st25r3916ReadRegister(ST25R3916_REG_CAPACITANCE_MEASURE_RESULT, &reg);
+            gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
+        }
+
+        if((irqs & ST25R3916_IRQ_MASK_WT) != 0U) {
+            /*******************************************************************************/
+            if(gRFAL.wum.cfg.swTagDetect) {
+                /* Enable Ready mode and wait the settle time */
+                st25r3916ChangeRegisterBits(
+                    ST25R3916_REG_OP_CONTROL,
+                    (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_wu),
+                    ST25R3916_REG_OP_CONTROL_en);
+                platformDelay(RFAL_ST25R3916_AAT_SETTLE);
+
+                /*******************************************************************************/
+                if(gRFAL.wum.cfg.indAmp.enabled) {
+                    /* Perform amplitude measurement */
+                    st25r3916MeasureAmplitude(&reg);
+
+                    /* Convert inputs to TD format */
+                    value = rfalConvTDFormat(reg);
+                    delta = rfalConvTDFormat(gRFAL.wum.cfg.indAmp.delta);
+
+                    /* Set first measurement as reference */
+                    if(gRFAL.wum.cfg.indAmp.reference == 0U) {
+                        gRFAL.wum.cfg.indAmp.reference = value;
+                    }
+
+                    /* Check if device should be woken */
+                    if((value >= (gRFAL.wum.cfg.indAmp.reference + delta)) ||
+                       (value <= (gRFAL.wum.cfg.indAmp.reference - delta))) {
+                        gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
+                        break;
+                    }
+
+                    /* Update moving reference if enabled */
+                    if(gRFAL.wum.cfg.indAmp.autoAvg) {
+                        gRFAL.wum.cfg.indAmp.reference = rfalWakeUpModeFilter(
+                            gRFAL.wum.cfg.indAmp.reference,
+                            value,
+                            (RFAL_WU_MIN_WEIGHT_VAL << (uint8_t)gRFAL.wum.cfg.indAmp.aaWeight));
+                    }
+                }
+
+                /*******************************************************************************/
+                if(gRFAL.wum.cfg.indPha.enabled) {
+                    /* Perform Phase measurement */
+                    st25r3916MeasurePhase(&reg);
+
+                    /* Convert inputs to TD format */
+                    value = rfalConvTDFormat(reg);
+                    delta = rfalConvTDFormat(gRFAL.wum.cfg.indPha.delta);
+
+                    /* Set first measurement as reference */
+                    if(gRFAL.wum.cfg.indPha.reference == 0U) {
+                        gRFAL.wum.cfg.indPha.reference = value;
+                    }
+
+                    /* Check if device should be woken */
+                    if((value >= (gRFAL.wum.cfg.indPha.reference + delta)) ||
+                       (value <= (gRFAL.wum.cfg.indPha.reference - delta))) {
+                        gRFAL.wum.state = RFAL_WUM_STATE_ENABLED_WOKE;
+                        break;
+                    }
+
+                    /* Update moving reference if enabled */
+                    if(gRFAL.wum.cfg.indPha.autoAvg) {
+                        gRFAL.wum.cfg.indPha.reference = rfalWakeUpModeFilter(
+                            gRFAL.wum.cfg.indPha.reference,
+                            value,
+                            (RFAL_WU_MIN_WEIGHT_VAL << (uint8_t)gRFAL.wum.cfg.indPha.aaWeight));
+                    }
+                }
+
+                /* Re-Enable low power Wake-Up mode for wto to trigger another measurement(s) */
+                st25r3916ChangeRegisterBits(
+                    ST25R3916_REG_OP_CONTROL,
+                    (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_wu),
+                    (ST25R3916_REG_OP_CONTROL_wu));
+            }
+        }
+        break;
+
+    default:
+        /* MISRA 16.4: no empty default statement (a comment being enough) */
+        break;
+    }
+}
+
+/*******************************************************************************/
+ReturnCode rfalWakeUpModeStop(void) {
+    /* Check if RFAL is in Wake-up mode */
+    if(gRFAL.state != RFAL_STATE_WUM) {
+        return ERR_WRONG_STATE;
+    }
+
+    gRFAL.wum.state = RFAL_WUM_STATE_NOT_INIT;
+
+    /* Disable Wake-Up Mode */
+    st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
+    st25r3916DisableInterrupts(
+        (ST25R3916_IRQ_MASK_WT | ST25R3916_IRQ_MASK_WAM | ST25R3916_IRQ_MASK_WPH |
+         ST25R3916_IRQ_MASK_WCAP));
+
+    /* Re-Enable External Field Detector as: Automatics */
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_OP_CONTROL,
+        ST25R3916_REG_OP_CONTROL_en_fd_mask,
+        ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
+
+    /* Re-Enable the Oscillator */
+    st25r3916OscOn();
+
+    /* Set Analog configurations for Wake-up Off event */
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_WAKEUP_OFF));
+
+    return ERR_NONE;
+}
+
+#endif /* RFAL_FEATURE_WAKEUP_MODE */
+
+/*******************************************************************************
+ *  Low-Power Mode                                                               *
+ *******************************************************************************/
+
+#if RFAL_FEATURE_LOWPOWER_MODE
+
+/*******************************************************************************/
+ReturnCode rfalLowPowerModeStart(void) {
+    /* Check if RFAL is not initialized */
+    if(gRFAL.state < RFAL_STATE_INIT) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Stop any ongoing activity and set the device in low power by disabling oscillator, transmitter, receiver and external field detector */
+    st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+    st25r3916ClrRegisterBits(
+        ST25R3916_REG_OP_CONTROL,
+        (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
+         ST25R3916_REG_OP_CONTROL_wu | ST25R3916_REG_OP_CONTROL_tx_en |
+         ST25R3916_REG_OP_CONTROL_en_fd_mask));
+
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_ON));
+
+    gRFAL.state = RFAL_STATE_IDLE;
+    gRFAL.lpm.isRunning = true;
+
+    platformDisableIrqCallback();
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalLowPowerModeStop(void) {
+    ReturnCode ret;
+
+    platformEnableIrqCallback();
+
+    /* Check if RFAL is on right state */
+    if(!gRFAL.lpm.isRunning) {
+        return ERR_WRONG_STATE;
+    }
+
+    /* Re-enable device */
+    EXIT_ON_ERR(ret, st25r3916OscOn());
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_OP_CONTROL,
+        ST25R3916_REG_OP_CONTROL_en_fd_mask,
+        ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
+
+    rfalSetAnalogConfig((RFAL_ANALOG_CONFIG_TECH_CHIP | RFAL_ANALOG_CONFIG_CHIP_LOWPOWER_OFF));
+
+    gRFAL.state = RFAL_STATE_INIT;
+    return ERR_NONE;
+}
+
+#endif /* RFAL_FEATURE_LOWPOWER_MODE */
+
+/*******************************************************************************
+ *  RF Chip                                                                    *  
+ *******************************************************************************/
+
+/*******************************************************************************/
+ReturnCode rfalChipWriteReg(uint16_t reg, const uint8_t* values, uint8_t len) {
+    if(!st25r3916IsRegValid((uint8_t)reg)) {
+        return ERR_PARAM;
+    }
+
+    return st25r3916WriteMultipleRegisters((uint8_t)reg, values, len);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipReadReg(uint16_t reg, uint8_t* values, uint8_t len) {
+    if(!st25r3916IsRegValid((uint8_t)reg)) {
+        return ERR_PARAM;
+    }
+
+    return st25r3916ReadMultipleRegisters((uint8_t)reg, values, len);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipExecCmd(uint16_t cmd) {
+    if(!st25r3916IsCmdValid((uint8_t)cmd)) {
+        return ERR_PARAM;
+    }
+
+    return st25r3916ExecuteCommand((uint8_t)cmd);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipWriteTestReg(uint16_t reg, uint8_t value) {
+    return st25r3916WriteTestRegister((uint8_t)reg, value);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipReadTestReg(uint16_t reg, uint8_t* value) {
+    return st25r3916ReadTestRegister((uint8_t)reg, value);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipChangeRegBits(uint16_t reg, uint8_t valueMask, uint8_t value) {
+    if(!st25r3916IsRegValid((uint8_t)reg)) {
+        return ERR_PARAM;
+    }
+
+    return st25r3916ChangeRegisterBits((uint8_t)reg, valueMask, value);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipChangeTestRegBits(uint16_t reg, uint8_t valueMask, uint8_t value) {
+    st25r3916ChangeTestRegisterBits((uint8_t)reg, valueMask, value);
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipSetRFO(uint8_t rfo) {
+    return st25r3916ChangeRegisterBits(
+        ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_d_res_mask, rfo);
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipGetRFO(uint8_t* result) {
+    ReturnCode ret;
+
+    ret = st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER, result);
+
+    (*result) = ((*result) & ST25R3916_REG_TX_DRIVER_d_res_mask);
+
+    return ret;
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipMeasureAmplitude(uint8_t* result) {
+    ReturnCode err;
+    uint8_t reg_opc, reg_mode, reg_conf1, reg_conf2;
+
+    /* Save registers which will be adjusted below */
+    st25r3916ReadRegister(ST25R3916_REG_OP_CONTROL, &reg_opc);
+    st25r3916ReadRegister(ST25R3916_REG_MODE, &reg_mode);
+    st25r3916ReadRegister(ST25R3916_REG_RX_CONF1, &reg_conf1);
+    st25r3916ReadRegister(ST25R3916_REG_RX_CONF2, &reg_conf2);
+
+    /* Set values as per defaults of DS. These regs/bits influence receiver chain and change amplitude */
+    /* Doing so achieves an amplitude comparable over a complete polling cylce */
+    st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, (reg_opc & ~ST25R3916_REG_OP_CONTROL_rx_chn));
+    st25r3916WriteRegister(
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_targ_init |
+            ST25R3916_REG_MODE_tr_am_ook | ST25R3916_REG_MODE_nfc_ar_off);
+    st25r3916WriteRegister(
+        ST25R3916_REG_RX_CONF1, (reg_conf1 & ~ST25R3916_REG_RX_CONF1_ch_sel_AM));
+    st25r3916WriteRegister(
+        ST25R3916_REG_RX_CONF2,
+        ((reg_conf2 & ~(ST25R3916_REG_RX_CONF2_demod_mode | ST25R3916_REG_RX_CONF2_amd_sel)) |
+         ST25R3916_REG_RX_CONF2_amd_sel_peak));
+
+    /* Perform the actual measurement */
+    err = st25r3916MeasureAmplitude(result);
+
+    /* Restore values */
+    st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, reg_opc);
+    st25r3916WriteRegister(ST25R3916_REG_MODE, reg_mode);
+    st25r3916WriteRegister(ST25R3916_REG_RX_CONF1, reg_conf1);
+    st25r3916WriteRegister(ST25R3916_REG_RX_CONF2, reg_conf2);
+
+    return err;
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipMeasurePhase(uint8_t* result) {
+    st25r3916MeasurePhase(result);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipMeasureCapacitance(uint8_t* result) {
+    st25r3916MeasureCapacitance(result);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode rfalChipMeasurePowerSupply(uint8_t param, uint8_t* result) {
+    *result = st25r3916MeasurePowerSupply(param);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+extern uint8_t invalid_size_of_stream_configs
+    [(sizeof(struct st25r3916StreamConfig) == sizeof(struct iso15693StreamConfig)) ? 1 : (-1)];

+ 801 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916.c

@@ -0,0 +1,801 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 high level interface
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "st25r3916.h"
+#include "st25r3916_com.h"
+#include "st25r3916_led.h"
+#include "st25r3916_irq.h"
+#include "../../utils.h"
+
+/*
+******************************************************************************
+* LOCAL DEFINES
+******************************************************************************
+*/
+
+#define ST25R3916_SUPPLY_THRESHOLD \
+    3600U /*!< Power supply measure threshold between 3.3V or 5V                   */
+#define ST25R3916_NRT_MAX \
+    0xFFFFU /*!< Max Register value of NRT                                           */
+
+#define ST25R3916_TOUT_MEASURE_VDD \
+    100U /*!< Max duration time of Measure Power Supply command  Datasheet: 25us  */
+#define ST25R3916_TOUT_MEASURE_AMPLITUDE \
+    10U /*!< Max duration time of Measure Amplitude command     Datasheet: 25us  */
+#define ST25R3916_TOUT_MEASURE_PHASE \
+    10U /*!< Max duration time of Measure Phase command         Datasheet: 25us  */
+#define ST25R3916_TOUT_MEASURE_CAPACITANCE \
+    10U /*!< Max duration time of Measure Capacitance command   Datasheet: 25us  */
+#define ST25R3916_TOUT_CALIBRATE_CAP_SENSOR \
+    4U /*!< Max duration Calibrate Capacitive Sensor command   Datasheet: 3ms   */
+#define ST25R3916_TOUT_ADJUST_REGULATORS \
+    6U /*!< Max duration time of Adjust Regulators command     Datasheet: 5ms   */
+#define ST25R3916_TOUT_CA \
+    10U /*!< Max duration time of Collision Avoidance command                    */
+
+#define ST25R3916_TEST_REG_PATTERN \
+    0x33U /*!< Register Read Write test pattern used during selftest               */
+#define ST25R3916_TEST_WU_TOUT \
+    12U /*!< Timeout used on WU timer during self test                           */
+#define ST25R3916_TEST_TMR_TOUT \
+    20U /*!< Timeout used during self test                                       */
+#define ST25R3916_TEST_TMR_TOUT_DELTA \
+    2U /*!< Timeout used during self test                                       */
+#define ST25R3916_TEST_TMR_TOUT_8FC \
+    (ST25R3916_TEST_TMR_TOUT * 16950U) /*!< Timeout in 8/fc                          */
+
+/*
+******************************************************************************
+* LOCAL CONSTANTS
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+static uint32_t gST25R3916NRT_64fcs;
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION
+ ******************************************************************************
+ */
+
+ReturnCode st25r3916ExecuteCommandAndGetResult(
+    uint8_t cmd,
+    uint8_t resReg,
+    uint8_t tout,
+    uint8_t* result) {
+    /* Clear and enable Direct Command interrupt */
+    st25r3916GetInterrupt(ST25R3916_IRQ_MASK_DCT);
+    st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_DCT);
+
+    st25r3916ExecuteCommand(cmd);
+
+    st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_DCT, tout);
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_DCT);
+
+    /* After execution read out the result if the pointer is not NULL */
+    if(result != NULL) {
+        st25r3916ReadRegister(resReg, result);
+    }
+
+    return ERR_NONE;
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+ReturnCode st25r3916Initialize(void) {
+    uint16_t vdd_mV;
+    ReturnCode ret;
+
+    /* Set default state on the ST25R3916 */
+    st25r3916ExecuteCommand(ST25R3916_CMD_SET_DEFAULT);
+
+#ifndef RFAL_USE_I2C
+    /* Increase MISO driving level as SPI can go up to 10MHz */
+    st25r3916WriteRegister(ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_io_drv_lvl);
+#endif /* RFAL_USE_I2C */
+
+    if(!st25r3916CheckChipID(NULL)) {
+        platformErrorHandle();
+        return ERR_HW_MISMATCH;
+    }
+
+    st25r3916InitInterrupts();
+    st25r3916ledInit();
+
+    gST25R3916NRT_64fcs = 0;
+
+#ifndef RFAL_USE_I2C
+    /* Enable pull downs on MISO line */
+    st25r3916SetRegisterBits(
+        ST25R3916_REG_IO_CONF2,
+        (ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2));
+#endif /* RFAL_USE_I2C */
+
+    /* Disable internal overheat protection */
+    st25r3916ChangeTestRegisterBits(0x04, 0x10, 0x10);
+
+#ifdef ST25R_SELFTEST
+    /******************************************************************************
+     * Check communication interface: 
+     *  - write a pattern in a register
+     *  - reads back the register value
+     *  - return ERR_IO in case the read value is different
+     */
+    st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, ST25R3916_TEST_REG_PATTERN);
+    if(!st25r3916CheckReg(
+           ST25R3916_REG_BIT_RATE,
+           (ST25R3916_REG_BIT_RATE_rxrate_mask | ST25R3916_REG_BIT_RATE_txrate_mask),
+           ST25R3916_TEST_REG_PATTERN)) {
+        platformErrorHandle();
+        return ERR_IO;
+    }
+
+    /* Restore default value */
+    st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, 0x00);
+
+    /*
+     * Check IRQ Handling:
+     *  - use the Wake-up timer to trigger an IRQ
+     *  - wait the Wake-up timer interrupt
+     *  - return ERR_TIMEOUT when the Wake-up timer interrupt is not received
+     */
+    st25r3916WriteRegister(
+        ST25R3916_REG_WUP_TIMER_CONTROL,
+        ST25R3916_REG_WUP_TIMER_CONTROL_wur | ST25R3916_REG_WUP_TIMER_CONTROL_wto);
+    st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_WT);
+    st25r3916ExecuteCommand(ST25R3916_CMD_START_WUP_TIMER);
+    if(st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_WT, ST25R3916_TEST_WU_TOUT) == 0U) {
+        platformErrorHandle();
+        return ERR_TIMEOUT;
+    }
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_WT);
+    st25r3916WriteRegister(ST25R3916_REG_WUP_TIMER_CONTROL, 0U);
+    /*******************************************************************************/
+#endif /* ST25R_SELFTEST */
+
+    /* Enable Oscillator and wait until it gets stable */
+    ret = st25r3916OscOn();
+    if(ret != ERR_NONE) {
+        platformErrorHandle();
+        return ret;
+    }
+
+    /* Measure VDD and set sup3V bit according to Power supplied  */
+    vdd_mV = st25r3916MeasureVoltage(ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd);
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_IO_CONF2,
+        ST25R3916_REG_IO_CONF2_sup3V,
+        ((vdd_mV < ST25R3916_SUPPLY_THRESHOLD) ? ST25R3916_REG_IO_CONF2_sup3V_3V :
+                                                 ST25R3916_REG_IO_CONF2_sup3V_5V));
+
+    /* Make sure Transmitter and Receiver are disabled */
+    st25r3916TxRxOff();
+
+#ifdef ST25R_SELFTEST_TIMER
+    /******************************************************************************
+     * Check SW timer operation :
+     *  - use the General Purpose timer to measure an amount of time
+     *  - test whether an interrupt is seen when less time was given
+     *  - test whether an interrupt is seen when sufficient time was given
+     */
+
+    st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_GPE);
+    st25r3916SetStartGPTimer(
+        (uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
+    if(st25r3916WaitForInterruptsTimed(
+           ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT - ST25R3916_TEST_TMR_TOUT_DELTA)) !=
+       0U) {
+        platformErrorHandle();
+        return ERR_SYSTEM;
+    }
+
+    /* Stop all activities to stop the GP timer */
+    st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+    st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_GPE);
+    st25r3916SetStartGPTimer(
+        (uint16_t)ST25R3916_TEST_TMR_TOUT_8FC, ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger);
+    if(st25r3916WaitForInterruptsTimed(
+           ST25R3916_IRQ_MASK_GPE, (ST25R3916_TEST_TMR_TOUT + ST25R3916_TEST_TMR_TOUT_DELTA)) ==
+       0U) {
+        platformErrorHandle();
+        return ERR_SYSTEM;
+    }
+
+    /* Stop all activities to stop the GP timer */
+    st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+    /*******************************************************************************/
+#endif /* ST25R_SELFTEST_TIMER */
+
+    /* After reset all interrupts are enabled, so disable them at first */
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
+
+    /* And clear them, just to be sure */
+    st25r3916ClearInterrupts();
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+void st25r3916Deinitialize(void) {
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
+
+    /* Disable Tx and Rx, Keep OSC On */
+    st25r3916TxRxOff();
+
+    return;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916OscOn(void) {
+    /* Check if oscillator is already turned on and stable                                                */
+    /* Use ST25R3916_REG_OP_CONTROL_en instead of ST25R3916_REG_AUX_DISPLAY_osc_ok to be on the safe side */
+    if(!st25r3916CheckReg(
+           ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en, ST25R3916_REG_OP_CONTROL_en)) {
+        /* Clear any eventual previous oscillator IRQ */
+        st25r3916GetInterrupt(ST25R3916_IRQ_MASK_OSC);
+
+        /* Enable oscillator frequency stable interrupt */
+        st25r3916EnableInterrupts(ST25R3916_IRQ_MASK_OSC);
+
+        /* Enable oscillator and regulator output */
+        st25r3916SetRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en);
+
+        /* Wait for the oscillator interrupt */
+        st25r3916WaitForInterruptsTimed(ST25R3916_IRQ_MASK_OSC, ST25R3916_TOUT_OSC_STABLE);
+        st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_OSC);
+    }
+
+    if(!st25r3916CheckReg(
+           ST25R3916_REG_AUX_DISPLAY,
+           ST25R3916_REG_AUX_DISPLAY_osc_ok,
+           ST25R3916_REG_AUX_DISPLAY_osc_ok)) {
+        return ERR_SYSTEM;
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+uint8_t st25r3916MeasurePowerSupply(uint8_t mpsv) {
+    uint8_t result;
+
+    /* Set the source of direct command: Measure Power Supply Voltage */
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask, mpsv);
+
+    /* Execute command: Measure Power Supply Voltage */
+    st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_MEASURE_VDD, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_VDD, &result);
+
+    return result;
+}
+
+/*******************************************************************************/
+uint16_t st25r3916MeasureVoltage(uint8_t mpsv) {
+    uint8_t result;
+    uint16_t mV;
+
+    result = st25r3916MeasurePowerSupply(mpsv);
+
+    /* Convert cmd output into mV (each step represents 23.4 mV )*/
+    mV = ((uint16_t)result) * 23U;
+    mV += (((((uint16_t)result) * 4U) + 5U) / 10U);
+
+    return mV;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916AdjustRegulators(uint16_t* result_mV) {
+    uint8_t result;
+
+    /* Reset logic and set regulated voltages to be defined by result of Adjust Regulators command */
+    st25r3916SetRegisterBits(
+        ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
+    st25r3916ClrRegisterBits(
+        ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
+
+    /* Execute Adjust regulators cmd and retrieve result */
+    st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_ADJUST_REGULATORS,
+        ST25R3916_REG_REGULATOR_RESULT,
+        ST25R3916_TOUT_ADJUST_REGULATORS,
+        &result);
+
+    /* Calculate result in mV */
+    result >>= ST25R3916_REG_REGULATOR_RESULT_reg_shift;
+
+    if(result_mV != NULL) {
+        if(st25r3916CheckReg(
+               ST25R3916_REG_IO_CONF2,
+               ST25R3916_REG_IO_CONF2_sup3V,
+               ST25R3916_REG_IO_CONF2_sup3V)) {
+            result =
+                MIN(result,
+                    (uint8_t)(result -
+                              5U)); /* In 3.3V mode [0,4] are not used                       */
+            *result_mV = 2400U; /* Minimum regulated voltage 2.4V in case of 3.3V supply */
+        } else {
+            *result_mV = 3600U; /* Minimum regulated voltage 3.6V in case of 5V supply   */
+        }
+
+        *result_mV +=
+            (uint16_t)result * 100U; /* 100mV steps in both 3.3V and 5V supply                */
+    }
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916MeasureAmplitude(uint8_t* result) {
+    return st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_MEASURE_AMPLITUDE,
+        ST25R3916_REG_AD_RESULT,
+        ST25R3916_TOUT_MEASURE_AMPLITUDE,
+        result);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916MeasurePhase(uint8_t* result) {
+    return st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_MEASURE_PHASE, ST25R3916_REG_AD_RESULT, ST25R3916_TOUT_MEASURE_PHASE, result);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916MeasureCapacitance(uint8_t* result) {
+    return st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_MEASURE_CAPACITANCE,
+        ST25R3916_REG_AD_RESULT,
+        ST25R3916_TOUT_MEASURE_CAPACITANCE,
+        result);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916CalibrateCapacitiveSensor(uint8_t* result) {
+    ReturnCode ret;
+    uint8_t res;
+
+    /* Clear Manual calibration values to enable automatic calibration mode */
+    st25r3916ClrRegisterBits(
+        ST25R3916_REG_CAP_SENSOR_CONTROL, ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_mask);
+
+    /* Execute automatic calibration */
+    ret = st25r3916ExecuteCommandAndGetResult(
+        ST25R3916_CMD_CALIBRATE_C_SENSOR,
+        ST25R3916_REG_CAP_SENSOR_RESULT,
+        ST25R3916_TOUT_CALIBRATE_CAP_SENSOR,
+        &res);
+
+    /* Check whether the calibration was successull */
+    if(((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) !=
+        ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end) ||
+       ((res & ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ==
+        ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err) ||
+       (ret != ERR_NONE)) {
+        return ERR_IO;
+    }
+
+    if(result != NULL) {
+        (*result) = (uint8_t)(res >> ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_shift);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916SetBitrate(uint8_t txrate, uint8_t rxrate) {
+    uint8_t reg;
+
+    st25r3916ReadRegister(ST25R3916_REG_BIT_RATE, &reg);
+    if(rxrate != ST25R3916_BR_DO_NOT_SET) {
+        if(rxrate > ST25R3916_BR_848) {
+            return ERR_PARAM;
+        }
+
+        reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_rxrate_mask); /* MISRA 10.3 */
+        reg |= rxrate << ST25R3916_REG_BIT_RATE_rxrate_shift;
+    }
+    if(txrate != ST25R3916_BR_DO_NOT_SET) {
+        if(txrate > ST25R3916_BR_6780) {
+            return ERR_PARAM;
+        }
+
+        reg = (uint8_t)(reg & ~ST25R3916_REG_BIT_RATE_txrate_mask); /* MISRA 10.3 */
+        reg |= txrate << ST25R3916_REG_BIT_RATE_txrate_shift;
+    }
+    return st25r3916WriteRegister(ST25R3916_REG_BIT_RATE, reg);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916PerformCollisionAvoidance(
+    uint8_t FieldONCmd,
+    uint8_t pdThreshold,
+    uint8_t caThreshold,
+    uint8_t nTRFW) {
+    uint8_t treMask;
+    uint32_t irqs;
+    ReturnCode err;
+
+    if((FieldONCmd != ST25R3916_CMD_INITIAL_RF_COLLISION) &&
+       (FieldONCmd != ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
+        return ERR_PARAM;
+    }
+
+    err = ERR_INTERNAL;
+
+    /* Check if new thresholds are to be applied */
+    if((pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) ||
+       (caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET)) {
+        treMask = 0;
+
+        if(pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
+            treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask;
+        }
+
+        if(caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
+            treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask;
+        }
+
+        /* Set Detection Threshold and|or Collision Avoidance Threshold */
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_FIELD_THRESHOLD_ACTV,
+            treMask,
+            (pdThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask) |
+                (caThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask));
+    }
+
+    /* Set n x TRFW */
+    st25r3916ChangeRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, nTRFW);
+
+    /*******************************************************************************/
+    /* Enable and clear CA specific interrupts and execute command */
+    st25r3916GetInterrupt(
+        (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
+    st25r3916EnableInterrupts(
+        (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
+
+    st25r3916ExecuteCommand(FieldONCmd);
+
+    /*******************************************************************************/
+    /* Wait for initial APON interrupt, indicating anticollision avoidance done and ST25R3916's 
+     * field is now on, or a CAC indicating a collision */
+    irqs = st25r3916WaitForInterruptsTimed(
+        (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_APON), ST25R3916_TOUT_CA);
+
+    if((ST25R3916_IRQ_MASK_CAC & irqs) != 0U) /* Collision occurred */
+    {
+        err = ERR_RF_COLLISION;
+    } else if((ST25R3916_IRQ_MASK_APON & irqs) != 0U) {
+        /* After APON wait for CAT interrupt, indication field was switched on minimum guard time has been fulfilled */
+        irqs = st25r3916WaitForInterruptsTimed((ST25R3916_IRQ_MASK_CAT), ST25R3916_TOUT_CA);
+
+        if((ST25R3916_IRQ_MASK_CAT & irqs) != 0U) /* No Collision detected, Field On */
+        {
+            err = ERR_NONE;
+        }
+    } else {
+        /* MISRA 15.7 - Empty else */
+    }
+
+    /* Clear any previous External Field events and disable CA specific interrupts */
+    st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON));
+    st25r3916DisableInterrupts(
+        (ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
+
+    return err;
+}
+
+/*******************************************************************************/
+void st25r3916SetNumTxBits(uint16_t nBits) {
+    st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)((nBits >> 0) & 0xFFU));
+    st25r3916WriteRegister(ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((nBits >> 8) & 0xFFU));
+}
+
+/*******************************************************************************/
+uint16_t st25r3916GetNumFIFOBytes(void) {
+    uint8_t reg;
+    uint16_t result;
+
+    st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, &reg);
+    reg =
+        ((reg & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
+         ST25R3916_REG_FIFO_STATUS2_fifo_b_shift);
+    result = ((uint16_t)reg << 8);
+
+    st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS1, &reg);
+    result |= (((uint16_t)reg) & 0x00FFU);
+
+    return result;
+}
+
+/*******************************************************************************/
+uint8_t st25r3916GetNumFIFOLastBits(void) {
+    uint8_t reg;
+
+    st25r3916ReadRegister(ST25R3916_REG_FIFO_STATUS2, &reg);
+
+    return (
+        (reg & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >>
+        ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift);
+}
+
+/*******************************************************************************/
+uint32_t st25r3916GetNoResponseTime(void) {
+    return gST25R3916NRT_64fcs;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916SetNoResponseTime(uint32_t nrt_64fcs) {
+    ReturnCode err;
+    uint8_t nrt_step;
+    uint32_t tmpNRT;
+
+    tmpNRT = nrt_64fcs; /* MISRA 17.8 */
+    err = ERR_NONE;
+
+    gST25R3916NRT_64fcs = tmpNRT; /* Store given NRT value in 64/fc into local var       */
+    nrt_step =
+        ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_64fc; /* Set default NRT in steps of 64/fc                   */
+
+    if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the given NRT value fits using 64/fc steps */
+    {
+        nrt_step =
+            ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_4096_fc; /* If not, change NRT set to 4096/fc                   */
+        tmpNRT = ((tmpNRT + 63U) / 64U); /* Calculate number of steps in 4096/fc                */
+
+        if(tmpNRT > ST25R3916_NRT_MAX) /* Check if the NRT value fits using 64/fc steps       */
+        {
+            tmpNRT = ST25R3916_NRT_MAX; /* Assign the maximum possible                         */
+            err = ERR_PARAM; /* Signal parameter error                              */
+        }
+        gST25R3916NRT_64fcs = (64U * tmpNRT);
+    }
+
+    /* Set the ST25R3916 NRT step units and the value */
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step, nrt_step);
+    st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER1, (uint8_t)(tmpNRT >> 8U));
+    st25r3916WriteRegister(ST25R3916_REG_NO_RESPONSE_TIMER2, (uint8_t)(tmpNRT & 0xFFU));
+
+    return err;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916SetStartNoResponseTimer(uint32_t nrt_64fcs) {
+    ReturnCode err;
+
+    err = st25r3916SetNoResponseTime(nrt_64fcs);
+    if(err == ERR_NONE) {
+        st25r3916ExecuteCommand(ST25R3916_CMD_START_NO_RESPONSE_TIMER);
+    }
+
+    return err;
+}
+
+/*******************************************************************************/
+void st25r3916SetGPTime(uint16_t gpt_8fcs) {
+    st25r3916WriteRegister(ST25R3916_REG_GPT1, (uint8_t)(gpt_8fcs >> 8));
+    st25r3916WriteRegister(ST25R3916_REG_GPT2, (uint8_t)(gpt_8fcs & 0xFFU));
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916SetStartGPTimer(uint16_t gpt_8fcs, uint8_t trigger_source) {
+    st25r3916SetGPTime(gpt_8fcs);
+    st25r3916ChangeRegisterBits(
+        ST25R3916_REG_TIMER_EMV_CONTROL,
+        ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask,
+        trigger_source);
+
+    /* If there's no trigger source, start GPT immediately */
+    if(trigger_source == ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger) {
+        st25r3916ExecuteCommand(ST25R3916_CMD_START_GP_TIMER);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+bool st25r3916CheckChipID(uint8_t* rev) {
+    uint8_t ID;
+
+    ID = 0;
+    st25r3916ReadRegister(ST25R3916_REG_IC_IDENTITY, &ID);
+
+    /* Check if IC Identity Register contains ST25R3916's IC type code */
+    if((ID & ST25R3916_REG_IC_IDENTITY_ic_type_mask) !=
+       ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) {
+        return false;
+    }
+
+    if(rev != NULL) {
+        *rev = (ID & ST25R3916_REG_IC_IDENTITY_ic_rev_mask);
+    }
+
+    return true;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916GetRegsDump(t_st25r3916Regs* regDump) {
+    uint8_t regIt;
+
+    if(regDump == NULL) {
+        return ERR_PARAM;
+    }
+
+    /* Dump Registers on space A */
+    for(regIt = ST25R3916_REG_IO_CONF1; regIt <= ST25R3916_REG_IC_IDENTITY; regIt++) {
+        st25r3916ReadRegister(regIt, &regDump->RsA[regIt]);
+    }
+
+    regIt = 0;
+
+    /* Read non-consecutive Registers on space B */
+    st25r3916ReadRegister(ST25R3916_REG_EMD_SUP_CONF, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_SUBC_START_TIME, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_P2P_RX_CONF, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_CORR_CONF1, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_CORR_CONF2, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_SQUELCH_TIMER, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_FIELD_ON_GT, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_AUX_MOD, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_TIMING, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_RES_AM_MOD, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_TX_DRIVER_STATUS, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_REGULATOR_RESULT, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF1, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_OVERSHOOT_CONF2, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF1, &regDump->RsB[regIt++]);
+    st25r3916ReadRegister(ST25R3916_REG_UNDERSHOOT_CONF2, &regDump->RsB[regIt++]);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+bool st25r3916IsCmdValid(uint8_t cmd) {
+    if(!((cmd >= ST25R3916_CMD_SET_DEFAULT) && (cmd <= ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) &&
+       !((cmd >= ST25R3916_CMD_GOTO_SENSE) && (cmd <= ST25R3916_CMD_GOTO_SLEEP)) &&
+       !((cmd >= ST25R3916_CMD_MASK_RECEIVE_DATA) && (cmd <= ST25R3916_CMD_MEASURE_AMPLITUDE)) &&
+       !((cmd >= ST25R3916_CMD_RESET_RXGAIN) && (cmd <= ST25R3916_CMD_ADJUST_REGULATORS)) &&
+       !((cmd >= ST25R3916_CMD_CALIBRATE_DRIVER_TIMING) &&
+         (cmd <= ST25R3916_CMD_START_PPON2_TIMER)) &&
+       (cmd != ST25R3916_CMD_SPACE_B_ACCESS) && (cmd != ST25R3916_CMD_STOP_NRT)) {
+        return false;
+    }
+    return true;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916StreamConfigure(const struct st25r3916StreamConfig* config) {
+    uint8_t smd;
+    uint8_t mode;
+
+    smd = 0;
+
+    if(config->useBPSK != 0U) {
+        mode = ST25R3916_REG_MODE_om_bpsk_stream;
+        if((config->din < 2U) || (config->din > 4U)) /* not in fc/4 .. fc/16 */
+        {
+            return ERR_PARAM;
+        }
+        smd |= ((4U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
+    } else {
+        mode = ST25R3916_REG_MODE_om_subcarrier_stream;
+        if((config->din < 3U) || (config->din > 6U)) /* not in fc/8 .. fc/64 */
+        {
+            return ERR_PARAM;
+        }
+        smd |= ((6U - config->din) << ST25R3916_REG_STREAM_MODE_scf_shift);
+        if(config->report_period_length == 0U) {
+            return ERR_PARAM;
+        }
+    }
+
+    if((config->dout < 1U) || (config->dout > 7U)) /* not in fc/2 .. fc/128 */
+    {
+        return ERR_PARAM;
+    }
+    smd |= (7U - config->dout) << ST25R3916_REG_STREAM_MODE_stx_shift;
+
+    if(config->report_period_length > 3U) {
+        return ERR_PARAM;
+    }
+    smd |= (config->report_period_length << ST25R3916_REG_STREAM_MODE_scp_shift);
+
+    st25r3916WriteRegister(ST25R3916_REG_STREAM_MODE, smd);
+    st25r3916ChangeRegisterBits(ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_mask, mode);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916GetRSSI(uint16_t* amRssi, uint16_t* pmRssi) {
+    /*******************************************************************************/
+    /* MISRA 8.9 An object should be defined at block scope if its identifier only appears in a single function */
+    /*< ST25R3916  RSSI Display Reg values:      0   1   2   3   4   5   6    7    8   9    a     b    c    d  e  f */
+    static const uint16_t st25r3916Rssi2mV[] = {
+        0, 20, 27, 37, 52, 72, 99, 136, 190, 262, 357, 500, 686, 950, 1150, 1150};
+
+    /* ST25R3916 2/3 stage gain reduction [dB]          0    0    0    0    0    3    6    9   12   15   18  na na na na na */
+    static const uint16_t st25r3916Gain2Percent[] = {
+        100, 100, 100, 100, 100, 141, 200, 281, 398, 562, 794, 1, 1, 1, 1, 1};
+    /*******************************************************************************/
+
+    uint8_t rssi;
+    uint8_t gainRed;
+
+    st25r3916ReadRegister(ST25R3916_REG_RSSI_RESULT, &rssi);
+    st25r3916ReadRegister(ST25R3916_REG_GAIN_RED_STATE, &gainRed);
+
+    if(amRssi != NULL) {
+        *amRssi =
+            (uint16_t)(((uint32_t)
+                            st25r3916Rssi2mV[(rssi >> ST25R3916_REG_RSSI_RESULT_rssi_am_shift)] *
+                        (uint32_t)st25r3916Gain2Percent[(
+                            gainRed >> ST25R3916_REG_GAIN_RED_STATE_gs_am_shift)]) /
+                       100U);
+    }
+
+    if(pmRssi != NULL) {
+        *pmRssi =
+            (uint16_t)(((uint32_t)
+                            st25r3916Rssi2mV[(rssi & ST25R3916_REG_RSSI_RESULT_rssi_pm_mask)] *
+                        (uint32_t)st25r3916Gain2Percent[(
+                            gainRed & ST25R3916_REG_GAIN_RED_STATE_gs_pm_mask)]) /
+                       100U);
+    }
+
+    return ERR_NONE;
+}

+ 669 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916.h

@@ -0,0 +1,669 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 high level interface
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25R3916
+ * \brief RFAL ST25R3916 Driver
+ * @{
+ * 
+ * \addtogroup ST25R3916_Driver
+ * \brief RFAL ST25R3916 Driver
+ * @{
+ * 
+ */
+
+#ifndef ST25R3916_H
+#define ST25R3916_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../../platform.h"
+#include "../../st_errno.h"
+#include "st25r3916_com.h"
+
+/*
+******************************************************************************
+* GLOBAL DATATYPES
+******************************************************************************
+*/
+
+/*! Struct to represent all regs on ST25R3916                                                             */
+typedef struct {
+    uint8_t RsA[(
+        ST25R3916_REG_IC_IDENTITY + 1U)]; /*!< Registers contained on ST25R3916 space A (Rs-A)     */
+    uint8_t
+        RsB[ST25R3916_SPACE_B_REG_LEN]; /*!< Registers contained on ST25R3916 space B (Rs-B)     */
+} t_st25r3916Regs;
+
+/*! Parameters how the stream mode should work                                                            */
+struct st25r3916StreamConfig {
+    uint8_t useBPSK; /*!< 0: subcarrier, 1:BPSK                                */
+    uint8_t din; /*!< Divider for the in subcarrier frequency: fc/2^din    */
+    uint8_t dout; /*!< Divider for the in subcarrier frequency fc/2^dout    */
+    uint8_t report_period_length; /*!< Length of the reporting period 2^report_period_length*/
+};
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+/* ST25R3916 direct commands */
+#define ST25R3916_CMD_SET_DEFAULT \
+    0xC1U /*!< Puts the chip in default state (same as after power-up) */
+#define ST25R3916_CMD_STOP 0xC2U /*!< Stops all activities and clears FIFO                    */
+#define ST25R3916_CMD_TRANSMIT_WITH_CRC \
+    0xC4U /*!< Transmit with CRC                                       */
+#define ST25R3916_CMD_TRANSMIT_WITHOUT_CRC \
+    0xC5U /*!< Transmit without CRC                                    */
+#define ST25R3916_CMD_TRANSMIT_REQA \
+    0xC6U /*!< Transmit REQA                                           */
+#define ST25R3916_CMD_TRANSMIT_WUPA \
+    0xC7U /*!< Transmit WUPA                                           */
+#define ST25R3916_CMD_INITIAL_RF_COLLISION \
+    0xC8U /*!< NFC transmit with Initial RF Collision Avoidance        */
+#define ST25R3916_CMD_RESPONSE_RF_COLLISION_N \
+    0xC9U /*!< NFC transmit with Response RF Collision Avoidance       */
+#define ST25R3916_CMD_GOTO_SENSE \
+    0xCDU /*!< Passive target logic to Sense/Idle state                */
+#define ST25R3916_CMD_GOTO_SLEEP \
+    0xCEU /*!< Passive target logic to Sleep/Halt state                */
+#define ST25R3916_CMD_MASK_RECEIVE_DATA \
+    0xD0U /*!< Mask receive data                                       */
+#define ST25R3916_CMD_UNMASK_RECEIVE_DATA \
+    0xD1U /*!< Unmask receive data                                     */
+#define ST25R3916_CMD_AM_MOD_STATE_CHANGE \
+    0xD2U /*!< AM Modulation state change                              */
+#define ST25R3916_CMD_MEASURE_AMPLITUDE \
+    0xD3U /*!< Measure signal amplitude on RFI inputs                  */
+#define ST25R3916_CMD_RESET_RXGAIN \
+    0xD5U /*!< Reset RX Gain                                           */
+#define ST25R3916_CMD_ADJUST_REGULATORS \
+    0xD6U /*!< Adjust regulators                                       */
+#define ST25R3916_CMD_CALIBRATE_DRIVER_TIMING \
+    0xD8U /*!< Starts the sequence to adjust the driver timing         */
+#define ST25R3916_CMD_MEASURE_PHASE \
+    0xD9U /*!< Measure phase between RFO and RFI signal                */
+#define ST25R3916_CMD_CLEAR_RSSI \
+    0xDAU /*!< Clear RSSI bits and restart the measurement             */
+#define ST25R3916_CMD_CLEAR_FIFO \
+    0xDBU /*!< Clears FIFO, Collision and IRQ status                   */
+#define ST25R3916_CMD_TRANSPARENT_MODE \
+    0xDCU /*!< Transparent mode                                        */
+#define ST25R3916_CMD_CALIBRATE_C_SENSOR \
+    0xDDU /*!< Calibrate the capacitive sensor                         */
+#define ST25R3916_CMD_MEASURE_CAPACITANCE \
+    0xDEU /*!< Measure capacitance                                     */
+#define ST25R3916_CMD_MEASURE_VDD \
+    0xDFU /*!< Measure power supply voltage                            */
+#define ST25R3916_CMD_START_GP_TIMER \
+    0xE0U /*!< Start the general purpose timer                         */
+#define ST25R3916_CMD_START_WUP_TIMER \
+    0xE1U /*!< Start the wake-up timer                                 */
+#define ST25R3916_CMD_START_MASK_RECEIVE_TIMER \
+    0xE2U /*!< Start the mask-receive timer                            */
+#define ST25R3916_CMD_START_NO_RESPONSE_TIMER \
+    0xE3U /*!< Start the no-response timer                             */
+#define ST25R3916_CMD_START_PPON2_TIMER \
+    0xE4U /*!< Start PPon2 timer                                       */
+#define ST25R3916_CMD_STOP_NRT \
+    0xE8U /*!< Stop No Response Timer                                  */
+#define ST25R3916_CMD_SPACE_B_ACCESS \
+    0xFBU /*!< Enable R/W access to the test registers                 */
+#define ST25R3916_CMD_TEST_ACCESS \
+    0xFCU /*!< Enable R/W access to the test registers                 */
+
+#define ST25R3916_THRESHOLD_DO_NOT_SET \
+    0xFFU /*!< Indicates not to change this Threshold                  */
+
+#define ST25R3916_BR_DO_NOT_SET \
+    0xFFU /*!< Indicates not to change this Bit Rate                   */
+#define ST25R3916_BR_106 0x00U /*!< ST25R3916 Bit Rate  106 kbit/s (fc/128)                 */
+#define ST25R3916_BR_212 0x01U /*!< ST25R3916 Bit Rate  212 kbit/s (fc/64)                  */
+#define ST25R3916_BR_424 0x02U /*!< ST25R3916 Bit Rate  424 kbit/s (fc/32)                  */
+#define ST25R3916_BR_848 0x03U /*!< ST25R3916 Bit Rate  848 kbit/s (fc/16)                  */
+#define ST25R3916_BR_1695 0x04U /*!< ST25R3916 Bit Rate 1696 kbit/s (fc/8)                   */
+#define ST25R3916_BR_3390 0x05U /*!< ST25R3916 Bit Rate 3390 kbit/s (fc/4)                   */
+#define ST25R3916_BR_6780 0x07U /*!< ST25R3916 Bit Rate 6780 kbit/s (fc/2)                   */
+
+#define ST25R3916_FIFO_DEPTH 512U /*!< Depth of FIFO                                           */
+#define ST25R3916_TOUT_OSC_STABLE \
+    10U /*!< Max timeout for Oscillator to get stable      DS: 700us */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+/*! Enables the Transmitter (Field On) and Receiver                                          */
+#define st25r3916TxRxOn()         \
+    st25r3916SetRegisterBits(     \
+        ST25R3916_REG_OP_CONTROL, \
+        (ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en))
+
+/*! Disables the Transmitter (Field Off) and Receiver                                         */
+#define st25r3916TxRxOff()        \
+    st25r3916ClrRegisterBits(     \
+        ST25R3916_REG_OP_CONTROL, \
+        (ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en))
+
+/*! Disables the Transmitter (Field Off)                                         */
+#define st25r3916TxOff() \
+    st25r3916ClrRegisterBits(ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_tx_en)
+
+/*! Checks if General Purpose Timer is still running by reading gpt_on flag                  */
+#define st25r3916IsGPTRunning()               \
+    st25r3916CheckReg(                        \
+        ST25R3916_REG_NFCIP1_BIT_RATE,        \
+        ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on, \
+        ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on)
+
+/*! Checks if External Filed is detected by reading ST25R3916 External Field Detector output    */
+#define st25r3916IsExtFieldOn()          \
+    st25r3916CheckReg(                   \
+        ST25R3916_REG_AUX_DISPLAY,       \
+        ST25R3916_REG_AUX_DISPLAY_efd_o, \
+        ST25R3916_REG_AUX_DISPLAY_efd_o)
+
+/*! Checks if Transmitter is enabled (Field On) */
+#define st25r3916IsTxEnabled() \
+    st25r3916CheckReg(         \
+        ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_tx_en, ST25R3916_REG_OP_CONTROL_tx_en)
+
+/*! Checks if NRT is in EMV mode */
+#define st25r3916IsNRTinEMV()                    \
+    st25r3916CheckReg(                           \
+        ST25R3916_REG_TIMER_EMV_CONTROL,         \
+        ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv, \
+        ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_on)
+
+/*! Checks if last FIFO byte is complete */
+#define st25r3916IsLastFIFOComplete() \
+    st25r3916CheckReg(ST25R3916_REG_FIFO_STATUS2, ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask, 0)
+
+/*! Checks if the Oscillator is enabled  */
+#define st25r3916IsOscOn() \
+    st25r3916CheckReg(     \
+        ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en, ST25R3916_REG_OP_CONTROL_en)
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ *  \brief  Initialise ST25R3916 driver
+ *
+ *  This function initialises the ST25R3916 driver.
+ *
+ *  \return ERR_NONE         : Operation successful
+ *  \return ERR_HW_MISMATCH  : Expected HW do not match or communication error
+ *  \return ERR_IO           : Error during communication selftest. Check communication interface
+ *  \return ERR_TIMEOUT      : Timeout during IRQ selftest. Check IRQ handling
+ *  \return ERR_SYSTEM       : Failure during oscillator activation or timer error 
+ *
+ *****************************************************************************
+ */
+ReturnCode st25r3916Initialize(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Deinitialize ST25R3916 driver
+ *
+ *  Calling this function deinitializes the ST25R3916 driver.
+ *
+ *****************************************************************************
+ */
+void st25r3916Deinitialize(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Turn on Oscillator and Regulator
+ *  
+ *  This function turn on oscillator and regulator and waits for the 
+ *  oscillator to become stable
+ * 
+ *  \return ERR_SYSTEM : Failure dusring Oscillator activation
+ *  \return ERR_NONE   : No error, Oscillator is active and stable, Regulator is on
+ *
+ *****************************************************************************
+ */
+ReturnCode st25r3916OscOn(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Sets the bitrate
+ *
+ *  This function sets the bitrates for rx and tx
+ *
+ *  \param txrate : speed is 2^txrate * 106 kb/s
+ *                  0xff : don't set txrate (ST25R3916_BR_DO_NOT_SET)
+ *  \param rxrate : speed is 2^rxrate * 106 kb/s
+ *                  0xff : don't set rxrate (ST25R3916_BR_DO_NOT_SET)
+ *
+ *  \return ERR_PARAM: At least one bit rate was invalid
+ *  \return ERR_NONE : No error, both bit rates were set
+ *
+ *****************************************************************************
+ */
+ReturnCode st25r3916SetBitrate(uint8_t txrate, uint8_t rxrate);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Adjusts supply regulators according to the current supply voltage
+ *
+ *  This function the power level is measured in maximum load conditions and
+ *  the regulated voltage reference is set to 250mV below this level.
+ *  Execution of this function lasts around 5ms. 
+ *
+ *  The regulated voltages will be set to the result of Adjust Regulators
+ *  
+ *  \param [out] result_mV : Result of calibration in milliVolts
+ *
+ *  \return ERR_IO : Error during communication with ST25R3916
+ *  \return ERR_NONE : No error
+ *
+ *****************************************************************************
+ */
+ReturnCode st25r3916AdjustRegulators(uint16_t* result_mV);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Measure Amplitude
+ *
+ *  This function measured the amplitude on the RFI inputs and stores the
+ *  result in parameter \a result.
+ *
+ *  \param[out] result:  result of RF measurement.
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916MeasureAmplitude(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Measure Power Supply
+ *
+ *  This function executes Measure Power Supply and returns the raw value
+ *
+ *  \param[in] mpsv : one of ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am
+ *
+ *  \return the measured voltage in raw format.
+ *
+ *****************************************************************************
+ */
+uint8_t st25r3916MeasurePowerSupply(uint8_t mpsv);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Measure Voltage
+ *
+ *  This function measures the voltage on one of VDD and VDD_* and returns 
+ *  the result in mV
+ *
+ *  \param[in] mpsv : one of ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a
+ *                           ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d
+ *                    or     ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am
+ *
+ *  \return the measured voltage in mV
+ *
+ *****************************************************************************
+ */
+uint16_t st25r3916MeasureVoltage(uint8_t mpsv);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Measure Phase
+ *
+ *  This function performs a Phase measurement.
+ *  The result is stored in the \a result parameter.
+ *
+ *  \param[out] result: 8 bit long result of the measurement.
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916MeasurePhase(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Measure Capacitance
+ *
+ *  This function performs the capacitance measurement and stores the
+ *  result in parameter \a result.
+ *
+ *  \param[out] result: 8 bit long result of RF measurement.
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916MeasureCapacitance(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Calibrates Capacitive Sensor
+ *
+ *  This function performs automatic calibration of the capacitive sensor 
+ *  and stores the result in parameter \a result.
+ *
+ * \warning To avoid interference with Xtal oscillator and reader magnetic 
+ *          field, it is strongly recommended to perform calibration
+ *          in Power-down mode only.
+ *          This method does not modify the Oscillator nor transmitter state, 
+ *          these should be configured before by user.
+ *
+ *  \param[out] result: 5 bit long result of the calibration.
+ *                      Binary weighted, step 0.1 pF, max 3.1 pF
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_IO    : The calibration was not successful 
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916CalibrateCapacitiveSensor(uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Get NRT time
+ *
+ *  This returns the last value set on the NRT
+ *   
+ *  \warning it does not read chip register, just the sw var that contains the 
+ *  last value set before
+ *
+ *  \return the value of the NRT in 64/fc 
+ */
+uint32_t st25r3916GetNoResponseTime(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Set NRT time
+ *
+ *  This function sets the No Response Time with the given value
+ *
+ *  \param [in] nrt_64fcs : no response time in steps of 64/fc (4.72us)
+ *
+ *  \return ERR_PARAM : Invalid parameter (time is too large)
+ *  \return ERR_NONE  : No error
+ *
+ *****************************************************************************  
+ */
+ReturnCode st25r3916SetNoResponseTime(uint32_t nrt_64fcs);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Set and Start NRT
+ *
+ *  This function sets the No Response Time with the given value and 
+ *  immediately starts it
+ *  Used when needs to add more time before timeout without performing Tx
+ *
+ *  \param [in] nrt_64fcs : no response time in steps of 64/fc (4.72us)
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *
+ *****************************************************************************  
+ */
+ReturnCode st25r3916SetStartNoResponseTimer(uint32_t nrt_64fcs);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Set GPT time
+ *
+ *  This function sets the General Purpose Timer time registers
+ *
+ *  \param [in] gpt_8fcs : general purpose timer timeout in steps of 8/fc (590ns)
+ *
+ *****************************************************************************
+ */
+void st25r3916SetGPTime(uint16_t gpt_8fcs);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Set and Start GPT
+ *
+ *  This function sets the General Purpose Timer with the given timeout and 
+ *  immediately starts it ONLY if the trigger source is not set to none.
+ *
+ *  \param [in] gpt_8fcs : general purpose timer timeout in  steps of8/fc (590ns)
+ *  \param [in] trigger_source : no trigger, start of Rx, end of Rx, end of Tx in NFC mode
+ *   
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error 
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916SetStartGPTimer(uint16_t gpt_8fcs, uint8_t trigger_source);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Sets the number Tx Bits
+ *  
+ *  Sets ST25R3916 internal registers with correct number of complete bytes and
+ *  bits to be sent
+ *  
+ *  \param [in] nBits : number of bits to be set/transmitted
+ *    
+ *****************************************************************************
+ */
+void st25r3916SetNumTxBits(uint16_t nBits);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Get amount of bytes in FIFO
+ *  
+ *  Gets the number of bytes currently in the FIFO
+ *  
+ *  \return the number of bytes currently in the FIFO
+ *    
+ *****************************************************************************
+ */
+uint16_t st25r3916GetNumFIFOBytes(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Get amount of bits of the last FIFO byte if incomplete
+ *  
+ *  Gets the number of bits of the last FIFO byte if incomplete
+ *  
+ *  \return the number of bits of the last FIFO byte if incomplete, 0 if 
+ *          the last byte is complete
+ *    
+ *****************************************************************************
+ */
+uint8_t st25r3916GetNumFIFOLastBits(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Perform Collision Avoidance
+ *
+ *  Performs Collision Avoidance with the given threshold and with the  
+ *  n number of TRFW 
+ *  
+ *  \param[in] FieldONCmd  : Field ON command to be executed ST25R3916_CMD_INITIAL_RF_COLLISION
+ *                           or ST25R3916_CMD_RESPONSE_RF_COLLISION_N  
+ *  \param[in] pdThreshold : Peer Detection Threshold  (ST25R3916_REG_FIELD_THRESHOLD_trg_xx)
+ *                           0xff : don't set Threshold (ST25R3916_THRESHOLD_DO_NOT_SET)
+ *  \param[in] caThreshold : Collision Avoidance Threshold (ST25R3916_REG_FIELD_THRESHOLD_rfe_xx)
+ *                           0xff : don't set Threshold (ST25R3916_THRESHOLD_DO_NOT_SET)
+ *  \param[in] nTRFW       : Number of TRFW
+ *
+ *  \return ERR_PARAM        : Invalid parameter 
+ *  \return ERR_RF_COLLISION : Collision detected
+ *  \return ERR_NONE         : No collision detected
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916PerformCollisionAvoidance(
+    uint8_t FieldONCmd,
+    uint8_t pdThreshold,
+    uint8_t caThreshold,
+    uint8_t nTRFW);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Check Identity
+ *
+ *  Checks if the chip ID is as expected.
+ *  
+ *  5 bit IC type code for ST25R3916: 00101
+ *  The 3 lsb contain the IC revision code
+ *   
+ *  \param[out] rev : the IC revision code
+ *    
+ *  \return  true when IC type is as expected
+ *  \return  false otherwise
+ */
+bool st25r3916CheckChipID(uint8_t* rev);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Retrieves all  internal registers from ST25R3916
+ *  
+ *  \param[out] regDump : pointer to the struct/buffer where the reg dump
+ *                        will be written
+ *  
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *****************************************************************************
+ */
+ReturnCode st25r3916GetRegsDump(t_st25r3916Regs* regDump);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Check if command is valid
+ *
+ *  Checks if the given command is a valid ST25R3916 command
+ *
+ *  \param[in] cmd: Command to check
+ *  
+ *  \return  true if is a valid command
+ *  \return  false otherwise
+ *
+ *****************************************************************************
+ */
+bool st25r3916IsCmdValid(uint8_t cmd);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Configure the stream mode of ST25R3916
+ *
+ *  This function initializes the stream with the given parameters
+ *
+ *  \param[in] config : all settings for bitrates, type, etc.
+ *
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error, stream mode driver initialized
+ *
+ *****************************************************************************
+ */
+ReturnCode st25r3916StreamConfigure(const struct st25r3916StreamConfig* config);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Executes a direct command and returns the result
+ *
+ *  This function executes the direct command given by \a cmd waits for
+ *  \a sleeptime for I_dct and returns the result read from register \a resreg.
+ *  The value of cmd is not checked.
+ *
+ *  \param[in]  cmd   : direct command to execute
+ *  \param[in]  resReg: address of the register containing the result
+ *  \param[in]  tout  : time in milliseconds to wait before reading the result
+ *  \param[out] result: result
+ *
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode
+    st25r3916ExecuteCommandAndGetResult(uint8_t cmd, uint8_t resReg, uint8_t tout, uint8_t* result);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Gets the RSSI values
+ *
+ *  This function gets the RSSI value of the previous reception taking into 
+ *  account the gain reductions that were used. 
+ *  RSSI value for both AM and PM channel can be retrieved.
+ *
+ *  \param[out] amRssi: the RSSI on the AM channel expressed in mV 
+ *  \param[out] pmRssi: the RSSI on the PM channel expressed in mV 
+ *  
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_NONE  : No error
+ *  
+ *****************************************************************************
+ */
+ReturnCode st25r3916GetRSSI(uint16_t* amRssi, uint16_t* pmRssi);
+#endif /* ST25R3916_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  * 
+  * @}
+  */

+ 366 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_aat.c

@@ -0,0 +1,366 @@
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file st25r3916_aat.c
+ *
+ *  \author 
+ *
+ *  \brief ST25R3916 Antenna Tuning 
+ *
+ * The antenna tuning algorithm tries to find the optimal settings for 
+ * the AAT_A and AAT_B registers, which are connected to variable capacitors 
+ * to tune the antenna matching.
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "st25r3916_aat.h"
+#include "../../utils.h"
+#include "../../st_errno.h"
+#include "st25r3916.h"
+#include "st25r3916_com.h"
+#include "../../platform.h"
+#include "../../include/rfal_chip.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+#define ST25R3916_AAT_CAP_DELAY_MAX 10 /*!< Max Variable Capacitor settle delay */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+#define st25r3916AatLog(...) /* platformLog(__VA_ARGS__) */ /*!< Logging macro */
+
+/*
+******************************************************************************
+* LOCAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+static ReturnCode aatHillClimb(
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus);
+static int32_t aatGreedyDescent(
+    uint32_t* f_min,
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus,
+    int32_t previousDir);
+static int32_t aatSteepestDescent(
+    uint32_t* f_min,
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus,
+    int32_t previousDir,
+    int32_t previousDir2);
+
+static ReturnCode aatMeasure(
+    uint8_t serCap,
+    uint8_t parCap,
+    uint8_t* amplitude,
+    uint8_t* phase,
+    uint16_t* measureCnt);
+static uint32_t
+    aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase);
+static ReturnCode aatStepDacVals(
+    const struct st25r3916AatTuneParams* tuningParams,
+    uint8_t* a,
+    uint8_t* b,
+    int32_t dir);
+
+/*******************************************************************************/
+ReturnCode st25r3916AatTune(
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus) {
+    ReturnCode err;
+    const struct st25r3916AatTuneParams* tp = tuningParams;
+    struct st25r3916AatTuneResult* ts = tuningStatus;
+    struct st25r3916AatTuneParams defaultTuningParams = {
+        .aat_a_min = 0,
+        .aat_a_max = 255,
+        .aat_a_start = 127,
+        .aat_a_stepWidth = 32,
+        .aat_b_min = 0,
+        .aat_b_max = 255,
+        .aat_b_start = 127,
+        .aat_b_stepWidth = 32,
+
+        .phaTarget = 128,
+        .phaWeight = 2,
+        .ampTarget = 196,
+        .ampWeight = 1,
+
+        .doDynamicSteps = true,
+        .measureLimit = 50,
+    };
+    struct st25r3916AatTuneResult defaultTuneResult;
+
+    if((NULL != tp) && ((tp->aat_a_min > tp->aat_a_max) || (tp->aat_a_start < tp->aat_a_min) ||
+                        (tp->aat_a_start > tp->aat_a_max) || (tp->aat_b_min > tp->aat_b_max) ||
+                        (tp->aat_b_start < tp->aat_b_min) || (tp->aat_b_start > tp->aat_b_max))) {
+        return ERR_PARAM;
+    }
+
+    if(NULL == tp) { /* Start from current caps with default params */
+        st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_A, &defaultTuningParams.aat_a_start);
+        st25r3916ReadRegister(ST25R3916_REG_ANT_TUNE_B, &defaultTuningParams.aat_b_start);
+        tp = &defaultTuningParams;
+    }
+
+    if(NULL == ts) {
+        ts = &defaultTuneResult;
+    }
+
+    ts->measureCnt = 0; /* Clear current measure count */
+
+    err = aatHillClimb(tp, ts);
+
+    return err;
+}
+
+/*******************************************************************************/
+static ReturnCode aatHillClimb(
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus) {
+    ReturnCode err = ERR_NONE;
+    uint32_t f_min;
+    int32_t direction, gdirection;
+    uint8_t amp, phs;
+    struct st25r3916AatTuneParams tp = *tuningParams; // local copy to obey const
+
+    tuningStatus->aat_a = tuningParams->aat_a_start;
+    tuningStatus->aat_b = tuningParams->aat_b_start;
+
+    /* Get a proper start value */
+    aatMeasure(tuningStatus->aat_a, tuningStatus->aat_b, &amp, &phs, &tuningStatus->measureCnt);
+    f_min = aatCalcF(&tp, amp, phs);
+    direction = 0;
+
+    st25r3916AatLog("%d %d: %d***\n", tuningStatus->aat_a, tuningStatus->aat_b, f_min);
+
+    do {
+        direction =
+            0; /* Initially and after reducing step sizes we don't have a previous direction */
+        do {
+            /* With the greedy step below always executed aftwards the -direction does never need to be investigated */
+            direction = aatSteepestDescent(&f_min, &tp, tuningStatus, direction, -direction);
+            if(tuningStatus->measureCnt > tp.measureLimit) {
+                err = ERR_OVERRUN;
+                break;
+            }
+            do {
+                gdirection = aatGreedyDescent(&f_min, &tp, tuningStatus, direction);
+                if(tuningStatus->measureCnt > tp.measureLimit) {
+                    err = ERR_OVERRUN;
+                    break;
+                }
+            } while(0 != gdirection);
+        } while(0 != direction);
+        tp.aat_a_stepWidth /= 2U; /* Reduce step sizes */
+        tp.aat_b_stepWidth /= 2U;
+    } while(tp.doDynamicSteps && ((tp.aat_a_stepWidth > 0U) || (tp.aat_b_stepWidth > 0U)));
+
+    return err;
+}
+
+/*******************************************************************************/
+static int32_t aatSteepestDescent(
+    uint32_t* f_min,
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus,
+    int32_t previousDir,
+    int32_t previousDir2) {
+    int32_t i;
+    uint8_t amp, phs;
+    uint32_t f;
+    int32_t bestdir =
+        0; /* Negative direction: decrease, Positive: increase. (-)1: aat_a, (-)2: aat_b */
+
+    for(i = -2; i <= 2; i++) {
+        uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b;
+
+        if((0 == i) || (i == -previousDir) ||
+           (i == -previousDir2)) { /* Skip no direction and avoid going backwards */
+            continue;
+        }
+        if(0U != aatStepDacVals(
+                     tuningParams,
+                     &a,
+                     &b,
+                     i)) { /* If stepping did not change the value, omit this direction */
+            continue;
+        }
+
+        aatMeasure(a, b, &amp, &phs, &tuningStatus->measureCnt);
+        f = aatCalcF(tuningParams, amp, phs);
+        st25r3916AatLog("%d : %d %d: %d", i, a, b, f);
+        if(f < *f_min) { /* Value is better than all previous ones */
+            st25r3916AatLog("*");
+            *f_min = f;
+            bestdir = i;
+        }
+        st25r3916AatLog("\n");
+    }
+    if(0 != bestdir) { /* Walk into the best direction */
+        aatStepDacVals(tuningParams, &tuningStatus->aat_a, &tuningStatus->aat_b, bestdir);
+    }
+    return bestdir;
+}
+
+/*******************************************************************************/
+static int32_t aatGreedyDescent(
+    uint32_t* f_min,
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus,
+    int32_t previousDir) {
+    uint8_t amp, phs;
+    uint32_t f;
+    uint8_t a = tuningStatus->aat_a, b = tuningStatus->aat_b;
+
+    if(0U != aatStepDacVals(
+                 tuningParams,
+                 &a,
+                 &b,
+                 previousDir)) { /* If stepping did not change the value, omit this direction */
+        return 0;
+    }
+
+    aatMeasure(a, b, &amp, &phs, &tuningStatus->measureCnt);
+    f = aatCalcF(tuningParams, amp, phs);
+    st25r3916AatLog("g : %d %d: %d", a, b, f);
+    if(f < *f_min) { /* Value is better than previous one */
+        st25r3916AatLog("*\n");
+        tuningStatus->aat_a = a;
+        tuningStatus->aat_b = b;
+        *f_min = f;
+        return previousDir;
+    }
+
+    st25r3916AatLog("\n");
+    return 0;
+}
+
+/*******************************************************************************/
+static uint32_t
+    aatCalcF(const struct st25r3916AatTuneParams* tuningParams, uint8_t amplitude, uint8_t phase) {
+    /* f(amp, pha) = (ampWeight * |amp - ampTarget|) + (phaWeight * |pha - phaTarget|) */
+    uint8_t ampTarget = tuningParams->ampTarget;
+    uint8_t phaTarget = tuningParams->phaTarget;
+
+    uint32_t ampWeight = tuningParams->ampWeight;
+    uint32_t phaWeight = tuningParams->phaWeight;
+
+    /* Temp variables to avoid MISRA R10.8 (cast on composite expression) */
+    uint8_t ad = ((amplitude > ampTarget) ? (amplitude - ampTarget) : (ampTarget - amplitude));
+    uint8_t pd = ((phase > phaTarget) ? (phase - phaTarget) : (phaTarget - phase));
+
+    uint32_t ampDelta = (uint32_t)ad;
+    uint32_t phaDelta = (uint32_t)pd;
+
+    return ((ampWeight * ampDelta) + (phaWeight * phaDelta));
+}
+
+/*******************************************************************************/
+static ReturnCode aatStepDacVals(
+    const struct st25r3916AatTuneParams* tuningParams,
+    uint8_t* a,
+    uint8_t* b,
+    int32_t dir) {
+    int16_t aat_a = (int16_t)*a, aat_b = (int16_t)*b;
+
+    switch(abs(dir)) { /* Advance by steps size in requested direction */
+    case 1:
+        aat_a = (dir < 0) ? (aat_a - (int16_t)tuningParams->aat_a_stepWidth) :
+                            (aat_a + (int16_t)tuningParams->aat_a_stepWidth);
+        if(aat_a < (int16_t)tuningParams->aat_a_min) {
+            aat_a = (int16_t)tuningParams->aat_a_min;
+        }
+        if(aat_a > (int16_t)tuningParams->aat_a_max) {
+            aat_a = (int16_t)tuningParams->aat_a_max;
+        }
+        if((int16_t)*a == aat_a) {
+            return ERR_PARAM;
+        }
+        break;
+    case 2:
+        aat_b = (dir < 0) ? (aat_b - (int16_t)tuningParams->aat_b_stepWidth) :
+                            (aat_b + (int16_t)tuningParams->aat_b_stepWidth);
+        if(aat_b < (int16_t)tuningParams->aat_b_min) {
+            aat_b = (int16_t)tuningParams->aat_b_min;
+        }
+        if(aat_b > (int16_t)tuningParams->aat_b_max) {
+            aat_b = (int16_t)tuningParams->aat_b_max;
+        }
+        if((int16_t)*b == aat_b) {
+            return ERR_PARAM;
+        }
+        break;
+    default:
+        return ERR_REQUEST;
+    }
+    /* We only get here if actual values have changed. In all other cases an error is returned */
+    *a = (uint8_t)aat_a;
+    *b = (uint8_t)aat_b;
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+static ReturnCode aatMeasure(
+    uint8_t serCap,
+    uint8_t parCap,
+    uint8_t* amplitude,
+    uint8_t* phase,
+    uint16_t* measureCnt) {
+    ReturnCode err;
+
+    *amplitude = 0;
+    *phase = 0;
+
+    st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_A, serCap);
+    st25r3916WriteRegister(ST25R3916_REG_ANT_TUNE_B, parCap);
+
+    /* Wait till caps have settled.. */
+    platformDelay(ST25R3916_AAT_CAP_DELAY_MAX);
+
+    /* Get amplitude and phase .. */
+    err = rfalChipMeasureAmplitude(amplitude);
+    if(ERR_NONE == err) {
+        err = rfalChipMeasurePhase(phase);
+    }
+
+    if(measureCnt != NULL) {
+        (*measureCnt)++;
+    }
+    return err;
+}

+ 109 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_aat.h

@@ -0,0 +1,109 @@
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file st25r3916_aat.h
+ *
+ *  \author
+ *
+ *  \brief ST25R3916 Antenna Tuning 
+ *
+ * The antenna tuning algorithm tries to find the optimal settings for 
+ * the AAT_A and AAT_B registers, which are connected to variable capacitors 
+ * to tune the antenna matching.
+ *
+ */
+
+#ifndef ST25R3916_AAT_H
+#define ST25R3916_AAT_H
+
+#include "../../platform.h"
+#include "../../st_errno.h"
+
+/*
+******************************************************************************
+* GLOBAL DATATYPES
+******************************************************************************
+*/
+
+/*!
+ * struct representing input parameters for the antenna tuning
+ */
+struct st25r3916AatTuneParams {
+    uint8_t aat_a_min; /*!< min value of A cap */
+    uint8_t aat_a_max; /*!< max value of A cap */
+    uint8_t aat_a_start; /*!< start value of A cap */
+    uint8_t aat_a_stepWidth; /*!< increment stepWidth for A cap */
+    uint8_t aat_b_min; /*!< min value of B cap */
+    uint8_t aat_b_max; /*!< max value of B cap */
+    uint8_t aat_b_start; /*!< start value of B cap */
+    uint8_t aat_b_stepWidth; /*!< increment stepWidth for B cap */
+
+    uint8_t phaTarget; /*!< target phase */
+    uint8_t phaWeight; /*!< weight of target phase */
+    uint8_t ampTarget; /*!< target amplitude */
+    uint8_t ampWeight; /*!< weight of target amplitude */
+
+    bool doDynamicSteps; /*!< dynamically reduce step size in algo */
+    uint8_t measureLimit; /*!< max number of allowed steps/measurements */
+};
+
+/*!
+ * struct representing out parameters for the antenna tuning
+ */
+struct st25r3916AatTuneResult {
+    uint8_t aat_a; /*!< serial cap after tuning */
+    uint8_t aat_b; /*!< parallel cap after tuning */
+    uint8_t pha; /*!< phase after tuning */
+    uint8_t amp; /*!< amplitude after tuning */
+    uint16_t measureCnt; /*!< number of measures performed */
+};
+
+/*! 
+ *****************************************************************************
+ *  \brief  Perform antenna tuning
+ *
+ *  This function starts an antenna tuning procedure by modifying the serial 
+ *  and parallel capacitors of the antenna matching circuit via the AAT_A
+ *  and AAT_B registers. 
+ *   
+ *  \param[in] tuningParams : Input parameters for the tuning algorithm. If NULL
+ *                            default values will be used.
+ *  \param[out] tuningStatus : Result information of performed tuning. If NULL
+ *                             no further information is returned, only registers
+ *                             ST25R3916 (AAT_A,B) will be adapted.
+ *
+ *  \return ERR_IO    : Error during communication.
+ *  \return ERR_PARAM : Invalid input parameters
+ *  \return ERR_NONE  : No error.
+ *
+ *****************************************************************************
+ */
+extern ReturnCode st25r3916AatTune(
+    const struct st25r3916AatTuneParams* tuningParams,
+    struct st25r3916AatTuneResult* tuningStatus);
+
+#endif /* ST25R3916_AAT_H */

+ 618 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_com.c

@@ -0,0 +1,618 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief Implementation of ST25R3916 communication
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "st25r3916.h"
+#include "st25r3916_com.h"
+#include "st25r3916_led.h"
+#include "../../st_errno.h"
+#include "../../platform.h"
+#include "../../utils.h"
+
+/*
+******************************************************************************
+* LOCAL DEFINES
+******************************************************************************
+*/
+
+#define ST25R3916_OPTIMIZE \
+    true /*!< Optimization switch: false always write value to register      */
+#define ST25R3916_I2C_ADDR \
+    (0xA0U >> 1) /*!< ST25R3916's default I2C address                                */
+#define ST25R3916_REG_LEN 1U /*!< Byte length of a ST25R3916 register                            */
+
+#define ST25R3916_WRITE_MODE \
+    (0U << 6) /*!< ST25R3916 Operation Mode: Write                                */
+#define ST25R3916_READ_MODE \
+    (1U << 6) /*!< ST25R3916 Operation Mode: Read                                 */
+#define ST25R3916_CMD_MODE \
+    (3U << 6) /*!< ST25R3916 Operation Mode: Direct Command                       */
+#define ST25R3916_FIFO_LOAD \
+    (0x80U) /*!< ST25R3916 Operation Mode: FIFO Load                            */
+#define ST25R3916_FIFO_READ \
+    (0x9FU) /*!< ST25R3916 Operation Mode: FIFO Read                            */
+#define ST25R3916_PT_A_CONFIG_LOAD \
+    (0xA0U) /*!< ST25R3916 Operation Mode: Passive Target Memory A-Config Load  */
+#define ST25R3916_PT_F_CONFIG_LOAD \
+    (0xA8U) /*!< ST25R3916 Operation Mode: Passive Target Memory F-Config Load  */
+#define ST25R3916_PT_TSN_DATA_LOAD \
+    (0xACU) /*!< ST25R3916 Operation Mode: Passive Target Memory TSN Load       */
+#define ST25R3916_PT_MEM_READ \
+    (0xBFU) /*!< ST25R3916 Operation Mode: Passive Target Memory Read           */
+
+#define ST25R3916_CMD_LEN \
+    (1U) /*!< ST25R3916 CMD length                                           */
+#define ST25R3916_BUF_LEN \
+    (ST25R3916_CMD_LEN +  \
+     ST25R3916_FIFO_DEPTH) /*!< ST25R3916 communication buffer: CMD + FIFO length    */
+
+/*
+******************************************************************************
+* MACROS
+******************************************************************************
+*/
+#ifdef RFAL_USE_I2C
+#define st25r3916I2CStart() \
+    platformI2CStart() /*!< ST25R3916 HAL I2C driver macro to start a I2C transfer         */
+#define st25r3916I2CStop() \
+    platformI2CStop() /*!< ST25R3916 HAL I2C driver macro to stop a I2C transfer          */
+#define st25r3916I2CRepeatStart() \
+    platformI2CRepeatStart() /*!< ST25R3916 HAL I2C driver macro to repeat Start                 */
+#define st25r3916I2CSlaveAddrWR(sA) \
+    platformI2CSlaveAddrWR(         \
+        sA) /*!< ST25R3916 HAL I2C driver macro to repeat Start                 */
+#define st25r3916I2CSlaveAddrRD(sA) \
+    platformI2CSlaveAddrRD(         \
+        sA) /*!< ST25R3916 HAL I2C driver macro to repeat Start                 */
+#endif /* RFAL_USE_I2C */
+
+#if defined(ST25R_COM_SINGLETXRX) && !defined(RFAL_USE_I2C)
+static uint8_t
+    comBuf[ST25R3916_BUF_LEN]; /*!< ST25R3916 communication buffer                                 */
+static uint16_t comBufIt; /*!< ST25R3916 communication buffer iterator                        */
+#endif /* ST25R_COM_SINGLETXRX */
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION PROTOTYPES
+ ******************************************************************************
+ */
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Start
+ * 
+ * This method performs the required actions to start communications with 
+ * ST25R3916, either by SPI or I2C 
+ ******************************************************************************
+ */
+static void st25r3916comStart(void);
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Stop
+ * 
+ * This method performs the required actions to terminate communications with 
+ * ST25R3916, either by SPI or I2C 
+ ******************************************************************************
+ */
+static void st25r3916comStop(void);
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Repeat Start
+ * 
+ * This method performs the required actions to repeat start a transmission
+ * with ST25R3916, either by SPI or I2C 
+ ******************************************************************************
+ */
+#ifdef RFAL_USE_I2C
+static void st25r3916comRepeatStart(void);
+#else
+#define st25r3916comRepeatStart()
+#endif /* RFAL_USE_I2C */
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Tx
+ * 
+ * This method performs the required actions to transmit the given buffer
+ * to ST25R3916, either by SPI or I2C
+ * 
+ * \param[in]  txBuf : the buffer to transmit
+ * \param[in]  txLen : the length of the buffer to transmit
+ * \param[in]  last   : true if last data to be transmitted
+ * \param[in]  txOnly : true no reception is to be performed
+ *  
+ ******************************************************************************
+ */
+static void st25r3916comTx(const uint8_t* txBuf, uint16_t txLen, bool last, bool txOnly);
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Rx
+ * 
+ * This method performs the required actions to receive from ST25R3916 the given 
+ * amount of bytes, either by SPI or I2C
+ * 
+ * \param[out]  rxBuf : the buffer place the received bytes
+ * \param[in]   rxLen : the length to receive
+ *  
+ ******************************************************************************
+ */
+static void st25r3916comRx(uint8_t* rxBuf, uint16_t rxLen);
+
+/*!
+ ******************************************************************************
+ * \brief ST25R3916 communication Tx Byte
+ * 
+ * This helper method transmits a byte passed by value and not by reference
+ * 
+ * \param[in]   txByte : the value of the byte to be transmitted
+ * \param[in]   last   : true if last byte to be transmitted
+ * \param[in]   txOnly : true no reception is to be performed
+ *  
+ ******************************************************************************
+ */
+static void st25r3916comTxByte(uint8_t txByte, bool last, bool txOnly);
+
+/*
+ ******************************************************************************
+ * LOCAL FUNCTION
+ ******************************************************************************
+ */
+static void st25r3916comStart(void) {
+    /* Make this operation atomic, disabling ST25R3916 interrupt during communications*/
+    platformProtectST25RComm();
+
+#ifdef RFAL_USE_I2C
+    /* I2C Start and send Slave Address */
+    st25r3916I2CStart();
+    st25r3916I2CSlaveAddrWR(ST25R3916_I2C_ADDR);
+#else
+    /* Perform the chip select */
+    platformSpiSelect();
+
+#if defined(ST25R_COM_SINGLETXRX)
+    comBufIt = 0; /* reset local buffer position   */
+#endif /* ST25R_COM_SINGLETXRX */
+
+#endif /* RFAL_USE_I2C */
+}
+
+/*******************************************************************************/
+static void st25r3916comStop(void) {
+#ifdef RFAL_USE_I2C
+    /* Generate Stop signal */
+    st25r3916I2CStop();
+#else
+    /* Release the chip select */
+    platformSpiDeselect();
+#endif /* RFAL_USE_I2C */
+
+    /* reEnable the ST25R3916 interrupt */
+    platformUnprotectST25RComm();
+}
+
+/*******************************************************************************/
+#ifdef RFAL_USE_I2C
+static void st25r3916comRepeatStart(void) {
+    st25r3916I2CRepeatStart();
+    st25r3916I2CSlaveAddrRD(ST25R3916_I2C_ADDR);
+}
+#endif /* RFAL_USE_I2C */
+
+/*******************************************************************************/
+static void st25r3916comTx(const uint8_t* txBuf, uint16_t txLen, bool last, bool txOnly) {
+    NO_WARNING(last);
+    NO_WARNING(txOnly);
+
+    if(txLen > 0U) {
+#ifdef RFAL_USE_I2C
+        platformI2CTx(txBuf, txLen, last, txOnly);
+#else /* RFAL_USE_I2C */
+
+#ifdef ST25R_COM_SINGLETXRX
+
+        ST_MEMCPY(
+            &comBuf[comBufIt],
+            txBuf,
+            MIN(txLen,
+                (ST25R3916_BUF_LEN -
+                 comBufIt))); /* copy tx data to local buffer                      */
+        comBufIt +=
+            MIN(txLen,
+                (ST25R3916_BUF_LEN -
+                 comBufIt)); /* store position on local buffer                    */
+
+        if(last && txOnly) /* only perform SPI transaction if no Rx will follow */
+        {
+            platformSpiTxRx(comBuf, NULL, comBufIt);
+        }
+
+#else
+        platformSpiTxRx(txBuf, NULL, txLen);
+#endif /* ST25R_COM_SINGLETXRX */
+
+#endif /* RFAL_USE_I2C */
+    }
+}
+
+/*******************************************************************************/
+static void st25r3916comRx(uint8_t* rxBuf, uint16_t rxLen) {
+    if(rxLen > 0U) {
+#ifdef RFAL_USE_I2C
+        platformI2CRx(rxBuf, rxLen);
+#else /* RFAL_USE_I2C */
+
+#ifdef ST25R_COM_SINGLETXRX
+        ST_MEMSET(
+            &comBuf[comBufIt],
+            0x00,
+            MIN(rxLen,
+                (ST25R3916_BUF_LEN -
+                 comBufIt))); /* clear outgoing buffer                                  */
+        platformSpiTxRx(
+            comBuf,
+            comBuf,
+            MIN((comBufIt + rxLen),
+                ST25R3916_BUF_LEN)); /* transceive as a single SPI call                        */
+        ST_MEMCPY(
+            rxBuf,
+            &comBuf[comBufIt],
+            MIN(rxLen,
+                (ST25R3916_BUF_LEN -
+                 comBufIt))); /* copy from local buf to output buffer and skip cmd byte */
+#else
+        if(rxBuf != NULL) {
+            ST_MEMSET(
+                rxBuf, 0x00, rxLen); /* clear outgoing buffer                                  */
+        }
+        platformSpiTxRx(NULL, rxBuf, rxLen);
+#endif /* ST25R_COM_SINGLETXRX */
+#endif /* RFAL_USE_I2C */
+    }
+}
+
+/*******************************************************************************/
+static void st25r3916comTxByte(uint8_t txByte, bool last, bool txOnly) {
+    uint8_t val = txByte; /* MISRA 17.8: use intermediate variable */
+    st25r3916comTx(&val, ST25R3916_REG_LEN, last, txOnly);
+}
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+ReturnCode st25r3916ReadRegister(uint8_t reg, uint8_t* val) {
+    return st25r3916ReadMultipleRegisters(reg, val, ST25R3916_REG_LEN);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length) {
+    if(length > 0U) {
+        st25r3916comStart();
+
+        /* If is a space-B register send a direct command first */
+        if((reg & ST25R3916_SPACE_B) != 0U) {
+            st25r3916comTxByte(ST25R3916_CMD_SPACE_B_ACCESS, false, false);
+        }
+
+        st25r3916comTxByte(((reg & ~ST25R3916_SPACE_B) | ST25R3916_READ_MODE), true, false);
+        st25r3916comRepeatStart();
+        st25r3916comRx(values, length);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WriteRegister(uint8_t reg, uint8_t val) {
+    uint8_t value = val; /* MISRA 17.8: use intermediate variable */
+    return st25r3916WriteMultipleRegisters(reg, &value, ST25R3916_REG_LEN);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length) {
+    if(length > 0U) {
+        st25r3916comStart();
+
+        if((reg & ST25R3916_SPACE_B) != 0U) {
+            st25r3916comTxByte(ST25R3916_CMD_SPACE_B_ACCESS, false, true);
+        }
+
+        st25r3916comTxByte(((reg & ~ST25R3916_SPACE_B) | ST25R3916_WRITE_MODE), false, true);
+        st25r3916comTx(values, length, true, true);
+        st25r3916comStop();
+
+        /* Send a WriteMultiReg event to LED handling */
+        st25r3916ledEvtWrMultiReg(reg, values, length);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WriteFifo(const uint8_t* values, uint16_t length) {
+    if(length > ST25R3916_FIFO_DEPTH) {
+        return ERR_PARAM;
+    }
+
+    if(length > 0U) {
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_FIFO_LOAD, false, true);
+        st25r3916comTx(values, length, true, true);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ReadFifo(uint8_t* buf, uint16_t length) {
+    if(length > 0U) {
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_FIFO_READ, true, false);
+
+        st25r3916comRepeatStart();
+        st25r3916comRx(buf, length);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WritePTMem(const uint8_t* values, uint16_t length) {
+    if(length > ST25R3916_PTM_LEN) {
+        return ERR_PARAM;
+    }
+
+    if(length > 0U) {
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_PT_A_CONFIG_LOAD, false, true);
+        st25r3916comTx(values, length, true, true);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ReadPTMem(uint8_t* values, uint16_t length) {
+    uint8_t
+        tmp[ST25R3916_REG_LEN +
+            ST25R3916_PTM_LEN]; /* local buffer to handle prepended byte on I2C and SPI */
+
+    if(length > 0U) {
+        if(length > ST25R3916_PTM_LEN) {
+            return ERR_PARAM;
+        }
+
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_PT_MEM_READ, true, false);
+
+        st25r3916comRepeatStart();
+        st25r3916comRx(tmp, (ST25R3916_REG_LEN + length)); /* skip prepended byte */
+        st25r3916comStop();
+
+        /* Copy PTMem content without prepended byte */
+        ST_MEMCPY(values, (tmp + ST25R3916_REG_LEN), length);
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WritePTMemF(const uint8_t* values, uint16_t length) {
+    if(length > (ST25R3916_PTM_F_LEN + ST25R3916_PTM_TSN_LEN)) {
+        return ERR_PARAM;
+    }
+
+    if(length > 0U) {
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_PT_F_CONFIG_LOAD, false, true);
+        st25r3916comTx(values, length, true, true);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WritePTMemTSN(const uint8_t* values, uint16_t length) {
+    if(length > ST25R3916_PTM_TSN_LEN) {
+        return ERR_PARAM;
+    }
+
+    if(length > 0U) {
+        st25r3916comStart();
+        st25r3916comTxByte(ST25R3916_PT_TSN_DATA_LOAD, false, true);
+        st25r3916comTx(values, length, true, true);
+        st25r3916comStop();
+    }
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ExecuteCommand(uint8_t cmd) {
+    st25r3916comStart();
+    st25r3916comTxByte((cmd | ST25R3916_CMD_MODE), true, true);
+    st25r3916comStop();
+
+    /* Send a cmd event to LED handling */
+    st25r3916ledEvtCmd(cmd);
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ReadTestRegister(uint8_t reg, uint8_t* val) {
+    st25r3916comStart();
+    st25r3916comTxByte(ST25R3916_CMD_TEST_ACCESS, false, false);
+    st25r3916comTxByte((reg | ST25R3916_READ_MODE), true, false);
+    st25r3916comRepeatStart();
+    st25r3916comRx(val, ST25R3916_REG_LEN);
+    st25r3916comStop();
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916WriteTestRegister(uint8_t reg, uint8_t val) {
+    uint8_t value = val; /* MISRA 17.8: use intermediate variable */
+
+    st25r3916comStart();
+    st25r3916comTxByte(ST25R3916_CMD_TEST_ACCESS, false, true);
+    st25r3916comTxByte((reg | ST25R3916_WRITE_MODE), false, true);
+    st25r3916comTx(&value, ST25R3916_REG_LEN, true, true);
+    st25r3916comStop();
+
+    return ERR_NONE;
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ClrRegisterBits(uint8_t reg, uint8_t clr_mask) {
+    ReturnCode ret;
+    uint8_t rdVal;
+
+    /* Read current reg value */
+    EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
+
+    /* Only perform a Write if value to be written is different */
+    if(ST25R3916_OPTIMIZE && (rdVal == (uint8_t)(rdVal & ~clr_mask))) {
+        return ERR_NONE;
+    }
+
+    /* Write new reg value */
+    return st25r3916WriteRegister(reg, (uint8_t)(rdVal & ~clr_mask));
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916SetRegisterBits(uint8_t reg, uint8_t set_mask) {
+    ReturnCode ret;
+    uint8_t rdVal;
+
+    /* Read current reg value */
+    EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
+
+    /* Only perform a Write if the value to be written is different */
+    if(ST25R3916_OPTIMIZE && (rdVal == (rdVal | set_mask))) {
+        return ERR_NONE;
+    }
+
+    /* Write new reg value */
+    return st25r3916WriteRegister(reg, (rdVal | set_mask));
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value) {
+    return st25r3916ModifyRegister(reg, valueMask, (valueMask & value));
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask) {
+    ReturnCode ret;
+    uint8_t rdVal;
+    uint8_t wrVal;
+
+    /* Read current reg value */
+    EXIT_ON_ERR(ret, st25r3916ReadRegister(reg, &rdVal));
+
+    /* Compute new value */
+    wrVal = (uint8_t)(rdVal & ~clr_mask);
+    wrVal |= set_mask;
+
+    /* Only perform a Write if the value to be written is different */
+    if(ST25R3916_OPTIMIZE && (rdVal == wrVal)) {
+        return ERR_NONE;
+    }
+
+    /* Write new reg value */
+    return st25r3916WriteRegister(reg, wrVal);
+}
+
+/*******************************************************************************/
+ReturnCode st25r3916ChangeTestRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value) {
+    ReturnCode ret;
+    uint8_t rdVal;
+    uint8_t wrVal;
+
+    /* Read current reg value */
+    EXIT_ON_ERR(ret, st25r3916ReadTestRegister(reg, &rdVal));
+
+    /* Compute new value */
+    wrVal = (uint8_t)(rdVal & ~valueMask);
+    wrVal |= (uint8_t)(value & valueMask);
+
+    /* Only perform a Write if the value to be written is different */
+    if(ST25R3916_OPTIMIZE && (rdVal == wrVal)) {
+        return ERR_NONE;
+    }
+
+    /* Write new reg value */
+    return st25r3916WriteTestRegister(reg, wrVal);
+}
+
+/*******************************************************************************/
+bool st25r3916CheckReg(uint8_t reg, uint8_t mask, uint8_t val) {
+    uint8_t regVal;
+
+    regVal = 0;
+    st25r3916ReadRegister(reg, &regVal);
+
+    return ((regVal & mask) == val);
+}
+
+/*******************************************************************************/
+bool st25r3916IsRegValid(uint8_t reg) {
+#pragma GCC diagnostic ignored "-Wtype-limits"
+    if(!(((int16_t)reg >= (int32_t)ST25R3916_REG_IO_CONF1) &&
+         (reg <= (ST25R3916_SPACE_B | ST25R3916_REG_IC_IDENTITY)))) {
+        return false;
+    }
+    return true;
+}

+ 1384 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_com.h

@@ -0,0 +1,1384 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 communication declaration file
+ *  
+ *  This driver provides basic abstraction for communication with the ST25R3916
+ *  
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25R3916
+ * \brief RFAL ST25R3916 Driver
+ * @{
+ * 
+ * \addtogroup ST25R3916_COM
+ * \brief RFAL ST25R3916 Communications
+ * @{
+ * 
+ */
+
+#ifndef ST25R3916_COM_H
+#define ST25R3916_COM_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "../../platform.h"
+#include "../../st_errno.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+#define ST25R3916_SPACE_B 0x40U /*!< ST25R3916 Space-B indicator                          */
+#define ST25R3916_SPACE_B_REG_LEN 16U /*!< Number of register in the space B                    */
+
+#define ST25R3916_FIFO_STATUS_LEN 2 /*!< Number of FIFO Status Register                       */
+
+#define ST25R3916_PTM_A_LEN 15U /*!< Passive target memory A config length                */
+#define ST25R3916_PTM_B_LEN 0U /*!< Passive target memory B config length                */
+#define ST25R3916_PTM_F_LEN 21U /*!< Passive target memory F config length                */
+#define ST25R3916_PTM_TSN_LEN 12U /*!< Passive target memory TSN data length                */
+
+/*! Full Passive target memory length */
+#define ST25R3916_PTM_LEN \
+    (ST25R3916_PTM_A_LEN + ST25R3916_PTM_B_LEN + ST25R3916_PTM_F_LEN + ST25R3916_PTM_TSN_LEN)
+
+/* IO configuration registers */
+#define ST25R3916_REG_IO_CONF1 0x00U /*!< RW IO Configuration Register 1                       */
+#define ST25R3916_REG_IO_CONF2 0x01U /*!< RW IO Configuration Register 2                       */
+
+/* Operation control and mode definition registers */
+#define ST25R3916_REG_OP_CONTROL 0x02U /*!< RW Operation Control Register                        */
+#define ST25R3916_REG_MODE 0x03U /*!< RW Mode Definition Register                          */
+#define ST25R3916_REG_BIT_RATE 0x04U /*!< RW Bit Rate Definition Register                      */
+
+/* Protocol Configuration registers */
+#define ST25R3916_REG_ISO14443A_NFC \
+    0x05U /*!< RW ISO14443A and NFC 106 kBit/s Settings Register    */
+#define ST25R3916_REG_EMD_SUP_CONF \
+    (ST25R3916_SPACE_B | 0x05U) /*!< RW EMD Suppression Configuration Register            */
+#define ST25R3916_REG_ISO14443B_1 \
+    0x06U /*!< RW ISO14443B Settings Register 1                     */
+#define ST25R3916_REG_SUBC_START_TIME \
+    (ST25R3916_SPACE_B | 0x06U) /*!< RW Subcarrier Start Time Register                    */
+#define ST25R3916_REG_ISO14443B_2 \
+    0x07U /*!< RW ISO14443B Settings Register 2                     */
+#define ST25R3916_REG_PASSIVE_TARGET \
+    0x08U /*!< RW Passive Target Definition Register                */
+#define ST25R3916_REG_STREAM_MODE \
+    0x09U /*!< RW Stream Mode Definition Register                   */
+#define ST25R3916_REG_AUX 0x0AU /*!< RW Auxiliary Definition Register                     */
+
+/* Receiver Configuration registers */
+#define ST25R3916_REG_RX_CONF1 0x0BU /*!< RW Receiver Configuration Register 1                 */
+#define ST25R3916_REG_RX_CONF2 0x0CU /*!< RW Receiver Configuration Register 2                 */
+#define ST25R3916_REG_RX_CONF3 0x0DU /*!< RW Receiver Configuration Register 3                 */
+#define ST25R3916_REG_RX_CONF4 0x0EU /*!< RW Receiver Configuration Register 4                 */
+#define ST25R3916_REG_P2P_RX_CONF \
+    (ST25R3916_SPACE_B | 0x0BU) /*!< RW P2P Receiver Configuration Register 1             */
+#define ST25R3916_REG_CORR_CONF1 \
+    (ST25R3916_SPACE_B | 0x0CU) /*!< RW Correlator configuration register 1               */
+#define ST25R3916_REG_CORR_CONF2 \
+    (ST25R3916_SPACE_B | 0x0DU) /*!< RW Correlator configuration register 2               */
+
+/* Timer definition registers */
+#define ST25R3916_REG_MASK_RX_TIMER \
+    0x0FU /*!< RW Mask Receive Timer Register                       */
+#define ST25R3916_REG_NO_RESPONSE_TIMER1 \
+    0x10U /*!< RW No-response Timer Register 1                      */
+#define ST25R3916_REG_NO_RESPONSE_TIMER2 \
+    0x11U /*!< RW No-response Timer Register 2                      */
+#define ST25R3916_REG_TIMER_EMV_CONTROL \
+    0x12U /*!< RW Timer and EMV Control                             */
+#define ST25R3916_REG_GPT1 0x13U /*!< RW General Purpose Timer Register 1                  */
+#define ST25R3916_REG_GPT2 0x14U /*!< RW General Purpose Timer Register 2                  */
+#define ST25R3916_REG_PPON2 0x15U /*!< RW PPON2 Field waiting Timer Register                */
+#define ST25R3916_REG_SQUELCH_TIMER \
+    (ST25R3916_SPACE_B | 0x0FU) /*!< RW Squelch timeout Register                          */
+#define ST25R3916_REG_FIELD_ON_GT \
+    (ST25R3916_SPACE_B | 0x15U) /*!< RW NFC Field on guard time                           */
+
+/* Interrupt and associated reporting registers */
+#define ST25R3916_REG_IRQ_MASK_MAIN \
+    0x16U /*!< RW Mask Main Interrupt Register                      */
+#define ST25R3916_REG_IRQ_MASK_TIMER_NFC \
+    0x17U /*!< RW Mask Timer and NFC Interrupt Register             */
+#define ST25R3916_REG_IRQ_MASK_ERROR_WUP \
+    0x18U /*!< RW Mask Error and Wake-up Interrupt Register         */
+#define ST25R3916_REG_IRQ_MASK_TARGET \
+    0x19U /*!< RW Mask 3916 Target Interrupt Register               */
+#define ST25R3916_REG_IRQ_MAIN 0x1AU /*!< R  Main Interrupt Register                           */
+#define ST25R3916_REG_IRQ_TIMER_NFC \
+    0x1BU /*!< R  Timer and NFC Interrupt Register                  */
+#define ST25R3916_REG_IRQ_ERROR_WUP \
+    0x1CU /*!< R  Error and Wake-up Interrupt Register              */
+#define ST25R3916_REG_IRQ_TARGET 0x1DU /*!< R  ST25R3916 Target Interrupt Register               */
+#define ST25R3916_REG_FIFO_STATUS1 \
+    0x1EU /*!< R  FIFO Status Register 1                            */
+#define ST25R3916_REG_FIFO_STATUS2 \
+    0x1FU /*!< R  FIFO Status Register 2                            */
+#define ST25R3916_REG_COLLISION_STATUS \
+    0x20U /*!< R  Collision Display Register                        */
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS \
+    0x21U /*!< R  Passive target state status                       */
+
+/* Definition of number of transmitted bytes */
+#define ST25R3916_REG_NUM_TX_BYTES1 \
+    0x22U /*!< RW Number of Transmitted Bytes Register 1            */
+#define ST25R3916_REG_NUM_TX_BYTES2 \
+    0x23U /*!< RW Number of Transmitted Bytes Register 2            */
+
+/* NFCIP Bit Rate Display Register */
+#define ST25R3916_REG_NFCIP1_BIT_RATE \
+    0x24U /*!< R  NFCIP Bit Rate Detection Display Register         */
+
+/* A/D Converter Output Register */
+#define ST25R3916_REG_AD_RESULT 0x25U /*!< R  A/D Converter Output Register                     */
+
+/* Antenna tuning registers */
+#define ST25R3916_REG_ANT_TUNE_A 0x26U /*!< RW Antenna Tuning Control (AAT-A) Register 1         */
+#define ST25R3916_REG_ANT_TUNE_B 0x27U /*!< RW Antenna Tuning Control (AAT-B) Register 2         */
+
+/* Antenna Driver and Modulation registers */
+#define ST25R3916_REG_TX_DRIVER 0x28U /*!< RW TX driver register                                */
+#define ST25R3916_REG_PT_MOD 0x29U /*!< RW PT modulation Register                            */
+#define ST25R3916_REG_AUX_MOD \
+    (ST25R3916_SPACE_B | 0x28U) /*!< RW Aux Modulation setting Register                   */
+#define ST25R3916_REG_TX_DRIVER_TIMING \
+    (ST25R3916_SPACE_B | 0x29U) /*!< RW TX driver timing Register                         */
+#define ST25R3916_REG_RES_AM_MOD \
+    (ST25R3916_SPACE_B | 0x2AU) /*!< RW Resistive AM modulation register                  */
+#define ST25R3916_REG_TX_DRIVER_STATUS \
+    (ST25R3916_SPACE_B | 0x2BU) /*!< R  TX driver timing readout Register                 */
+
+/* External Field Detector Threshold Registers */
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV \
+    0x2AU /*!< RW External Field Detector Activation Threshold Reg  */
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV \
+    0x2BU /*!< RW External Field Detector Deactivation Threshold Reg*/
+
+/* Regulator registers */
+#define ST25R3916_REG_REGULATOR_CONTROL \
+    0x2CU /*!< RW Regulated Voltage Control Register                */
+#define ST25R3916_REG_REGULATOR_RESULT \
+    (ST25R3916_SPACE_B | 0x2CU) /*!< R Regulator Display Register                         */
+
+/* Receiver State Display Register */
+#define ST25R3916_REG_RSSI_RESULT \
+    0x2DU /*!< R RSSI Display Register                              */
+#define ST25R3916_REG_GAIN_RED_STATE \
+    0x2EU /*!< R Gain Reduction State Register                      */
+#define ST25R3916_REG_CAP_SENSOR_CONTROL \
+    0x2FU /*!< RW Capacitive Sensor Control Register                */
+#define ST25R3916_REG_CAP_SENSOR_RESULT \
+    0x30U /*!< R  Capacitive Sensor Display Register                */
+#define ST25R3916_REG_AUX_DISPLAY \
+    0x31U /*!< R Auxiliary Display Register                         */
+
+/* Over/Undershoot Protection Configuration Registers */
+#define ST25R3916_REG_OVERSHOOT_CONF1 \
+    (ST25R3916_SPACE_B | 0x30U) /*!< RW  Overshoot Protection Configuration Register 1    */
+#define ST25R3916_REG_OVERSHOOT_CONF2 \
+    (ST25R3916_SPACE_B | 0x31U) /*!< RW  Overshoot Protection Configuration Register 2    */
+#define ST25R3916_REG_UNDERSHOOT_CONF1 \
+    (ST25R3916_SPACE_B | 0x32U) /*!< RW  Undershoot Protection Configuration Register 1   */
+#define ST25R3916_REG_UNDERSHOOT_CONF2 \
+    (ST25R3916_SPACE_B | 0x33U) /*!< RW  Undershoot Protection Configuration Register 2   */
+
+/* Detection of card presence */
+#define ST25R3916_REG_WUP_TIMER_CONTROL \
+    0x32U /*!< RW Wake-up Timer Control Register                    */
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF \
+    0x33U /*!< RW Amplitude Measurement Configuration Register      */
+#define ST25R3916_REG_AMPLITUDE_MEASURE_REF \
+    0x34U /*!< RW Amplitude Measurement Reference Register          */
+#define ST25R3916_REG_AMPLITUDE_MEASURE_AA_RESULT \
+    0x35U /*!< R  Amplitude Measurement Auto Averaging Display Reg  */
+#define ST25R3916_REG_AMPLITUDE_MEASURE_RESULT \
+    0x36U /*!< R  Amplitude Measurement Display Register            */
+#define ST25R3916_REG_PHASE_MEASURE_CONF \
+    0x37U /*!< RW Phase Measurement Configuration Register          */
+#define ST25R3916_REG_PHASE_MEASURE_REF \
+    0x38U /*!< RW Phase Measurement Reference Register              */
+#define ST25R3916_REG_PHASE_MEASURE_AA_RESULT \
+    0x39U /*!< R  Phase Measurement Auto Averaging Display Register */
+#define ST25R3916_REG_PHASE_MEASURE_RESULT \
+    0x3AU /*!< R  Phase Measurement Display Register                */
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF \
+    0x3BU /*!< RW Capacitance Measurement Configuration Register    */
+#define ST25R3916_REG_CAPACITANCE_MEASURE_REF \
+    0x3CU /*!< RW Capacitance Measurement Reference Register        */
+#define ST25R3916_REG_CAPACITANCE_MEASURE_AA_RESULT \
+    0x3DU /*!< R  Capacitance Measurement Auto Averaging Display Reg*/
+#define ST25R3916_REG_CAPACITANCE_MEASURE_RESULT \
+    0x3EU /*!< R  Capacitance Measurement Display Register          */
+
+/* IC identity  */
+#define ST25R3916_REG_IC_IDENTITY \
+    0x3FU /*!< R  Chip Id: 0 for old silicon, v2 silicon: 0x09      */
+
+/*! Register bit definitions  \cond DOXYGEN_SUPRESS */
+
+#define ST25R3916_REG_IO_CONF1_single (1U << 7)
+#define ST25R3916_REG_IO_CONF1_rfo2 (1U << 6)
+#define ST25R3916_REG_IO_CONF1_i2c_thd1 (1U << 5)
+#define ST25R3916_REG_IO_CONF1_i2c_thd0 (1U << 4)
+#define ST25R3916_REG_IO_CONF1_i2c_thd_mask (3U << 4)
+#define ST25R3916_REG_IO_CONF1_i2c_thd_shift (4U)
+#define ST25R3916_REG_IO_CONF1_rfu (1U << 3)
+#define ST25R3916_REG_IO_CONF1_out_cl1 (1U << 2)
+#define ST25R3916_REG_IO_CONF1_out_cl0 (1U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_disabled (3U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_13_56MHZ (2U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_4_78MHZ (1U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_3_39MHZ (0U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_mask (3U << 1)
+#define ST25R3916_REG_IO_CONF1_out_cl_shift (1U)
+#define ST25R3916_REG_IO_CONF1_lf_clk_off (1U << 0)
+#define ST25R3916_REG_IO_CONF1_lf_clk_off_on (1U << 0)
+#define ST25R3916_REG_IO_CONF1_lf_clk_off_off (0U << 0)
+
+#define ST25R3916_REG_IO_CONF2_sup3V (1U << 7)
+#define ST25R3916_REG_IO_CONF2_sup3V_3V (1U << 7)
+#define ST25R3916_REG_IO_CONF2_sup3V_5V (0U << 7)
+#define ST25R3916_REG_IO_CONF2_vspd_off (1U << 6)
+#define ST25R3916_REG_IO_CONF2_aat_en (1U << 5)
+#define ST25R3916_REG_IO_CONF2_miso_pd2 (1U << 4)
+#define ST25R3916_REG_IO_CONF2_miso_pd1 (1U << 3)
+#define ST25R3916_REG_IO_CONF2_io_drv_lvl (1U << 2)
+#define ST25R3916_REG_IO_CONF2_slow_up (1U << 0)
+
+#define ST25R3916_REG_OP_CONTROL_en (1U << 7)
+#define ST25R3916_REG_OP_CONTROL_rx_en (1U << 6)
+#define ST25R3916_REG_OP_CONTROL_rx_chn (1U << 5)
+#define ST25R3916_REG_OP_CONTROL_rx_man (1U << 4)
+#define ST25R3916_REG_OP_CONTROL_tx_en (1U << 3)
+#define ST25R3916_REG_OP_CONTROL_wu (1U << 2)
+#define ST25R3916_REG_OP_CONTROL_en_fd_c1 (1U << 1)
+#define ST25R3916_REG_OP_CONTROL_en_fd_c0 (1U << 0)
+#define ST25R3916_REG_OP_CONTROL_en_fd_efd_off (0U << 0)
+#define ST25R3916_REG_OP_CONTROL_en_fd_manual_efd_ca (1U << 0)
+#define ST25R3916_REG_OP_CONTROL_en_fd_manual_efd_pdt (2U << 0)
+#define ST25R3916_REG_OP_CONTROL_en_fd_auto_efd (3U << 0)
+#define ST25R3916_REG_OP_CONTROL_en_fd_shift (0U)
+#define ST25R3916_REG_OP_CONTROL_en_fd_mask (3U << 0)
+
+#define ST25R3916_REG_MODE_targ (1U << 7)
+#define ST25R3916_REG_MODE_targ_targ (1U << 7)
+#define ST25R3916_REG_MODE_targ_init (0U << 7)
+#define ST25R3916_REG_MODE_om3 (1U << 6)
+#define ST25R3916_REG_MODE_om2 (1U << 5)
+#define ST25R3916_REG_MODE_om1 (1U << 4)
+#define ST25R3916_REG_MODE_om0 (1U << 3)
+#define ST25R3916_REG_MODE_om_bpsk_stream (0xfU << 3)
+#define ST25R3916_REG_MODE_om_subcarrier_stream (0xeU << 3)
+#define ST25R3916_REG_MODE_om_topaz (0x4U << 3)
+#define ST25R3916_REG_MODE_om_felica (0x3U << 3)
+#define ST25R3916_REG_MODE_om_iso14443b (0x2U << 3)
+#define ST25R3916_REG_MODE_om_iso14443a (0x1U << 3)
+#define ST25R3916_REG_MODE_om_targ_nfca (0x1U << 3)
+#define ST25R3916_REG_MODE_om_targ_nfcb (0x2U << 3)
+#define ST25R3916_REG_MODE_om_targ_nfcf (0x4U << 3)
+#define ST25R3916_REG_MODE_om_targ_nfcip (0x7U << 3)
+#define ST25R3916_REG_MODE_om_nfc (0x0U << 3)
+#define ST25R3916_REG_MODE_om_mask (0xfU << 3)
+#define ST25R3916_REG_MODE_om_shift (3U)
+#define ST25R3916_REG_MODE_tr_am (1U << 2)
+#define ST25R3916_REG_MODE_tr_am_ook (0U << 2)
+#define ST25R3916_REG_MODE_tr_am_am (1U << 2)
+#define ST25R3916_REG_MODE_nfc_ar1 (1U << 1)
+#define ST25R3916_REG_MODE_nfc_ar0 (1U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_off (0U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_auto_rx (1U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_eof (2U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_rfu (3U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_mask (3U << 0)
+#define ST25R3916_REG_MODE_nfc_ar_shift (0U)
+
+#define ST25R3916_REG_BIT_RATE_txrate_106 (0x0U << 4)
+#define ST25R3916_REG_BIT_RATE_txrate_212 (0x1U << 4)
+#define ST25R3916_REG_BIT_RATE_txrate_424 (0x2U << 4)
+#define ST25R3916_REG_BIT_RATE_txrate_848 (0x3U << 4)
+#define ST25R3916_REG_BIT_RATE_txrate_mask (0x3U << 4)
+#define ST25R3916_REG_BIT_RATE_txrate_shift (4U)
+#define ST25R3916_REG_BIT_RATE_rxrate_106 (0x0U << 0)
+#define ST25R3916_REG_BIT_RATE_rxrate_212 (0x1U << 0)
+#define ST25R3916_REG_BIT_RATE_rxrate_424 (0x2U << 0)
+#define ST25R3916_REG_BIT_RATE_rxrate_848 (0x3U << 0)
+#define ST25R3916_REG_BIT_RATE_rxrate_mask (0x3U << 0)
+#define ST25R3916_REG_BIT_RATE_rxrate_shift (0U)
+
+#define ST25R3916_REG_ISO14443A_NFC_no_tx_par (1U << 7)
+#define ST25R3916_REG_ISO14443A_NFC_no_tx_par_off (0U << 7)
+#define ST25R3916_REG_ISO14443A_NFC_no_rx_par (1U << 6)
+#define ST25R3916_REG_ISO14443A_NFC_no_rx_par_off (0U << 6)
+#define ST25R3916_REG_ISO14443A_NFC_nfc_f0 (1U << 5)
+#define ST25R3916_REG_ISO14443A_NFC_nfc_f0_off (0U << 5)
+#define ST25R3916_REG_ISO14443A_NFC_p_len3 (1U << 4)
+#define ST25R3916_REG_ISO14443A_NFC_p_len2 (1U << 3)
+#define ST25R3916_REG_ISO14443A_NFC_p_len1 (1U << 2)
+#define ST25R3916_REG_ISO14443A_NFC_p_len0 (1U << 1)
+#define ST25R3916_REG_ISO14443A_NFC_p_len_mask (0xfU << 1)
+#define ST25R3916_REG_ISO14443A_NFC_p_len_shift (1U)
+#define ST25R3916_REG_ISO14443A_NFC_antcl (1U << 0)
+
+#define ST25R3916_REG_EMD_SUP_CONF_emd_emv (1U << 7)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_emv_on (1U << 7)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_emv_off (0U << 7)
+#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv (1U << 6)
+#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on (1U << 6)
+#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_off (0U << 6)
+#define ST25R3916_REG_EMD_SUP_CONF_rfu1 (1U << 5)
+#define ST25R3916_REG_EMD_SUP_CONF_rfu0 (1U << 4)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld3 (1U << 3)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld2 (1U << 2)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld1 (1U << 1)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld0 (1U << 0)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld_mask (0xfU << 0)
+#define ST25R3916_REG_EMD_SUP_CONF_emd_thld_shift (0U)
+
+#define ST25R3916_REG_SUBC_START_TIME_rfu2 (1U << 7)
+#define ST25R3916_REG_SUBC_START_TIME_rfu1 (1U << 6)
+#define ST25R3916_REG_SUBC_START_TIME_rfu0 (1U << 5)
+#define ST25R3916_REG_SUBC_START_TIME_sst4 (1U << 4)
+#define ST25R3916_REG_SUBC_START_TIME_sst3 (1U << 3)
+#define ST25R3916_REG_SUBC_START_TIME_sst2 (1U << 2)
+#define ST25R3916_REG_SUBC_START_TIME_sst1 (1U << 1)
+#define ST25R3916_REG_SUBC_START_TIME_sst0 (1U << 0)
+#define ST25R3916_REG_SUBC_START_TIME_sst_mask (0x1fU << 0)
+#define ST25R3916_REG_SUBC_START_TIME_sst_shift (0U)
+
+#define ST25R3916_REG_ISO14443B_1_egt2 (1U << 7)
+#define ST25R3916_REG_ISO14443B_1_egt1 (1U << 6)
+#define ST25R3916_REG_ISO14443B_1_egt0 (1U << 5)
+#define ST25R3916_REG_ISO14443B_1_egt_shift (5U)
+#define ST25R3916_REG_ISO14443B_1_egt_mask (7U << 5)
+#define ST25R3916_REG_ISO14443B_1_sof_1 (1U << 3)
+#define ST25R3916_REG_ISO14443B_1_sof_1_3etu (1U << 3)
+#define ST25R3916_REG_ISO14443B_1_sof_1_2etu (0U << 3)
+#define ST25R3916_REG_ISO14443B_1_sof_0 (1U << 4)
+#define ST25R3916_REG_ISO14443B_1_sof_0_11etu (1U << 4)
+#define ST25R3916_REG_ISO14443B_1_sof_0_10etu (0U << 4)
+#define ST25R3916_REG_ISO14443B_1_sof_mask (3U << 3)
+#define ST25R3916_REG_ISO14443B_1_eof (1U << 2)
+#define ST25R3916_REG_ISO14443B_1_eof_11etu (1U << 2)
+#define ST25R3916_REG_ISO14443B_1_eof_10etu (0U << 2)
+#define ST25R3916_REG_ISO14443B_1_half (1U << 1)
+#define ST25R3916_REG_ISO14443B_1_rx_st_om (1U << 0)
+
+#define ST25R3916_REG_ISO14443B_2_tr1_1 (1U << 7)
+#define ST25R3916_REG_ISO14443B_2_tr1_0 (1U << 6)
+#define ST25R3916_REG_ISO14443B_2_tr1_64fs32fs (1U << 6)
+#define ST25R3916_REG_ISO14443B_2_tr1_80fs80fs (0U << 6)
+#define ST25R3916_REG_ISO14443B_2_tr1_mask (3U << 6)
+#define ST25R3916_REG_ISO14443B_2_tr1_shift (6U)
+#define ST25R3916_REG_ISO14443B_2_no_sof (1U << 5)
+#define ST25R3916_REG_ISO14443B_2_no_eof (1U << 4)
+#define ST25R3916_REG_ISO14443B_rfu1 (1U << 3)
+#define ST25R3916_REG_ISO14443B_rfu0 (1U << 2)
+#define ST25R3916_REG_ISO14443B_2_f_p1 (1U << 1)
+#define ST25R3916_REG_ISO14443B_2_f_p0 (1U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_96 (3U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_80 (2U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_64 (1U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_48 (0U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_mask (3U << 0)
+#define ST25R3916_REG_ISO14443B_2_f_p_shift (0U)
+
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_3 (1U << 7)
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_2 (1U << 6)
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_1 (1U << 5)
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_0 (1U << 4)
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_mask (0xfU << 4)
+#define ST25R3916_REG_PASSIVE_TARGET_fdel_shift (4U)
+#define ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p (1U << 3)
+#define ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r (1U << 2)
+#define ST25R3916_REG_PASSIVE_TARGET_rfu (1U << 1)
+#define ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a (1U << 0)
+
+#define ST25R3916_REG_STREAM_MODE_rfu (1U << 7)
+#define ST25R3916_REG_STREAM_MODE_scf1 (1U << 6)
+#define ST25R3916_REG_STREAM_MODE_scf0 (1U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_sc212 (0U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_sc424 (1U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_sc848 (2U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_sc1695 (3U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_bpsk848 (0U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_bpsk1695 (1U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_bpsk3390 (2U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_bpsk106 (3U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_mask (3U << 5)
+#define ST25R3916_REG_STREAM_MODE_scf_shift (5U)
+#define ST25R3916_REG_STREAM_MODE_scp1 (1U << 4)
+#define ST25R3916_REG_STREAM_MODE_scp0 (1U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_1pulse (0U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_2pulses (1U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_4pulses (2U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_8pulses (3U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_mask (3U << 3)
+#define ST25R3916_REG_STREAM_MODE_scp_shift (3U)
+#define ST25R3916_REG_STREAM_MODE_stx2 (1U << 2)
+#define ST25R3916_REG_STREAM_MODE_stx1 (1U << 1)
+#define ST25R3916_REG_STREAM_MODE_stx0 (1U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_106 (0U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_212 (1U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_424 (2U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_848 (3U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_mask (7U << 0)
+#define ST25R3916_REG_STREAM_MODE_stx_shift (0U)
+
+#define ST25R3916_REG_AUX_no_crc_rx (1U << 7)
+#define ST25R3916_REG_AUX_rfu (1U << 6)
+#define ST25R3916_REG_AUX_nfc_id1 (1U << 5)
+#define ST25R3916_REG_AUX_nfc_id0 (1U << 4)
+#define ST25R3916_REG_AUX_nfc_id_7bytes (1U << 4)
+#define ST25R3916_REG_AUX_nfc_id_4bytes (0U << 4)
+#define ST25R3916_REG_AUX_nfc_id_mask (3U << 4)
+#define ST25R3916_REG_AUX_nfc_id_shift (4U)
+#define ST25R3916_REG_AUX_mfaz_cl90 (1U << 3)
+#define ST25R3916_REG_AUX_dis_corr (1U << 2)
+#define ST25R3916_REG_AUX_dis_corr_coherent (1U << 2)
+#define ST25R3916_REG_AUX_dis_corr_correlator (0U << 2)
+#define ST25R3916_REG_AUX_nfc_n1 (1U << 1)
+#define ST25R3916_REG_AUX_nfc_n0 (1U << 0)
+#define ST25R3916_REG_AUX_nfc_n_mask (3U << 0)
+#define ST25R3916_REG_AUX_nfc_n_shift (0U)
+
+#define ST25R3916_REG_RX_CONF1_ch_sel (1U << 7)
+#define ST25R3916_REG_RX_CONF1_ch_sel_PM (1U << 7)
+#define ST25R3916_REG_RX_CONF1_ch_sel_AM (0U << 7)
+#define ST25R3916_REG_RX_CONF1_lp2 (1U << 6)
+#define ST25R3916_REG_RX_CONF1_lp1 (1U << 5)
+#define ST25R3916_REG_RX_CONF1_lp0 (1U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_1200khz (0U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_600khz (1U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_300khz (2U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_2000khz (4U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_7000khz (5U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_mask (7U << 4)
+#define ST25R3916_REG_RX_CONF1_lp_shift (4U)
+#define ST25R3916_REG_RX_CONF1_z600k (1U << 3)
+#define ST25R3916_REG_RX_CONF1_h200 (1U << 2)
+#define ST25R3916_REG_RX_CONF1_h80 (1U << 1)
+#define ST25R3916_REG_RX_CONF1_z12k (1U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_60_400khz (0U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_60_200khz (4U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_40_80khz (2U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_12_200khz (1U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_12_80khz (3U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_12_200khz_alt (5U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_600_400khz (8U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_600_200khz (12U << 0)
+#define ST25R3916_REG_RX_CONF1_hz_mask (0xfU << 0)
+#define ST25R3916_REG_RX_CONF1_hz_shift (0U)
+
+#define ST25R3916_REG_RX_CONF2_demod_mode (1U << 7)
+#define ST25R3916_REG_RX_CONF2_amd_sel (1U << 6)
+#define ST25R3916_REG_RX_CONF2_amd_sel_mixer (1U << 6)
+#define ST25R3916_REG_RX_CONF2_amd_sel_peak (0U << 6)
+#define ST25R3916_REG_RX_CONF2_sqm_dyn (1U << 5)
+#define ST25R3916_REG_RX_CONF2_pulz_61 (1U << 4)
+#define ST25R3916_REG_RX_CONF2_agc_en (1U << 3)
+#define ST25R3916_REG_RX_CONF2_agc_m (1U << 2)
+#define ST25R3916_REG_RX_CONF2_agc_alg (1U << 1)
+#define ST25R3916_REG_RX_CONF2_agc6_3 (1U << 0)
+
+#define ST25R3916_REG_RX_CONF3_rg1_am2 (1U << 7)
+#define ST25R3916_REG_RX_CONF3_rg1_am1 (1U << 6)
+#define ST25R3916_REG_RX_CONF3_rg1_am0 (1U << 5)
+#define ST25R3916_REG_RX_CONF3_rg1_am_mask (0x7U << 5)
+#define ST25R3916_REG_RX_CONF3_rg1_am_shift (5U)
+#define ST25R3916_REG_RX_CONF3_rg1_pm2 (1U << 4)
+#define ST25R3916_REG_RX_CONF3_rg1_pm1 (1U << 3)
+#define ST25R3916_REG_RX_CONF3_rg1_pm0 (1U << 2)
+#define ST25R3916_REG_RX_CONF3_rg1_pm_mask (0x7U << 2)
+#define ST25R3916_REG_RX_CONF3_rg1_pm_shift (2U)
+#define ST25R3916_REG_RX_CONF3_lf_en (1U << 1)
+#define ST25R3916_REG_RX_CONF3_lf_op (1U << 0)
+
+#define ST25R3916_REG_RX_CONF4_rg2_am3 (1U << 7)
+#define ST25R3916_REG_RX_CONF4_rg2_am2 (1U << 6)
+#define ST25R3916_REG_RX_CONF4_rg2_am1 (1U << 5)
+#define ST25R3916_REG_RX_CONF4_rg2_am0 (1U << 4)
+#define ST25R3916_REG_RX_CONF4_rg2_am_mask (0xfU << 4)
+#define ST25R3916_REG_RX_CONF4_rg2_am_shift (4U)
+#define ST25R3916_REG_RX_CONF4_rg2_pm3 (1U << 3)
+#define ST25R3916_REG_RX_CONF4_rg2_pm2 (1U << 2)
+#define ST25R3916_REG_RX_CONF4_rg2_pm1 (1U << 1)
+#define ST25R3916_REG_RX_CONF4_rg2_pm0 (1U << 0)
+#define ST25R3916_REG_RX_CONF4_rg2_pm_mask (0xfU << 0)
+#define ST25R3916_REG_RX_CONF4_rg2_pm_shift (0U)
+
+#define ST25R3916_REG_P2P_RX_CONF_ook_fd (1U << 7)
+#define ST25R3916_REG_P2P_RX_CONF_ook_rc1 (1U << 6)
+#define ST25R3916_REG_P2P_RX_CONF_ook_rc0 (1U << 5)
+#define ST25R3916_REG_P2P_RX_CONF_ook_thd1 (1U << 4)
+#define ST25R3916_REG_P2P_RX_CONF_ook_thd0 (1U << 3)
+#define ST25R3916_REG_P2P_RX_CONF_ask_rc1 (1U << 2)
+#define ST25R3916_REG_P2P_RX_CONF_ask_rc0 (1U << 1)
+#define ST25R3916_REG_P2P_RX_CONF_ask_thd (1U << 0)
+
+#define ST25R3916_REG_CORR_CONF1_corr_s7 (1U << 7)
+#define ST25R3916_REG_CORR_CONF1_corr_s6 (1U << 6)
+#define ST25R3916_REG_CORR_CONF1_corr_s5 (1U << 5)
+#define ST25R3916_REG_CORR_CONF1_corr_s4 (1U << 4)
+#define ST25R3916_REG_CORR_CONF1_corr_s3 (1U << 3)
+#define ST25R3916_REG_CORR_CONF1_corr_s2 (1U << 2)
+#define ST25R3916_REG_CORR_CONF1_corr_s1 (1U << 1)
+#define ST25R3916_REG_CORR_CONF1_corr_s0 (1U << 0)
+
+#define ST25R3916_REG_CORR_CONF2_rfu5 (1U << 7)
+#define ST25R3916_REG_CORR_CONF2_rfu4 (1U << 6)
+#define ST25R3916_REG_CORR_CONF2_rfu3 (1U << 5)
+#define ST25R3916_REG_CORR_CONF2_rfu2 (1U << 4)
+#define ST25R3916_REG_CORR_CONF2_rfu1 (1U << 3)
+#define ST25R3916_REG_CORR_CONF2_rfu0 (1U << 2)
+#define ST25R3916_REG_CORR_CONF2_corr_s9 (1U << 1)
+#define ST25R3916_REG_CORR_CONF2_corr_s8 (1U << 0)
+
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc2 (1U << 7)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc1 (1U << 6)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc0 (1U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger (0U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx (1U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_srx (2U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc (3U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask (7U << 5)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_shift (5U)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_rfu (1U << 4)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step (1U << 3)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_512 (1U << 3)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_64 (0U << 3)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc (1U << 2)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_on (1U << 2)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off (0U << 2)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv (1U << 1)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_on (1U << 1)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_off (0U << 1)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step (1U << 0)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_64fc (0U << 0)
+#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_4096_fc (1U << 0)
+
+#define ST25R3916_REG_FIFO_STATUS2_fifo_b9 (1U << 7)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_b8 (1U << 6)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_b_mask (3U << 6)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_b_shift (6U)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_unf (1U << 5)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_ovr (1U << 4)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_lb2 (1U << 3)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_lb1 (1U << 2)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_lb0 (1U << 1)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask (7U << 1)
+#define ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift (1U)
+#define ST25R3916_REG_FIFO_STATUS2_np_lb (1U << 0)
+
+#define ST25R3916_REG_COLLISION_STATUS_c_byte3 (1U << 7)
+#define ST25R3916_REG_COLLISION_STATUS_c_byte2 (1U << 6)
+#define ST25R3916_REG_COLLISION_STATUS_c_byte1 (1U << 5)
+#define ST25R3916_REG_COLLISION_STATUS_c_byte0 (1U << 4)
+#define ST25R3916_REG_COLLISION_STATUS_c_byte_mask (0xfU << 4)
+#define ST25R3916_REG_COLLISION_STATUS_c_byte_shift (4U)
+#define ST25R3916_REG_COLLISION_STATUS_c_bit2 (1U << 3)
+#define ST25R3916_REG_COLLISION_STATUS_c_bit1 (1U << 2)
+#define ST25R3916_REG_COLLISION_STATUS_c_bit0 (1U << 1)
+#define ST25R3916_REG_COLLISION_STATUS_c_pb (1U << 0)
+#define ST25R3916_REG_COLLISION_STATUS_c_bit_mask (3U << 1)
+#define ST25R3916_REG_COLLISION_STATUS_c_bit_shift (1U)
+
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu (1U << 7)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu1 (1U << 6)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu2 (1U << 5)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu3 (1U << 4)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state3 (1U << 3)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state2 (1U << 2)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state1 (1U << 1)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state0 (1U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_power_off (0x0U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_idle (0x1U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l1 (0x2U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l2 (0x3U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu4 (0x4U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_active (0x5U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu6 (0x6U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu7 (0x7U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu8 (0x8U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_halt (0x9U << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l1_x (0xaU << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l2_x (0xbU << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu12 (0xcU << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_active_x (0xdU << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state_mask (0xfU << 0)
+#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state_shift (0U)
+
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx4 (1U << 7)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx3 (1U << 6)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx2 (1U << 5)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx1 (1U << 4)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx0 (1U << 3)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx_mask (0x1fU << 3)
+#define ST25R3916_REG_NUM_TX_BYTES2_ntx_shift (3U)
+#define ST25R3916_REG_NUM_TX_BYTES2_nbtx2 (1U << 2)
+#define ST25R3916_REG_NUM_TX_BYTES2_nbtx1 (1U << 1)
+#define ST25R3916_REG_NUM_TX_BYTES2_nbtx0 (1U << 0)
+#define ST25R3916_REG_NUM_TX_BYTES2_nbtx_mask (7U << 0)
+#define ST25R3916_REG_NUM_TX_BYTES2_nbtx_shift (0U)
+
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rfu1 (1U << 7)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rfu0 (1U << 6)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate1 (1U << 5)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate0 (1U << 4)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_mask (0x3U << 4)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift (4U)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_ppt2_on (1U << 3)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on (1U << 2)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on (1U << 1)
+#define ST25R3916_REG_NFCIP1_BIT_RATE_mrt_on (1U << 0)
+
+#define ST25R3916_REG_TX_DRIVER_am_mod3 (1U << 7)
+#define ST25R3916_REG_TX_DRIVER_am_mod2 (1U << 6)
+#define ST25R3916_REG_TX_DRIVER_am_mod1 (1U << 5)
+#define ST25R3916_REG_TX_DRIVER_am_mod0 (1U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_5percent (0x0U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_6percent (0x1U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_7percent (0x2U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_8percent (0x3U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_9percent (0x4U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_10percent (0x5U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_11percent (0x6U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_12percent (0x7U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_13percent (0x8U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_14percent (0x9U << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_15percent (0xaU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_17percent (0xbU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_19percent (0xcU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_22percent (0xdU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_26percent (0xeU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_40percent (0xfU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_mask (0xfU << 4)
+#define ST25R3916_REG_TX_DRIVER_am_mod_shift (4U)
+#define ST25R3916_REG_TX_DRIVER_d_res3 (1U << 3)
+#define ST25R3916_REG_TX_DRIVER_d_res2 (1U << 2)
+#define ST25R3916_REG_TX_DRIVER_d_res1 (1U << 1)
+#define ST25R3916_REG_TX_DRIVER_d_res0 (1U << 0)
+#define ST25R3916_REG_TX_DRIVER_d_res_mask (0xfU << 0)
+#define ST25R3916_REG_TX_DRIVER_d_res_shift (0U)
+
+#define ST25R3916_REG_PT_MOD_ptm_res3 (1U << 7)
+#define ST25R3916_REG_PT_MOD_ptm_res2 (1U << 6)
+#define ST25R3916_REG_PT_MOD_ptm_res1 (1U << 5)
+#define ST25R3916_REG_PT_MOD_ptm_res0 (1U << 4)
+#define ST25R3916_REG_PT_MOD_ptm_res_mask (0xfU << 4)
+#define ST25R3916_REG_PT_MOD_ptm_res_shift (4U)
+#define ST25R3916_REG_PT_MOD_pt_res3 (1U << 3)
+#define ST25R3916_REG_PT_MOD_pt_res2 (1U << 2)
+#define ST25R3916_REG_PT_MOD_pt_res1 (1U << 1)
+#define ST25R3916_REG_PT_MOD_pt_res0 (1U << 0)
+#define ST25R3916_REG_PT_MOD_pt_res_mask (0xfU << 0)
+#define ST25R3916_REG_PT_MOD_pt_res_shift (0U)
+
+#define ST25R3916_REG_AUX_MOD_dis_reg_am (1U << 7)
+#define ST25R3916_REG_AUX_MOD_lm_ext_pol (1U << 6)
+#define ST25R3916_REG_AUX_MOD_lm_ext (1U << 5)
+#define ST25R3916_REG_AUX_MOD_lm_dri (1U << 4)
+#define ST25R3916_REG_AUX_MOD_res_am (1U << 3)
+#define ST25R3916_REG_AUX_MOD_rfu2 (1U << 2)
+#define ST25R3916_REG_AUX_MOD_rfu1 (1U << 1)
+#define ST25R3916_REG_AUX_MOD_rfu0 (1U << 0)
+
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t3 (1U << 7)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t2 (1U << 6)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t1 (1U << 5)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t0 (1U << 4)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_mask (0xfU << 4)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_shift (4U)
+#define ST25R3916_REG_TX_DRIVER_TIMING_rfu (1U << 3)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m2 (1U << 2)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m1 (1U << 1)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m0 (1U << 0)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m_mask (0x7U << 0)
+#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m_shift (0U)
+
+#define ST25R3916_REG_RES_AM_MOD_fa3_f (1U << 7)
+#define ST25R3916_REG_RES_AM_MOD_md_res6 (1U << 6)
+#define ST25R3916_REG_RES_AM_MOD_md_res5 (1U << 5)
+#define ST25R3916_REG_RES_AM_MOD_md_res4 (1U << 4)
+#define ST25R3916_REG_RES_AM_MOD_md_res3 (1U << 3)
+#define ST25R3916_REG_RES_AM_MOD_md_res2 (1U << 2)
+#define ST25R3916_REG_RES_AM_MOD_md_res1 (1U << 1)
+#define ST25R3916_REG_RES_AM_MOD_md_res0 (1U << 0)
+#define ST25R3916_REG_RES_AM_MOD_md_res_mask (0x7FU << 0)
+#define ST25R3916_REG_RES_AM_MOD_md_res_shift (0U)
+
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r3 (1U << 7)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r2 (1U << 6)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r1 (1U << 5)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r0 (1U << 4)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_mask (0xfU << 4)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_shift (4U)
+#define ST25R3916_REG_TX_DRIVER_STATUS_rfu (1U << 3)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r2 (1U << 2)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r1 (1U << 1)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r0 (1U << 0)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_mask (0x7U << 0)
+#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_shift (0U)
+
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l2a (1U << 6)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l1a (1U << 5)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l0a (1U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_75mV (0x0U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV (0x1U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_150mV (0x2U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_205mV (0x3U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_290mV (0x4U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_400mV (0x5U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_560mV (0x6U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_800mV (0x7U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask (7U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_shift (4U)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t3a (1U << 3)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t2a (1U << 2)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t1a (1U << 1)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t0a (1U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_75mV (0x0U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV (0x1U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_150mV (0x2U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_205mV (0x3U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_290mV (0x4U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_400mV (0x5U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_560mV (0x6U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_800mV (0x7U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_25mV (0x8U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_33mV (0x9U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_47mV (0xAU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_64mV (0xBU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_90mV (0xCU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_125mV (0xDU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_175mV (0xEU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_250mV (0xFU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask (0xfU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_shift (0U)
+
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l2d (1U << 6)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l1d (1U << 5)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l0d (1U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV (0x0U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_105mV (0x1U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_150mV (0x2U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_205mV (0x3U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_290mV (0x4U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_400mV (0x5U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_560mV (0x6U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_800mV (0x7U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask (7U << 4)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_shift (4U)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t3d (1U << 3)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t2d (1U << 2)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t1d (1U << 1)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t0d (1U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV (0x0U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_105mV (0x1U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_150mV (0x2U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_205mV (0x3U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_290mV (0x4U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_400mV (0x5U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_560mV (0x6U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_800mV (0x7U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_25mV (0x8U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_33mV (0x9U << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_47mV (0xAU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_64mV (0xBU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_90mV (0xCU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_125mV (0xDU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_175mV (0xEU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_250mV (0xFU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask (0xfU << 0)
+#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_shift (0U)
+
+#define ST25R3916_REG_REGULATOR_CONTROL_reg_s (1U << 7)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_3 (1U << 6)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_2 (1U << 5)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_1 (1U << 4)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_0 (1U << 3)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_mask (0xfU << 3)
+#define ST25R3916_REG_REGULATOR_CONTROL_rege_shift (3U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv2 (2U << 2)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv1 (1U << 1)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv0 (1U << 0)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd (0U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a (1U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d (2U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf (3U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am (4U)
+#define ST25R3916_REG_REGULATOR_CONTROL_rfu (5U)
+#define ST25R3916_REG_REGULATOR_CONTROL_rfu1 (6U)
+#define ST25R3916_REG_REGULATOR_CONTROL_rfu2 (7U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask (7U)
+#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_shift (0U)
+
+#define ST25R3916_REG_REGULATOR_RESULT_reg_3 (1U << 7)
+#define ST25R3916_REG_REGULATOR_RESULT_reg_2 (1U << 6)
+#define ST25R3916_REG_REGULATOR_RESULT_reg_1 (1U << 5)
+#define ST25R3916_REG_REGULATOR_RESULT_reg_0 (1U << 4)
+#define ST25R3916_REG_REGULATOR_RESULT_reg_mask (0xfU << 4)
+#define ST25R3916_REG_REGULATOR_RESULT_reg_shift (4U)
+#define ST25R3916_REG_REGULATOR_RESULT_i_lim (1U << 0)
+
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_3 (1U << 7)
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_2 (1U << 6)
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_1 (1U << 5)
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_0 (1U << 4)
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_mask (0xfU << 4)
+#define ST25R3916_REG_RSSI_RESULT_rssi_am_shift (4U)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm3 (1U << 3)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm2 (1U << 2)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm1 (1U << 1)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm0 (1U << 0)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm_mask (0xfU << 0)
+#define ST25R3916_REG_RSSI_RESULT_rssi_pm_shift (0U)
+
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_3 (1U << 7)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_2 (1U << 6)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_1 (1U << 5)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_0 (1U << 4)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_mask (0xfU << 4)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_am_shift (4U)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_3 (1U << 3)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_2 (1U << 2)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_1 (1U << 1)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_0 (1U << 0)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_mask (0xfU << 0)
+#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_shift (0U)
+
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal4 (1U << 7)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal3 (1U << 6)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal2 (1U << 5)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal1 (1U << 4)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal0 (1U << 3)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_mask (0x1fU << 3)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_shift (3U)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g2 (1U << 2)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g1 (1U << 1)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g0 (1U << 0)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g_mask (7U << 0)
+#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g_shift (0U)
+
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal4 (1U << 7)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal3 (1U << 6)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal2 (1U << 5)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal1 (1U << 4)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal0 (1U << 3)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_mask (0x1fU << 3)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_shift (3U)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end (1U << 2)
+#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err (1U << 1)
+
+#define ST25R3916_REG_AUX_DISPLAY_a_cha (1U << 7)
+#define ST25R3916_REG_AUX_DISPLAY_efd_o (1U << 6)
+#define ST25R3916_REG_AUX_DISPLAY_tx_on (1U << 5)
+#define ST25R3916_REG_AUX_DISPLAY_osc_ok (1U << 4)
+#define ST25R3916_REG_AUX_DISPLAY_rx_on (1U << 3)
+#define ST25R3916_REG_AUX_DISPLAY_rx_act (1U << 2)
+#define ST25R3916_REG_AUX_DISPLAY_en_peer (1U << 1)
+#define ST25R3916_REG_AUX_DISPLAY_en_ac (1U << 0)
+
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_tx_mode1 (1U << 7)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_tx_mode0 (1U << 6)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern13 (1U << 5)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern12 (1U << 4)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern11 (1U << 3)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern10 (1U << 2)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern9 (1U << 1)
+#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern8 (1U << 0)
+
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern7 (1U << 7)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern6 (1U << 6)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern5 (1U << 5)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern4 (1U << 4)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern3 (1U << 3)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern2 (1U << 2)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern1 (1U << 1)
+#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern0 (1U << 0)
+
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_tx_mode1 (1U << 7)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_tx_mode0 (1U << 6)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern13 (1U << 5)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern12 (1U << 4)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern11 (1U << 3)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern10 (1U << 2)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern9 (1U << 1)
+#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern8 (1U << 0)
+
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern7 (1U << 7)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern6 (1U << 6)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern5 (1U << 5)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern4 (1U << 4)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern3 (1U << 3)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern2 (1U << 2)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern1 (1U << 1)
+#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern0 (1U << 0)
+
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wur (1U << 7)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wut2 (1U << 6)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wut1 (1U << 5)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wut0 (1U << 4)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wut_mask (7U << 4)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wut_shift (4U)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wto (1U << 3)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wam (1U << 2)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wph (1U << 1)
+#define ST25R3916_REG_WUP_TIMER_CONTROL_wcap (1U << 0)
+
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d3 (1U << 7)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d2 (1U << 6)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d1 (1U << 5)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d0 (1U << 4)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_mask (0xfU << 4)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_shift (4U)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aam (1U << 3)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew1 (1U << 2)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew0 (1U << 1)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_mask (0x3U << 1)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_shift (1U)
+#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_ae (1U << 0)
+
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d3 (1U << 7)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d2 (1U << 6)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d1 (1U << 5)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d0 (1U << 4)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_mask (0xfU << 4)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_shift (4U)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aam (1U << 3)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew1 (1U << 2)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew0 (1U << 1)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_mask (0x3U << 1)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_shift (1U)
+#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_ae (1U << 0)
+
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d3 (1U << 7)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d2 (1U << 6)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d1 (1U << 5)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d0 (1U << 4)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_mask (0xfU << 4)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_shift (4U)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aam (1U << 3)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew1 (1U << 2)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew0 (1U << 1)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_mask (0x3U << 1)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_shift (1U)
+#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_ae (1U << 0)
+
+#define ST25R3916_REG_IC_IDENTITY_ic_type4 (1U << 7)
+#define ST25R3916_REG_IC_IDENTITY_ic_type3 (1U << 6)
+#define ST25R3916_REG_IC_IDENTITY_ic_type2 (1U << 5)
+#define ST25R3916_REG_IC_IDENTITY_ic_type1 (1U << 4)
+#define ST25R3916_REG_IC_IDENTITY_ic_type0 (1U << 3)
+#define ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916 (5U << 3)
+#define ST25R3916_REG_IC_IDENTITY_ic_type_mask (0x1fU << 3)
+#define ST25R3916_REG_IC_IDENTITY_ic_type_shift (3U)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev2 (1U << 2)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev1 (1U << 1)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev0 (1U << 0)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev_v0 (0U << 0)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev_mask (7U << 0)
+#define ST25R3916_REG_IC_IDENTITY_ic_rev_shift (0U)
+
+/*! \endcond DOXYGEN_SUPRESS */
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ *  \brief  Returns the content of a register within the ST25R3916
+ *
+ *  This function is used to read out the content of ST25R3916 registers.
+ *
+ *  \param[in]  reg: Address of register to read.
+ *  \param[out] val: Returned value.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ReadRegister(uint8_t reg, uint8_t* val);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Reads from multiple ST25R3916 registers
+ *
+ *  This function is used to read from multiple registers using the
+ *  auto-increment feature. That is, after each read the address pointer
+ *  inside the ST25R3916 gets incremented automatically.
+ *
+ *  \param[in]  reg: Address of the first register to read from.
+ *  \param[in]  values: pointer to a buffer where the result shall be written to.
+ *  \param[in]  length: Number of registers to be read out.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ReadMultipleRegisters(uint8_t reg, uint8_t* values, uint8_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes a given value to a register within the ST25R3916
+ *
+ *  This function is used to write \a val to address \a reg within the ST25R3916.
+ *
+ *  \param[in]  reg: Address of the register to write.
+ *  \param[in]  val: Value to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WriteRegister(uint8_t reg, uint8_t val);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes multiple values to ST25R3916 registers
+ *
+ *  This function is used to write multiple values to the ST25R3916 using the
+ *  auto-increment feature. That is, after each write the address pointer
+ *  inside the ST25R3916 gets incremented automatically.
+ *
+ *  \param[in]  reg: Address of the first register to write.
+ *  \param[in]  values: pointer to a buffer containing the values to be written.
+ *  \param[in]  length: Number of values to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WriteMultipleRegisters(uint8_t reg, const uint8_t* values, uint8_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes values to ST25R3916 FIFO
+ *
+ *  This function needs to be called in order to write to the ST25R3916 FIFO.
+ *
+ *  \param[in]  values: pointer to a buffer containing the values to be written
+ *                      to the FIFO.
+ *  \param[in]  length: Number of values to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WriteFifo(const uint8_t* values, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Read values from ST25R3916 FIFO
+ *
+ *  This function needs to be called in order to read from ST25R3916 FIFO.
+ *
+ *  \param[out]  buf: pointer to a buffer where the FIFO content shall be
+ *                       written to.
+ *  \param[in]  length: Number of bytes to read.
+ *  
+ *  \note: This function doesn't check whether \a length is really the
+ *  number of available bytes in FIFO
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ReadFifo(uint8_t* buf, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes values to ST25R3916 PTM
+ *
+ *  Accesses to the begging of ST25R3916 Passive Target Memory (PTM A Config)
+ *  and writes the given values 
+ *
+ *  \param[in]  values: pointer to a buffer containing the values to be written
+ *                      to the Passive Target Memory.
+ *  \param[in]  length: Number of values to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WritePTMem(const uint8_t* values, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Reads the ST25R3916 PTM
+ *
+ *  Accesses to the begging of ST25R3916 Passive Target Memory (PTM A Config)
+ *  and reads the memory for the given length 
+ *
+ *  \param[out] values: pointer to a buffer where the PTM content shall be
+ *                       written to.
+ *  \param[in]  length: Number of bytes to read.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ReadPTMem(uint8_t* values, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes values to ST25R3916 PTM F config
+ *
+ *  Accesses ST25R3916 Passive Target Memory F config and writes the given values 
+ *
+ *  \param[in]  values: pointer to a buffer containing the values to be written
+ *                      to the Passive Target Memory 
+ *  \param[in]  length: Number of values to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WritePTMemF(const uint8_t* values, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes values to ST25R3916 PTM TSN Data
+ *
+ *  Accesses ST25R3916 Passive Target Memory TSN data and writes the given values 
+ *
+ *  \param[in]  values: pointer to a buffer containing the values to be written
+ *                      to the Passive Target Memory.
+ *  \param[in]  length: Number of values to be written.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WritePTMemTSN(const uint8_t* values, uint16_t length);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Execute a direct command
+ *
+ *  This function is used to start so-called direct command. These commands
+ *  are implemented inside the chip and each command has unique code (see
+ *  datasheet).
+ *
+ *  \param[in]  cmd : code of the direct command to be executed.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ExecuteCommand(uint8_t cmd);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Read a test register within the ST25R3916
+ *
+ *  This function is used to read the content of test address \a reg within the ST25R3916
+ *
+ *  \param[in]   reg: Address of the register to read
+ *  \param[out]  val: Returned read value
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ReadTestRegister(uint8_t reg, uint8_t* val);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Writes a given value to a test register within the ST25R3916
+ *
+ *  This function is used to write \a val to test address \a reg within the ST25R3916
+ *
+ *  \param[in]  reg: Address of the register to write
+ *  \param[in]  val: Value to be written
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916WriteTestRegister(uint8_t reg, uint8_t val);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Cleart bits on Register
+ *
+ *  This function clears the given bitmask on the register 
+ *
+ *  \param[in]  reg: Address of the register clear
+ *  \param[in]  clr_mask: Bitmask of bit to be cleared
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ClrRegisterBits(uint8_t reg, uint8_t clr_mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Set bits on Register
+ *
+ *  This function sets the given bitmask on the register 
+ *
+ *  \param[in]  reg: Address of the register clear
+ *  \param[in]  set_mask: Bitmask of bit to be cleared
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916SetRegisterBits(uint8_t reg, uint8_t set_mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Changes the given bits on a ST25R3916 register
+ *
+ *  This function is used if only a particular bits should be changed within
+ *  an ST25R3916 register.
+ *
+ *  \param[in]  reg: Address of the register to change.
+ *  \param[in]  valueMask: bitmask of bits to be changed
+ *  \param[in]  value: the bits to be written on the enabled valueMask bits
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ChangeRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Modifies a value within a ST25R3916 register
+ *
+ *  This function is used if only a particular bits should be changed within
+ *  an ST25R3916 register.
+ *
+ *  \param[in]  reg: Address of the register to write.
+ *  \param[in]  clr_mask: bitmask of bits to be cleared to 0.
+ *  \param[in]  set_mask: bitmask of bits to be set to 1.
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ModifyRegister(uint8_t reg, uint8_t clr_mask, uint8_t set_mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Changes the given bits on a ST25R3916 Test register
+ *
+ *  This function is used if only a particular bits should be changed within
+ *  an ST25R3916 register.
+ *
+ *  \param[in]  reg: Address of the Test register to change.
+ *  \param[in]  valueMask: bitmask of bits to be changed
+ *  \param[in]  value: the bits to be written on the enabled valueMask bits
+ *
+ *  \return ERR_NONE  : Operation successful
+ *  \return ERR_PARAM : Invalid parameter
+ *  \return ERR_SEND  : Transmission error or acknowledge not received
+ *****************************************************************************
+ */
+ReturnCode st25r3916ChangeTestRegisterBits(uint8_t reg, uint8_t valueMask, uint8_t value);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Checks if register contains a expected value
+ *
+ *  This function checks if the given reg contains a value that once masked
+ *  equals the expected value
+ *
+ *  \param reg  : the register to check the value
+ *  \param mask : the mask apply on register value
+ *  \param val  : expected value to be compared to
+ *    
+ *  \return  true when reg contains the expected value | false otherwise
+ */
+bool st25r3916CheckReg(uint8_t reg, uint8_t mask, uint8_t val);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Check if register ID is valid
+ *
+ *  Checks if the given register ID a valid ST25R3916 register
+ *
+ *  \param[in]  reg: Address of register to check
+ *  
+ *  \return  true if is a valid register ID
+ *  \return  false otherwise
+ *
+ *****************************************************************************
+ */
+bool st25r3916IsRegValid(uint8_t reg);
+
+#endif /* ST25R3916_COM_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  * 
+  * @}
+  */

+ 231 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_irq.c

@@ -0,0 +1,231 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 Interrupt handling
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "st25r3916_irq.h"
+#include "st25r3916_com.h"
+#include "st25r3916_led.h"
+#include "st25r3916.h"
+#include "../../utils.h"
+
+/*
+ ******************************************************************************
+ * LOCAL DATA TYPES
+ ******************************************************************************
+ */
+
+/*! Holds current and previous interrupt callback pointer as well as current Interrupt status and mask */
+typedef struct {
+    void (*prevCallback)(void); /*!< call back function for ST25R3916 interrupt          */
+    void (*callback)(void); /*!< call back function for ST25R3916 interrupt          */
+    uint32_t status; /*!< latest interrupt status                             */
+    uint32_t mask; /*!< Interrupt mask. Negative mask = ST25R3916 mask regs */
+} st25r3916Interrupt;
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+/*! Length of the interrupt registers       */
+#define ST25R3916_INT_REGS_LEN ((ST25R3916_REG_IRQ_TARGET - ST25R3916_REG_IRQ_MAIN) + 1U)
+
+/*
+******************************************************************************
+* GLOBAL VARIABLES
+******************************************************************************
+*/
+
+static volatile st25r3916Interrupt st25r3916interrupt; /*!< Instance of ST25R3916 interrupt */
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+void st25r3916InitInterrupts(void) {
+    platformIrqST25RPinInitialize();
+    platformIrqST25RSetCallback(st25r3916Isr);
+
+    st25r3916interrupt.callback = NULL;
+    st25r3916interrupt.prevCallback = NULL;
+    st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
+    st25r3916interrupt.mask = ST25R3916_IRQ_MASK_NONE;
+}
+
+/*******************************************************************************/
+void st25r3916Isr(void) {
+    st25r3916CheckForReceivedInterrupts();
+
+    // Check if callback is set and run it
+    if(NULL != st25r3916interrupt.callback) {
+        st25r3916interrupt.callback();
+    }
+}
+
+/*******************************************************************************/
+void st25r3916CheckForReceivedInterrupts(void) {
+    uint8_t iregs[ST25R3916_INT_REGS_LEN];
+    uint32_t irqStatus;
+
+    /* Initialize iregs */
+    irqStatus = ST25R3916_IRQ_MASK_NONE;
+    ST_MEMSET(iregs, (int32_t)(ST25R3916_IRQ_MASK_ALL & 0xFFU), ST25R3916_INT_REGS_LEN);
+
+    /* In case the IRQ is Edge (not Level) triggered read IRQs until done */
+    while(platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
+        st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
+
+        irqStatus |= (uint32_t)iregs[0];
+        irqStatus |= (uint32_t)iregs[1] << 8;
+        irqStatus |= (uint32_t)iregs[2] << 16;
+        irqStatus |= (uint32_t)iregs[3] << 24;
+    }
+
+    /* Forward all interrupts, even masked ones to application */
+    platformProtectST25RIrqStatus();
+    st25r3916interrupt.status |= irqStatus;
+    platformUnprotectST25RIrqStatus();
+
+    /* Send an IRQ event to LED handling */
+    st25r3916ledEvtIrq(st25r3916interrupt.status);
+}
+
+/*******************************************************************************/
+void st25r3916ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask) {
+    uint8_t i;
+    uint32_t old_mask;
+    uint32_t new_mask;
+
+    old_mask = st25r3916interrupt.mask;
+    new_mask = ((~old_mask & set_mask) | (old_mask & clr_mask));
+    st25r3916interrupt.mask &= ~clr_mask;
+    st25r3916interrupt.mask |= set_mask;
+
+    for(i = 0; i < ST25R3916_INT_REGS_LEN; i++) {
+        if(((new_mask >> (8U * i)) & 0xFFU) == 0U) {
+            continue;
+        }
+
+        st25r3916WriteRegister(
+            ST25R3916_REG_IRQ_MASK_MAIN + i,
+            (uint8_t)((st25r3916interrupt.mask >> (8U * i)) & 0xFFU));
+    }
+    return;
+}
+
+/*******************************************************************************/
+uint32_t st25r3916WaitForInterruptsTimed(uint32_t mask, uint16_t tmo) {
+    uint32_t tmrDelay;
+    uint32_t status;
+
+    tmrDelay = platformTimerCreate(tmo);
+
+    /* Run until specific interrupt has happen or the timer has expired */
+    do {
+        status = (st25r3916interrupt.status & mask);
+    } while((!platformTimerIsExpired(tmrDelay) || (tmo == 0U)) && (status == 0U));
+
+    platformTimerDestroy(tmrDelay);
+
+    status = st25r3916interrupt.status & mask;
+
+    platformProtectST25RIrqStatus();
+    st25r3916interrupt.status &= ~status;
+    platformUnprotectST25RIrqStatus();
+
+    return status;
+}
+
+/*******************************************************************************/
+uint32_t st25r3916GetInterrupt(uint32_t mask) {
+    uint32_t irqs;
+
+    irqs = (st25r3916interrupt.status & mask);
+    if(irqs != ST25R3916_IRQ_MASK_NONE) {
+        platformProtectST25RIrqStatus();
+        st25r3916interrupt.status &= ~irqs;
+        platformUnprotectST25RIrqStatus();
+    }
+
+    return irqs;
+}
+
+/*******************************************************************************/
+void st25r3916ClearAndEnableInterrupts(uint32_t mask) {
+    st25r3916GetInterrupt(mask);
+    st25r3916EnableInterrupts(mask);
+}
+
+/*******************************************************************************/
+void st25r3916EnableInterrupts(uint32_t mask) {
+    st25r3916ModifyInterrupts(mask, 0);
+}
+
+/*******************************************************************************/
+void st25r3916DisableInterrupts(uint32_t mask) {
+    st25r3916ModifyInterrupts(0, mask);
+}
+
+/*******************************************************************************/
+void st25r3916ClearInterrupts(void) {
+    uint8_t iregs[ST25R3916_INT_REGS_LEN];
+
+    st25r3916ReadMultipleRegisters(ST25R3916_REG_IRQ_MAIN, iregs, ST25R3916_INT_REGS_LEN);
+
+    platformProtectST25RIrqStatus();
+    st25r3916interrupt.status = ST25R3916_IRQ_MASK_NONE;
+    platformUnprotectST25RIrqStatus();
+    return;
+}
+
+/*******************************************************************************/
+void st25r3916IRQCallbackSet(void (*cb)(void)) {
+    st25r3916interrupt.prevCallback = st25r3916interrupt.callback;
+    st25r3916interrupt.callback = cb;
+}
+
+/*******************************************************************************/
+void st25r3916IRQCallbackRestore(void) {
+    st25r3916interrupt.callback = st25r3916interrupt.prevCallback;
+    st25r3916interrupt.prevCallback = NULL;
+}

+ 296 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_irq.h

@@ -0,0 +1,296 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 Interrupt handling
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25R3916
+ * \brief RFAL ST25R3916 Driver
+ * @{
+ * 
+ * \addtogroup ST25R3916_IRQ
+ * \brief RFAL ST25R3916 IRQ
+ * @{
+ * 
+ */
+
+#ifndef ST25R3916_IRQ_H
+#define ST25R3916_IRQ_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "../../platform.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+#define ST25R3916_IRQ_MASK_ALL \
+    (uint32_t)(0xFFFFFFFFUL) /*!< All ST25R3916 interrupt sources                             */
+#define ST25R3916_IRQ_MASK_NONE \
+    (uint32_t)(0x00000000UL) /*!< No ST25R3916 interrupt source                               */
+
+/* Main interrupt register */
+#define ST25R3916_IRQ_MASK_OSC \
+    (uint32_t)(0x00000080U) /*!< ST25R3916 oscillator stable interrupt                       */
+#define ST25R3916_IRQ_MASK_FWL \
+    (uint32_t)(0x00000040U) /*!< ST25R3916 FIFO water level interrupt                        */
+#define ST25R3916_IRQ_MASK_RXS \
+    (uint32_t)(0x00000020U) /*!< ST25R3916 start of receive interrupt                        */
+#define ST25R3916_IRQ_MASK_RXE \
+    (uint32_t)(0x00000010U) /*!< ST25R3916 end of receive interrupt                          */
+#define ST25R3916_IRQ_MASK_TXE \
+    (uint32_t)(0x00000008U) /*!< ST25R3916 end of transmission interrupt                     */
+#define ST25R3916_IRQ_MASK_COL \
+    (uint32_t)(0x00000004U) /*!< ST25R3916 bit collision interrupt                           */
+#define ST25R3916_IRQ_MASK_RX_REST \
+    (uint32_t)(0x00000002U) /*!< ST25R3916 automatic reception restart interrupt             */
+#define ST25R3916_IRQ_MASK_RFU \
+    (uint32_t)(0x00000001U) /*!< ST25R3916 RFU interrupt                                     */
+
+/* Timer and NFC interrupt register */
+#define ST25R3916_IRQ_MASK_DCT \
+    (uint32_t)(0x00008000U) /*!< ST25R3916 termination of direct command interrupt.          */
+#define ST25R3916_IRQ_MASK_NRE \
+    (uint32_t)(0x00004000U) /*!< ST25R3916 no-response timer expired interrupt               */
+#define ST25R3916_IRQ_MASK_GPE \
+    (uint32_t)(0x00002000U) /*!< ST25R3916 general purpose timer expired interrupt           */
+#define ST25R3916_IRQ_MASK_EON \
+    (uint32_t)(0x00001000U) /*!< ST25R3916 external field on interrupt                       */
+#define ST25R3916_IRQ_MASK_EOF \
+    (uint32_t)(0x00000800U) /*!< ST25R3916 external field off interrupt                      */
+#define ST25R3916_IRQ_MASK_CAC \
+    (uint32_t)(0x00000400U) /*!< ST25R3916 collision during RF collision avoidance interrupt */
+#define ST25R3916_IRQ_MASK_CAT \
+    (uint32_t)(0x00000200U) /*!< ST25R3916 minimum guard time expired interrupt              */
+#define ST25R3916_IRQ_MASK_NFCT \
+    (uint32_t)(0x00000100U) /*!< ST25R3916 initiator bit rate recognised interrupt           */
+
+/* Error and wake-up interrupt register */
+#define ST25R3916_IRQ_MASK_CRC \
+    (uint32_t)(0x00800000U) /*!< ST25R3916 CRC error interrupt                               */
+#define ST25R3916_IRQ_MASK_PAR \
+    (uint32_t)(0x00400000U) /*!< ST25R3916 parity error interrupt                            */
+#define ST25R3916_IRQ_MASK_ERR2 \
+    (uint32_t)(0x00200000U) /*!< ST25R3916 soft framing error interrupt                      */
+#define ST25R3916_IRQ_MASK_ERR1 \
+    (uint32_t)(0x00100000U) /*!< ST25R3916 hard framing error interrupt                      */
+#define ST25R3916_IRQ_MASK_WT \
+    (uint32_t)(0x00080000U) /*!< ST25R3916 wake-up interrupt                                 */
+#define ST25R3916_IRQ_MASK_WAM \
+    (uint32_t)(0x00040000U) /*!< ST25R3916 wake-up due to amplitude interrupt                */
+#define ST25R3916_IRQ_MASK_WPH \
+    (uint32_t)(0x00020000U) /*!< ST25R3916 wake-up due to phase interrupt                    */
+#define ST25R3916_IRQ_MASK_WCAP \
+    (uint32_t)(0x00010000U) /*!< ST25R3916 wake-up due to capacitance measurement            */
+
+/* Passive Target Interrupt Register */
+#define ST25R3916_IRQ_MASK_PPON2 \
+    (uint32_t)(0x80000000U) /*!< ST25R3916 PPON2 Field on waiting Timer interrupt            */
+#define ST25R3916_IRQ_MASK_SL_WL \
+    (uint32_t)(0x40000000U) /*!< ST25R3916 Passive target slot number water level interrupt  */
+#define ST25R3916_IRQ_MASK_APON \
+    (uint32_t)(0x20000000U) /*!< ST25R3916 Anticollision done and Field On interrupt         */
+#define ST25R3916_IRQ_MASK_RXE_PTA \
+    (uint32_t)(0x10000000U) /*!< ST25R3916 RXE with an automatic response interrupt          */
+#define ST25R3916_IRQ_MASK_WU_F \
+    (uint32_t)(0x08000000U) /*!< ST25R3916 212/424b/s Passive target interrupt: Active       */
+#define ST25R3916_IRQ_MASK_RFU2 \
+    (uint32_t)(0x04000000U) /*!< ST25R3916 RFU2 interrupt                                    */
+#define ST25R3916_IRQ_MASK_WU_A_X \
+    (uint32_t)(0x02000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active*   */
+#define ST25R3916_IRQ_MASK_WU_A \
+    (uint32_t)(0x01000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active    */
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ *  \brief  Wait until an ST25R3916 interrupt occurs
+ *
+ *  This function is used to access the ST25R3916 interrupt flags. Use this
+ *  to wait for max. \a tmo milliseconds for the \b first interrupt indicated
+ *  with mask \a mask to occur.
+ *
+ *  \param[in] mask : mask indicating the interrupts to wait for.
+ *  \param[in] tmo : time in milliseconds until timeout occurs. If set to 0
+ *                   the functions waits forever.
+ *
+ *  \return : 0 if timeout occurred otherwise a mask indicating the cleared
+ *              interrupts.
+ *
+ *****************************************************************************
+ */
+uint32_t st25r3916WaitForInterruptsTimed(uint32_t mask, uint16_t tmo);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Get status for the given interrupt
+ *
+ *  This function is used to check whether the interrupt given by \a mask
+ *  has occurred. If yes the interrupt gets cleared. This function returns
+ *  only status bits which are inside \a mask.
+ *
+ *  \param[in] mask : mask indicating the interrupt to check for.
+ *
+ *  \return the mask of the interrupts occurred
+ *
+ *****************************************************************************
+ */
+uint32_t st25r3916GetInterrupt(uint32_t mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Init the 3916 interrupt
+ *
+ *  This function is used to check whether the interrupt given by \a mask
+ *  has occurred. 
+ *
+ *****************************************************************************
+ */
+void st25r3916InitInterrupts(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Modifies the Interrupt
+ *
+ *  This function modifies the interrupt
+ *  
+ *  \param[in] clr_mask : bit mask to be cleared on the interrupt mask 
+ *  \param[in] set_mask : bit mask to be set on the interrupt mask 
+ *****************************************************************************
+ */
+void st25r3916ModifyInterrupts(uint32_t clr_mask, uint32_t set_mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief Checks received interrupts
+ *
+ *  Checks received interrupts and saves the result into global params
+ *****************************************************************************
+ */
+void st25r3916CheckForReceivedInterrupts(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  ISR Service routine
+ *
+ *  This function modiefies the interrupt
+ *****************************************************************************
+ */
+void st25r3916Isr(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Enable a given ST25R3916 Interrupt source
+ *
+ *  This function enables all interrupts given by \a mask, 
+ *  ST25R3916_IRQ_MASK_ALL enables all interrupts.
+ *
+ *  \param[in] mask: mask indicating the interrupts to be enabled
+ *
+ *****************************************************************************
+ */
+void st25r3916EnableInterrupts(uint32_t mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Disable one or more a given ST25R3916 Interrupt sources
+ *
+ *  This function disables all interrupts given by \a mask. 0xff disables all.
+ *
+ *  \param[in] mask: mask indicating the interrupts to be disabled.
+ *
+ *****************************************************************************
+ */
+void st25r3916DisableInterrupts(uint32_t mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Clear all ST25R3916 irq flags
+ *
+ *****************************************************************************
+ */
+void st25r3916ClearInterrupts(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Clears and then enables the given ST25R3916 Interrupt sources
+ *
+ *  \param[in] mask: mask indicating the interrupts to be cleared and enabled
+ *****************************************************************************
+ */
+void st25r3916ClearAndEnableInterrupts(uint32_t mask);
+
+/*! 
+ *****************************************************************************
+ *  \brief  Sets IRQ callback for the ST25R3916 interrupt
+ *
+ *****************************************************************************
+ */
+void st25r3916IRQCallbackSet(void (*cb)(void));
+
+/*! 
+ *****************************************************************************
+ *  \brief  Sets IRQ callback for the ST25R3916 interrupt
+ *
+ *****************************************************************************
+ */
+void st25r3916IRQCallbackRestore(void);
+
+#endif /* ST25R3916_IRQ_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  * 
+  * @}
+  */

+ 148 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_led.c

@@ -0,0 +1,148 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *       www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 LEDs handling
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "st25r3916_led.h"
+#include "st25r3916_irq.h"
+#include "st25r3916_com.h"
+#include "st25r3916.h"
+
+/*
+******************************************************************************
+* MACROS
+******************************************************************************
+*/
+
+#ifdef PLATFORM_LED_RX_PIN
+#define st25r3916ledRxOn()    \
+    platformLedOn(            \
+        PLATFORM_LED_RX_PORT, \
+        PLATFORM_LED_RX_PIN); /*!< LED Rx Pin On from system HAL            */
+#define st25r3916ledRxOff()   \
+    platformLedOff(           \
+        PLATFORM_LED_RX_PORT, \
+        PLATFORM_LED_RX_PIN); /*!< LED Rx Pin Off from system HAL           */
+#else /* PLATFORM_LED_RX_PIN */
+#define st25r3916ledRxOn()
+#define st25r3916ledRxOff()
+#endif /* PLATFORM_LED_RX_PIN */
+
+#ifdef PLATFORM_LED_FIELD_PIN
+#define st25r3916ledFieldOn()    \
+    platformLedOn(               \
+        PLATFORM_LED_FIELD_PORT, \
+        PLATFORM_LED_FIELD_PIN); /*!< LED Field Pin On from system HAL            */
+#define st25r3916ledFieldOff()   \
+    platformLedOff(              \
+        PLATFORM_LED_FIELD_PORT, \
+        PLATFORM_LED_FIELD_PIN); /*!< LED Field Pin Off from system HAL           */
+#else /* PLATFORM_LED_FIELD_PIN */
+#define st25r3916ledFieldOn()
+#define st25r3916ledFieldOff()
+#endif /* PLATFORM_LED_FIELD_PIN */
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+void st25r3916ledInit(void) {
+    /* Initialize LEDs if existing and defined */
+    platformLedsInitialize();
+
+    st25r3916ledRxOff();
+    st25r3916ledFieldOff();
+}
+
+/*******************************************************************************/
+void st25r3916ledEvtIrq(uint32_t irqs) {
+    if((irqs & (ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_CAT)) != 0U) {
+        st25r3916ledFieldOn();
+    }
+
+    if((irqs & (ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_NFCT)) != 0U) {
+        st25r3916ledRxOn();
+    }
+
+    if((irqs & (ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_NRE | ST25R3916_IRQ_MASK_RX_REST |
+                ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_A | ST25R3916_IRQ_MASK_WU_A_X |
+                ST25R3916_IRQ_MASK_WU_F | ST25R3916_IRQ_MASK_RFU2)) != 0U) {
+        st25r3916ledRxOff();
+    }
+}
+
+/*******************************************************************************/
+void st25r3916ledEvtWrReg(uint8_t reg, uint8_t val) {
+    if(reg == ST25R3916_REG_OP_CONTROL) {
+        if((ST25R3916_REG_OP_CONTROL_tx_en & val) != 0U) {
+            st25r3916ledFieldOn();
+        } else {
+            st25r3916ledFieldOff();
+        }
+    }
+}
+
+/*******************************************************************************/
+void st25r3916ledEvtWrMultiReg(uint8_t reg, const uint8_t* vals, uint8_t len) {
+    uint8_t i;
+
+    for(i = 0; i < (len); i++) {
+        st25r3916ledEvtWrReg((reg + i), vals[i]);
+    }
+}
+
+/*******************************************************************************/
+void st25r3916ledEvtCmd(uint8_t cmd) {
+    if((cmd >= ST25R3916_CMD_TRANSMIT_WITH_CRC) &&
+       (cmd <= ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
+        st25r3916ledFieldOff();
+    }
+
+    if(cmd == ST25R3916_CMD_UNMASK_RECEIVE_DATA) {
+        st25r3916ledRxOff();
+    }
+
+    if(cmd == ST25R3916_CMD_SET_DEFAULT) {
+        st25r3916ledFieldOff();
+        st25r3916ledRxOff();
+    }
+}

+ 151 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/source/st25r3916/st25r3916_led.h

@@ -0,0 +1,151 @@
+
+/******************************************************************************
+  * \attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2020 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   ST25R3916 firmware
+ *      Revision: 
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Gustavo Patricio
+ *
+ *  \brief ST25R3916 LEDs handling
+ *
+ *
+ * \addtogroup RFAL
+ * @{
+ *
+ * \addtogroup RFAL-HAL
+ * \brief RFAL Hardware Abstraction Layer
+ * @{
+ *
+ * \addtogroup ST25R3916
+ * \brief RFAL ST25R3916 Driver
+ * @{
+ * 
+ * \addtogroup ST25R3916_LED
+ * \brief RFAL ST25R3916 LED
+ * @{
+ * 
+ */
+
+#ifndef ST25R3916_LED_H
+#define ST25R3916_LED_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include "../../platform.h"
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ *  \brief  ST25R3916 LED Initialize
+ *
+ *  This function initializes the LEDs that represent ST25R3916 activity 
+ *
+ *****************************************************************************
+ */
+void st25r3916ledInit(void);
+
+/*! 
+ *****************************************************************************
+ *  \brief   ST25R3916 LED Event Interrupt
+ *
+ *  This function should be called upon a ST25R3916 Interrupt, providing 
+ *  the interrupt event with ST25R3916 irq flags to update LEDs 
+ *
+ *  \param[in] irqs: ST25R3916 irqs mask
+ *
+ *****************************************************************************
+ */
+void st25r3916ledEvtIrq(uint32_t irqs);
+
+/*! 
+ *****************************************************************************
+ *  \brief   ST25R3916 LED Event Write Register
+ *
+ *  This function should be called on a ST25R3916 Write Register operation
+ *  providing the event with the register and value to update LEDs 
+ *
+ *  \param[in] reg: ST25R3916 register to be written
+ *  \param[in] val: value to be written on the register
+ *
+ *****************************************************************************
+ */
+void st25r3916ledEvtWrReg(uint8_t reg, uint8_t val);
+
+/*! 
+ *****************************************************************************
+ *  \brief   ST25R3916 LED Event Write Multiple Register
+ *
+ *  This function should be called upon a ST25R3916 Write Multiple Registers, 
+ *  providing the event with the registers and values to update LEDs 
+ *
+ *  \param[in] reg : ST25R3916 first register written
+ *  \param[in] vals: pointer to the values written
+ *  \param[in] len : number of registers written
+ *
+ *****************************************************************************
+ */
+void st25r3916ledEvtWrMultiReg(uint8_t reg, const uint8_t* vals, uint8_t len);
+
+/*! 
+ *****************************************************************************
+ *  \brief   ST25R3916 LED Event Direct Command
+ *
+ *  This function should be called upon a ST25R3916 direct command, providing 
+ *  the event with the command executed
+ *
+ *  \param[in] cmd: ST25R3916 cmd executed
+ *
+ *****************************************************************************
+ */
+void st25r3916ledEvtCmd(uint8_t cmd);
+
+#endif /* ST25R3916_LED_H */
+
+/**
+  * @}
+  *
+  * @}
+  *
+  * @}
+  * 
+  * @}
+  */

+ 158 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/st_errno.h

@@ -0,0 +1,158 @@
+
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   STxxxx firmware
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file st_errno.h
+ *
+ *  \author 
+ *
+ *  \brief Main error codes
+ *
+ */
+
+#ifndef ST_ERRNO_H
+#define ST_ERRNO_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+
+#include <stdint.h>
+
+/*
+******************************************************************************
+* GLOBAL DATA TYPES
+******************************************************************************
+*/
+
+typedef uint16_t ReturnCode; /*!< Standard Return Code type from function. */
+
+/*
+******************************************************************************
+* DEFINES
+******************************************************************************
+*/
+
+/*
+ * Error codes to be used within the application.
+ * They are represented by an uint8_t
+ */
+enum {
+    ERR_NONE = 0, /*!< no error occurred */
+    ERR_NOMEM = 1, /*!< not enough memory to perform the requested operation */
+    ERR_BUSY = 2, /*!< device or resource busy */
+    ERR_IO = 3, /*!< generic IO error */
+    ERR_TIMEOUT = 4, /*!< error due to timeout */
+    ERR_REQUEST = 5, /*!< invalid request or requested function can't be executed at the moment */
+    ERR_NOMSG = 6, /*!< No message of desired type */
+    ERR_PARAM = 7, /*!< Parameter error */
+    ERR_SYSTEM = 8, /*!< System error */
+    ERR_FRAMING = 9, /*!< Framing error */
+    ERR_OVERRUN = 10, /*!< lost one or more received bytes */
+    ERR_PROTO = 11, /*!< protocol error */
+    ERR_INTERNAL = 12, /*!< Internal Error */
+    ERR_AGAIN = 13, /*!< Call again */
+    ERR_MEM_CORRUPT = 14, /*!< memory corruption */
+    ERR_NOT_IMPLEMENTED = 15, /*!< not implemented */
+    ERR_PC_CORRUPT =
+        16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */
+    ERR_SEND = 17, /*!< error sending*/
+    ERR_IGNORE = 18, /*!< indicates error detected but to be ignored */
+    ERR_SEMANTIC = 19, /*!< indicates error in state machine (unexpected cmd) */
+    ERR_SYNTAX = 20, /*!< indicates error in state machine (unknown cmd) */
+    ERR_CRC = 21, /*!< crc error */
+    ERR_NOTFOUND = 22, /*!< transponder not found */
+    ERR_NOTUNIQUE = 23, /*!< transponder not unique - more than one transponder in field */
+    ERR_NOTSUPP = 24, /*!< requested operation not supported */
+    ERR_WRITE = 25, /*!< write error */
+    ERR_FIFO = 26, /*!< fifo over or underflow error */
+    ERR_PAR = 27, /*!< parity error */
+    ERR_DONE = 28, /*!< transfer has already finished */
+    ERR_RF_COLLISION =
+        29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */
+    ERR_HW_OVERRUN = 30, /*!< lost one or more received bytes */
+    ERR_RELEASE_REQ = 31, /*!< device requested release */
+    ERR_SLEEP_REQ = 32, /*!< device requested sleep */
+    ERR_WRONG_STATE = 33, /*!< incorrent state for requested operation */
+    ERR_MAX_RERUNS = 34, /*!< blocking procedure reached maximum runs */
+    ERR_DISABLED = 35, /*!< operation aborted due to disabled configuration */
+    ERR_HW_MISMATCH = 36, /*!< expected hw do not match  */
+    ERR_LINK_LOSS =
+        37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */
+    ERR_INVALID_HANDLE = 38, /*!< invalid or not initalized device handle */
+
+    ERR_INCOMPLETE_BYTE = 40, /*!< Incomplete byte rcvd         */
+    ERR_INCOMPLETE_BYTE_01 = 41, /*!< Incomplete byte rcvd - 1 bit */
+    ERR_INCOMPLETE_BYTE_02 = 42, /*!< Incomplete byte rcvd - 2 bit */
+    ERR_INCOMPLETE_BYTE_03 = 43, /*!< Incomplete byte rcvd - 3 bit */
+    ERR_INCOMPLETE_BYTE_04 = 44, /*!< Incomplete byte rcvd - 4 bit */
+    ERR_INCOMPLETE_BYTE_05 = 45, /*!< Incomplete byte rcvd - 5 bit */
+    ERR_INCOMPLETE_BYTE_06 = 46, /*!< Incomplete byte rcvd - 6 bit */
+    ERR_INCOMPLETE_BYTE_07 = 47, /*!< Incomplete byte rcvd - 7 bit */
+};
+
+/* General Sub-category number */
+#define ERR_GENERIC_GRP (0x0000) /*!< Reserved value for generic error no */
+#define ERR_WARN_GRP (0x0100) /*!< Errors which are not expected in normal operation */
+#define ERR_PROCESS_GRP (0x0200) /*!< Processes management errors */
+#define ERR_SIO_GRP (0x0800) /*!< SIO errors due to logging */
+#define ERR_RINGBUF_GRP (0x0900) /*!< Ring Buffer errors */
+#define ERR_MQ_GRP (0x0A00) /*!< MQ errors */
+#define ERR_TIMER_GRP (0x0B00) /*!< Timer errors */
+#define ERR_RFAL_GRP (0x0C00) /*!< RFAL errors */
+#define ERR_UART_GRP (0x0D00) /*!< UART errors */
+#define ERR_SPI_GRP (0x0E00) /*!< SPI errors */
+#define ERR_I2C_GRP (0x0F00) /*!< I2c errors */
+
+#define ERR_INSERT_SIO_GRP(x) (ERR_SIO_GRP | x) /*!< Insert the SIO grp */
+#define ERR_INSERT_RINGBUF_GRP(x) (ERR_RINGBUF_GRP | x) /*!< Insert the Ring Buffer grp */
+#define ERR_INSERT_RFAL_GRP(x) (ERR_RFAL_GRP | x) /*!< Insert the RFAL grp */
+#define ERR_INSERT_SPI_GRP(x) (ERR_SPI_GRP | x) /*!< Insert the spi grp */
+#define ERR_INSERT_I2C_GRP(x) (ERR_I2C_GRP | x) /*!< Insert the i2c grp */
+#define ERR_INSERT_UART_GRP(x) (ERR_UART_GRP | x) /*!< Insert the uart grp */
+#define ERR_INSERT_TIMER_GRP(x) (ERR_TIMER_GRP | x) /*!< Insert the timer grp */
+#define ERR_INSERT_MQ_GRP(x) (ERR_MQ_GRP | x) /*!< Insert the mq grp */
+#define ERR_INSERT_PROCESS_GRP(x) (ERR_PROCESS_GRP | x) /*!< Insert the process grp */
+#define ERR_INSERT_WARN_GRP(x) (ERR_WARN_GRP | x) /*!< Insert the i2c grp */
+#define ERR_INSERT_GENERIC_GRP(x) (ERR_GENERIC_GRP | x) /*!< Insert the generic grp */
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+
+#define ERR_NO_MASK(x) (x & 0x00FF) /*!< Mask the error number */
+
+/*! Common code to exit a function with the error if function f return error */
+#define EXIT_ON_ERR(r, f)     \
+    if(ERR_NONE != (r = f)) { \
+        return r;             \
+    }
+
+#endif /* ST_ERRNO_H */

+ 105 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/timer.c

@@ -0,0 +1,105 @@
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      $Revision: $
+ *      LANGUAGE:  ANSI C
+ */
+
+/*! \file timer.c
+ *
+ *  \brief SW Timer implementation
+ *
+ *  \author Gustavo Patricio
+ *
+ *   This module makes use of a System Tick in millisconds and provides
+ *   an abstraction for SW timers
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include "timer.h"
+#include <furi.h>
+
+/*
+******************************************************************************
+* LOCAL DEFINES
+******************************************************************************
+*/
+
+/*
+******************************************************************************
+* LOCAL VARIABLES
+******************************************************************************
+*/
+
+static uint32_t timerStopwatchTick;
+
+/*
+******************************************************************************
+* GLOBAL FUNCTIONS
+******************************************************************************
+*/
+
+/*******************************************************************************/
+uint32_t timerCalculateTimer(uint16_t time) {
+    return (furi_get_tick() + time);
+}
+
+/*******************************************************************************/
+bool timerIsExpired(uint32_t timer) {
+    uint32_t uDiff;
+    int32_t sDiff;
+
+    uDiff = (timer - furi_get_tick()); /* Calculate the diff between the timers */
+    sDiff = uDiff; /* Convert the diff to a signed var      */
+
+    /* Check if the given timer has expired already */
+    if(sDiff < 0) {
+        return true;
+    }
+
+    return false;
+}
+
+/*******************************************************************************/
+void timerDelay(uint16_t tOut) {
+    uint32_t t;
+
+    /* Calculate the timer and wait blocking until is running */
+    t = timerCalculateTimer(tOut);
+    while(timerIsRunning(t))
+        ;
+}
+
+/*******************************************************************************/
+void timerStopwatchStart(void) {
+    timerStopwatchTick = furi_get_tick();
+}
+
+/*******************************************************************************/
+uint32_t timerStopwatchMeasure(void) {
+    return (uint32_t)(furi_get_tick() - timerStopwatchTick);
+}

+ 125 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/timer.h

@@ -0,0 +1,125 @@
+#pragma once
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2016 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+/*
+ *      PROJECT:   ST25R391x firmware
+ *      $Revision: $
+ *      LANGUAGE:  ANSI C
+ */
+
+/*! \file timer.h
+ *
+ *  \brief SW Timer implementation header file
+ *   
+ *   This module makes use of a System Tick in millisconds and provides
+ *   an abstraction for SW timers
+ *
+ */
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+#define timerIsRunning(t) (!timerIsExpired(t))
+
+/*
+******************************************************************************
+* GLOBAL DEFINES
+******************************************************************************
+*/
+
+/*! 
+ *****************************************************************************
+ * \brief  Calculate Timer
+ *  
+ * This method calculates when the timer will be expired given the amount
+ * time in milliseconds /a tOut.
+ * Once the timer has been calculated it will then be used to check when
+ * it expires.
+ * 
+ * \see timersIsExpired
+ *
+ * \param[in]  time : time/duration in Milliseconds for the timer
+ *
+ * \return u32 : The new timer calculated based on the given time 
+ *****************************************************************************
+ */
+uint32_t timerCalculateTimer(uint16_t time);
+
+/*! 
+ *****************************************************************************
+ * \brief  Checks if a Timer is Expired
+ *  
+ * This method checks if a timer has already expired.
+ * Based on the given timer previously calculated it checks if this timer
+ * has already elapsed
+ * 
+ * \see timersCalculateTimer
+ *
+ * \param[in]  timer : the timer to check 
+ *
+ * \return true  : timer has already expired
+ * \return false : timer is still running
+ *****************************************************************************
+ */
+bool timerIsExpired(uint32_t timer);
+
+/*! 
+ *****************************************************************************
+ * \brief  Performs a Delay
+ *  
+ * This method performs a delay for the given amount of time in Milliseconds
+ * 
+ * \param[in]  time : time/duration in Milliseconds of the delay
+ *
+ *****************************************************************************
+ */
+void timerDelay(uint16_t time);
+
+/*! 
+ *****************************************************************************
+ * \brief  Stopwatch start
+ *  
+ * This method initiates the stopwatch to later measure the time in ms
+ * 
+ *****************************************************************************
+ */
+void timerStopwatchStart(void);
+
+/*! 
+ *****************************************************************************
+ * \brief  Stopwatch Measure
+ *  
+ * This method returns the elapsed time in ms since the stopwatch was initiated
+ * 
+ * \return The time in ms since the stopwatch was started
+ *****************************************************************************
+ */
+uint32_t timerStopwatchMeasure(void);

+ 100 - 0
esubghz_chat/lib/nfclegacy/ST25RFAL002/utils.h

@@ -0,0 +1,100 @@
+
+/******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
+  *
+  * Licensed under ST MYLIBERTY SOFTWARE LICENSE AGREEMENT (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/myliberty
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+  * AND SPECIFICALLY DISCLAIMING THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+******************************************************************************/
+
+/*
+ *      PROJECT:   NFCC firmware
+ *      $Revision: $
+ *      LANGUAGE:  ISO C99
+ */
+
+/*! \file
+ *
+ *  \author Ulrich Herrmann
+ *
+ *  \brief Common and helpful macros
+ *
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+/*
+******************************************************************************
+* INCLUDES
+******************************************************************************
+*/
+#include <string.h>
+#include <stdint.h>
+
+/*
+******************************************************************************
+* GLOBAL MACROS
+******************************************************************************
+*/
+/*! 
+ * this macro evaluates an error variable \a ERR against an error code \a EC.
+ * in case it is not equal it jumps to the given label \a LABEL.
+ */
+#define EVAL_ERR_NE_GOTO(EC, ERR, LABEL) \
+    if(EC != ERR) goto LABEL;
+
+/*! 
+ * this macro evaluates an error variable \a ERR against an error code \a EC.
+ * in case it is equal it jumps to the given label \a LABEL.
+ */
+#define EVAL_ERR_EQ_GOTO(EC, ERR, LABEL) \
+    if(EC == ERR) goto LABEL;
+#define BITMASK_1 (0x01) /*!< Bit mask for lsb bit                   */
+#define BITMASK_2 (0x03) /*!< Bit mask for two lsb bits              */
+#define BITMASK_3 (0x07) /*!< Bit mask for three lsb bits            */
+#define BITMASK_4 (0x0F) /*!< Bit mask for four lsb bits             */
+#define U16TOU8(a) ((a)&0x00FF) /*!< Cast 16-bit unsigned to 8-bit unsigned */
+#define GETU16(a) \
+    (uint16_t)(   \
+        (a[0] << 8) | a[1]) /*!< Cast two Big Endian 8-bits byte array to 16-bits unsigned */
+
+#define REVERSE_BYTES(pData, nDataSize)                           \
+    unsigned char swap, *lo = pData, *hi = pData + nDataSize - 1; \
+    while(lo < hi) {                                              \
+        swap = *lo;                                               \
+        *lo++ = *hi;                                              \
+        *hi-- = swap;                                             \
+    }
+
+#define ST_MEMMOVE memmove /*!< map memmove to string library code */
+#define ST_MEMCPY memcpy /*!< map memcpy to string library code  */
+#define ST_MEMSET memset /*!< map memset to string library code  */
+#define ST_BYTECMP memcmp /*!< map bytecmp to string library code */
+
+#define NO_WARNING(v) ((void)(v)) /*!< Macro to suppress compiler warning */
+
+#ifndef NULL
+#define NULL (void*)0 /*!< represents a NULL pointer */
+#endif /* !NULL */
+
+/*
+******************************************************************************
+* GLOBAL FUNCTION PROTOTYPES
+******************************************************************************
+*/
+
+#endif /* UTILS_H */

+ 666 - 0
esubghz_chat/lib/nfclegacy/digital_signal/digital_signal.c

@@ -0,0 +1,666 @@
+#include "digital_signal.h"
+
+#include <furi.h>
+#include <furi_hal.h>
+#include <furi_hal_resources.h>
+#include <math.h>
+
+#include <stm32wbxx_ll_dma.h>
+#include <stm32wbxx_ll_tim.h>
+
+/* must be on bank B */
+// For debugging purposes use `--extra-define=DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN=gpio_ext_pb3` fbt option
+
+struct ReloadBuffer {
+    uint32_t* buffer; /* DMA ringbuffer */
+    uint32_t size; /* maximum entry count of the ring buffer */
+    uint32_t write_pos; /* current buffer write index */
+    uint32_t read_pos; /* current buffer read index */
+    bool dma_active;
+};
+
+struct DigitalSequence {
+    uint8_t signals_size;
+    bool bake;
+    uint32_t sequence_used;
+    uint32_t sequence_size;
+    DigitalSignal** signals;
+    uint8_t* sequence;
+    const GpioPin* gpio;
+    uint32_t send_time;
+    bool send_time_active;
+    LL_DMA_InitTypeDef dma_config_gpio;
+    LL_DMA_InitTypeDef dma_config_timer;
+    uint32_t* gpio_buff;
+    struct ReloadBuffer* dma_buffer;
+};
+
+struct DigitalSignalInternals {
+    uint64_t factor;
+    uint32_t reload_reg_entries;
+    uint32_t reload_reg_remainder;
+    uint32_t gpio_buff[2];
+    const GpioPin* gpio;
+    LL_DMA_InitTypeDef dma_config_gpio;
+    LL_DMA_InitTypeDef dma_config_timer;
+};
+
+#define TAG "DigitalSignal"
+
+#define F_TIM (64000000.0)
+#define T_TIM 1562 /* 15.625 ns *100 */
+#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */
+
+/* end marker in DMA ringbuffer, will get written into timer register at the end */
+#define SEQ_TIMER_MAX 0xFFFFFFFF
+
+/* time to wait in loops before returning */
+#define SEQ_LOCK_WAIT_MS 10UL
+#define SEQ_LOCK_WAIT_TICKS (SEQ_LOCK_WAIT_MS * 1000 * 64)
+
+/* maximum entry count of the sequence dma ring buffer */
+#define RINGBUFFER_SIZE 128
+
+/* maximum number of DigitalSignals in a sequence */
+#define SEQUENCE_SIGNALS_SIZE 32
+/*
+ * if sequence size runs out from the initial value passed to digital_sequence_alloc
+ * the size will be increased by this amount and reallocated
+ */
+#define SEQUENCE_SIZE_REALLOCATE_INCREMENT 256
+
+DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
+    DigitalSignal* signal = malloc(sizeof(DigitalSignal));
+    signal->start_level = true;
+    signal->edges_max_cnt = max_edges_cnt;
+    signal->edge_timings = malloc(signal->edges_max_cnt * sizeof(uint32_t));
+    signal->edge_cnt = 0;
+    signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t));
+
+    signal->internals = malloc(sizeof(DigitalSignalInternals));
+    DigitalSignalInternals* internals = signal->internals;
+
+    internals->factor = 1024 * 1024;
+
+    internals->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
+    internals->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
+    internals->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
+    internals->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
+    internals->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
+    internals->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
+    internals->dma_config_gpio.NbData = 2;
+    internals->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
+    internals->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
+
+    internals->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
+    internals->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
+    internals->dma_config_timer.Mode = LL_DMA_MODE_NORMAL;
+    internals->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
+    internals->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
+    internals->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
+    internals->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
+    internals->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
+    internals->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
+
+    return signal;
+}
+
+void digital_signal_free(DigitalSignal* signal) {
+    furi_assert(signal);
+
+    free(signal->edge_timings);
+    free(signal->reload_reg_buff);
+    free(signal->internals);
+    free(signal);
+}
+
+bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) {
+    furi_assert(signal_a);
+    furi_assert(signal_b);
+
+    if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) {
+        return false;
+    }
+    /* in case there are no edges in our target signal, the signal to append makes the rules */
+    if(!signal_a->edge_cnt) {
+        signal_a->start_level = signal_b->start_level;
+    }
+    bool end_level = signal_a->start_level;
+    if(signal_a->edge_cnt) {
+        end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2);
+    }
+    uint8_t start_copy = 0;
+    if(end_level == signal_b->start_level) {
+        if(signal_a->edge_cnt) {
+            signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0];
+            start_copy += 1;
+        } else {
+            signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0];
+        }
+    }
+
+    for(size_t i = 0; i < signal_b->edge_cnt - start_copy; i++) {
+        signal_a->edge_timings[signal_a->edge_cnt + i] = signal_b->edge_timings[start_copy + i];
+    }
+    signal_a->edge_cnt += signal_b->edge_cnt - start_copy;
+
+    return true;
+}
+
+bool digital_signal_get_start_level(DigitalSignal* signal) {
+    furi_assert(signal);
+
+    return signal->start_level;
+}
+
+uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) {
+    furi_assert(signal);
+
+    return signal->edge_cnt;
+}
+
+void digital_signal_add(DigitalSignal* signal, uint32_t ticks) {
+    furi_assert(signal);
+    furi_assert(signal->edge_cnt < signal->edges_max_cnt);
+
+    signal->edge_timings[signal->edge_cnt++] = ticks;
+}
+
+void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level) {
+    furi_assert(signal);
+    furi_assert(signal->edge_cnt < signal->edges_max_cnt);
+
+    /* virgin signal? add it as the only level */
+    if(signal->edge_cnt == 0) {
+        signal->start_level = level;
+        signal->edge_timings[signal->edge_cnt++] = ticks;
+    } else {
+        bool end_level = signal->start_level ^ !(signal->edge_cnt % 2);
+
+        if(level != end_level) {
+            signal->edge_timings[signal->edge_cnt++] = ticks;
+        } else {
+            signal->edge_timings[signal->edge_cnt - 1] += ticks;
+        }
+    }
+}
+
+uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
+    furi_assert(signal);
+    furi_assert(edge_num < signal->edge_cnt);
+
+    return signal->edge_timings[edge_num];
+}
+
+void digital_signal_prepare_arr(DigitalSignal* signal) {
+    furi_assert(signal);
+
+    DigitalSignalInternals* internals = signal->internals;
+
+    /* set up signal polarities */
+    if(internals->gpio) {
+        uint32_t bit_set = internals->gpio->pin;
+        uint32_t bit_reset = internals->gpio->pin << 16;
+
+#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
+        bit_set |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin;
+        bit_reset |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin << 16;
+#endif
+
+        if(signal->start_level) {
+            internals->gpio_buff[0] = bit_set;
+            internals->gpio_buff[1] = bit_reset;
+        } else {
+            internals->gpio_buff[0] = bit_reset;
+            internals->gpio_buff[1] = bit_set;
+        }
+    }
+
+    /* set up edge timings */
+    internals->reload_reg_entries = 0;
+
+    for(size_t pos = 0; pos < signal->edge_cnt; pos++) {
+        uint32_t pulse_duration = signal->edge_timings[pos] + internals->reload_reg_remainder;
+        if(pulse_duration < 10 || pulse_duration > 10000000) {
+            FURI_LOG_D(
+                TAG,
+                "[prepare] pulse_duration out of range: %lu = %lu * %llu",
+                pulse_duration,
+                signal->edge_timings[pos],
+                internals->factor);
+            pulse_duration = 100;
+        }
+        uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM;
+        internals->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM);
+
+        if(pulse_ticks > 1) {
+            signal->reload_reg_buff[internals->reload_reg_entries++] = pulse_ticks - 1;
+        }
+    }
+}
+
+static void digital_signal_stop_dma() {
+    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
+    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
+    LL_DMA_ClearFlag_TC1(DMA1);
+    LL_DMA_ClearFlag_TC2(DMA1);
+}
+
+static void digital_signal_stop_timer() {
+    LL_TIM_DisableCounter(TIM2);
+    LL_TIM_DisableUpdateEvent(TIM2);
+    LL_TIM_DisableDMAReq_UPDATE(TIM2);
+
+    furi_hal_bus_disable(FuriHalBusTIM2);
+}
+
+static void digital_signal_setup_timer() {
+    furi_hal_bus_enable(FuriHalBusTIM2);
+
+    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, SEQ_TIMER_MAX);
+    LL_TIM_SetCounter(TIM2, 0);
+}
+
+static void digital_signal_start_timer() {
+    LL_TIM_EnableCounter(TIM2);
+    LL_TIM_EnableUpdateEvent(TIM2);
+    LL_TIM_EnableDMAReq_UPDATE(TIM2);
+    LL_TIM_GenerateEvent_UPDATE(TIM2);
+}
+
+static bool digital_signal_setup_dma(DigitalSignal* signal) {
+    furi_assert(signal);
+    DigitalSignalInternals* internals = signal->internals;
+
+    if(!signal->internals->reload_reg_entries) {
+        return false;
+    }
+    digital_signal_stop_dma();
+
+    internals->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)internals->gpio_buff;
+    internals->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (internals->gpio->port->BSRR);
+    internals->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
+    internals->dma_config_timer.NbData = signal->internals->reload_reg_entries;
+
+    /* set up DMA channel 1 and 2 for GPIO and timer copy operations */
+    LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &internals->dma_config_gpio);
+    LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &internals->dma_config_timer);
+
+    /* enable both DMA channels */
+    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
+    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
+
+    return true;
+}
+
+void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
+    furi_assert(signal);
+
+    if(!signal->edge_cnt) {
+        return;
+    }
+
+    /* Configure gpio as output */
+    signal->internals->gpio = gpio;
+    furi_hal_gpio_init(
+        signal->internals->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+
+    digital_signal_prepare_arr(signal);
+
+    digital_signal_setup_dma(signal);
+    digital_signal_setup_timer();
+    digital_signal_start_timer();
+
+    while(!LL_DMA_IsActiveFlag_TC2(DMA1)) {
+    }
+
+    digital_signal_stop_timer();
+    digital_signal_stop_dma();
+}
+
+static void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) {
+    sequence->signals_size = size;
+    sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*));
+}
+
+static void digital_sequence_alloc_sequence(DigitalSequence* sequence, uint32_t size) {
+    sequence->sequence_used = 0;
+    sequence->sequence_size = size;
+    sequence->sequence = malloc(sequence->sequence_size);
+    sequence->send_time = 0;
+    sequence->send_time_active = false;
+}
+
+DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) {
+    furi_assert(gpio);
+
+    DigitalSequence* sequence = malloc(sizeof(DigitalSequence));
+
+    sequence->gpio = gpio;
+    sequence->bake = false;
+
+    sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer));
+    sequence->dma_buffer->size = RINGBUFFER_SIZE;
+    sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t));
+
+    sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
+    sequence->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR;
+    sequence->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
+    sequence->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
+    sequence->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
+    sequence->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
+    sequence->dma_config_gpio.NbData = 2;
+    sequence->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
+    sequence->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH;
+
+    sequence->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
+    sequence->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR;
+    sequence->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
+    sequence->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
+    sequence->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
+    sequence->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
+    sequence->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
+    sequence->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)sequence->dma_buffer->buffer;
+    sequence->dma_config_timer.NbData = sequence->dma_buffer->size;
+    sequence->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
+    sequence->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH;
+
+    digital_sequence_alloc_signals(sequence, SEQUENCE_SIGNALS_SIZE);
+    digital_sequence_alloc_sequence(sequence, size);
+
+    return sequence;
+}
+
+void digital_sequence_free(DigitalSequence* sequence) {
+    furi_assert(sequence);
+
+    free(sequence->signals);
+    free(sequence->sequence);
+    free(sequence->dma_buffer->buffer);
+    free(sequence->dma_buffer);
+    free(sequence);
+}
+
+void digital_sequence_set_signal(
+    DigitalSequence* sequence,
+    uint8_t signal_index,
+    DigitalSignal* signal) {
+    furi_assert(sequence);
+    furi_assert(signal);
+    furi_assert(signal_index < sequence->signals_size);
+
+    sequence->signals[signal_index] = signal;
+    signal->internals->gpio = sequence->gpio;
+    signal->internals->reload_reg_remainder = 0;
+
+    digital_signal_prepare_arr(signal);
+}
+
+void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time) {
+    furi_assert(sequence);
+
+    sequence->send_time = send_time;
+    sequence->send_time_active = true;
+}
+
+void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) {
+    furi_assert(sequence);
+    furi_assert(signal_index < sequence->signals_size);
+
+    if(sequence->sequence_used >= sequence->sequence_size) {
+        sequence->sequence_size += SEQUENCE_SIZE_REALLOCATE_INCREMENT;
+        sequence->sequence = realloc(sequence->sequence, sequence->sequence_size); //-V701
+        furi_assert(sequence->sequence);
+    }
+
+    sequence->sequence[sequence->sequence_used++] = signal_index;
+}
+
+static bool digital_sequence_setup_dma(DigitalSequence* sequence) {
+    furi_assert(sequence);
+
+    digital_signal_stop_dma();
+
+    sequence->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)sequence->gpio_buff;
+    sequence->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) & (sequence->gpio->port->BSRR);
+
+    /* set up DMA channel 1 and 2 for GPIO and timer copy operations */
+    LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &sequence->dma_config_gpio);
+    LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &sequence->dma_config_timer);
+
+    /* enable both DMA channels */
+    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
+    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
+
+    return true;
+}
+
+static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) {
+    furi_assert(sequence);
+
+    uint32_t edges = 0;
+
+    for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) {
+        uint8_t signal_index = sequence->sequence[pos];
+        DigitalSignal* sig = sequence->signals[signal_index];
+
+        edges += sig->edge_cnt;
+    }
+
+    DigitalSignal* ret = digital_signal_alloc(edges);
+
+    for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) {
+        uint8_t signal_index = sequence->sequence[pos];
+        DigitalSignal* sig = sequence->signals[signal_index];
+
+        digital_signal_append(ret, sig);
+    }
+
+    return ret;
+}
+
+static void digital_sequence_finish(DigitalSequence* sequence) {
+    struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
+
+    if(dma_buffer->dma_active) {
+        uint32_t prev_timer = DWT->CYCCNT;
+        do {
+            /* we are finished, when the DMA transferred the SEQ_TIMER_MAX marker */
+            if(TIM2->ARR == SEQ_TIMER_MAX) {
+                break;
+            }
+            if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) {
+                dma_buffer->read_pos =
+                    RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
+                FURI_LOG_D(
+                    TAG,
+                    "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)",
+                    SEQ_LOCK_WAIT_MS,
+                    TIM2->ARR,
+                    dma_buffer->read_pos,
+                    dma_buffer->write_pos);
+                break;
+            }
+        } while(1);
+    }
+
+    digital_signal_stop_timer();
+    digital_signal_stop_dma();
+}
+
+static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t length) {
+    struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
+
+    if(dma_buffer->dma_active) {
+        uint32_t prev_timer = DWT->CYCCNT;
+        do {
+            dma_buffer->read_pos = RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
+
+            uint32_t free =
+                (RINGBUFFER_SIZE + dma_buffer->read_pos - dma_buffer->write_pos) % RINGBUFFER_SIZE;
+
+            if(free > 2) {
+                break;
+            }
+
+            if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) {
+                FURI_LOG_D(
+                    TAG,
+                    "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)",
+                    SEQ_LOCK_WAIT_MS,
+                    TIM2->ARR,
+                    dma_buffer->read_pos,
+                    dma_buffer->write_pos);
+                break;
+            }
+            if(TIM2->ARR == SEQ_TIMER_MAX) {
+                FURI_LOG_D(
+                    TAG,
+                    "[SEQ] buffer underrun in queue (ARR 0x%08lx, read %lu, write %lu)",
+                    TIM2->ARR,
+                    dma_buffer->read_pos,
+                    dma_buffer->write_pos);
+                break;
+            }
+        } while(1);
+    }
+
+    dma_buffer->buffer[dma_buffer->write_pos] = length;
+    dma_buffer->write_pos++;
+    dma_buffer->write_pos %= RINGBUFFER_SIZE;
+    dma_buffer->buffer[dma_buffer->write_pos] = SEQ_TIMER_MAX;
+}
+
+bool digital_sequence_send(DigitalSequence* sequence) {
+    furi_assert(sequence);
+
+    struct ReloadBuffer* dma_buffer = sequence->dma_buffer;
+
+    furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN
+    furi_hal_gpio_init(
+        &DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+#endif
+
+    if(sequence->bake) {
+        DigitalSignal* sig = digital_sequence_bake(sequence);
+
+        digital_signal_send(sig, sequence->gpio);
+        digital_signal_free(sig);
+        return true;
+    }
+
+    if(!sequence->sequence_used) {
+        return false;
+    }
+
+    int32_t remainder = 0;
+    uint32_t trade_for_next = 0;
+    uint32_t seq_pos_next = 1;
+
+    dma_buffer->dma_active = false;
+    dma_buffer->buffer[0] = SEQ_TIMER_MAX;
+    dma_buffer->read_pos = 0;
+    dma_buffer->write_pos = 0;
+
+    /* already prepare the current signal pointer */
+    DigitalSignal* sig = sequence->signals[sequence->sequence[0]];
+    DigitalSignal* sig_next = NULL;
+    /* re-use the GPIO buffer from the first signal */
+    sequence->gpio_buff = sig->internals->gpio_buff;
+
+    FURI_CRITICAL_ENTER();
+
+    while(sig) {
+        bool last_signal = (seq_pos_next >= sequence->sequence_used);
+
+        if(!last_signal) {
+            sig_next = sequence->signals[sequence->sequence[seq_pos_next++]];
+        }
+
+        for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) {
+            bool last_pulse = ((pulse_pos + 1) >= sig->internals->reload_reg_entries);
+            uint32_t pulse_length = sig->reload_reg_buff[pulse_pos] + trade_for_next;
+
+            trade_for_next = 0;
+
+            /* when we are too late more than half a tick, make the first edge temporarily longer */
+            if(remainder >= T_TIM_DIV2) {
+                remainder -= T_TIM;
+                pulse_length += 1;
+            }
+
+            /* last pulse in current signal and have a next signal? */
+            if(last_pulse && sig_next) {
+                /* when a signal ends with the same level as the next signal begins, let the next signal generate the whole pulse.
+                   beware, we do not want the level after the last edge, but the last level before that edge */
+                bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0);
+
+                /* if they have the same level, pass the duration to the next pulse(s) */
+                if(end_level == sig_next->start_level) {
+                    trade_for_next = pulse_length;
+                }
+            }
+
+            /* if it was decided, that the next signal's first pulse shall also handle our "length", then do not queue here */
+            if(!trade_for_next) {
+                digital_sequence_queue_pulse(sequence, pulse_length);
+
+                if(!dma_buffer->dma_active) {
+                    /* start transmission when buffer was filled enough */
+                    bool start_send = sequence->dma_buffer->write_pos >= (RINGBUFFER_SIZE - 2);
+
+                    /* or it was the last pulse */
+                    if(last_pulse && last_signal) {
+                        start_send = true;
+                    }
+
+                    /* start transmission */
+                    if(start_send) {
+                        digital_sequence_setup_dma(sequence);
+                        digital_signal_setup_timer();
+
+                        /* if the send time is specified, wait till the core timer passed beyond that time */
+                        if(sequence->send_time_active) {
+                            sequence->send_time_active = false;
+                            while(sequence->send_time - DWT->CYCCNT < 0x80000000) {
+                            }
+                        }
+                        digital_signal_start_timer();
+                        dma_buffer->dma_active = true;
+                    }
+                }
+            }
+        }
+
+        remainder += sig->internals->reload_reg_remainder;
+        sig = sig_next;
+        sig_next = NULL;
+    }
+
+    /* wait until last dma transaction was finished */
+    FURI_CRITICAL_EXIT();
+    digital_sequence_finish(sequence);
+
+    return true;
+}
+
+void digital_sequence_clear(DigitalSequence* sequence) {
+    furi_assert(sequence);
+
+    sequence->sequence_used = 0;
+}
+
+void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor) {
+    for(uint32_t sig_pos = 0; sig_pos < sequence->signals_size; sig_pos++) {
+        DigitalSignal* signal = sequence->signals[sig_pos];
+
+        if(signal) {
+            signal->internals->factor = (uint32_t)(1024 * 1024 * factor);
+            digital_signal_prepare_arr(signal);
+        }
+    }
+}

+ 75 - 0
esubghz_chat/lib/nfclegacy/digital_signal/digital_signal.h

@@ -0,0 +1,75 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <furi_hal_gpio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* helper for easier signal generation */
+#define DIGITAL_SIGNAL_MS(x) ((x)*100000000UL)
+#define DIGITAL_SIGNAL_US(x) ((x)*100000UL)
+#define DIGITAL_SIGNAL_NS(x) ((x)*100UL)
+#define DIGITAL_SIGNAL_PS(x) ((x) / 10UL)
+
+/* using an anonymous type for the internals */
+typedef struct DigitalSignalInternals DigitalSignalInternals;
+
+/* and a public one for accessing user-side fields */
+typedef struct DigitalSignal {
+    bool start_level;
+    uint32_t edge_cnt;
+    uint32_t edges_max_cnt;
+    uint32_t* edge_timings;
+    uint32_t* reload_reg_buff; /* internal, but used by unit tests */
+    DigitalSignalInternals* internals;
+} DigitalSignal;
+
+typedef struct DigitalSequence DigitalSequence;
+
+DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt);
+
+void digital_signal_free(DigitalSignal* signal);
+
+void digital_signal_add(DigitalSignal* signal, uint32_t ticks);
+
+void digital_signal_add_pulse(DigitalSignal* signal, uint32_t ticks, bool level);
+
+bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b);
+
+void digital_signal_prepare_arr(DigitalSignal* signal);
+
+bool digital_signal_get_start_level(DigitalSignal* signal);
+
+uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal);
+
+uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num);
+
+void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio);
+
+DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio);
+
+void digital_sequence_free(DigitalSequence* sequence);
+
+void digital_sequence_set_signal(
+    DigitalSequence* sequence,
+    uint8_t signal_index,
+    DigitalSignal* signal);
+
+void digital_sequence_set_sendtime(DigitalSequence* sequence, uint32_t send_time);
+
+void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index);
+
+bool digital_sequence_send(DigitalSequence* sequence);
+
+void digital_sequence_clear(DigitalSequence* sequence);
+
+void digital_sequence_timebase_correction(DigitalSequence* sequence, float factor);
+
+#ifdef __cplusplus
+}
+#endif

+ 839 - 0
esubghz_chat/lib/nfclegacy/furi_hal_nfc.c

@@ -0,0 +1,839 @@
+#include <limits.h>
+#include "./furi_hal_nfc.h"
+#include "ST25RFAL002/source/st25r3916/st25r3916.h"
+#include "ST25RFAL002/source/st25r3916/st25r3916_irq.h"
+#include "ST25RFAL002/include/rfal_rf.h"
+#include <furi.h>
+
+#include "digital_signal/digital_signal.h"
+#include <furi_hal_spi.h>
+#include <furi_hal_gpio.h>
+#include <furi_hal_cortex.h>
+#include <furi_hal_resources.h>
+
+#define TAG "FurryHalNfc"
+
+static const uint32_t clocks_in_ms = 64 * 1000;
+
+FuriEventFlag* event = NULL;
+#define EVENT_FLAG_INTERRUPT (1UL << 0)
+#define EVENT_FLAG_STATE_CHANGED (1UL << 1)
+#define EVENT_FLAG_STOP (1UL << 2)
+#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP)
+
+#define FURRY_HAL_NFC_UID_INCOMPLETE (0x04)
+
+void furry_hal_nfc_init() {
+    furi_assert(!event);
+    event = furi_event_flag_alloc();
+
+    ReturnCode ret = rfalNfcInitialize();
+    if(ret == ERR_NONE) {
+        furry_hal_nfc_start_sleep();
+        FURI_LOG_I(TAG, "Init OK");
+    } else {
+        FURI_LOG_W(TAG, "Init Failed, RFAL returned: %d", ret);
+    }
+}
+
+void furry_hal_nfc_deinit() {
+    ReturnCode ret = rfalDeinitialize();
+    if(ret == ERR_NONE) {
+        FURI_LOG_I(TAG, "Deinit OK");
+    } else {
+        FURI_LOG_W(TAG, "Deinit Failed, RFAL returned: %d", ret);
+    }
+
+    if(event) {
+        furi_event_flag_free(event);
+        event = NULL;
+    }
+}
+
+bool furry_hal_nfc_is_busy() {
+    return rfalNfcGetState() != RFAL_NFC_STATE_IDLE;
+}
+
+bool furry_hal_nfc_is_init() {
+    return rfalNfcGetState() != RFAL_NFC_STATE_NOTINIT;
+}
+
+void furry_hal_nfc_field_on() {
+    furry_hal_nfc_exit_sleep();
+    st25r3916TxRxOn();
+}
+
+void furry_hal_nfc_field_off() {
+    st25r3916TxRxOff();
+    furry_hal_nfc_start_sleep();
+}
+
+void furry_hal_nfc_start_sleep() {
+    rfalLowPowerModeStart();
+}
+
+void furry_hal_nfc_exit_sleep() {
+    rfalLowPowerModeStop();
+}
+
+bool furry_hal_nfc_detect(FurryHalNfcDevData* nfc_data, uint32_t timeout) {
+    furi_assert(nfc_data);
+
+    rfalNfcDevice* dev_list = NULL;
+    uint8_t dev_cnt = 0;
+    bool detected = false;
+
+    rfalLowPowerModeStop();
+    rfalNfcState state = rfalNfcGetState();
+    rfalNfcState state_old = 0;
+    if(state == RFAL_NFC_STATE_NOTINIT) {
+        rfalNfcInitialize();
+    }
+    rfalNfcDiscoverParam params;
+    params.compMode = RFAL_COMPLIANCE_MODE_EMV;
+    params.techs2Find = RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F |
+                        RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB;
+    params.totalDuration = 1000;
+    params.devLimit = 3;
+    params.wakeupEnabled = false;
+    params.wakeupConfigDefault = true;
+    params.nfcfBR = RFAL_BR_212;
+    params.ap2pBR = RFAL_BR_424;
+    params.maxBR = RFAL_BR_KEEP;
+    params.GBLen = RFAL_NFCDEP_GB_MAX_LEN;
+    params.notifyCb = NULL;
+
+    uint32_t start = DWT->CYCCNT;
+    rfalNfcDiscover(&params);
+    while(true) {
+        rfalNfcWorker();
+        state = rfalNfcGetState();
+        if(state != state_old) {
+            FURI_LOG_T(TAG, "State change %d -> %d", state_old, state);
+        }
+        state_old = state;
+        if(state == RFAL_NFC_STATE_ACTIVATED) {
+            detected = true;
+            break;
+        }
+        if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
+            start = DWT->CYCCNT;
+            continue;
+        }
+        if(state == RFAL_NFC_STATE_POLL_SELECT) {
+            rfalNfcSelect(0);
+        }
+        if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
+            rfalNfcDeactivate(true);
+            FURI_LOG_T(TAG, "Timeout");
+            break;
+        }
+        furi_delay_tick(1);
+    }
+    rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
+    if(detected) {
+        if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
+            nfc_data->type = FurryHalNfcTypeA;
+            nfc_data->atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
+            nfc_data->atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
+            nfc_data->sak = dev_list[0].dev.nfca.selRes.sak;
+            uint8_t* cuid_start = dev_list[0].nfcid;
+            if(dev_list[0].nfcidLen == 7) {
+                cuid_start = &dev_list[0].nfcid[3];
+            }
+            nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
+                             (cuid_start[3]);
+        } else if(
+            dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB ||
+            dev_list[0].type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
+            nfc_data->type = FurryHalNfcTypeB;
+        } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) {
+            nfc_data->type = FurryHalNfcTypeF;
+        } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) {
+            nfc_data->type = FurryHalNfcTypeV;
+        }
+        if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_RF) {
+            nfc_data->interface = FurryHalNfcInterfaceRf;
+        } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
+            nfc_data->interface = FurryHalNfcInterfaceIsoDep;
+        } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
+            nfc_data->interface = FurryHalNfcInterfaceNfcDep;
+        }
+        nfc_data->uid_len = dev_list[0].nfcidLen;
+        memcpy(nfc_data->uid, dev_list[0].nfcid, nfc_data->uid_len);
+    }
+
+    return detected;
+}
+
+bool furry_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
+    rfalNfcDevice* dev_list;
+    uint8_t dev_cnt = 0;
+    rfalLowPowerModeStop();
+    rfalNfcState state = rfalNfcGetState();
+    if(state == RFAL_NFC_STATE_NOTINIT) {
+        rfalNfcInitialize();
+    }
+    rfalNfcDiscoverParam params = {
+        .compMode = RFAL_COMPLIANCE_MODE_NFC,
+        .techs2Find = RFAL_NFC_POLL_TECH_A,
+        .totalDuration = 1000,
+        .devLimit = 3,
+        .wakeupEnabled = false,
+        .wakeupConfigDefault = true,
+        .nfcfBR = RFAL_BR_212,
+        .ap2pBR = RFAL_BR_424,
+        .maxBR = RFAL_BR_KEEP,
+        .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
+        .notifyCb = NULL,
+    };
+    uint32_t start = DWT->CYCCNT;
+    rfalNfcDiscover(&params);
+    while(state != RFAL_NFC_STATE_ACTIVATED) {
+        rfalNfcWorker();
+        state = rfalNfcGetState();
+        FURI_LOG_T(TAG, "Current state %d", state);
+        if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
+            start = DWT->CYCCNT;
+            continue;
+        }
+        if(state == RFAL_NFC_STATE_POLL_SELECT) {
+            rfalNfcSelect(0);
+        }
+        if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
+            rfalNfcDeactivate(true);
+            FURI_LOG_T(TAG, "Timeout");
+            return false;
+        }
+        furi_thread_yield();
+    }
+    rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
+    // Take first device and set cuid
+    if(cuid) {
+        uint8_t* cuid_start = dev_list[0].nfcid;
+        if(dev_list[0].nfcidLen == 7) {
+            cuid_start = &dev_list[0].nfcid[3];
+        }
+        *cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
+                (cuid_start[3]);
+        FURI_LOG_T(TAG, "Activated tag with cuid: %lX", *cuid);
+    }
+    return true;
+}
+
+bool furry_hal_nfc_listen(
+    uint8_t* uid,
+    uint8_t uid_len,
+    uint8_t* atqa,
+    uint8_t sak,
+    bool activate_after_sak,
+    uint32_t timeout) {
+    rfalNfcState state = rfalNfcGetState();
+    if(state == RFAL_NFC_STATE_NOTINIT) {
+        rfalNfcInitialize();
+    } else if(state >= RFAL_NFC_STATE_ACTIVATED) {
+        rfalNfcDeactivate(false);
+    }
+    rfalLowPowerModeStop();
+    rfalNfcDiscoverParam params = {
+        .techs2Find = RFAL_NFC_LISTEN_TECH_A,
+        .totalDuration = 1000,
+        .devLimit = 1,
+        .wakeupEnabled = false,
+        .wakeupConfigDefault = true,
+        .nfcfBR = RFAL_BR_212,
+        .ap2pBR = RFAL_BR_424,
+        .maxBR = RFAL_BR_KEEP,
+        .GBLen = RFAL_NFCDEP_GB_MAX_LEN,
+        .notifyCb = NULL,
+        .activate_after_sak = activate_after_sak,
+    };
+    if(FURI_BIT(sak, 5)) {
+        params.compMode = RFAL_COMPLIANCE_MODE_EMV;
+    } else {
+        params.compMode = RFAL_COMPLIANCE_MODE_NFC;
+    }
+    params.lmConfigPA.nfcidLen = uid_len;
+    memcpy(params.lmConfigPA.nfcid, uid, uid_len);
+    params.lmConfigPA.SENS_RES[0] = atqa[0];
+    params.lmConfigPA.SENS_RES[1] = atqa[1];
+    params.lmConfigPA.SEL_RES = sak;
+    rfalNfcDiscover(&params);
+
+    // Disable EMD suppression.
+    st25r3916ModifyRegister(ST25R3916_REG_EMD_SUP_CONF, ST25R3916_REG_EMD_SUP_CONF_emd_emv, 0);
+
+    uint32_t start = DWT->CYCCNT;
+    while(state != RFAL_NFC_STATE_ACTIVATED) {
+        rfalNfcWorker();
+        state = rfalNfcGetState();
+        if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
+            rfalNfcDeactivate(true);
+            return false;
+        }
+        furi_delay_tick(1);
+    }
+    return true;
+}
+
+static void furry_hal_nfc_read_fifo(uint8_t* data, uint16_t* bits) {
+    uint8_t fifo_status[2];
+    uint8_t rx_buff[64];
+
+    st25r3916ReadMultipleRegisters(
+        ST25R3916_REG_FIFO_STATUS1, fifo_status, ST25R3916_FIFO_STATUS_LEN);
+    uint16_t rx_bytes =
+        ((((uint16_t)fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
+          ST25R3916_REG_FIFO_STATUS2_fifo_b_shift)
+         << 8);
+    rx_bytes |= (((uint16_t)fifo_status[0]) & 0x00FFU);
+    st25r3916ReadFifo(rx_buff, rx_bytes);
+
+    memcpy(data, rx_buff, rx_bytes);
+    *bits = rx_bytes * 8;
+}
+
+void furry_hal_nfc_listen_sleep() {
+    st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP);
+}
+
+void furry_hal_nfc_stop_cmd() {
+    st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+}
+
+bool furry_hal_nfc_listen_rx(FurryHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) {
+    furi_assert(tx_rx);
+
+    // Wait for interrupts
+    uint32_t start = furi_get_tick();
+    bool data_received = false;
+    while(true) {
+        if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) {
+            st25r3916CheckForReceivedInterrupts();
+            if(st25r3916GetInterrupt(ST25R3916_IRQ_MASK_RXE)) {
+                furry_hal_nfc_read_fifo(tx_rx->rx_data, &tx_rx->rx_bits);
+                data_received = true;
+                if(tx_rx->sniff_rx) {
+                    tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context);
+                }
+                break;
+            }
+            continue;
+        }
+        if(furi_get_tick() - start > timeout_ms) {
+            FURI_LOG_T(TAG, "Interrupt waiting timeout");
+            furi_delay_tick(1);
+            break;
+        }
+    }
+
+    return data_received;
+}
+
+void furry_hal_nfc_listen_start(FurryHalNfcDevData* nfc_data) {
+    furi_assert(nfc_data);
+
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
+    // Clear interrupts
+    st25r3916ClearInterrupts();
+    // Mask all interrupts
+    st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
+    // RESET
+    st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
+    // Setup registers
+    st25r3916WriteRegister(
+        ST25R3916_REG_OP_CONTROL,
+        ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
+            ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
+    st25r3916WriteRegister(
+        ST25R3916_REG_MODE,
+        ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0);
+    st25r3916WriteRegister(
+        ST25R3916_REG_PASSIVE_TARGET,
+        ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 |
+            ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r);
+    st25r3916WriteRegister(ST25R3916_REG_MASK_RX_TIMER, 0x02);
+
+    // Mask interrupts
+    uint32_t clear_irq_mask =
+        (ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_A_X |
+         ST25R3916_IRQ_MASK_WU_A);
+    st25r3916EnableInterrupts(clear_irq_mask);
+
+    // Set 4 or 7 bytes UID
+    if(nfc_data->uid_len == 4) {
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_4bytes);
+    } else {
+        st25r3916ChangeRegisterBits(
+            ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_7bytes);
+    }
+    // Write PT Memory
+    uint8_t pt_memory[15] = {};
+    memcpy(pt_memory, nfc_data->uid, nfc_data->uid_len);
+    pt_memory[10] = nfc_data->atqa[0];
+    pt_memory[11] = nfc_data->atqa[1];
+    if(nfc_data->uid_len == 4) {
+        pt_memory[12] = nfc_data->sak & ~FURRY_HAL_NFC_UID_INCOMPLETE;
+    } else {
+        pt_memory[12] = FURRY_HAL_NFC_UID_INCOMPLETE;
+    }
+    pt_memory[13] = nfc_data->sak & ~FURRY_HAL_NFC_UID_INCOMPLETE;
+    pt_memory[14] = nfc_data->sak & ~FURRY_HAL_NFC_UID_INCOMPLETE;
+
+    st25r3916WritePTMem(pt_memory, sizeof(pt_memory));
+    // Go to sense
+    st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SENSE);
+}
+
+void rfal_interrupt_callback_handler() {
+    furi_event_flag_set(event, EVENT_FLAG_INTERRUPT);
+}
+
+void rfal_state_changed_callback(void* context) {
+    UNUSED(context);
+    furi_event_flag_set(event, EVENT_FLAG_STATE_CHANGED);
+}
+
+void furry_hal_nfc_stop() {
+    if(event) {
+        furi_event_flag_set(event, EVENT_FLAG_STOP);
+    }
+}
+
+bool furry_hal_nfc_emulate_nfca(
+    uint8_t* uid,
+    uint8_t uid_len,
+    uint8_t* atqa,
+    uint8_t sak,
+    FurryHalNfcEmulateCallback callback,
+    void* context,
+    uint32_t timeout) {
+    rfalSetUpperLayerCallback(rfal_interrupt_callback_handler);
+    rfal_set_state_changed_callback(rfal_state_changed_callback);
+
+    rfalLmConfPA config;
+    config.nfcidLen = uid_len;
+    memcpy(config.nfcid, uid, uid_len);
+    memcpy(config.SENS_RES, atqa, RFAL_LM_SENS_RES_LEN);
+    config.SEL_RES = sak;
+    uint8_t buff_rx[256];
+    uint16_t buff_rx_size = 256;
+    uint16_t buff_rx_len = 0;
+    uint8_t buff_tx[1040];
+    uint16_t buff_tx_len = 0;
+    uint32_t data_type = FURRY_HAL_NFC_TXRX_DEFAULT;
+
+    rfalLowPowerModeStop();
+    if(rfalListenStart(
+           RFAL_LM_MASK_NFCA,
+           &config,
+           NULL,
+           NULL,
+           buff_rx,
+           rfalConvBytesToBits(buff_rx_size),
+           &buff_rx_len)) {
+        rfalListenStop();
+        FURI_LOG_E(TAG, "Failed to start listen mode");
+        return false;
+    }
+    while(true) {
+        buff_rx_len = 0;
+        buff_tx_len = 0;
+        uint32_t flag = furi_event_flag_wait(event, EVENT_FLAG_ALL, FuriFlagWaitAny, timeout);
+        if(flag == (unsigned)FuriFlagErrorTimeout || flag == EVENT_FLAG_STOP) {
+            break;
+        }
+        bool data_received = false;
+        buff_rx_len = 0;
+        rfalWorker();
+        rfalLmState state = rfalListenGetState(&data_received, NULL);
+        if(data_received) {
+            rfalTransceiveBlockingRx();
+            if(nfca_emulation_handler(buff_rx, buff_rx_len, buff_tx, &buff_tx_len)) {
+                if(rfalListenSleepStart(
+                       RFAL_LM_STATE_SLEEP_A,
+                       buff_rx,
+                       rfalConvBytesToBits(buff_rx_size),
+                       &buff_rx_len)) {
+                    FURI_LOG_E(TAG, "Failed to enter sleep mode");
+                    break;
+                } else {
+                    continue;
+                }
+            }
+            if(buff_tx_len) {
+                ReturnCode ret = rfalTransceiveBitsBlockingTx(
+                    buff_tx,
+                    buff_tx_len,
+                    buff_rx,
+                    rfalConvBytesToBits(buff_rx_size),
+                    &buff_rx_len,
+                    data_type,
+                    RFAL_FWT_NONE);
+                if(ret) {
+                    FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
+                    break;
+                }
+                continue;
+            }
+            if((state == RFAL_LM_STATE_ACTIVE_A || state == RFAL_LM_STATE_ACTIVE_Ax)) {
+                if(callback) {
+                    callback(buff_rx, buff_rx_len, buff_tx, &buff_tx_len, &data_type, context);
+                }
+                if(!rfalIsExtFieldOn()) {
+                    break;
+                }
+                if(buff_tx_len) {
+                    if(buff_tx_len == UINT16_MAX) buff_tx_len = 0;
+
+                    ReturnCode ret = rfalTransceiveBitsBlockingTx(
+                        buff_tx,
+                        buff_tx_len,
+                        buff_rx,
+                        rfalConvBytesToBits(buff_rx_size),
+                        &buff_rx_len,
+                        data_type,
+                        RFAL_FWT_NONE);
+                    if(ret) {
+                        FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
+                        continue;
+                    }
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+    rfalListenStop();
+    return true;
+}
+
+static bool furry_hal_nfc_transparent_tx_rx(FurryHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
+    furi_assert(tx_rx->nfca_signal);
+
+    bool ret = false;
+
+    // Start transparent mode
+    st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
+    // Reconfigure gpio for Transparent mode
+    furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
+
+    // Send signal
+    FURI_CRITICAL_ENTER();
+    nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits, tx_rx->tx_parity);
+    digital_signal_send(tx_rx->nfca_signal->tx_signal, &gpio_spi_r_mosi);
+    FURI_CRITICAL_EXIT();
+    furi_hal_gpio_write(&gpio_spi_r_mosi, false);
+
+    // Configure gpio back to SPI and exit transparent
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
+    st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA);
+
+    // Manually wait for interrupt
+    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
+    st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE);
+
+    if(tx_rx->sniff_tx) {
+        tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context);
+    }
+
+    uint32_t irq = 0;
+    uint8_t rxe = 0;
+    uint32_t start = DWT->CYCCNT;
+    while(true) {
+        if(!rfalIsExtFieldOn()) {
+            return false;
+        }
+        if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) {
+            st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe);
+            if(rxe & (1 << 4)) {
+                irq = 1;
+                break;
+            }
+        }
+        uint32_t timeout = DWT->CYCCNT - start;
+        if(timeout / furi_hal_cortex_instructions_per_microsecond() > timeout_ms * 1000) {
+            FURI_LOG_D(TAG, "Interrupt waiting timeout");
+            break;
+        }
+    }
+    if(irq) {
+        uint8_t fifo_stat[2];
+        st25r3916ReadMultipleRegisters(
+            ST25R3916_REG_FIFO_STATUS1, fifo_stat, ST25R3916_FIFO_STATUS_LEN);
+        uint16_t len =
+            ((((uint16_t)fifo_stat[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
+              ST25R3916_REG_FIFO_STATUS2_fifo_b_shift)
+             << RFAL_BITS_IN_BYTE);
+        len |= (((uint16_t)fifo_stat[0]) & 0x00FFU);
+        uint8_t rx[100];
+        st25r3916ReadFifo(rx, len);
+
+        tx_rx->rx_bits = len * 8;
+        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;
+    } else {
+        FURI_LOG_E(TAG, "Timeout error");
+        ret = false;
+    }
+
+    st25r3916ClearInterrupts();
+
+    return ret;
+}
+
+static uint32_t furry_hal_nfc_tx_rx_get_flag(FurryHalNfcTxRxType type) {
+    uint32_t flags = 0;
+
+    if(type == FurryHalNfcTxRxTypeRxNoCrc) {
+        flags = RFAL_TXRX_FLAGS_CRC_RX_KEEP;
+    } else if(type == FurryHalNfcTxRxTypeRxKeepPar) {
+        flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                RFAL_TXRX_FLAGS_PAR_RX_KEEP;
+    } else if(type == FurryHalNfcTxRxTypeRaw) {
+        flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE;
+    } else if(type == FurryHalNfcTxRxTypeRxRaw) {
+        flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
+                RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE;
+    }
+
+    return flags;
+}
+
+static uint16_t furry_hal_nfc_data_and_parity_to_bitstream(
+    uint8_t* data,
+    uint16_t len,
+    uint8_t* parity,
+    uint8_t* out) {
+    furi_assert(data);
+    furi_assert(out);
+
+    uint8_t next_par_bit = 0;
+    uint16_t curr_bit_pos = 0;
+    for(uint16_t i = 0; i < len; i++) {
+        next_par_bit = FURI_BIT(parity[i / 8], 7 - (i % 8));
+        if(curr_bit_pos % 8 == 0) {
+            out[curr_bit_pos / 8] = data[i];
+            curr_bit_pos += 8;
+            out[curr_bit_pos / 8] = next_par_bit;
+            curr_bit_pos++;
+        } else {
+            out[curr_bit_pos / 8] |= data[i] << (curr_bit_pos % 8);
+            out[curr_bit_pos / 8 + 1] = data[i] >> (8 - curr_bit_pos % 8);
+            out[curr_bit_pos / 8 + 1] |= next_par_bit << (curr_bit_pos % 8);
+            curr_bit_pos += 9;
+        }
+    }
+    return curr_bit_pos;
+}
+
+uint16_t furry_hal_nfc_bitstream_to_data_and_parity(
+    uint8_t* in_buff,
+    uint16_t in_buff_bits,
+    uint8_t* out_data,
+    uint8_t* out_parity) {
+    if(in_buff_bits < 8) {
+        out_data[0] = in_buff[0];
+        return in_buff_bits;
+    }
+    if(in_buff_bits % 9 != 0) {
+        return 0;
+    }
+
+    uint8_t curr_byte = 0;
+    uint16_t bit_processed = 0;
+    memset(out_parity, 0, in_buff_bits / 9);
+    while(bit_processed < in_buff_bits) {
+        out_data[curr_byte] = in_buff[bit_processed / 8] >> (bit_processed % 8);
+        out_data[curr_byte] |= in_buff[bit_processed / 8 + 1] << (8 - bit_processed % 8);
+        out_parity[curr_byte / 8] |= FURI_BIT(in_buff[bit_processed / 8 + 1], bit_processed % 8)
+                                     << (7 - curr_byte % 8);
+        bit_processed += 9;
+        curr_byte++;
+    }
+    return curr_byte * 8;
+}
+
+bool furry_hal_nfc_tx_rx(FurryHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
+    furi_assert(tx_rx);
+
+    ReturnCode ret;
+    rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
+    uint8_t temp_tx_buff[FURRY_HAL_NFC_DATA_BUFF_SIZE] = {};
+    uint16_t temp_tx_bits = 0;
+    uint8_t* temp_rx_buff = NULL;
+    uint16_t* temp_rx_bits = NULL;
+
+    if(tx_rx->tx_rx_type == FurryHalNfcTxRxTransparent) {
+        return furry_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms);
+    }
+
+    // Prepare data for FIFO if necessary
+    uint32_t flags = furry_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type);
+    if(tx_rx->tx_rx_type == FurryHalNfcTxRxTypeRaw) {
+        temp_tx_bits = furry_hal_nfc_data_and_parity_to_bitstream(
+            tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity, temp_tx_buff);
+        ret = rfalNfcDataExchangeCustomStart(
+            temp_tx_buff, temp_tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
+    } else {
+        ret = rfalNfcDataExchangeCustomStart(
+            tx_rx->tx_data, tx_rx->tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
+    }
+    if(ret != ERR_NONE) {
+        FURI_LOG_E(TAG, "Failed to start data exchange");
+        return false;
+    }
+
+    if(tx_rx->sniff_tx) {
+        bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_TX_MANUAL);
+        tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, crc_dropped, tx_rx->sniff_context);
+    }
+
+    uint32_t start = DWT->CYCCNT;
+    while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) {
+        rfalNfcWorker();
+        state = rfalNfcGetState();
+        ret = rfalNfcDataExchangeGetStatus();
+        if(ret == ERR_WRONG_STATE) {
+            return false;
+        } else if(ret == ERR_BUSY) {
+            if(DWT->CYCCNT - start > timeout_ms * clocks_in_ms) {
+                FURI_LOG_D(TAG, "Timeout during data exchange");
+                return false;
+            }
+            continue;
+        } else {
+            start = DWT->CYCCNT;
+        }
+        furi_delay_tick(1);
+    }
+
+    if(tx_rx->tx_rx_type == FurryHalNfcTxRxTypeRaw ||
+       tx_rx->tx_rx_type == FurryHalNfcTxRxTypeRxRaw) {
+        tx_rx->rx_bits = furry_hal_nfc_bitstream_to_data_and_parity(
+            temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity);
+    } else {
+        memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURRY_HAL_NFC_DATA_BUFF_SIZE));
+        tx_rx->rx_bits = *temp_rx_bits;
+    }
+
+    if(tx_rx->sniff_rx) {
+        bool crc_dropped = !(flags & RFAL_TXRX_FLAGS_CRC_RX_KEEP);
+        tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, crc_dropped, tx_rx->sniff_context);
+    }
+
+    return true;
+}
+
+bool furry_hal_nfc_tx_rx_full(FurryHalNfcTxRxContext* tx_rx) {
+    uint16_t part_len_bytes;
+
+    if(!furry_hal_nfc_tx_rx(tx_rx, 1000)) {
+        return false;
+    }
+    while(tx_rx->rx_bits && tx_rx->rx_data[0] == 0xAF) {
+        FurryHalNfcTxRxContext tmp = *tx_rx;
+        tmp.tx_data[0] = 0xAF;
+        tmp.tx_bits = 8;
+        if(!furry_hal_nfc_tx_rx(&tmp, 1000)) {
+            return false;
+        }
+        part_len_bytes = tmp.rx_bits / 8;
+        if(part_len_bytes > FURRY_HAL_NFC_DATA_BUFF_SIZE - tx_rx->rx_bits / 8) {
+            FURI_LOG_W(TAG, "Overrun rx buf");
+            return false;
+        }
+        if(part_len_bytes == 0) {
+            FURI_LOG_W(TAG, "Empty 0xAF response");
+            return false;
+        }
+        memcpy(tx_rx->rx_data + tx_rx->rx_bits / 8, tmp.rx_data + 1, part_len_bytes - 1);
+        tx_rx->rx_data[0] = tmp.rx_data[0];
+        tx_rx->rx_bits += 8 * (part_len_bytes - 1);
+    }
+
+    return true;
+}
+
+void furry_hal_nfc_sleep() {
+    rfalNfcDeactivate(false);
+    rfalLowPowerModeStart();
+}
+
+FurryHalNfcReturn furry_hal_nfc_ll_set_mode(
+    FurryHalNfcMode mode,
+    FurryHalNfcBitrate txBR,
+    FurryHalNfcBitrate rxBR) {
+    return rfalSetMode((rfalMode)mode, (rfalBitRate)txBR, (rfalBitRate)rxBR);
+}
+
+void furry_hal_nfc_ll_set_error_handling(FurryHalNfcErrorHandling eHandling) {
+    rfalSetErrorHandling((rfalEHandling)eHandling);
+}
+
+void furry_hal_nfc_ll_set_guard_time(uint32_t cycles) {
+    rfalSetGT(cycles);
+}
+
+void furry_hal_nfc_ll_set_fdt_listen(uint32_t cycles) {
+    rfalSetFDTListen(cycles);
+}
+
+void furry_hal_nfc_ll_set_fdt_poll(uint32_t FDTPoll) {
+    rfalSetFDTPoll(FDTPoll);
+}
+
+void furry_hal_nfc_ll_txrx_on() {
+    st25r3916TxRxOn();
+}
+
+void furry_hal_nfc_ll_txrx_off() {
+    st25r3916TxRxOff();
+}
+
+FurryHalNfcReturn furry_hal_nfc_ll_txrx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    return rfalTransceiveBlockingTxRx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt);
+}
+
+FurryHalNfcReturn furry_hal_nfc_ll_txrx_bits(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt) {
+    return rfalTransceiveBitsBlockingTxRx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt);
+}
+
+void furry_hal_nfc_ll_poll() {
+    rfalWorker();
+}
+
+void furry_hal_nfc_field_detect_start() {
+    st25r3916WriteRegister(
+        ST25R3916_REG_OP_CONTROL,
+        ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask);
+    st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om0);
+}
+
+bool furry_hal_nfc_field_is_present() {
+    return st25r3916CheckReg(
+        ST25R3916_REG_AUX_DISPLAY,
+        ST25R3916_REG_AUX_DISPLAY_efd_o,
+        ST25R3916_REG_AUX_DISPLAY_efd_o);
+}

+ 438 - 0
esubghz_chat/lib/nfclegacy/furi_hal_nfc.h

@@ -0,0 +1,438 @@
+/**
+ * @file furry_hal_nfc.h
+ * NFC HAL API
+ */
+
+#pragma once
+
+#include "ST25RFAL002/st_errno.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "ST25RFAL002/include/rfal_nfc.h"
+#include "protocols/nfca.h"
+
+#define FURRY_HAL_NFC_UID_MAX_LEN 10
+#define FURRY_HAL_NFC_DATA_BUFF_SIZE (512)
+#define FURRY_HAL_NFC_PARITY_BUFF_SIZE (FURRY_HAL_NFC_DATA_BUFF_SIZE / 8)
+
+#define FURRY_HAL_NFC_TXRX_DEFAULT                                                   \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
+
+#define FURRY_HAL_NFC_TX_DEFAULT_RX_NO_CRC                                           \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
+
+#define FURRY_HAL_NFC_TXRX_WITH_PAR                                                    \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
+
+#define FURRY_HAL_NFC_TXRX_RAW                                                         \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE)
+
+#define FURRY_HAL_NFC_TX_RAW_RX_DEFAULT                                                \
+    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
+     (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE)
+
+typedef enum {
+    FurryHalNfcTxRxTypeDefault,
+    FurryHalNfcTxRxTypeRxNoCrc,
+    FurryHalNfcTxRxTypeRxKeepPar,
+    FurryHalNfcTxRxTypeRaw,
+    FurryHalNfcTxRxTypeRxRaw,
+    FurryHalNfcTxRxTransparent,
+} FurryHalNfcTxRxType;
+
+typedef bool (*FurryHalNfcEmulateCallback)(
+    uint8_t* buff_rx,
+    uint16_t buff_rx_len,
+    uint8_t* buff_tx,
+    uint16_t* buff_tx_len,
+    uint32_t* flags,
+    void* context);
+
+typedef enum {
+    FurryHalNfcTypeA,
+    FurryHalNfcTypeB,
+    FurryHalNfcTypeF,
+    FurryHalNfcTypeV,
+} FurryHalNfcType;
+
+typedef enum {
+    FurryHalNfcInterfaceRf,
+    FurryHalNfcInterfaceIsoDep,
+    FurryHalNfcInterfaceNfcDep,
+} FurryHalNfcInterface;
+
+typedef struct {
+    FurryHalNfcType type;
+    FurryHalNfcInterface interface;
+    uint8_t uid_len;
+    uint8_t uid[10];
+    uint32_t cuid;
+    uint8_t atqa[2];
+    uint8_t sak;
+} FurryHalNfcDevData;
+
+typedef void (
+    *FurryHalNfcTxRxSniffCallback)(uint8_t* data, uint16_t bits, bool crc_dropped, void* context);
+
+typedef struct {
+    uint8_t tx_data[FURRY_HAL_NFC_DATA_BUFF_SIZE];
+    uint8_t tx_parity[FURRY_HAL_NFC_PARITY_BUFF_SIZE];
+    uint16_t tx_bits;
+    uint8_t rx_data[FURRY_HAL_NFC_DATA_BUFF_SIZE];
+    uint8_t rx_parity[FURRY_HAL_NFC_PARITY_BUFF_SIZE];
+    uint16_t rx_bits;
+    FurryHalNfcTxRxType tx_rx_type;
+    NfcaSignal* nfca_signal;
+
+    FurryHalNfcTxRxSniffCallback sniff_tx;
+    FurryHalNfcTxRxSniffCallback sniff_rx;
+    void* sniff_context;
+} FurryHalNfcTxRxContext;
+
+/** Init nfc
+ */
+void furry_hal_nfc_init();
+
+/** Deinit nfc
+ */
+void furry_hal_nfc_deinit();
+
+/** Check if nfc worker is busy
+ *
+ * @return     true if busy
+ */
+bool furry_hal_nfc_is_busy();
+
+/** Check if nfc is initialized
+ *
+ * @return     true if initialized
+ */
+bool furry_hal_nfc_is_init();
+
+/** NFC field on
+ */
+void furry_hal_nfc_field_on();
+
+/** NFC field off
+ */
+void furry_hal_nfc_field_off();
+
+/** NFC start sleep
+ */
+void furry_hal_nfc_start_sleep();
+
+void furry_hal_nfc_stop_cmd();
+
+/** NFC stop sleep
+ */
+void furry_hal_nfc_exit_sleep();
+
+/** NFC poll
+ *
+ * @param      dev_list    pointer to rfalNfcDevice buffer
+ * @param      dev_cnt     pointer device count
+ * @param      timeout     timeout in ms
+ * @param      deactivate  deactivate flag
+ *
+ * @return     true on success
+ */
+bool furry_hal_nfc_detect(FurryHalNfcDevData* nfc_data, uint32_t timeout);
+
+/** Activate NFC-A tag
+ *
+ * @param      timeout      timeout in ms
+ * @param      cuid         pointer to 32bit uid
+ *
+ * @return     true on succeess
+ */
+bool furry_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid);
+
+/** NFC listen
+ *
+ * @param      uid                 pointer to uid buffer
+ * @param      uid_len             uid length
+ * @param      atqa                pointer to atqa
+ * @param      sak                 sak
+ * @param      activate_after_sak  activate after sak flag
+ * @param      timeout             timeout in ms
+ *
+ * @return     true on success
+ */
+bool furry_hal_nfc_listen(
+    uint8_t* uid,
+    uint8_t uid_len,
+    uint8_t* atqa,
+    uint8_t sak,
+    bool activate_after_sak,
+    uint32_t timeout);
+
+/** Start Target Listen mode
+ * @note RFAL free implementation
+ *
+ * @param       nfc_data            FurryHalNfcDevData instance
+ */
+void furry_hal_nfc_listen_start(FurryHalNfcDevData* nfc_data);
+
+/** Read data in Target Listen mode
+ * @note Must be called only after furry_hal_nfc_listen_start()
+ *
+ * @param       tx_rx               FurryHalNfcTxRxContext instance
+ * @param       timeout_ms          timeout im ms
+ *
+ * @return      true on not empty receive
+ */
+bool furry_hal_nfc_listen_rx(FurryHalNfcTxRxContext* tx_rx, uint32_t timeout_ms);
+
+/** Set Target in Sleep state */
+void furry_hal_nfc_listen_sleep();
+
+/** Emulate NFC-A Target
+ * @note RFAL based implementation
+ *
+ * @param       uid                 NFC-A UID
+ * @param       uid_len             NFC-A UID length
+ * @param       atqa                NFC-A ATQA
+ * @param       sak                 NFC-A SAK
+ * @param       callback            FurryHalNfcEmulateCallback instance
+ * @param       context             pointer to context for callback
+ * @param       timeout             timeout in ms
+ *
+ * @return      true on success
+ */
+bool furry_hal_nfc_emulate_nfca(
+    uint8_t* uid,
+    uint8_t uid_len,
+    uint8_t* atqa,
+    uint8_t sak,
+    FurryHalNfcEmulateCallback callback,
+    void* context,
+    uint32_t timeout);
+
+/** NFC data exchange
+ *
+ * @param       tx_rx_ctx   FurryHalNfcTxRxContext instance
+ *
+ * @return      true on success
+ */
+bool furry_hal_nfc_tx_rx(FurryHalNfcTxRxContext* tx_rx, uint16_t timeout_ms);
+
+/** NFC data full exhange
+ *
+ * @param       tx_rx_ctx   FurryHalNfcTxRxContext instance
+ *
+ * @return      true on success
+ */
+bool furry_hal_nfc_tx_rx_full(FurryHalNfcTxRxContext* tx_rx);
+
+/** NFC deactivate and start sleep
+ */
+void furry_hal_nfc_sleep();
+
+void furry_hal_nfc_stop();
+
+/* Low level transport API, use it to implement your own transport layers */
+
+#define furry_hal_nfc_ll_ms2fc rfalConvMsTo1fc
+
+#define FURRY_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL RFAL_TXRX_FLAGS_CRC_TX_MANUAL
+#define FURRY_HAL_NFC_LL_TXRX_FLAGS_AGC_ON RFAL_TXRX_FLAGS_AGC_ON
+#define FURRY_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV RFAL_TXRX_FLAGS_PAR_RX_REMV
+#define FURRY_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP RFAL_TXRX_FLAGS_CRC_RX_KEEP
+
+typedef enum {
+    FurryHalNfcReturnOk = 0, /*!< no error occurred */
+    FurryHalNfcReturnNomem = 1, /*!< not enough memory to perform the requested operation */
+    FurryHalNfcReturnBusy = 2, /*!< device or resource busy */
+    FurryHalNfcReturnIo = 3, /*!< generic IO error */
+    FurryHalNfcReturnTimeout = 4, /*!< error due to timeout */
+    FurryHalNfcReturnRequest =
+        5, /*!< invalid request or requested function can't be executed at the moment */
+    FurryHalNfcReturnNomsg = 6, /*!< No message of desired type */
+    FurryHalNfcReturnParam = 7, /*!< Parameter error */
+    FurryHalNfcReturnSystem = 8, /*!< System error */
+    FurryHalNfcReturnFraming = 9, /*!< Framing error */
+    FurryHalNfcReturnOverrun = 10, /*!< lost one or more received bytes */
+    FurryHalNfcReturnProto = 11, /*!< protocol error */
+    FurryHalNfcReturnInternal = 12, /*!< Internal Error */
+    FurryHalNfcReturnAgain = 13, /*!< Call again */
+    FurryHalNfcReturnMemCorrupt = 14, /*!< memory corruption */
+    FurryHalNfcReturnNotImplemented = 15, /*!< not implemented */
+    FurryHalNfcReturnPcCorrupt =
+        16, /*!< Program Counter has been manipulated or spike/noise trigger illegal operation */
+    FurryHalNfcReturnSend = 17, /*!< error sending*/
+    FurryHalNfcReturnIgnore = 18, /*!< indicates error detected but to be ignored */
+    FurryHalNfcReturnSemantic = 19, /*!< indicates error in state machine (unexpected cmd) */
+    FurryHalNfcReturnSyntax = 20, /*!< indicates error in state machine (unknown cmd) */
+    FurryHalNfcReturnCrc = 21, /*!< crc error */
+    FurryHalNfcReturnNotfound = 22, /*!< transponder not found */
+    FurryHalNfcReturnNotunique =
+        23, /*!< transponder not unique - more than one transponder in field */
+    FurryHalNfcReturnNotsupp = 24, /*!< requested operation not supported */
+    FurryHalNfcReturnWrite = 25, /*!< write error */
+    FurryHalNfcReturnFifo = 26, /*!< fifo over or underflow error */
+    FurryHalNfcReturnPar = 27, /*!< parity error */
+    FurryHalNfcReturnDone = 28, /*!< transfer has already finished */
+    FurryHalNfcReturnRfCollision =
+        29, /*!< collision error (Bit Collision or during RF Collision avoidance ) */
+    FurryHalNfcReturnHwOverrun = 30, /*!< lost one or more received bytes */
+    FurryHalNfcReturnReleaseReq = 31, /*!< device requested release */
+    FurryHalNfcReturnSleepReq = 32, /*!< device requested sleep */
+    FurryHalNfcReturnWrongState = 33, /*!< incorrent state for requested operation */
+    FurryHalNfcReturnMaxReruns = 34, /*!< blocking procedure reached maximum runs */
+    FurryHalNfcReturnDisabled = 35, /*!< operation aborted due to disabled configuration */
+    FurryHalNfcReturnHwMismatch = 36, /*!< expected hw do not match  */
+    FurryHalNfcReturnLinkLoss =
+        37, /*!< Other device's field didn't behave as expected: turned off by Initiator in Passive mode, or AP2P did not turn on field */
+    FurryHalNfcReturnInvalidHandle = 38, /*!< invalid or not initalized device handle */
+    FurryHalNfcReturnIncompleteByte = 40, /*!< Incomplete byte rcvd         */
+    FurryHalNfcReturnIncompleteByte01 = 41, /*!< Incomplete byte rcvd - 1 bit */
+    FurryHalNfcReturnIncompleteByte02 = 42, /*!< Incomplete byte rcvd - 2 bit */
+    FurryHalNfcReturnIncompleteByte03 = 43, /*!< Incomplete byte rcvd - 3 bit */
+    FurryHalNfcReturnIncompleteByte04 = 44, /*!< Incomplete byte rcvd - 4 bit */
+    FurryHalNfcReturnIncompleteByte05 = 45, /*!< Incomplete byte rcvd - 5 bit */
+    FurryHalNfcReturnIncompleteByte06 = 46, /*!< Incomplete byte rcvd - 6 bit */
+    FurryHalNfcReturnIncompleteByte07 = 47, /*!< Incomplete byte rcvd - 7 bit */
+} FurryHalNfcReturn;
+
+typedef enum {
+    FurryHalNfcModeNone = 0, /*!< No mode selected/defined */
+    FurryHalNfcModePollNfca = 1, /*!< Mode to perform as NFCA (ISO14443A) Poller (PCD) */
+    FurryHalNfcModePollNfcaT1t = 2, /*!< Mode to perform as NFCA T1T (Topaz) Poller (PCD) */
+    FurryHalNfcModePollNfcb = 3, /*!< Mode to perform as NFCB (ISO14443B) Poller (PCD) */
+    FurryHalNfcModePollBPrime = 4, /*!< Mode to perform as B' Calypso (Innovatron) (PCD) */
+    FurryHalNfcModePollBCts = 5, /*!< Mode to perform as CTS Poller (PCD) */
+    FurryHalNfcModePollNfcf = 6, /*!< Mode to perform as NFCF (FeliCa) Poller (PCD) */
+    FurryHalNfcModePollNfcv = 7, /*!< Mode to perform as NFCV (ISO15963) Poller (PCD) */
+    FurryHalNfcModePollPicopass = 8, /*!< Mode to perform as PicoPass / iClass Poller (PCD) */
+    FurryHalNfcModePollActiveP2p = 9, /*!< Mode to perform as Active P2P (ISO18092) Initiator  */
+    FurryHalNfcModeListenNfca = 10, /*!< Mode to perform as NFCA (ISO14443A) Listener (PICC) */
+    FurryHalNfcModeListenNfcb = 11, /*!< Mode to perform as NFCA (ISO14443B) Listener (PICC) */
+    FurryHalNfcModeListenNfcf = 12, /*!< Mode to perform as NFCA (ISO15963) Listener (PICC) */
+    FurryHalNfcModeListenActiveP2p = 13 /*!< Mode to perform as Active P2P (ISO18092) Target  */
+} FurryHalNfcMode;
+
+typedef enum {
+    FurryHalNfcBitrate106 = 0, /*!< Bit Rate 106 kbit/s (fc/128) */
+    FurryHalNfcBitrate212 = 1, /*!< Bit Rate 212 kbit/s (fc/64) */
+    FurryHalNfcBitrate424 = 2, /*!< Bit Rate 424 kbit/s (fc/32) */
+    FurryHalNfcBitrate848 = 3, /*!< Bit Rate 848 kbit/s (fc/16) */
+    FurryHalNfcBitrate1695 = 4, /*!< Bit Rate 1695 kbit/s (fc/8) */
+    FurryHalNfcBitrate3390 = 5, /*!< Bit Rate 3390 kbit/s (fc/4) */
+    FurryHalNfcBitrate6780 = 6, /*!< Bit Rate 6780 kbit/s (fc/2) */
+    FurryHalNfcBitrate13560 = 7, /*!< Bit Rate 13560 kbit/s (fc) */
+    FurryHalNfcBitrate52p97 = 0xEB, /*!< Bit Rate 52.97 kbit/s (fc/256) Fast Mode VICC->VCD */
+    FurryHalNfcBitrate26p48 =
+        0xEC, /*!< Bit Rate 26,48 kbit/s (fc/512) NFCV VICC->VCD & VCD->VICC 1of4 */
+    FurryHalNfcBitrate1p66 = 0xED, /*!< Bit Rate 1,66 kbit/s (fc/8192) NFCV VCD->VICC 1of256 */
+    FurryHalNfcBitrateKeep = 0xFF /*!< Value indicating to keep the same previous bit rate */
+} FurryHalNfcBitrate;
+
+FurryHalNfcReturn furry_hal_nfc_ll_set_mode(
+    FurryHalNfcMode mode,
+    FurryHalNfcBitrate txBR,
+    FurryHalNfcBitrate rxBR);
+
+#define FURRY_HAL_NFC_LL_GT_NFCA \
+    furry_hal_nfc_ll_ms2fc(5U) /*!< GTA  Digital 2.0  6.10.4.1 & B.2 */
+#define FURRY_HAL_NFC_LL_GT_NFCB \
+    furry_hal_nfc_ll_ms2fc(5U) /*!< GTB  Digital 2.0  7.9.4.1  & B.3 */
+#define FURRY_HAL_NFC_LL_GT_NFCF \
+    furry_hal_nfc_ll_ms2fc(20U) /*!< GTF  Digital 2.0  8.7.4.1  & B.4 */
+#define FURRY_HAL_NFC_LL_GT_NFCV \
+    furry_hal_nfc_ll_ms2fc(5U) /*!< GTV  Digital 2.0  9.7.5.1  & B.5 */
+#define FURRY_HAL_NFC_LL_GT_PICOPASS furry_hal_nfc_ll_ms2fc(1U) /*!< GT Picopass */
+#define FURRY_HAL_NFC_LL_GT_AP2P furry_hal_nfc_ll_ms2fc(5U) /*!< TIRFG  Ecma 340  11.1.1 */
+#define FURRY_HAL_NFC_LL_GT_AP2P_ADJUSTED \
+    furry_hal_nfc_ll_ms2fc(               \
+        5U +                              \
+        25U) /*!< Adjusted GT for greater interoperability (Sony XPERIA P, Nokia N9, Huawei P2) */
+
+void furry_hal_nfc_ll_set_guard_time(uint32_t cycles);
+
+typedef enum {
+    FurryHalNfcErrorHandlingNone = 0, /*!< No special error handling will be performed */
+    FurryHalNfcErrorHandlingNfc = 1, /*!< Error handling set to perform as NFC compliant device */
+    FurryHalNfcErrorHandlingEmvco =
+        2 /*!< Error handling set to perform as EMVCo compliant device */
+} FurryHalNfcErrorHandling;
+
+void furry_hal_nfc_ll_set_error_handling(FurryHalNfcErrorHandling eHandling);
+
+/* RFAL Frame Delay Time (FDT) Listen default values   */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER \
+    1172U /*!< FDTA,LISTEN,MIN (n=9) Last bit: Logic "1" - tnn,min/2 Digital 1.1  6.10 ;  EMV CCP Spec Book D v2.01  4.8.1.3 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCB_POLLER \
+    1008U /*!< TR0B,MIN         Digital 1.1  7.1.3 & A.3  ; EMV CCP Spec Book D v2.01  4.8.1.3 & Table A.5 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCF_POLLER \
+    2672U /*!< TR0F,LISTEN,MIN  Digital 1.1  8.7.1.1 & A.4 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER \
+    4310U /*!< FDTV,LISTEN,MIN  t1 min       Digital 2.1  B.5  ;  ISO15693-3 2009  9.1 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_PICOPASS_POLLER \
+    3400U /*!< ISO15693 t1 min - observed adjustment */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_AP2P_POLLER \
+    64U /*!< FDT AP2P No actual FDTListen is required as fields switch and collision avoidance */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCA_LISTENER 1172U /*!< FDTA,LISTEN,MIN  Digital 1.1  6.10 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCB_LISTENER \
+    1024U /*!< TR0B,MIN         Digital 1.1  7.1.3 & A.3  ;  EMV CCP Spec Book D v2.01  4.8.1.3 & Table A.5 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_NFCF_LISTENER \
+    2688U /*!< TR0F,LISTEN,MIN  Digital 2.1  8.7.1.1 & B.4 */
+#define FURRY_HAL_NFC_LL_FDT_LISTEN_AP2P_LISTENER \
+    64U /*!< FDT AP2P No actual FDTListen exists as fields switch and collision avoidance */
+
+void furry_hal_nfc_ll_set_fdt_listen(uint32_t cycles);
+
+/*  RFAL Frame Delay Time (FDT) Poll default values    */
+#define FURRY_HAL_NFC_LL_FDT_POLL_NFCA_POLLER \
+    6780U /*!< FDTA,POLL,MIN   Digital 1.1  6.10.3.1 & A.2 */
+#define FURRY_HAL_NFC_LL_FDT_POLL_NFCA_T1T_POLLER \
+    384U /*!< RRDDT1T,MIN,B1  Digital 1.1  10.7.1 & A.5 */
+#define FURRY_HAL_NFC_LL_FDT_POLL_NFCB_POLLER \
+    6780U /*!< FDTB,POLL,MIN = TR2B,MIN,DEFAULT Digital 1.1 7.9.3 & A.3  ;  EMVCo 3.0 FDTB,PCD,MIN  Table A.5 */
+#define FURRY_HAL_NFC_LL_FDT_POLL_NFCF_POLLER \
+    6800U /*!< FDTF,POLL,MIN   Digital 2.1  8.7.3 & B.4 */
+#define FURRY_HAL_NFC_LL_FDT_POLL_NFCV_POLLER 4192U /*!< FDTV,POLL  Digital 2.1  9.7.3.1  & B.5 */
+#define FURRY_HAL_NFC_LL_FDT_POLL_PICOPASS_POLLER 1790U /*!< FDT Max */
+#define FURRY_HAL_NFC_LL_FDT_POLL_AP2P_POLLER \
+    0U /*!< FDT AP2P No actual FDTPoll exists as fields switch and collision avoidance */
+
+void furry_hal_nfc_ll_set_fdt_poll(uint32_t FDTPoll);
+
+void furry_hal_nfc_ll_txrx_on();
+
+void furry_hal_nfc_ll_txrx_off();
+
+FurryHalNfcReturn furry_hal_nfc_ll_txrx(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+FurryHalNfcReturn furry_hal_nfc_ll_txrx_bits(
+    uint8_t* txBuf,
+    uint16_t txBufLen,
+    uint8_t* rxBuf,
+    uint16_t rxBufLen,
+    uint16_t* actLen,
+    uint32_t flags,
+    uint32_t fwt);
+
+void furry_hal_nfc_ll_poll();
+
+void furry_hal_nfc_field_detect_start();
+
+bool furry_hal_nfc_field_is_present();
+
+#ifdef __cplusplus
+}
+#endif

+ 558 - 0
esubghz_chat/lib/nfclegacy/nfc_device.c

@@ -0,0 +1,558 @@
+#include "nfc_device.h"
+#include "nfc_types.h"
+
+#include <lib/toolbox/path.h>
+#include <lib/toolbox/hex.h>
+#include "protocols/nfc_util.h"
+#include <flipper_format/flipper_format.h>
+
+#define TAG "NfcDevice"
+#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/.cache")
+#define NFC_DEVICE_KEYS_EXTENSION ".keys"
+
+static const char* nfc_file_header = "Flipper NFC device";
+static const uint32_t nfc_file_version = 3;
+
+// Protocols format versions
+static const uint32_t nfc_mifare_ultralight_data_format_version = 1;
+
+NfcDevice* nfc_device_alloc() {
+    NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
+    nfc_dev->storage = furi_record_open(RECORD_STORAGE);
+    nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
+    nfc_dev->load_path = furi_string_alloc();
+    nfc_dev->dev_data.parsed_data = furi_string_alloc();
+    nfc_dev->folder = furi_string_alloc();
+
+    return nfc_dev;
+}
+
+void nfc_device_free(NfcDevice* nfc_dev) {
+    furi_assert(nfc_dev);
+    nfc_device_clear(nfc_dev);
+    furi_record_close(RECORD_STORAGE);
+    furi_record_close(RECORD_DIALOGS);
+    furi_string_free(nfc_dev->load_path);
+    if(nfc_dev->dev_data.parsed_data != NULL) {
+        furi_string_free(nfc_dev->dev_data.parsed_data);
+    }
+    furi_string_free(nfc_dev->folder);
+    free(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");
+    }
+}
+
+static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_string) {
+    if(furi_string_start_with_str(format_string, "UID")) {
+        dev->format = NfcDeviceSaveFormatUid;
+        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;
+        }
+    }
+    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;
+}
+
+void nfc_device_set_name(NfcDevice* dev, const char* name) {
+    furi_assert(dev);
+
+    strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN);
+}
+
+static void nfc_device_get_path_without_ext(FuriString* orig_path, FuriString* shadow_path) {
+    // TODO: this won't work if there is ".nfc" anywhere in the path other than
+    // at the end
+    size_t ext_start = furi_string_search(orig_path, NFC_APP_FILENAME_EXTENSION);
+    furi_string_set_n(shadow_path, orig_path, 0, ext_start);
+}
+
+static void nfc_device_get_shadow_path(FuriString* orig_path, FuriString* shadow_path) {
+    nfc_device_get_path_without_ext(orig_path, shadow_path);
+    furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION);
+}
+
+static void nfc_device_get_folder_from_path(FuriString* path, FuriString* folder) {
+    size_t last_slash = furi_string_search_rchar(path, '/');
+    if(last_slash == FURI_STRING_FAILURE) {
+        // No slashes in the path, treat the whole path as a folder
+        furi_string_set(folder, path);
+    } else {
+        furi_string_set_n(folder, path, 0, last_slash);
+    }
+}
+
+bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
+    return false;
+    furi_assert(dev);
+
+    bool saved = false;
+    FlipperFormat* file = flipper_format_file_alloc(dev->storage);
+    FurryHalNfcDevData* data = &dev->dev_data.nfc_data;
+    FuriString* temp_str;
+    temp_str = furi_string_alloc();
+
+    do {
+        // Create directory if necessary
+        FuriString* folder = furi_string_alloc();
+        // Get folder from filename (filename is in the form of "folder/filename.nfc", so the folder is "folder/")
+        furi_string_set(temp_str, dev_name);
+        // Get folder from filename
+        nfc_device_get_folder_from_path(temp_str, folder);
+        FURI_LOG_I("Nfc", "Saving to folder %s", furi_string_get_cstr(folder));
+        if(!storage_simply_mkdir(dev->storage, furi_string_get_cstr(folder))) {
+            FURI_LOG_E("Nfc", "Failed to create folder %s", furi_string_get_cstr(folder));
+            break;
+        }
+        furi_string_free(folder);
+        // First remove nfc device file if it was saved
+        // Open file
+        if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
+        // Write header
+        if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
+        // Write nfc device type
+        if(!flipper_format_write_comment_cstr(
+               file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic or ISO15693"))
+            break;
+        nfc_device_prepare_format_string(dev, temp_str);
+        if(!flipper_format_write_string(file, "Device type", temp_str)) break;
+        // Write UID
+        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;
+        }
+
+        // Save more data if necessary
+        if(dev->format == NfcDeviceSaveFormatMifareUl) {
+            if(!nfc_device_save_mifare_ul_data(file, dev)) break;
+        }
+        saved = true;
+    } while(0);
+
+    if(!saved) { //-V547
+        dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
+    }
+    furi_string_free(temp_str);
+    flipper_format_free(file);
+    return saved;
+}
+
+bool nfc_device_save_shadow(NfcDevice* dev, const char* path) {
+    return false;
+    dev->shadow_file_exist = true;
+    // Replace extension from .nfc to .shd if necessary
+    FuriString* orig_path = furi_string_alloc();
+    furi_string_set_str(orig_path, path);
+    FuriString* shadow_path = furi_string_alloc();
+    nfc_device_get_shadow_path(orig_path, shadow_path);
+
+    bool file_saved = nfc_device_save(dev, furi_string_get_cstr(shadow_path));
+    furi_string_free(orig_path);
+    furi_string_free(shadow_path);
+
+    return file_saved;
+}
+
+static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) {
+    bool parsed = false;
+    FlipperFormat* file = flipper_format_file_alloc(dev->storage);
+    FurryHalNfcDevData* data = &dev->dev_data.nfc_data;
+    uint32_t data_cnt = 0;
+    FuriString* temp_str;
+    temp_str = furi_string_alloc();
+    bool deprecated_version = false;
+
+    // Version 2 of file format had ATQA bytes swapped
+    uint32_t version_with_lsb_atqa = 2;
+
+    if(dev->loading_cb) {
+        dev->loading_cb(dev->loading_cb_ctx, true);
+    }
+
+    do {
+        // Check existence of shadow file
+        nfc_device_get_shadow_path(path, temp_str);
+        dev->shadow_file_exist =
+            storage_common_stat(dev->storage, furi_string_get_cstr(temp_str), NULL) == FSE_OK;
+        // Open shadow file if it exists. If not - open original
+        if(dev->shadow_file_exist) {
+            if(!flipper_format_file_open_existing(file, furi_string_get_cstr(temp_str))) break;
+        } else {
+            if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
+        }
+        // Read and verify file header
+        uint32_t version = 0;
+        if(!flipper_format_read_header(file, temp_str, &version)) break;
+        if(furi_string_cmp_str(temp_str, nfc_file_header)) break;
+        if(version != nfc_file_version) {
+            if(version < version_with_lsb_atqa) {
+                deprecated_version = true;
+                break;
+            }
+        }
+        // Read Nfc device type
+        if(!flipper_format_read_string(file, "Device type", temp_str)) break;
+        if(!nfc_device_parse_format_string(dev, temp_str)) break;
+        // Read and parse UID, ATQA and SAK
+        if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
+        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;
+        }
+        // Load CUID
+        uint8_t* cuid_start = data->uid;
+        if(data->uid_len == 7) {
+            cuid_start = &data->uid[3];
+        }
+        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;
+        }
+        parsed = true;
+    } while(false);
+
+    if(dev->loading_cb) {
+        dev->loading_cb(dev->loading_cb_ctx, false);
+    }
+
+    if((!parsed) && (show_dialog)) {
+        if(deprecated_version) {
+            dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
+        } else {
+            dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
+        }
+    }
+
+    furi_string_free(temp_str);
+    flipper_format_free(file);
+    return parsed;
+}
+
+bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog) {
+    furi_assert(dev);
+    furi_assert(file_path);
+
+    // Load device data
+    furi_string_set(dev->load_path, file_path);
+    bool dev_load = nfc_device_load_data(dev, dev->load_path, show_dialog);
+    if(dev_load) {
+        // Set device name
+        FuriString* filename;
+        filename = furi_string_alloc();
+        path_extract_filename_no_ext(file_path, filename);
+        nfc_device_set_name(dev, furi_string_get_cstr(filename));
+        furi_string_free(filename);
+    }
+
+    return dev_load;
+}
+
+void nfc_device_data_clear(NfcDeviceData* dev_data) {
+    if(dev_data->protocol == NfcDeviceProtocolMifareUl) {
+        mf_ul_reset(&dev_data->mf_ul_data);
+    }
+
+    memset(&dev_data->nfc_data, 0, sizeof(FurryHalNfcDevData));
+    dev_data->protocol = NfcDeviceProtocolUnknown;
+    if(dev_data->parsed_data != NULL) {
+        furi_string_reset(dev_data->parsed_data);
+    }
+}
+
+void nfc_device_clear(NfcDevice* dev) {
+    furi_assert(dev);
+
+    nfc_device_set_name(dev, "");
+    nfc_device_data_clear(&dev->dev_data);
+    dev->format = NfcDeviceSaveFormatUid;
+    furi_string_reset(dev->load_path);
+}
+
+bool nfc_device_delete(NfcDevice* dev, bool use_load_path) {
+    furi_assert(dev);
+
+    bool deleted = false;
+    FuriString* file_path;
+    file_path = furi_string_alloc();
+
+    do {
+        // Delete original file
+        if(use_load_path && !furi_string_empty(dev->load_path)) {
+            furi_string_set(file_path, dev->load_path);
+        } else {
+            furi_string_printf(
+                file_path,
+                "%s/%s%s",
+                furi_string_get_cstr(dev->folder),
+                dev->dev_name,
+                NFC_APP_FILENAME_EXTENSION);
+        }
+        if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
+        // Delete shadow file if it exists
+        if(dev->shadow_file_exist) {
+            if(use_load_path && !furi_string_empty(dev->load_path)) {
+                nfc_device_get_shadow_path(dev->load_path, file_path);
+            } else {
+                furi_string_printf(
+                    file_path,
+                    "%s/%s%s",
+                    furi_string_get_cstr(dev->folder),
+                    dev->dev_name,
+                    NFC_APP_SHADOW_EXTENSION);
+            }
+            if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
+        }
+        deleted = true;
+    } while(0);
+
+    if(!deleted) {
+        dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
+    }
+
+    furi_string_free(file_path);
+    return deleted;
+}
+
+bool nfc_device_restore(NfcDevice* dev, bool use_load_path) {
+    furi_assert(dev);
+    furi_assert(dev->shadow_file_exist);
+
+    bool restored = false;
+    FuriString* path;
+
+    path = furi_string_alloc();
+
+    do {
+        if(use_load_path && !furi_string_empty(dev->load_path)) {
+            nfc_device_get_shadow_path(dev->load_path, path);
+        } else {
+            furi_string_printf(
+                path,
+                "%s/%s%s",
+                furi_string_get_cstr(dev->folder),
+                dev->dev_name,
+                NFC_APP_SHADOW_EXTENSION);
+        }
+        if(!storage_simply_remove(dev->storage, furi_string_get_cstr(path))) break;
+        dev->shadow_file_exist = false;
+        if(use_load_path && !furi_string_empty(dev->load_path)) {
+            furi_string_set(path, dev->load_path);
+        } else {
+            furi_string_printf(
+                path,
+                "%s/%s%s",
+                furi_string_get_cstr(dev->folder),
+                dev->dev_name,
+                NFC_APP_FILENAME_EXTENSION);
+        }
+        if(!nfc_device_load_data(dev, path, true)) break;
+        restored = true;
+    } while(0);
+
+    furi_string_free(path);
+    return restored;
+}
+
+void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context) {
+    furi_assert(dev);
+
+    dev->loading_cb = callback;
+    dev->loading_cb_ctx = context;
+}

+ 111 - 0
esubghz_chat/lib/nfclegacy/nfc_device.h

@@ -0,0 +1,111 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <storage/storage.h>
+#include <dialogs/dialogs.h>
+
+#include "./furi_hal_nfc.h"
+#include "protocols/mifare_ultralight.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NFC_DEV_NAME_MAX_LEN 22
+#define NFC_READER_DATA_MAX_SIZE 64
+#define NFC_DICT_KEY_BATCH_SIZE 10
+
+#define NFC_APP_FILENAME_PREFIX "NFC"
+#define NFC_APP_FILENAME_EXTENSION ".nfc"
+#define NFC_APP_SHADOW_EXTENSION ".shd"
+
+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 {
+    uint8_t data[NFC_READER_DATA_MAX_SIZE];
+    uint16_t size;
+} NfcReaderRequestData;
+
+typedef enum {
+    NfcReadModeAuto,
+    NfcReadModeMfClassic,
+    NfcReadModeMfUltralight,
+    NfcReadModeMfDesfire,
+    NfcReadModeEMV,
+    NfcReadModeNFCA,
+} NfcReadMode;
+
+typedef struct {
+    FurryHalNfcDevData nfc_data;
+    NfcProtocol protocol;
+    NfcReadMode read_mode;
+    union {
+        NfcReaderRequestData reader_data;
+        MfUltralightAuth mf_ul_auth;
+    };
+    union {
+        MfUltralightData mf_ul_data;
+    };
+    FuriString* parsed_data;
+} NfcDeviceData;
+
+typedef struct {
+    Storage* storage;
+    DialogsApp* dialogs;
+    NfcDeviceData dev_data;
+    char dev_name[NFC_DEV_NAME_MAX_LEN + 1];
+    FuriString* load_path;
+    FuriString* folder;
+    NfcDeviceSaveFormat format;
+    bool shadow_file_exist;
+
+    NfcLoadingCallback loading_cb;
+    void* loading_cb_ctx;
+} NfcDevice;
+
+NfcDevice* nfc_device_alloc();
+
+void nfc_device_free(NfcDevice* nfc_dev);
+
+void nfc_device_set_name(NfcDevice* dev, const char* name);
+
+bool nfc_device_save(NfcDevice* dev, const char* dev_name);
+
+bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);
+
+bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);
+
+bool nfc_device_load_key_cache(NfcDevice* dev);
+
+void nfc_device_data_clear(NfcDeviceData* dev);
+
+void nfc_device_clear(NfcDevice* dev);
+
+bool nfc_device_delete(NfcDevice* dev, bool use_load_path);
+
+bool nfc_device_restore(NfcDevice* dev, bool use_load_path);
+
+void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context);
+
+#ifdef __cplusplus
+}
+#endif

+ 57 - 0
esubghz_chat/lib/nfclegacy/nfc_types.c

@@ -0,0 +1,57 @@
+#include "nfc_types.h"
+
+const char* nfc_get_dev_type(FurryHalNfcType type) {
+    if(type == FurryHalNfcTypeA) {
+        return "NFC-A";
+    } else if(type == FurryHalNfcTypeB) {
+        return "NFC-B";
+    } else if(type == FurryHalNfcTypeF) {
+        return "NFC-F";
+    } else if(type == FurryHalNfcTypeV) {
+        return "NFC-V";
+    } else {
+        return "Unknown";
+    }
+}
+
+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) {
+        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";
+    }
+}

+ 17 - 0
esubghz_chat/lib/nfclegacy/nfc_types.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include "nfc_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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);
+
+#ifdef __cplusplus
+}
+#endif

+ 390 - 0
esubghz_chat/lib/nfclegacy/nfc_worker.c

@@ -0,0 +1,390 @@
+#include "nfc_worker_i.h"
+#include <furi_hal_rtc.h>
+
+#include "ST25RFAL002/platform.h"
+
+#define TAG "NfcWorker"
+
+/***************************** NFC Worker API *******************************/
+
+NfcWorker* nfc_worker_alloc() {
+    NfcWorker* nfc_worker = malloc(sizeof(NfcWorker));
+
+    // Worker thread attributes
+    nfc_worker->thread = furi_thread_alloc_ex("NfcWorker", 8192, nfc_worker_task, nfc_worker);
+
+    nfc_worker->callback = NULL;
+    nfc_worker->context = NULL;
+    nfc_worker->storage = furi_record_open(RECORD_STORAGE);
+
+    // Initialize rfal
+    while(furry_hal_nfc_is_busy()) {
+        furi_delay_ms(10);
+    }
+    nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
+
+    return nfc_worker;
+}
+
+void nfc_worker_free(NfcWorker* nfc_worker) {
+    furi_assert(nfc_worker);
+
+    furi_thread_free(nfc_worker->thread);
+
+    furi_record_close(RECORD_STORAGE);
+
+    free(nfc_worker);
+}
+
+NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
+    return nfc_worker->state;
+}
+
+void nfc_worker_start(
+    NfcWorker* nfc_worker,
+    NfcWorkerState state,
+    NfcDeviceData* dev_data,
+    NfcWorkerCallback callback,
+    void* context) {
+    furi_check(nfc_worker);
+    //furi_check(dev_data);
+    while(furry_hal_nfc_is_busy()) {
+        furi_delay_ms(10);
+    }
+    furry_hal_nfc_deinit();
+    furry_hal_nfc_init();
+
+    nfc_worker->callback = callback;
+    nfc_worker->context = context;
+    nfc_worker->dev_data = dev_data;
+    nfc_worker_change_state(nfc_worker, state);
+    furi_thread_start(nfc_worker->thread);
+}
+
+void nfc_worker_stop(NfcWorker* nfc_worker) {
+    furi_assert(nfc_worker);
+    furi_assert(nfc_worker->thread);
+    if(furi_thread_get_state(nfc_worker->thread) != FuriThreadStateStopped) {
+        furry_hal_nfc_stop();
+        nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
+        furi_thread_join(nfc_worker->thread);
+    }
+}
+
+void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
+    nfc_worker->state = state;
+}
+
+/***************************** NFC Worker Thread *******************************/
+
+int32_t nfc_worker_task(void* context) {
+    NfcWorker* nfc_worker = context;
+
+    furry_hal_nfc_exit_sleep();
+
+    if(nfc_worker->state == NfcWorkerStateRead) {
+        if(nfc_worker->dev_data->read_mode == NfcReadModeAuto) {
+            nfc_worker_read(nfc_worker);
+        } else {
+            nfc_worker_read_type(nfc_worker);
+        }
+    } 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 == NfcWorkerStateReadMfUltralightReadAuth) {
+        nfc_worker_mf_ultralight_read_auth(nfc_worker);
+    }
+    furry_hal_nfc_sleep();
+    nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
+
+    return 0;
+}
+
+static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FurryHalNfcTxRxContext* tx_rx) {
+    bool read_success = false;
+    MfUltralightReader reader = {};
+    MfUltralightData data = {};
+
+    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);
+
+    return read_success;
+}
+
+static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FurryHalNfcTxRxContext* tx_rx) {
+    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
+
+    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(nfc_data->interface == FurryHalNfcInterfaceIsoDep) {
+        FURI_LOG_I(TAG, "ISO14443-4 card detected");
+
+        nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
+
+        card_read = true;
+    } else {
+        nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
+        card_read = true;
+    }
+
+    return card_read;
+}
+
+void nfc_worker_read(NfcWorker* nfc_worker) {
+    furi_assert(nfc_worker);
+    furi_assert(nfc_worker->callback);
+
+    nfc_device_data_clear(nfc_worker->dev_data);
+    NfcDeviceData* dev_data = nfc_worker->dev_data;
+    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
+    FurryHalNfcTxRxContext tx_rx = {};
+    NfcWorkerEvent event = 0;
+    bool card_not_detected_notified = false;
+
+    while(nfc_worker->state == NfcWorkerStateRead) {
+        if(furry_hal_nfc_detect(nfc_data, 300)) {
+            // Process first found device
+            nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
+            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) {
+                        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;
+                    }
+                } else {
+                    if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
+                        event = NfcWorkerEventReadMfClassicDictAttackRequired;
+                        break;
+                    }
+                }
+            } else if(nfc_data->type == FurryHalNfcTypeB) {
+                event = NfcWorkerEventReadUidNfcB;
+                break;
+            } else if(nfc_data->type == FurryHalNfcTypeF) {
+                event = NfcWorkerEventReadUidNfcF;
+                break;
+            }
+        } else {
+            if(!card_not_detected_notified) {
+                nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
+                card_not_detected_notified = true;
+            }
+        }
+        furry_hal_nfc_sleep();
+        furi_delay_ms(100);
+    }
+    // Notify caller and exit
+    if(event > NfcWorkerEventReserved) {
+        nfc_worker->callback(event, nfc_worker->context);
+    }
+}
+
+void nfc_worker_read_type(NfcWorker* nfc_worker) {
+    furi_assert(nfc_worker);
+    furi_assert(nfc_worker->callback);
+
+    NfcReadMode read_mode = nfc_worker->dev_data->read_mode;
+    nfc_device_data_clear(nfc_worker->dev_data);
+    //NfcDeviceData* dev_data = nfc_worker->dev_data;
+    FurryHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
+    FurryHalNfcTxRxContext tx_rx = {};
+    NfcWorkerEvent event = 0;
+    bool card_not_detected_notified = false;
+
+    while(nfc_worker->state == NfcWorkerStateRead) {
+        if(furry_hal_nfc_detect(nfc_data, 300)) {
+            FURI_LOG_D(TAG, "Card detected");
+            furry_hal_nfc_sleep();
+            // Process first found device
+            nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
+            card_not_detected_notified = false;
+            if(nfc_data->type == FurryHalNfcTypeA) {
+                if(read_mode == NfcReadModeMfClassic) {
+                    // none
+                } 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;
+                    break;
+                }
+            }
+        } else {
+            if(!card_not_detected_notified) {
+                nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
+                card_not_detected_notified = true;
+            }
+        }
+        furry_hal_nfc_sleep();
+        furi_delay_ms(100);
+    }
+    // Notify caller and exit
+    if(event > NfcWorkerEventReserved) {
+        nfc_worker->callback(event, nfc_worker->context);
+    }
+}
+
+void nfc_worker_emulate_uid(NfcWorker* nfc_worker) {
+    FurryHalNfcTxRxContext tx_rx = {};
+    FurryHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
+    NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
+
+    // TODO add support for RATS
+    // Need to save ATS to support ISO-14443A-4 emulation
+
+    while(nfc_worker->state == NfcWorkerStateUidEmulate) {
+        if(furry_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) {
+            if(furry_hal_nfc_tx_rx(&tx_rx, 100)) {
+                reader_data->size = tx_rx.rx_bits / 8;
+                if(reader_data->size > 0) {
+                    memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
+                    if(nfc_worker->callback) {
+                        nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
+                    }
+                }
+            } else {
+                FURI_LOG_E(TAG, "Failed to get reader commands");
+            }
+        }
+    }
+}
+
+void nfc_worker_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();
+}
+
+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);
+
+    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);
+        }
+    }
+}

+ 109 - 0
esubghz_chat/lib/nfclegacy/nfc_worker.h

@@ -0,0 +1,109 @@
+#pragma once
+
+#include "nfc_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct NfcWorker NfcWorker;
+
+typedef enum {
+    // Init states
+    NfcWorkerStateNone,
+    NfcWorkerStateReady,
+    // Main worker states
+    NfcWorkerStateRead,
+    NfcWorkerStateUidEmulate,
+    NfcWorkerStateMfUltralightEmulate,
+    NfcWorkerStateMfClassicEmulate,
+    NfcWorkerStateMfClassicWrite,
+    NfcWorkerStateMfClassicUpdate,
+    NfcWorkerStateReadMfUltralightReadAuth,
+    NfcWorkerStateMfClassicDictAttack,
+    NfcWorkerStateAnalyzeReader,
+    NfcWorkerStateNfcVEmulate,
+    NfcWorkerStateNfcVUnlock,
+    NfcWorkerStateNfcVUnlockAndSave,
+    NfcWorkerStateNfcVSniff,
+    // Debug
+    NfcWorkerStateEmulateApdu,
+    NfcWorkerStateField,
+    // Transition
+    NfcWorkerStateStop,
+} NfcWorkerState;
+
+typedef enum {
+    // Reserve first 50 events for application events
+    NfcWorkerEventReserved = 50,
+
+    // Nfc read events
+    NfcWorkerEventReadUidNfcB,
+    NfcWorkerEventReadUidNfcV,
+    NfcWorkerEventReadUidNfcF,
+    NfcWorkerEventReadUidNfcA,
+    NfcWorkerEventReadMfUltralight,
+    NfcWorkerEventReadMfDesfire,
+    NfcWorkerEventReadMfClassicDone,
+    NfcWorkerEventReadMfClassicLoadKeyCache,
+    NfcWorkerEventReadMfClassicDictAttackRequired,
+    NfcWorkerEventReadBankCard,
+    NfcWorkerEventReadNfcV,
+
+    // Nfc worker common events
+    NfcWorkerEventSuccess,
+    NfcWorkerEventFail,
+    NfcWorkerEventAborted,
+    NfcWorkerEventCardDetected,
+    NfcWorkerEventNoCardDetected,
+    NfcWorkerEventWrongCardDetected,
+
+    // Read Mifare Classic events
+    NfcWorkerEventNoDictFound,
+    NfcWorkerEventNewSector,
+    NfcWorkerEventNewDictKeyBatch,
+    NfcWorkerEventFoundKeyA,
+    NfcWorkerEventFoundKeyB,
+    NfcWorkerEventKeyAttackStart,
+    NfcWorkerEventKeyAttackStop,
+    NfcWorkerEventKeyAttackNextSector,
+
+    // 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);
+
+NfcWorker* nfc_worker_alloc();
+
+NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker);
+
+void nfc_worker_free(NfcWorker* nfc_worker);
+
+void nfc_worker_start(
+    NfcWorker* nfc_worker,
+    NfcWorkerState state,
+    NfcDeviceData* dev_data,
+    NfcWorkerCallback callback,
+    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
+}
+#endif

+ 52 - 0
esubghz_chat/lib/nfclegacy/nfc_worker_i.h

@@ -0,0 +1,52 @@
+#pragma once
+
+#include "nfc_worker.h"
+
+#include <furi.h>
+#include <lib/toolbox/stream/file_stream.h>
+
+#include "protocols/nfc_util.h"
+#include "protocols/mifare_common.h"
+#include "protocols/mifare_ultralight.h"
+#include "protocols/nfca.h"
+
+struct NfcWorker {
+    FuriThread* thread;
+    Storage* storage;
+    Stream* dict_stream;
+
+    NfcDeviceData* dev_data;
+
+    NfcWorkerCallback callback;
+    void* context;
+
+    NfcWorkerState state;
+};
+
+void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
+
+int32_t nfc_worker_task(void* context);
+
+void nfc_worker_read(NfcWorker* nfc_worker);
+
+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);
+
+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);

+ 128 - 0
esubghz_chat/lib/nfclegacy/protocols/crypto1.c

@@ -0,0 +1,128 @@
+#include "crypto1.h"
+#include "nfc_util.h"
+#include <furi.h>
+
+// Algorithm from https://github.com/RfidResearchGroup/proxmark3.git
+
+#define SWAPENDIAN(x) \
+    ((x) = ((x) >> 8 & 0xff00ff) | ((x)&0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
+#define LF_POLY_ODD (0x29CE5C)
+#define LF_POLY_EVEN (0x870804)
+
+#define BEBIT(x, n) FURI_BIT(x, (n) ^ 24)
+
+void crypto1_reset(Crypto1* crypto1) {
+    furi_assert(crypto1);
+    crypto1->even = 0;
+    crypto1->odd = 0;
+}
+
+void crypto1_init(Crypto1* crypto1, uint64_t key) {
+    furi_assert(crypto1);
+    crypto1->even = 0;
+    crypto1->odd = 0;
+    for(int8_t i = 47; i > 0; i -= 2) {
+        crypto1->odd = crypto1->odd << 1 | FURI_BIT(key, (i - 1) ^ 7);
+        crypto1->even = crypto1->even << 1 | FURI_BIT(key, i ^ 7);
+    }
+}
+
+uint32_t crypto1_filter(uint32_t in) {
+    uint32_t out = 0;
+    out = 0xf22c0 >> (in & 0xf) & 16;
+    out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8;
+    out |= 0x3c8b0 >> (in >> 8 & 0xf) & 4;
+    out |= 0x1e458 >> (in >> 12 & 0xf) & 2;
+    out |= 0x0d938 >> (in >> 16 & 0xf) & 1;
+    return FURI_BIT(0xEC57E80A, out);
+}
+
+uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) {
+    furi_assert(crypto1);
+    uint8_t out = crypto1_filter(crypto1->odd);
+    uint32_t feed = out & (!!is_encrypted);
+    feed ^= !!in;
+    feed ^= LF_POLY_ODD & crypto1->odd;
+    feed ^= LF_POLY_EVEN & crypto1->even;
+    crypto1->even = crypto1->even << 1 | (nfc_util_even_parity32(feed));
+
+    FURI_SWAP(crypto1->odd, crypto1->even);
+    return out;
+}
+
+uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) {
+    furi_assert(crypto1);
+    uint8_t out = 0;
+    for(uint8_t i = 0; i < 8; i++) {
+        out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i;
+    }
+    return out;
+}
+
+uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) {
+    furi_assert(crypto1);
+    uint32_t out = 0;
+    for(uint8_t i = 0; i < 32; i++) {
+        out |= crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i);
+    }
+    return out;
+}
+
+uint32_t prng_successor(uint32_t x, uint32_t n) {
+    SWAPENDIAN(x);
+    while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
+
+    return SWAPENDIAN(x);
+}
+
+void crypto1_decrypt(
+    Crypto1* crypto,
+    uint8_t* encrypted_data,
+    uint16_t encrypted_data_bits,
+    uint8_t* decrypted_data) {
+    furi_assert(crypto);
+    furi_assert(encrypted_data);
+    furi_assert(decrypted_data);
+
+    if(encrypted_data_bits < 8) {
+        uint8_t decrypted_byte = 0;
+        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0;
+        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1;
+        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2;
+        decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3;
+        decrypted_data[0] = decrypted_byte;
+    } else {
+        for(size_t i = 0; i < encrypted_data_bits / 8; i++) {
+            decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i];
+        }
+    }
+}
+
+void crypto1_encrypt(
+    Crypto1* crypto,
+    uint8_t* keystream,
+    uint8_t* plain_data,
+    uint16_t plain_data_bits,
+    uint8_t* encrypted_data,
+    uint8_t* encrypted_parity) {
+    furi_assert(crypto);
+    furi_assert(plain_data);
+    furi_assert(encrypted_data);
+    furi_assert(encrypted_parity);
+
+    if(plain_data_bits < 8) {
+        encrypted_data[0] = 0;
+        for(size_t i = 0; i < plain_data_bits; i++) {
+            encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i;
+        }
+    } else {
+        memset(encrypted_parity, 0, plain_data_bits / 8 + 1);
+        for(uint8_t i = 0; i < plain_data_bits / 8; i++) {
+            encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^
+                                plain_data[i];
+            encrypted_parity[i / 8] |=
+                (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01)
+                 << (7 - (i & 0x0007)));
+        }
+    }
+}

+ 45 - 0
esubghz_chat/lib/nfclegacy/protocols/crypto1.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    uint32_t odd;
+    uint32_t even;
+} Crypto1;
+
+void crypto1_reset(Crypto1* crypto1);
+
+void crypto1_init(Crypto1* crypto1, uint64_t key);
+
+uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted);
+
+uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted);
+
+uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted);
+
+uint32_t crypto1_filter(uint32_t in);
+
+uint32_t prng_successor(uint32_t x, uint32_t n);
+
+void crypto1_decrypt(
+    Crypto1* crypto,
+    uint8_t* encrypted_data,
+    uint16_t encrypted_data_bits,
+    uint8_t* decrypted_data);
+
+void crypto1_encrypt(
+    Crypto1* crypto,
+    uint8_t* keystream,
+    uint8_t* plain_data,
+    uint16_t plain_data_bits,
+    uint8_t* encrypted_data,
+    uint8_t* encrypted_parity);
+
+#ifdef __cplusplus
+}
+#endif

+ 19 - 0
esubghz_chat/lib/nfclegacy/protocols/mifare_common.c

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

+ 12 - 0
esubghz_chat/lib/nfclegacy/protocols/mifare_common.h

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

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

@@ -0,0 +1,1946 @@
+#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;
+}

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

@@ -0,0 +1,269 @@
+#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

+ 70 - 0
esubghz_chat/lib/nfclegacy/protocols/nfc_util.c

@@ -0,0 +1,70 @@
+#include "nfc_util.h"
+
+#include <furi.h>
+
+static const uint8_t nfc_util_odd_byte_parity[256] = {
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,
+    1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
+    1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
+    0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0,
+    1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1,
+    0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
+    0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
+    0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+    1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
+
+void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) {
+    furi_assert(dest);
+    furi_assert(len <= 8);
+
+    while(len--) {
+        dest[len] = (uint8_t)src;
+        src >>= 8;
+    }
+}
+
+uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
+    furi_assert(src);
+    furi_assert(len <= 8);
+
+    uint64_t res = 0;
+    while(len--) {
+        res = (res << 8) | (*src);
+        src++;
+    }
+    return res;
+}
+
+uint8_t nfc_util_even_parity32(uint32_t data) {
+    // data ^= data >> 16;
+    // data ^= data >> 8;
+    // return !nfc_util_odd_byte_parity[data];
+    return (__builtin_parity(data) & 0xFF);
+}
+
+uint8_t nfc_util_odd_parity8(uint8_t data) {
+    return nfc_util_odd_byte_parity[data];
+}
+
+void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len) {
+    furi_assert(src);
+    furi_assert(dst);
+
+    uint8_t parity = 0;
+    uint8_t bit = 0;
+    while(len--) {
+        parity |= nfc_util_odd_parity8(*src) << (7 - bit); // parity is MSB first
+        bit++;
+        if(bit == 8) {
+            *dst = parity;
+            dst++;
+            parity = 0;
+            bit = 0;
+        }
+        src++;
+    }
+
+    if(bit) {
+        *dst = parity;
+    }
+}

+ 21 - 0
esubghz_chat/lib/nfclegacy/protocols/nfc_util.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest);
+
+uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len);
+
+uint8_t nfc_util_even_parity32(uint32_t data);
+
+uint8_t nfc_util_odd_parity8(uint8_t data);
+
+void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len);
+
+#ifdef __cplusplus
+}
+#endif

+ 140 - 0
esubghz_chat/lib/nfclegacy/protocols/nfca.c

@@ -0,0 +1,140 @@
+#include "nfca.h"
+#include <string.h>
+#include <stdio.h>
+#include <furi.h>
+
+#define NFCA_CRC_INIT (0x6363)
+
+#define NFCA_F_SIG (13560000.0)
+#define T_SIG 7374 //73.746ns*100
+#define T_SIG_x8 58992 //T_SIG*8
+#define T_SIG_x8_x8 471936 //T_SIG*8*8
+#define T_SIG_x8_x9 530928 //T_SIG*8*9
+
+#define NFCA_SIGNAL_MAX_EDGES (1350)
+
+typedef struct {
+    uint8_t cmd;
+    uint8_t param;
+} nfca_cmd_rats;
+
+static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00};
+
+static uint8_t nfca_halt_req[] = {NFCA_CMD_HALT, 0x00};
+
+uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) {
+    uint16_t crc = NFCA_CRC_INIT;
+    uint8_t byte = 0;
+
+    for(uint8_t i = 0; i < len; i++) {
+        byte = buff[i];
+        byte ^= (uint8_t)(crc & 0xff);
+        byte ^= byte << 4;
+        crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^
+              (((uint16_t)byte) >> 4);
+    }
+
+    return crc;
+}
+
+void nfca_append_crc16(uint8_t* buff, uint16_t len) {
+    uint16_t crc = nfca_get_crc16(buff, len);
+    buff[len] = (uint8_t)crc;
+    buff[len + 1] = (uint8_t)(crc >> 8);
+}
+
+bool nfca_emulation_handler(
+    uint8_t* buff_rx,
+    uint16_t buff_rx_len,
+    uint8_t* buff_tx,
+    uint16_t* buff_tx_len) {
+    bool halt = false;
+    uint8_t rx_bytes = buff_rx_len / 8;
+
+    if(rx_bytes == sizeof(nfca_halt_req) && !memcmp(buff_rx, nfca_halt_req, rx_bytes)) {
+        halt = true;
+    } else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) {
+        memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats));
+        *buff_tx_len = sizeof(nfca_default_ats) * 8;
+    }
+
+    return halt;
+}
+
+static void nfca_add_bit(DigitalSignal* signal, bool bit) {
+    if(bit) {
+        signal->start_level = true;
+        for(size_t i = 0; i < 7; i++) {
+            signal->edge_timings[i] = T_SIG_x8;
+        }
+        signal->edge_timings[7] = T_SIG_x8_x9;
+        signal->edge_cnt = 8;
+    } else {
+        signal->start_level = false;
+        signal->edge_timings[0] = T_SIG_x8_x8;
+        for(size_t i = 1; i < 9; i++) {
+            signal->edge_timings[i] = T_SIG_x8;
+        }
+        signal->edge_cnt = 9;
+    }
+}
+
+static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) {
+    for(uint8_t i = 0; i < 8; i++) {
+        if(byte & (1 << i)) {
+            digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
+        } else {
+            digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
+        }
+    }
+    if(parity) {
+        digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
+    } else {
+        digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
+    }
+}
+
+NfcaSignal* nfca_signal_alloc() {
+    NfcaSignal* nfca_signal = malloc(sizeof(NfcaSignal));
+    nfca_signal->one = digital_signal_alloc(10);
+    nfca_signal->zero = digital_signal_alloc(10);
+    nfca_add_bit(nfca_signal->one, true);
+    nfca_add_bit(nfca_signal->zero, false);
+    nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES);
+
+    return nfca_signal;
+}
+
+void nfca_signal_free(NfcaSignal* nfca_signal) {
+    furi_assert(nfca_signal);
+
+    digital_signal_free(nfca_signal->one);
+    digital_signal_free(nfca_signal->zero);
+    digital_signal_free(nfca_signal->tx_signal);
+    free(nfca_signal);
+}
+
+void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity) {
+    furi_assert(nfca_signal);
+    furi_assert(data);
+    furi_assert(parity);
+
+    nfca_signal->tx_signal->edge_cnt = 0;
+    nfca_signal->tx_signal->start_level = true;
+    // Start of frame
+    digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
+
+    if(bits < 8) {
+        for(size_t i = 0; i < bits; i++) {
+            if(FURI_BIT(data[0], i)) {
+                digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
+            } else {
+                digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
+            }
+        }
+    } else {
+        for(size_t i = 0; i < bits / 8; i++) {
+            nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07))));
+        }
+    }
+}

+ 31 - 0
esubghz_chat/lib/nfclegacy/protocols/nfca.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "../digital_signal/digital_signal.h"
+
+#define NFCA_CMD_RATS (0xE0U)
+#define NFCA_CMD_HALT (0x50U)
+
+typedef struct {
+    DigitalSignal* one;
+    DigitalSignal* zero;
+    DigitalSignal* tx_signal;
+} NfcaSignal;
+
+uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len);
+
+void nfca_append_crc16(uint8_t* buff, uint16_t len);
+
+bool nfca_emulation_handler(
+    uint8_t* buff_rx,
+    uint16_t buff_rx_len,
+    uint8_t* buff_tx,
+    uint16_t* buff_tx_len);
+
+NfcaSignal* nfca_signal_alloc();
+
+void nfca_signal_free(NfcaSignal* nfca_signal);
+
+void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity);

+ 71 - 0
esubghz_chat/lib/parity/parity.c

@@ -0,0 +1,71 @@
+#include "parity.h"
+
+uint32_t __paritysi2(uint32_t a) {
+    uint32_t x = (uint32_t)a;
+    x ^= x >> 16;
+    x ^= x >> 8;
+    x ^= x >> 4;
+    return (0x6996 >> (x & 0xF)) & 1;
+}
+
+static const uint8_t g_odd_byte_parity[256] = {
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,
+    1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
+    1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
+    0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0,
+    1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1,
+    0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
+    0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
+    0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+    1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
+
+#define ODD_PARITY8(x) \
+    { g_odd_byte_parity[x] }
+#define EVEN_PARITY8(x) \
+    { !g_odd_byte_parity[x] }
+
+uint8_t oddparity8(const uint8_t x) {
+    return g_odd_byte_parity[x];
+}
+
+uint8_t evenparity8(const uint8_t x) {
+    return !g_odd_byte_parity[x];
+}
+
+uint8_t evenparity16(uint16_t x) {
+#if !defined __GNUC__
+    x ^= x >> 8;
+    return EVEN_PARITY8(x);
+#else
+    return (__builtin_parity(x) & 0xFF);
+#endif
+}
+
+uint8_t oddparity16(uint16_t x) {
+#if !defined __GNUC__
+    x ^= x >> 8;
+    return ODD_PARITY8(x);
+#else
+    return !__builtin_parity(x);
+#endif
+}
+
+uint8_t evenparity32(uint32_t x) {
+#if !defined __GNUC__
+    x ^= x >> 16;
+    x ^= x >> 8;
+    return EVEN_PARITY8(x);
+#else
+    return (__builtin_parity(x) & 0xFF);
+#endif
+}
+
+uint8_t oddparity32(uint32_t x) {
+#if !defined __GNUC__
+    x ^= x >> 16;
+    x ^= x >> 8;
+    return ODD_PARITY8(x);
+#else
+    return !__builtin_parity(x);
+#endif
+}

+ 10 - 0
esubghz_chat/lib/parity/parity.h

@@ -0,0 +1,10 @@
+#include "stdint.h"
+
+uint8_t oddparity8(const uint8_t x);
+uint8_t evenparity8(const uint8_t x);
+
+uint8_t evenparity16(uint16_t x);
+uint8_t oddparity16(uint16_t x);
+
+uint8_t evenparity32(uint32_t x);
+uint8_t oddparity32(uint32_t x);

+ 6 - 6
esubghz_chat/scenes/esubghz_chat_key_display.c

@@ -88,7 +88,7 @@ void scene_on_enter_key_display(void* context) {
     dialog_ex_set_left_button_text(state->key_display, "Back");
 
     if(state->encrypted) {
-        // dialog_ex_set_center_button_text(state->key_display, "Share");
+        dialog_ex_set_center_button_text(state->key_display, "Share");
     }
 
     dialog_ex_set_result_callback(state->key_display, key_display_result_cb);
@@ -119,11 +119,11 @@ bool scene_on_event_key_display(void* context, SceneManagerEvent event) {
             consumed = true;
             break;
 
-            /* open key sharing popup */
-            // case ESubGhzChatEvent_KeyDisplayShare:
-            //     scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeySharePopup);
-            //     consumed = true;
-            //     break;
+        /* open key sharing popup */
+        case ESubGhzChatEvent_KeyDisplayShare:
+            scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeySharePopup);
+            consumed = true;
+            break;
         }
         break;
 

+ 17 - 17
esubghz_chat/scenes/esubghz_chat_key_menu.c

@@ -5,7 +5,7 @@ typedef enum {
     ESubGhzChatKeyMenuItems_Password,
     ESubGhzChatKeyMenuItems_HexKey,
     ESubGhzChatKeyMenuItems_GenKey,
-    // ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
+    ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
 } ESubGhzChatKeyMenuItems;
 
 static void key_menu_cb(void* context, uint32_t index) {
@@ -52,10 +52,10 @@ static void key_menu_cb(void* context, uint32_t index) {
         view_dispatcher_send_custom_event(state->view_dispatcher, ESubGhzChatEvent_KeyMenuGenKey);
         break;
 
-        // case ESubGhzChatKeyMenuItems_ReadKeyFromNfc:
-        //     view_dispatcher_send_custom_event(
-        //         state->view_dispatcher, ESubGhzChatEvent_KeyMenuReadKeyFromNfc);
-        //     break;
+    case ESubGhzChatKeyMenuItems_ReadKeyFromNfc:
+        view_dispatcher_send_custom_event(
+            state->view_dispatcher, ESubGhzChatEvent_KeyMenuReadKeyFromNfc);
+        break;
 
     default:
         break;
@@ -98,13 +98,13 @@ void scene_on_enter_key_menu(void* context) {
         ESubGhzChatKeyMenuItems_GenKey,
         key_menu_cb,
         state);
-    // menu_add_item(
-    //     state->menu,
-    //     "Read Key from NFC",
-    //     &I_Nfc_14px,
-    //     ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
-    //     key_menu_cb,
-    //     state);
+    menu_add_item(
+        state->menu,
+        "Read Key from NFC",
+        &I_Nfc_14px,
+        ESubGhzChatKeyMenuItems_ReadKeyFromNfc,
+        key_menu_cb,
+        state);
 
     view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_Menu);
 }
@@ -140,11 +140,11 @@ bool scene_on_event_key_menu(void* context, SceneManagerEvent event) {
             consumed = true;
             break;
 
-            /* switch to hex key read scene */
-            // case ESubGhzChatEvent_KeyMenuReadKeyFromNfc:
-            //     scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
-            //     consumed = true;
-            //     break;
+        /* switch to hex key read scene */
+        case ESubGhzChatEvent_KeyMenuReadKeyFromNfc:
+            scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
+            consumed = true;
+            break;
         }
 
         break;

+ 268 - 273
esubghz_chat/scenes/esubghz_chat_key_read_popup.c

@@ -1,273 +1,268 @@
-// #include "../esubghz_chat_i.h"
-// #include "../helpers/nfc_helpers.h"
-
-// typedef enum {
-//     KeyReadPopupState_Idle,
-//     KeyReadPopupState_Detecting,
-//     KeyReadPopupState_Reading,
-//     KeyReadPopupState_Fail,
-//     KeyReadPopupState_Success,
-// } KeyReadPopupState;
-
-// static bool read_worker_cb(NfcWorkerEvent event, void* context) {
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
-
-//     view_dispatcher_send_custom_event(state->view_dispatcher, event);
-
-//     return true;
-// }
-
-// static void key_read_popup_timeout_cb(void* context) {
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
-
-//     uint32_t cur_state =
-//         scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
-
-//     /* done displaying our failure */
-//     if(cur_state == KeyReadPopupState_Fail) {
-//         view_dispatcher_send_custom_event(
-//             state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupFailed);
-//         /* done displaying our success */
-//     } else if(cur_state == KeyReadPopupState_Success) {
-//         view_dispatcher_send_custom_event(
-//             state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupSucceeded);
-//     }
-// }
-
-// struct ReplayDictNfcReaderContext {
-//     uint8_t* cur;
-//     uint8_t* max;
-// };
-
-// static bool replay_dict_nfc_reader(uint64_t* run_id, uint32_t* counter, void* context) {
-//     struct ReplayDictNfcReaderContext* ctx = (struct ReplayDictNfcReaderContext*)context;
-
-//     if(ctx->cur + sizeof(struct ReplayDictNfcEntry) > ctx->max) {
-//         return false;
-//     }
-
-//     struct ReplayDictNfcEntry* entry = (struct ReplayDictNfcEntry*)ctx->cur;
-//     *run_id = entry->run_id;
-//     *counter = __ntohl(entry->counter);
-
-//     ctx->cur += sizeof(struct ReplayDictNfcEntry);
-
-//     return true;
-// }
-
-// static bool key_read_popup_handle_key_read(ESubGhzChatState* state) {
-//     NfcDeviceData* dev_data = state->nfc_dev_data;
-
-//     /* check for config pages */
-//     if(dev_data->mf_ul_data.data_read < NFC_CONFIG_PAGES * 4) {
-//         return false;
-//     }
-
-//     size_t data_read = dev_data->mf_ul_data.data_read - (NFC_CONFIG_PAGES * 4);
-
-//     /* check if key was transmitted */
-//     if(data_read < KEY_BITS / 8) {
-//         return false;
-//     }
-
-//     /* initiate the crypto context */
-//     bool ret = crypto_ctx_set_key(
-//         state->crypto_ctx, dev_data->mf_ul_data.data, state->name_prefix, furi_get_tick());
-
-//     /* cleanup */
-//     crypto_explicit_bzero(dev_data->mf_ul_data.data, KEY_BITS / 8);
-
-//     if(!ret) {
-//         crypto_ctx_clear(state->crypto_ctx);
-//         return false;
-//     }
-
-//     /* read the frequency */
-//     if(data_read >= (KEY_BITS / 8) + sizeof(struct FreqNfcEntry)) {
-//         struct FreqNfcEntry* freq_entry =
-//             (struct FreqNfcEntry*)(dev_data->mf_ul_data.data + (KEY_BITS / 8));
-//         state->frequency = __ntohl(freq_entry->frequency);
-//     }
-
-//     /* read the replay dict */
-//     struct ReplayDictNfcReaderContext rd_ctx = {
-//         .cur = dev_data->mf_ul_data.data + (KEY_BITS / 8) + sizeof(struct FreqNfcEntry),
-//         .max =
-//             dev_data->mf_ul_data.data + (data_read < NFC_MAX_BYTES ? data_read : NFC_MAX_BYTES)};
-
-//     crypto_ctx_read_replay_dict(state->crypto_ctx, replay_dict_nfc_reader, &rd_ctx);
-
-//     /* set encrypted flag */
-//     state->encrypted = true;
-
-//     return true;
-// }
-
-// static void key_read_popup_set_state(ESubGhzChatState* state, KeyReadPopupState new_state) {
-//     uint32_t cur_state =
-//         scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
-//     if(cur_state == new_state) {
-//         return;
-//     }
-
-//     if(new_state == KeyReadPopupState_Detecting) {
-//         popup_reset(state->nfc_popup);
-//         popup_disable_timeout(state->nfc_popup);
-//         popup_set_text(state->nfc_popup, "Tap Flipper\n to sender", 97, 24, AlignCenter, AlignTop);
-//         popup_set_icon(state->nfc_popup, 0, 8, &I_NFC_manual_60x50);
-//         notification_message(state->notification, &sequence_blink_start_cyan);
-//     } else if(new_state == KeyReadPopupState_Reading) {
-//         popup_reset(state->nfc_popup);
-//         popup_disable_timeout(state->nfc_popup);
-//         popup_set_header(
-//             state->nfc_popup,
-//             "Reading key\nDon't "
-//             "move...",
-//             85,
-//             24,
-//             AlignCenter,
-//             AlignTop);
-//         popup_set_icon(state->nfc_popup, 12, 23, &I_Loading_24);
-//         notification_message(state->notification, &sequence_blink_start_yellow);
-//     } else if(new_state == KeyReadPopupState_Fail) {
-//         nfc_worker_stop(state->nfc_worker);
-
-//         popup_reset(state->nfc_popup);
-//         popup_set_header(state->nfc_popup, "Failure!", 64, 2, AlignCenter, AlignTop);
-//         popup_set_text(state->nfc_popup, "Failed\nto read\nkey.", 78, 16, AlignLeft, AlignTop);
-//         popup_set_icon(state->nfc_popup, 14, 10, &I_dolph_cry_49x54);
-
-//         popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
-//         popup_set_context(state->nfc_popup, state);
-//         popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
-//         popup_enable_timeout(state->nfc_popup);
-
-//         notification_message(state->notification, &sequence_blink_stop);
-//     } else if(new_state == KeyReadPopupState_Success) {
-//         nfc_worker_stop(state->nfc_worker);
-
-//         popup_reset(state->nfc_popup);
-//         popup_set_header(state->nfc_popup, "Key\nread!", 13, 22, AlignLeft, AlignBottom);
-//         popup_set_icon(state->nfc_popup, 36, 5, &I_DolphinDone_80x58);
-
-//         popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
-//         popup_set_context(state->nfc_popup, state);
-//         popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
-//         popup_enable_timeout(state->nfc_popup);
-
-//         notification_message(state->notification, &sequence_success);
-//         notification_message(state->notification, &sequence_blink_stop);
-//     }
-
-//     scene_manager_set_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup, new_state);
-
-//     view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
-// }
-
-// /* Prepares the key share read scene. */
-// void scene_on_enter_key_read_popup(void* context) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_read_popup");
-
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
-
-//     key_read_popup_set_state(state, KeyReadPopupState_Detecting);
-
-//     state->nfc_dev_data->parsed_data = furi_string_alloc();
-//     if(state->nfc_dev_data->parsed_data == NULL) {
-//         /* can't do anything here, crash */
-//         furi_check(0);
-//     }
-
-//     nfc_worker_start(
-//         state->nfc_worker, NfcWorkerStateRead, state->nfc_dev_data, read_worker_cb, state);
-// }
-
-// /* Handles scene manager events for the key read popup scene. */
-// bool scene_on_event_key_read_popup(void* context, SceneManagerEvent event) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_read_popup");
-
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
-
-//     bool consumed = false;
-
-//     switch(event.type) {
-//     case SceneManagerEventTypeCustom:
-//         switch(event.event) {
-//         /* card detected */
-//         case NfcWorkerEventCardDetected:
-//             key_read_popup_set_state(state, KeyReadPopupState_Reading);
-//             consumed = true;
-//             break;
-
-//         /* no card detected */
-//         case NfcWorkerEventNoCardDetected:
-//             key_read_popup_set_state(state, KeyReadPopupState_Detecting);
-//             consumed = true;
-//             break;
-
-//         /* key probably read */
-//         case NfcWorkerEventReadMfUltralight:
-//             if(key_read_popup_handle_key_read(state)) {
-//                 key_read_popup_set_state(state, KeyReadPopupState_Success);
-//             } else {
-//                 key_read_popup_set_state(state, KeyReadPopupState_Fail);
-//             }
-//             consumed = true;
-//             break;
-
-//         /* close the popup and go back */
-//         case ESubGhzChatEvent_KeyReadPopupFailed:
-//             if(!scene_manager_previous_scene(state->scene_manager)) {
-//                 view_dispatcher_stop(state->view_dispatcher);
-//             }
-//             consumed = true;
-//             break;
-
-//         /* success, go to frequency input */
-//         case ESubGhzChatEvent_KeyReadPopupSucceeded:
-//             scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_FreqInput);
-//             consumed = true;
-//             break;
-
-//         /* something else happend, treat as failure */
-//         default:
-//             key_read_popup_set_state(state, KeyReadPopupState_Fail);
-//             consumed = true;
-//             break;
-//         }
-
-//         break;
-
-//     default:
-//         consumed = false;
-//         break;
-//     }
-
-//     return consumed;
-// }
-
-// /* Cleans up the key read popup scene. */
-// void scene_on_exit_key_read_popup(void* context) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_read_popup");
-
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
-
-//     popup_reset(state->nfc_popup);
-//     scene_manager_set_scene_state(
-//         state->scene_manager, ESubGhzChatScene_KeyReadPopup, KeyReadPopupState_Idle);
-
-//     notification_message(state->notification, &sequence_blink_stop);
-
-//     nfc_worker_stop(state->nfc_worker);
-
-//     crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
-//     if(state->nfc_dev_data->parsed_data != NULL) {
-//         furi_string_free(state->nfc_dev_data->parsed_data);
-//     }
-//     memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
-// }
+#include "../esubghz_chat_i.h"
+#include "../helpers/nfc_helpers.h"
+#include <machine/endian.h>
+
+typedef enum {
+    KeyReadPopupState_Idle,
+    KeyReadPopupState_Detecting,
+    KeyReadPopupState_Reading,
+    KeyReadPopupState_Fail,
+    KeyReadPopupState_Success,
+} KeyReadPopupState;
+
+static bool read_worker_cb(NfcWorkerEvent event, void* context) {
+    furi_assert(context);
+    ESubGhzChatState* state = context;
+
+    view_dispatcher_send_custom_event(state->view_dispatcher, event);
+
+    return true;
+}
+
+static void key_read_popup_timeout_cb(void* context) {
+    furi_assert(context);
+    ESubGhzChatState* state = context;
+
+    uint32_t cur_state =
+        scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
+
+    /* done displaying our failure */
+    if(cur_state == KeyReadPopupState_Fail) {
+        view_dispatcher_send_custom_event(
+            state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupFailed);
+        /* done displaying our success */
+    } else if(cur_state == KeyReadPopupState_Success) {
+        view_dispatcher_send_custom_event(
+            state->view_dispatcher, ESubGhzChatEvent_KeyReadPopupSucceeded);
+    }
+}
+
+struct ReplayDictNfcReaderContext {
+    uint8_t* cur;
+    uint8_t* max;
+};
+
+static bool replay_dict_nfc_reader(uint64_t* run_id, uint32_t* counter, void* context) {
+    struct ReplayDictNfcReaderContext* ctx = (struct ReplayDictNfcReaderContext*)context;
+
+    if(ctx->cur + sizeof(struct ReplayDictNfcEntry) > ctx->max) {
+        return false;
+    }
+
+    struct ReplayDictNfcEntry* entry = (struct ReplayDictNfcEntry*)ctx->cur;
+    *run_id = entry->run_id;
+    *counter = __ntohl(entry->counter);
+
+    ctx->cur += sizeof(struct ReplayDictNfcEntry);
+
+    return true;
+}
+
+static bool key_read_popup_handle_key_read(ESubGhzChatState* state) {
+    NfcDeviceData* dev_data = state->nfc_dev_data;
+
+    /* check for config pages */
+    if(dev_data->mf_ul_data.data_read < NFC_CONFIG_PAGES * 4) {
+        return false;
+    }
+
+    size_t data_read = dev_data->mf_ul_data.data_read - (NFC_CONFIG_PAGES * 4);
+
+    /* check if key was transmitted */
+    if(data_read < KEY_BITS / 8) {
+        return false;
+    }
+
+    /* initiate the crypto context */
+    bool ret = crypto_ctx_set_key(
+        state->crypto_ctx, dev_data->mf_ul_data.data, state->name_prefix, furi_get_tick());
+
+    /* cleanup */
+    crypto_explicit_bzero(dev_data->mf_ul_data.data, KEY_BITS / 8);
+
+    if(!ret) {
+        crypto_ctx_clear(state->crypto_ctx);
+        return false;
+    }
+
+    /* read the frequency */
+    if(data_read >= (KEY_BITS / 8) + sizeof(struct FreqNfcEntry)) {
+        struct FreqNfcEntry* freq_entry =
+            (struct FreqNfcEntry*)(dev_data->mf_ul_data.data + (KEY_BITS / 8));
+        state->frequency = __ntohl(freq_entry->frequency);
+    }
+
+    /* read the replay dict */
+    struct ReplayDictNfcReaderContext rd_ctx = {
+        .cur = dev_data->mf_ul_data.data + (KEY_BITS / 8) + sizeof(struct FreqNfcEntry),
+        .max =
+            dev_data->mf_ul_data.data + (data_read < NFC_MAX_BYTES ? data_read : NFC_MAX_BYTES)};
+
+    crypto_ctx_read_replay_dict(state->crypto_ctx, replay_dict_nfc_reader, &rd_ctx);
+
+    /* set encrypted flag */
+    state->encrypted = true;
+
+    return true;
+}
+
+static void key_read_popup_set_state(ESubGhzChatState* state, KeyReadPopupState new_state) {
+    uint32_t cur_state =
+        scene_manager_get_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup);
+    if(cur_state == new_state) {
+        return;
+    }
+
+    if(new_state == KeyReadPopupState_Detecting) {
+        popup_reset(state->nfc_popup);
+        popup_disable_timeout(state->nfc_popup);
+        popup_set_text(state->nfc_popup, "Tap Flipper\n to sender", 97, 24, AlignCenter, AlignTop);
+        popup_set_icon(state->nfc_popup, 0, 8, &I_NFC_manual_60x50);
+        notification_message(state->notification, &sequence_blink_start_cyan);
+    } else if(new_state == KeyReadPopupState_Reading) {
+        popup_reset(state->nfc_popup);
+        popup_disable_timeout(state->nfc_popup);
+        popup_set_header(
+            state->nfc_popup,
+            "Reading key\nDon't "
+            "move...",
+            85,
+            24,
+            AlignCenter,
+            AlignTop);
+        popup_set_icon(state->nfc_popup, 12, 23, &I_Loading_24);
+        notification_message(state->notification, &sequence_blink_start_yellow);
+    } else if(new_state == KeyReadPopupState_Fail) {
+        nfc_worker_stop(state->nfc_worker);
+
+        popup_reset(state->nfc_popup);
+        popup_set_header(state->nfc_popup, "Failure!", 64, 2, AlignCenter, AlignTop);
+        popup_set_text(state->nfc_popup, "Failed\nto read\nkey.", 78, 16, AlignLeft, AlignTop);
+        popup_set_icon(state->nfc_popup, 21, 13, &I_Cry_dolph_55x52);
+
+        popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
+        popup_set_context(state->nfc_popup, state);
+        popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
+        popup_enable_timeout(state->nfc_popup);
+
+        notification_message(state->notification, &sequence_blink_stop);
+    } else if(new_state == KeyReadPopupState_Success) {
+        nfc_worker_stop(state->nfc_worker);
+
+        popup_reset(state->nfc_popup);
+        popup_set_header(state->nfc_popup, "Key\nread!", 13, 22, AlignLeft, AlignBottom);
+        popup_set_icon(state->nfc_popup, 32, 5, &I_DolphinNice_96x59);
+
+        popup_set_timeout(state->nfc_popup, KEY_READ_POPUP_MS);
+        popup_set_context(state->nfc_popup, state);
+        popup_set_callback(state->nfc_popup, key_read_popup_timeout_cb);
+        popup_enable_timeout(state->nfc_popup);
+
+        notification_message(state->notification, &sequence_success);
+        notification_message(state->notification, &sequence_blink_stop);
+    }
+
+    scene_manager_set_scene_state(state->scene_manager, ESubGhzChatScene_KeyReadPopup, new_state);
+
+    view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
+}
+
+/* Prepares the key share read scene. */
+void scene_on_enter_key_read_popup(void* context) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_read_popup");
+
+    furi_assert(context);
+    ESubGhzChatState* state = context;
+
+    key_read_popup_set_state(state, KeyReadPopupState_Detecting);
+
+    nfc_worker_start(
+        state->nfc_worker, NfcWorkerStateRead, state->nfc_dev_data, read_worker_cb, state);
+}
+
+/* Handles scene manager events for the key read popup scene. */
+bool scene_on_event_key_read_popup(void* context, SceneManagerEvent event) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_read_popup");
+
+    furi_assert(context);
+    ESubGhzChatState* state = context;
+
+    bool consumed = false;
+
+    switch(event.type) {
+    case SceneManagerEventTypeCustom:
+        switch(event.event) {
+        /* card detected */
+        case NfcWorkerEventCardDetected:
+            key_read_popup_set_state(state, KeyReadPopupState_Reading);
+            consumed = true;
+            break;
+
+        /* no card detected */
+        case NfcWorkerEventNoCardDetected:
+            key_read_popup_set_state(state, KeyReadPopupState_Detecting);
+            consumed = true;
+            break;
+
+        /* key probably read */
+        case NfcWorkerEventReadMfUltralight:
+            if(key_read_popup_handle_key_read(state)) {
+                key_read_popup_set_state(state, KeyReadPopupState_Success);
+            } else {
+                key_read_popup_set_state(state, KeyReadPopupState_Fail);
+            }
+            consumed = true;
+            break;
+
+        /* close the popup and go back */
+        case ESubGhzChatEvent_KeyReadPopupFailed:
+            if(!scene_manager_previous_scene(state->scene_manager)) {
+                view_dispatcher_stop(state->view_dispatcher);
+            }
+            consumed = true;
+            break;
+
+        /* success, go to frequency input */
+        case ESubGhzChatEvent_KeyReadPopupSucceeded:
+            scene_manager_next_scene(state->scene_manager, ESubGhzChatScene_FreqInput);
+            consumed = true;
+            break;
+
+        /* something else happend, treat as failure */
+        default:
+            key_read_popup_set_state(state, KeyReadPopupState_Fail);
+            consumed = true;
+            break;
+        }
+
+        break;
+
+    default:
+        consumed = false;
+        break;
+    }
+
+    return consumed;
+}
+
+/* Cleans up the key read popup scene. */
+void scene_on_exit_key_read_popup(void* context) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_read_popup");
+
+    furi_assert(context);
+    ESubGhzChatState* state = context;
+
+    popup_reset(state->nfc_popup);
+    scene_manager_set_scene_state(
+        state->scene_manager, ESubGhzChatScene_KeyReadPopup, KeyReadPopupState_Idle);
+
+    notification_message(state->notification, &sequence_blink_stop);
+
+    nfc_worker_stop(state->nfc_worker);
+
+    crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
+    /*if(state->nfc_dev_data->parsed_data != NULL) {
+        furi_string_free(state->nfc_dev_data->parsed_data);
+    }*/
+    //memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
+}

+ 103 - 91
esubghz_chat/scenes/esubghz_chat_key_share_popup.c

@@ -1,124 +1,136 @@
-// #include "../esubghz_chat_i.h"
-// #include "../helpers/nfc_helpers.h"
+#include "../esubghz_chat_i.h"
+#include "../helpers/nfc_helpers.h"
+#include <machine/endian.h>
 
-// struct ReplayDictNfcWriterContext {
-//     uint8_t* cur;
-//     uint8_t* max;
-// };
+struct ReplayDictNfcWriterContext {
+    uint8_t* cur;
+    uint8_t* max;
+};
 
-// static bool replay_dict_nfc_writer(uint64_t run_id, uint32_t counter, void* context) {
-//     struct ReplayDictNfcWriterContext* ctx = (struct ReplayDictNfcWriterContext*)context;
+static bool replay_dict_nfc_writer(uint64_t run_id, uint32_t counter, void* context) {
+    struct ReplayDictNfcWriterContext* ctx = (struct ReplayDictNfcWriterContext*)context;
 
-//     struct ReplayDictNfcEntry entry = {.run_id = run_id, .counter = __htonl(counter), .unused = 0};
+    struct ReplayDictNfcEntry entry = {.run_id = run_id, .counter = __htonl(counter), .unused = 0};
 
-//     if(ctx->cur + sizeof(entry) > ctx->max) {
-//         return false;
-//     }
+    if(ctx->cur + sizeof(entry) > ctx->max) {
+        return false;
+    }
 
-//     memcpy(ctx->cur, &entry, sizeof(entry));
-//     ctx->cur += sizeof(entry);
+    memcpy(ctx->cur, &entry, sizeof(entry));
+    ctx->cur += sizeof(entry);
 
-//     return true;
-// }
+    return true;
+}
 
-// static void prepare_nfc_dev_data(ESubGhzChatState* state) {
-//     NfcDeviceData* dev_data = state->nfc_dev_data;
+static void prepare_nfc_dev_data(ESubGhzChatState* state) {
+    NfcDeviceData* dev_data = state->nfc_dev_data;
 
-//     dev_data->protocol = NfcDeviceProtocolMifareUl;
-//     furi_hal_random_fill_buf(dev_data->nfc_data.uid, 7);
-//     dev_data->nfc_data.uid_len = 7;
-//     dev_data->nfc_data.atqa[0] = 0x44;
-//     dev_data->nfc_data.atqa[1] = 0x00;
-//     dev_data->nfc_data.sak = 0x00;
+    dev_data->protocol = NfcDeviceProtocolMifareUl;
+    furi_hal_random_fill_buf(dev_data->nfc_data.uid, 7);
+    dev_data->nfc_data.uid_len = 7;
+    dev_data->nfc_data.atqa[0] = 0x44;
+    dev_data->nfc_data.atqa[1] = 0x00;
+    dev_data->nfc_data.sak = 0x00;
 
-//     dev_data->mf_ul_data.type = MfUltralightTypeNTAG215;
-//     dev_data->mf_ul_data.version.header = 0x00;
-//     dev_data->mf_ul_data.version.vendor_id = 0x04;
-//     dev_data->mf_ul_data.version.prod_type = 0x04;
-//     dev_data->mf_ul_data.version.prod_subtype = 0x02;
-//     dev_data->mf_ul_data.version.prod_ver_major = 0x01;
-//     dev_data->mf_ul_data.version.prod_ver_minor = 0x00;
-//     dev_data->mf_ul_data.version.storage_size = 0x11;
-//     dev_data->mf_ul_data.version.protocol_type = 0x03;
+    dev_data->mf_ul_data.type = MfUltralightTypeNTAG215;
+    dev_data->mf_ul_data.version.header = 0x00;
+    dev_data->mf_ul_data.version.vendor_id = 0x04;
+    dev_data->mf_ul_data.version.prod_type = 0x04;
+    dev_data->mf_ul_data.version.prod_subtype = 0x02;
+    dev_data->mf_ul_data.version.prod_ver_major = 0x01;
+    dev_data->mf_ul_data.version.prod_ver_minor = 0x00;
+    dev_data->mf_ul_data.version.storage_size = 0x11;
+    dev_data->mf_ul_data.version.protocol_type = 0x03;
 
-//     size_t data_written = 0;
+    size_t data_written = 0;
 
-//     /* write key */
-//     crypto_ctx_get_key(state->crypto_ctx, dev_data->mf_ul_data.data);
-//     data_written += (KEY_BITS / 8);
+    /* write key */
+    crypto_ctx_get_key(state->crypto_ctx, dev_data->mf_ul_data.data);
+    data_written += (KEY_BITS / 8);
 
-//     /* write frequency */
-//     struct FreqNfcEntry* freq_entry =
-//         (struct FreqNfcEntry*)(dev_data->mf_ul_data.data + data_written);
-//     freq_entry->frequency = __htonl(state->frequency);
-//     freq_entry->unused1 = 0;
-//     freq_entry->unused2 = 0;
-//     freq_entry->unused3 = 0;
-//     data_written += sizeof(struct FreqNfcEntry);
+    /* write frequency */
+    struct FreqNfcEntry* freq_entry =
+        (struct FreqNfcEntry*)(dev_data->mf_ul_data.data + data_written);
+    freq_entry->frequency = __htonl(state->frequency);
+    freq_entry->unused1 = 0;
+    freq_entry->unused2 = 0;
+    freq_entry->unused3 = 0;
+    data_written += sizeof(struct FreqNfcEntry);
 
-//     /* write the replay dict */
-//     struct ReplayDictNfcWriterContext wr_ctx = {
-//         .cur = dev_data->mf_ul_data.data + data_written,
-//         .max = dev_data->mf_ul_data.data + NFC_MAX_BYTES};
+    /* write the replay dict */
+    struct ReplayDictNfcWriterContext wr_ctx = {
+        .cur = dev_data->mf_ul_data.data + data_written,
+        .max = dev_data->mf_ul_data.data + NFC_MAX_BYTES};
 
-//     size_t n_entries =
-//         crypto_ctx_dump_replay_dict(state->crypto_ctx, replay_dict_nfc_writer, &wr_ctx);
-//     data_written += n_entries * sizeof(struct ReplayDictNfcEntry);
+    size_t n_entries =
+        crypto_ctx_dump_replay_dict(state->crypto_ctx, replay_dict_nfc_writer, &wr_ctx);
+    data_written += n_entries * sizeof(struct ReplayDictNfcEntry);
 
-//     /* calculate size of data, add 16 for config pages */
-//     dev_data->mf_ul_data.data_size = data_written + (NFC_CONFIG_PAGES * 4);
-// }
+    /* calculate size of data, add 16 for config pages */
+    dev_data->mf_ul_data.data_size = data_written + (NFC_CONFIG_PAGES * 4);
+}
 
-// /* Prepares the key share popup scene. */
-// void scene_on_enter_key_share_popup(void* context) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_share_popup");
+/* Prepares the key share popup scene. */
+void scene_on_enter_key_share_popup(void* context) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_enter_key_share_popup");
 
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
+    furi_assert(context);
+    ESubGhzChatState* state = context;
 
-//     popup_reset(state->nfc_popup);
+    popup_reset(state->nfc_popup);
 
-//     popup_disable_timeout(state->nfc_popup);
+    popup_disable_timeout(state->nfc_popup);
 
-//     popup_set_header(state->nfc_popup, "Sharing...", 67, 13, AlignLeft, AlignTop);
-//     popup_set_icon(state->nfc_popup, 0, 3, &I_NFC_dolphin_emulation_51x64);
-//     popup_set_text(state->nfc_popup, "Sharing\nKey via\nNFC", 90, 28, AlignCenter, AlignTop);
+    popup_set_header(state->nfc_popup, "Sharing...", 67, 13, AlignLeft, AlignTop);
+    popup_set_icon(state->nfc_popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
+    popup_set_text(state->nfc_popup, "Sharing\nKey via\nNFC", 90, 28, AlignCenter, AlignTop);
 
-//     prepare_nfc_dev_data(state);
-//     nfc_worker_start(
-//         state->nfc_worker, NfcWorkerStateMfUltralightEmulate, state->nfc_dev_data, NULL, NULL);
+    prepare_nfc_dev_data(state);
+    nfc_worker_start(
+        state->nfc_worker, NfcWorkerStateMfUltralightEmulate, state->nfc_dev_data, NULL, NULL);
 
-//     notification_message(state->notification, &sequence_blink_start_magenta);
+    notification_message(state->notification, &sequence_blink_start_magenta);
 
-//     view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
-// }
+    view_dispatcher_switch_to_view(state->view_dispatcher, ESubGhzChatView_NfcPopup);
+}
 
-// /* Handles scene manager events for the key share popup scene. */
-// bool scene_on_event_key_share_popup(void* context, SceneManagerEvent event) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_share_popup");
+/* Handles scene manager events for the key share popup scene. */
+bool scene_on_event_key_share_popup(void* context, SceneManagerEvent event) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_event_key_share_popup");
 
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
+    furi_assert(context);
+    ESubGhzChatState* state = context;
 
-//     UNUSED(state);
-//     UNUSED(event);
+    UNUSED(state);
+    UNUSED(event);
 
-//     return false;
-// }
+    return false;
+}
 
-// /* Cleans up the key share popup scene. */
-// void scene_on_exit_key_share_popup(void* context) {
-//     FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_share_popup");
+static bool temp_read_worker_cb(NfcWorkerEvent event, void* context) {
+    UNUSED(event);
+    UNUSED(context);
+    return true;
+}
 
-//     furi_assert(context);
-//     ESubGhzChatState* state = context;
+/* Cleans up the key share popup scene. */
+void scene_on_exit_key_share_popup(void* context) {
+    FURI_LOG_T(APPLICATION_NAME, "scene_on_exit_key_share_popup");
 
-//     popup_reset(state->nfc_popup);
+    furi_assert(context);
+    ESubGhzChatState* state = context;
 
-//     notification_message(state->notification, &sequence_blink_stop);
+    popup_reset(state->nfc_popup);
 
-//     nfc_worker_stop(state->nfc_worker);
+    notification_message(state->notification, &sequence_blink_stop);
 
-//     crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
-//     memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
-// }
+    nfc_worker_stop(state->nfc_worker);
+
+    nfc_worker_start(
+        state->nfc_worker, NfcWorkerStateRead, state->nfc_dev_data, temp_read_worker_cb, state);
+
+    nfc_worker_stop(state->nfc_worker);
+
+    crypto_explicit_bzero(state->nfc_dev_data->mf_ul_data.data, KEY_BITS / 8);
+    memset(state->nfc_dev_data, 0, sizeof(NfcDeviceData));
+}

+ 2 - 2
esubghz_chat/scenes/esubghz_chat_scene_config.h

@@ -2,8 +2,8 @@ ADD_SCENE(esubghz_chat, freq_input, FreqInput)
 ADD_SCENE(esubghz_chat, key_menu, KeyMenu)
 ADD_SCENE(esubghz_chat, pass_input, PassInput)
 ADD_SCENE(esubghz_chat, hex_key_input, HexKeyInput)
-// ADD_SCENE(esubghz_chat, key_read_popup, KeyReadPopup)
+ADD_SCENE(esubghz_chat, key_read_popup, KeyReadPopup)
 ADD_SCENE(esubghz_chat, chat_input, ChatInput)
 ADD_SCENE(esubghz_chat, chat_box, ChatBox)
 ADD_SCENE(esubghz_chat, key_display, KeyDisplay)
-// ADD_SCENE(esubghz_chat, key_share_popup, KeySharePopup)
+ADD_SCENE(esubghz_chat, key_share_popup, KeySharePopup)