/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : app_nfc.c
  * @brief          : Aliro NFC application main logic
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
 
/* Includes ------------------------------------------------------------------*/
#include "app_nfc.h"

#ifdef ST25R200
#include "utils.h"
#endif //ST25R200

/* Vendor's original source had:
 *   #include "../st25R200/utils.h"
 * That path doesn't resolve (no capital-R "st25R200" dir exists in the tree;
 * the driver lives at Drivers/BSP/Components/st25r200). The preceding
 * #include "utils.h" already pulls it in via the CMake include path when
 * ST25R200 is defined, so the broken line was redundant. Dropped. */

#include "rfal_nfc.h"
#include "rfal_t2t.h"

#ifdef ST25R200
#include "st25r200_irq.h"
#endif //ST25R200

#ifdef ST25R500
#include "st25r500_irq.h"
#define ST_MEMCPY    memcpy
#endif //ST25R500

#include <string.h>
#include "provisioning.h"
#include "app_aliro.h"
#include "tlwrapper.h"

/* Private typedef -----------------------------------------------------------*/

/* Defines ------------------------------------------------------------*/
/* Definition of possible states the demo state machine could have */
#define DEMO_ST_NOTINIT               0     /*!< Demo State:  Not initialized | Stopped */
/**
 * @def DEMO_ST_NOTINIT
 * @brief Demo State: Not initialized or stopped
 */
#define DEMO_ST_START_DISCOVERY       1     /*!< Demo State:  Start Discovery           */
/**
 * @def DEMO_ST_START_DISCOVERY
 * @brief Demo State: Start NFC device discovery
 */
#define DEMO_ST_DISCOVERY             2     /*!< Demo State:  Discovery                 */
/**
 * @def DEMO_ST_DISCOVERY
 * @brief Demo State: Discovery in progress
 */

#define TEST_NFCV_TAG                 0
#define DEMO_NFCV_BLOCK_LEN           4     /*!< NFCV Block len                         */
                                                                                        
#define DEMO_NFCV_USE_SELECT_MODE     false /*!< NFCV demonstrate select mode           */
#define DEMO_NFCV_WRITE_TAG           false /*!< NFCV demonstrate Write Single Block    */
    
/* Definition of various Listen Mode constants */
#if defined(DEMO_LISTEN_MODE_TARGET) 
#define DEMO_LM_SEL_RES       0x40U         /*!<NFC-A SEL_RES configured for the NFC-DEP protocol    */
#define DEMO_LM_NFCID2_BYTE1  0x01U         /*!<NFC-F SENSF_RES configured for the NFC-DEP protocol  */ 
#define DEMO_LM_SC_BYTE1      0xFFU         /*!<NFC-F System Code byte 1                             */ 
#define DEMO_LM_SC_BYTE2      0xFFU         /*!<NFC-F System Code byte 2                             */ 
#define DEMO_LM_PAD0          0xFFU         /*!<NFC-F PAD0                                           */ 
#else
#define DEMO_LM_SEL_RES       0x20U         /*!<NFC-A SEL_RES configured for Type 4A Tag Platform    */
#define DEMO_LM_NFCID2_BYTE1  0x02U         /*!<NFC-F SENSF_RES configured for Type 3 Tag Platform   */ 
#define DEMO_LM_SC_BYTE1      0x12U         /*!<NFC-F System Code byte 1                             */ 
#define DEMO_LM_SC_BYTE2      0xFCU         /*!<NFC-F System Code byte 2                             */ 
#define DEMO_LM_PAD0          0x00U         /*!<NFC-F PAD0                                           */ 
#endif

// Debug PA - Define masks
#define BIT8  128
#define BIT7  64
#define BIT6  32
#define BIT5  16
#define BIT4  8
#define BIT3  4
#define BIT2  2
#define BIT1  1

#ifndef PLATFORM_LED_AP2P_PORT
#define PLATFORM_LED_AP2P_PORT  PLATFORM_LED_F_PORT
#endif //PLATFORM_LED_AP2P_PORT

#ifndef PLATFORM_LED_AP2P_PIN
#define PLATFORM_LED_AP2P_PIN   PLATFORM_LED_F_PIN
#endif //PLATFORM_LED_AP2P_PIN

/* Macros -------------------------------------------------------------*/

/* Constants --------------------------------------------------------*/

/* Extern variables ---------------------------------------------------------*/

/* Variables ---------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
/* P2P communication data */
static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
static uint8_t GB[] = {0x46, 0x66, 0x6d, 0x01, 0x01, 0x11, 0x02, 0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03, 0x04, 0x01, 0x32, 0x07, 0x01, 0x03};

static rfalNfcDiscoverParam discParam;
static uint8_t              state = DEMO_ST_NOTINIT;
static bool                 multiSel;


/* Private function prototypes -----------------------------------------------*/
static void demoAPDU( ACWG_SessionContext_t *context );
#if TEST_NFCV_TAG
static void demoNfcv(rfalNfcvListenDevice *nfcvDev);
#endif //TEST_NFCV_TAG
static void demoNotif( rfalNfcState st );
ReturnCode  demoTransceiveBlocking( uint8_t *txBuf, uint16_t txBufSize, uint8_t **rxBuf, uint16_t **rcvLen, uint32_t fwt );








/* Private function -----------------------------------------------*/
/*!
 *****************************************************************************
 * \brief Demo Notification
 *
 *  This function receives the event notifications from RFAL
 *****************************************************************************
 */
 /**
 * @brief Notification callback for NFC state changes.
 *
 * Receives event notifications from RFAL and handles state transitions.
 * @param st The current NFC state.
 */
static void demoNotif( rfalNfcState st )
{
    uint8_t       devCnt = 0;
    rfalNfcDevice *dev;
    
    if( st == RFAL_NFC_STATE_WAKEUP_MODE )
    {
        PLATFORM_LOG(VERB_INFO, "Wake Up mode started \r\n");
    }
    else if( st == RFAL_NFC_STATE_POLL_TECHDETECT )
    {
        if( discParam.wakeupEnabled )
        {
            PLATFORM_LOG(VERB_INFO, "Wake Up mode terminated. Polling for devices \r\n");
        }
    }
    else if( st == RFAL_NFC_STATE_POLL_SELECT )
    {
        /* Check if in case of multiple devices, selection is already attempted */
        if( (!multiSel) )
        {
            multiSel = true;
            /* Multiple devices were found, activate first of them */
            rfalNfcGetDevicesFound( &dev, &devCnt );
            rfalNfcSelect( 0 );
            
            PLATFORM_LOG(VERB_INFO, "Multiple Tags detected: %d \r\n", devCnt);
        }
        else
        {
            rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_DISCOVERY );
        }
    }
    else if( st == RFAL_NFC_STATE_START_DISCOVERY )
    {
        /* Clear multiple device selection flag */
        multiSel = false;
    }
}







/* Public functions -----------------------------------------------*/

/*!
 *****************************************************************************
 * \brief Returns the RFAL NFC Discovery Parameter: Tech2Find
 *****************************************************************************
 */
/**
 * @brief Returns the NFC discovery parameter: Techs2Find.
 * @return The techs2Find value from the discovery parameters.
 */
uint16_t AliroNfcGetDiscoverTechs2Find( void )
{
    return discParam.techs2Find;
}

/*!
 *****************************************************************************
 * \brief Returns the RFAL NFC Discovery Parameter: Total Duration
 *****************************************************************************
 */
/**
 * @brief Returns the total duration for NFC discovery.
 * @return The total duration value from the discovery parameters.
 */
uint16_t AliroNfcGetDiscoverTotalDuration( void )
{
    return discParam.totalDuration;
}


/*!
 *****************************************************************************
 * \brief Demo Ini
 *
 *  This function initializes the required layers for the demo
 *
 * \return true  : Initialization ok
 * \return false : Initialization failed
 *****************************************************************************
 */

/**
 * @brief Initializes the NFC demo layers and parameters.
 * @param context Pointer to the session context.
 * @return true if initialization is successful, false otherwise.
 */
bool AliroNfcIni( ACWG_SessionContext_t *context )
{
    ReturnCode err;

    err = rfalNfcInitialize();
    if( err == ERR_NONE )
    {
        rfalNfcDefaultDiscParams( &discParam );
     
//         discParam.wakeupEnabled = 1; //LPCD //TODO: load default config from app parameters

        discParam.devLimit      = 1U;
        
        ST_MEMCPY( &discParam.nfcid3, NFCID3, sizeof(NFCID3) );
        ST_MEMCPY( &discParam.GB, GB, sizeof(GB) );
        discParam.GBLen         = sizeof(GB);
        discParam.p2pNfcaPrio   = true;

        discParam.notifyCb             = demoNotif;
        discParam.totalDuration        = ALIRO_NFC_TOTAL_DURATION;
        discParam.techs2Find           = RFAL_NFC_TECH_NONE;          /* For the demo, enable the NFC Technologies based on RFAL Feature switches */

        #ifdef ST25R95
        discParam.isoDepFS           = RFAL_ISODEP_FSXI_128;          /* ST25R95 cannot support 256 bytes of data block */
        #endif /* ST25R95 */

        AliroFilltechs2Find(&discParam.techs2Find);

#if TEST_NFCV_TAG
        discParam.techs2Find           |= RFAL_NFC_POLL_TECH_V;
#endif // TEST_NFCV_TAG
        
        ST_MEMSET(&discParam.propNfc, 0x00, sizeof(rfalNfcPropCallbacks) );

        ReturnCode demoPropNfcInitialize( void );
        ReturnCode demoPropNfcTechnologyDetection( void );

        discParam.propNfc.rfalNfcpPollerInitialize          = demoPropNfcInitialize;
        discParam.propNfc.rfalNfcpPollerTechnologyDetection = demoPropNfcTechnologyDetection;

        err = rfalNfcDiscover( &discParam );
        if( err != ERR_NONE )
        {
            return false;
        }
        
        context->init.authPolicy = 0x1;
        context->init.interface = 0x5e; // NFC interface
        state = DEMO_ST_START_DISCOVERY;
        return true;
    }
    return false;
}

/**
 * @brief Converts a byte array to a hexadecimal string.
 * @param data Pointer to the data array.
 * @param dataLen Length of the data array.
 * @return Pointer to the static output string.
 */
char* hex2Str(unsigned char * data, size_t dataLen)
{
    const char * hex = "0123456789ABCDEF";
    
    unsigned char * pin  = data;
    static char spout[] = "0123456789ABCDEF";
    
    char *          pout = spout;

    if( dataLen > (16/2) )
    {
        dataLen = (16/2) - 1;
    }

    for(uint32_t i = 0; i < dataLen; i++)
    {
        *pout++ = hex[(*pin>>4) & 0x0F];
        *pout++ = hex[(*pin++)  & 0x0F];
    }
    *pout = 0;
    
    return spout;
}

/**
 * @brief Reads a block from a Type 2 Tag and logs the result.
 */
void demoT2t( void )
{
    ReturnCode            err;
    uint16_t              rcvLen;
    uint8_t               blockNum = 0;
    uint8_t               rxBuf[ RFAL_T2T_READ_DATA_LEN ] = {0};
    
    err = rfalT2TPollerRead(blockNum, rxBuf, sizeof(rxBuf), &rcvLen);
    PLATFORM_LOG(VERB_INFO, " Read Block: %s %s\r\n", (err != ERR_NONE) ? "FAIL": "OK Data:", (err != ERR_NONE) ? "" : hex2Str( rxBuf, RFAL_T2T_READ_DATA_LEN));
    
}

/**
 * @brief Checks and processes application commands related to NFC wakeup.
 */
void CheckAppCmds(void)
{
//  if(appctx.cmds.nfcwakeup)
//  {
//    if(appctx.status.nfcwakeup == appctx.cmds.nfcwakeup)
//    {
//      //nothing to do
//      PLATFORM_LOG(VERB_VERBOSE, "NFC WAKEUP already %s\r\n", (appctx.status.nfcwakeup==NFC_WKUP_ENABLE)?("NFC_WKUP_ENABLE"):("NFC_WKUP_DISABLE"));
//    }
//    else
//    {
//      discParam.wakeupEnabled = (appctx.status.nfcwakeup==NFC_WKUP_ENABLE)?(1):(0);    /* enable/disable wakeup */
//      state = DEMO_ST_START_DISCOVERY;                       /* restart loop          */
//      PLATFORM_LOG(VERB_VERBOSE, "Toggling Wake Up mode %s\r\n", discParam.wakeupEnabled ? "ON": "OFF");
//      
//      /* Re-start discovery with new Wake-up configuration */
//      rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_IDLE );
//      rfalNfcDiscover( &discParam );
//      appctx.status.nfcwakeup = appctx.cmds.nfcwakeup;
//    }
//    appctx.cmds.nfcwakeup = 0;
//  }
}

/*!
 *****************************************************************************
 * \brief Demo Cycle
 *
 *  This function executes the demo state machine. 
 *  It must be called periodically
 *****************************************************************************
 */
/**
 * @brief Executes the NFC demo state machine. Should be called periodically.
 * @param context Pointer to the session context.
 */
void AliroNfcCycle( ACWG_SessionContext_t *context )
{
//  static uint8_t a = 0;
//  if(a)
//  {
//  RESET_TIME_STAMP();
//  HAL_Delay(200);
//  PRINT_TIME_STAMP(SELECT_APP_POS, "1 Label");
//  HAL_Delay(300);
//  PRINT_TIME_STAMP(SELECT_APP_POS2, "2 Label");
//  HAL_Delay(300);
//  PRINT_TIME_STAMP(SELECT_APP_POS3, "3 Label");
//  HAL_Delay(200);
//  PRINT_TIME_STAMP(SELECT_APP_POS4, "4 Label");
//  HAL_Delay(200);
//  PRINT_TIME_STAMP(SELECT_APP_POS5, "5 Label");
//  HAL_Delay(200);
//  TIME_STAMP_REPORT();
//  }
    static rfalNfcDevice *nfcDevice;
    
    rfalNfcWorker();                                    /* Run RFAL worker periodically */
    
    CheckAppCmds();

#if defined(SW1_GPIO_Port) && defined(SW1_Pin)
	
/* Check if button is supported (even if the pins are defined). MCUs may have the pin but not connected | shorted to GND */
  #ifdef platformIsUserButtonSupported
    if( platformIsUserButtonSupported() )
  #endif  /*platformIsUserButtonSupported()*/
		
        /*******************************************************************************/
        /* Check if USER button is pressed */
        if( platformGpioIsLow(SW1_GPIO_Port, SW1_Pin))
        {
            discParam.wakeupEnabled = !discParam.wakeupEnabled;    /* enable/disable wakeup */
            state = DEMO_ST_START_DISCOVERY;                       /* restart loop          */
            PLATFORM_LOG(VERB_INFO, "Toggling Wake Up mode %s\r\n", discParam.wakeupEnabled ? "ON": "OFF");

            /* Re-start discovery with new Wake-up configuration */
            rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_IDLE );
            rfalNfcDiscover( &discParam );

            /* Debounce button */
            while( platformGpioIsLow(SW1_GPIO_Port, SW1_Pin) );
        }
#endif /* SW1_Pin */
    
    switch( state )
    {
        /*******************************************************************************/
        case DEMO_ST_START_DISCOVERY:

//          platformLedOff(PLATFORM_LED_A_PORT, PLATFORM_LED_A_PIN);
//          platformLedOff(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
//          platformLedOff(PLATFORM_LED_F_PORT, PLATFORM_LED_F_PIN);
//          platformLedOff(PLATFORM_LED_V_PORT, PLATFORM_LED_V_PIN);
//          platformLedOff(PLATFORM_LED_AP2P_PORT, PLATFORM_LED_AP2P_PIN);
          #ifdef LED_FIELD_GPIO_Port
                    platformLedOff(PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN);
          #endif //LED_FIELD_GPIO_Port
          
          multiSel = false;
          state    = DEMO_ST_DISCOVERY;
          break;

        /*******************************************************************************/
        case DEMO_ST_DISCOVERY:
        
            if( rfalNfcIsDevActivated( rfalNfcGetState() ) )
            {
                rfalNfcGetActiveDevice( &nfcDevice );
                
                switch( nfcDevice->type )
                {
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_NFCA:
                    
                        platformLedOn(PLATFORM_LED_A_PORT, PLATFORM_LED_A_PIN);
                        switch( nfcDevice->dev.nfca.type )
                        {
                            case RFAL_NFCA_T1T:
                                PLATFORM_LOG(VERB_NORMAL, "ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                                break;
                            
                            case RFAL_NFCA_T4T:
                                PLATFORM_LOG(VERB_NORMAL, "NFCA Passive ISO-DEP device found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                            
//                                demoAPDU();
                                break;
                            
                            case RFAL_NFCA_T4T_NFCDEP:
                            case RFAL_NFCA_NFCDEP:
                                PLATFORM_LOG(VERB_NORMAL, "NFCA Passive P2P device found. NFCID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                                
//                                demoP2P( nfcDevice );
                                break;
                                
                            default:
                                PLATFORM_LOG(VERB_NORMAL, "ISO14443A/NFC-A card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                                
//                                demoT2t();
                                break;
                        }
                        break;
                    
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_NFCB:
                        
                        platformLedOn(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
                        PLATFORM_LOG(VERB_NORMAL, "ISO14443B/NFC-B card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                    
                        if( rfalNfcbIsIsoDepSupported( &nfcDevice->dev.nfcb ) )
                        {
//                            demoAPDUCalypso();
                        }
                        break;
                        
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_NFCF:
                        
                        platformLedOn(PLATFORM_LED_F_PORT, PLATFORM_LED_F_PIN);
                        if( rfalNfcfIsNfcDepSupported( &nfcDevice->dev.nfcf ) )
                        {
                            PLATFORM_LOG(VERB_NORMAL, "NFCF Passive P2P device found. NFCID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
//                            demoP2P( nfcDevice );
                        }
                        else
                        {
                            PLATFORM_LOG(VERB_NORMAL, "Felica/NFC-F card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ));
                            
//                            demoNfcf( &nfcDevice->dev.nfcf );
                        }
                        
                        break;
                    
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_NFCV:
                        {
                            uint8_t devUID[RFAL_NFCV_UID_LEN];
                            
                            platformLedOn(PLATFORM_LED_V_PORT, PLATFORM_LED_V_PIN);
                            
                            ST_MEMCPY( devUID, nfcDevice->nfcid, nfcDevice->nfcidLen );   /* Copy the UID into local var */
                            REVERSE_BYTES( devUID, RFAL_NFCV_UID_LEN );                 /* Reverse the UID for display purposes */
                            PLATFORM_LOG(VERB_NORMAL, "ISO15693/NFC-V card found. UID: %s\r\n", hex2Str(devUID, RFAL_NFCV_UID_LEN));
                            
#if TEST_NFCV_TAG
                            demoNfcv( &nfcDevice->dev.nfcv );
#endif //TEST_NFCV_TAG
                        }
                        break;
                        
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_ST25TB:
                        
                        platformLedOn(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
                        PLATFORM_LOG(VERB_NORMAL, "ST25TB card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ));
                        break;
                    
                    /*******************************************************************************/
                    case RFAL_NFC_LISTEN_TYPE_AP2P:
                    case RFAL_NFC_POLL_TYPE_AP2P:
                        
                        platformLedOn(PLATFORM_LED_AP2P_PORT, PLATFORM_LED_AP2P_PIN);
                        PLATFORM_LOG(VERB_NORMAL, "NFC Active P2P device found. NFCID3: %s\r\n", hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
                    
//                        demoP2P( nfcDevice );
                        break;
                    
                    /*******************************************************************************/
                    case RFAL_NFC_POLL_TYPE_NFCA:
                    case RFAL_NFC_POLL_TYPE_NFCF:
                        
                        platformLedOn( ((nfcDevice->type == RFAL_NFC_POLL_TYPE_NFCA) ? PLATFORM_LED_A_PORT : PLATFORM_LED_F_PORT), 
                                       ((nfcDevice->type == RFAL_NFC_POLL_TYPE_NFCA) ? PLATFORM_LED_A_PIN  : PLATFORM_LED_F_PIN)  );
                        PLATFORM_LOG(VERB_NORMAL, "Activated in CE %s mode.\r\n", (nfcDevice->type == RFAL_NFC_POLL_TYPE_NFCA) ? "NFC-A" : "NFC-F");

                        if( nfcDevice->rfInterface == RFAL_NFC_INTERFACE_NFCDEP )
                        {
//                            demoP2P( nfcDevice );
                        }
                        else
                        {
//                            demoCE( nfcDevice );
                        }
                        break;
                    
                    /*******************************************************************************/
                    default:
                        break;
                }

                if (nfcDevice->type == RFAL_NFC_LISTEN_TYPE_NFCA)
                {
//                  platformLedOn(PLATFORM_LED_A_PORT, PLATFORM_LED_A_PIN);
                  if (nfcDevice->dev.nfca.type == RFAL_NFCA_T4T)
                  {
//                    PLATFORM_LOG(VERB_NORMAL, "NFCA Passive ISO-DEP device found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
                    PrintBufferHex("NFCA Passive ISO-DEP device found. UID: ", nfcDevice->nfcid, nfcDevice->nfcidLen);
                    demoAPDU(context);
                  }
                  else
                  {
                    PLATFORM_LOG(VERB_VERBOSE, "Card not supported (NOT RFAL_NFCA_T4T)\r\n");
                  }
                
                }
#if TEST_NFCV_TAG
                else if (nfcDevice->type == RFAL_NFC_LISTEN_TYPE_NFCV)
                {
                }
#endif //TEST_NFCV_TAG
                else
                {
                  PLATFORM_LOG(VERB_VERBOSE, "Card not supported (not RFAL_NFC_LISTEN_TYPE_NFCA)\r\n");
                }
                
                rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_DISCOVERY );
                state = DEMO_ST_START_DISCOVERY;
            }
            break;

        /*******************************************************************************/
        case DEMO_ST_NOTINIT:
        default:
            break;
    }
    // ProcessUartInput();
}

/*!
 *****************************************************************************
 * \brief Demo Stop
 *
 *  This function stops the demo operation
 *
 *****************************************************************************
 */
/**
 * @brief Stops the NFC demo operation and deactivates NFC.
 */
void AliroNfcStop( void )
{
    rfalNfcDeactivate( RFAL_NFC_DEACTIVATE_IDLE );
    state = DEMO_ST_NOTINIT;
}

#if TEST_NFCV_TAG
/*!
 *****************************************************************************
 * \brief Demo NFC-V Exchange
 *
 * Example how to exchange read and write blocks on a NFC-V tag
 *
 *****************************************************************************
 */
/**
 * @brief Example of NFC-V block read/write exchange.
 * @param nfcvDev Pointer to the NFC-V device structure.
 */
void demoNfcv(rfalNfcvListenDevice *nfcvDev)
{
#if RFAL_FEATURE_NFCV
  
  ReturnCode            err;
  uint16_t              rcvLen;
  uint8_t               blockNum = 1;
  uint8_t               rxBuf[ 1 + DEMO_NFCV_BLOCK_LEN + RFAL_CRC_LEN ];                           /* Flags + Block Data + CRC */
//  uint8_t               txBuf[32];                                                      /* Tempporary buffer */
  uint8_t               *uid;
  uint8_t               reqFlag;
  uint8_t               wrData[DEMO_NFCV_BLOCK_LEN];             /* Write block example */
//  uint8_t               wrBoardName[8] = {'T', 'r', 'u', 'E', 'L', 'o', 'c', 'k'};      // 2 blocks x 4 byte
  int result;
  
  uid     = nfcvDev->InvRes.UID;
  reqFlag = RFAL_NFCV_REQ_FLAG_DEFAULT;
  
  /*
  * Read block using Read Single Block command
  * with addressed mode (uid != NULL) or selected mode (uid == NULL)
  */
  err = rfalNfcvPollerReadSingleBlock(reqFlag, uid, blockNum, rxBuf, sizeof(rxBuf), &rcvLen);
  PLATFORM_LOG(VERB_VERBOSE, "\tRead Block: %s %s\r\n", (err != RFAL_ERR_NONE) ? "FAIL": "OK Data:", (err != RFAL_ERR_NONE) ? "" : hex2Str( &rxBuf[1], DEMO_NFCV_BLOCK_LEN));
  
  if (err == RFAL_ERR_NONE) {
    memcpy(wrData, &rxBuf[1], DEMO_NFCV_BLOCK_LEN);
    
    uint32_t value = (wrData[0] << 24) | (wrData[1] << 16) | (wrData[2] << 8) | wrData[3];
    value += 1;
    wrData[0] = (value >> 24) & 0xFF;
    wrData[1] = (value >> 16) & 0xFF;
    wrData[2] = (value >> 8) & 0xFF;
    wrData[3] = value & 0xFF;
    
    err = rfalNfcvPollerWriteSingleBlock(reqFlag, uid, blockNum, wrData, sizeof(wrData));
    PLATFORM_LOG(VERB_VERBOSE, "\tWrite Block: %s Data: %s\r\n", (err != RFAL_ERR_NONE) ? "FAIL": "OK", hex2Str( wrData, DEMO_NFCV_BLOCK_LEN) );


//    err = rfalNfcvPollerWriteMultipleBlocks(reqFlag, uid, 6, 2, txBuf, sizeof(txBuf), 4, wrBoardName, sizeof(wrBoardName));
//    PLATFORM_LOG(VERB_VERBOSE, "\tWrite Block: %s Data: %s\r\n", (err != RFAL_ERR_NONE) ? "FAIL": "OK", hex2Str( wrBoardName, sizeof(wrBoardName)));

    
    err = rfalNfcvPollerReadSingleBlock(reqFlag, uid, blockNum, rxBuf, sizeof(rxBuf), &rcvLen);
    PLATFORM_LOG(VERB_VERBOSE, "\tRead Block: %s %s\r\n", (err != RFAL_ERR_NONE) ? "FAIL": "OK Data:", (err != RFAL_ERR_NONE) ? "" : hex2Str( &rxBuf[1], DEMO_NFCV_BLOCK_LEN));
    
    result = memcmp(wrData, &rxBuf[1], DEMO_NFCV_BLOCK_LEN);
    if (result == 0) 
    {
//      EOL_TestNCResult = TEST_PASSED;
      PLATFORM_LOG(VERB_VERBOSE, "Read/write OK\r\n");
    } 
    else 
    {
//      EOL_TestNCResult = TEST_FAILED;
      PLATFORM_LOG(VERB_VERBOSE, "Read/write FAILED\r\n");
    }  
  }
  HAL_Delay(500);
  
#endif /* RFAL_FEATURE_NFCV */
}
#endif //TEST_NFCV_TAG

/**
 * @brief Verifies the endpoint public key in the session context.
 * @param context Pointer to the session context.
 * @return 1 if verification is successful, 0 otherwise.
 */
uint8_t VerifyEndpointPubKey(ACWG_SessionContext_t *context)
{
  return (0==tlw_CheckEndpointKey(context));
}

#define CANNOT_CONTINUE() (!((err == ERR_NONE) && (secondLastValue == 0x90 && lastValue == 0x00)))
//#define PLATFORM_LOG(VERB_INFO, ...)        
/*!
 *****************************************************************************
 * \brief Demo APDUs Exchange
 *
 * Example how to exchange a set of predefined APDUs with PICC. The NDEF
 * application will be selected and then CC will be selected and read.
 * 
 *****************************************************************************
 */
/**
 * @brief Exchanges a set of predefined APDUs with PICC.
 * Selects the NDEF application and reads the Capability Container.
 * @param context Pointer to the session context.
 */
void demoAPDU( ACWG_SessionContext_t *context )
{
    ReturnCode err;
    // uint16_t   *rxLen;
    // uint8_t    *rxData;
    
    // uint32_t size = TMP_BUF_SIZE;
    // ACWG_Status_t ret = ACWG_Error_Generic;
    // uint8_t endpointPropTLV[32] = {0};
    // uint8_t authResult = 0;
    // uint8_t ind = 0;
     uint8_t command = 0x1;
    
    tlw_error_e tlw_status = TLW_ERROR_NONE;
    extern tlw_SM_nfc_t nfc_SM;
    
    AliroPort_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
    
    tlw_init_nfc(context);
    
    while (tlw_status != TLW_END)
    {
      tlw_status = tlw_prepare_nfc();
      if (tlw_status == TLW_NEW_OUTPUT)
      {
#ifdef ALIRO_APDU_TRACE
        PLATFORM_LOG(VERB_ALWAYS, "DTBMARK-BEFORE\r\n");
        {
          PLATFORM_LOG(VERB_ALWAYS, "[APDU >] len=%u ", (unsigned)nfc_SM.output_len);
          for (uint16_t _i = 0; _i < nfc_SM.output_len; _i++)
            PLATFORM_LOG(VERB_ALWAYS, "%02x", nfc_SM.output[_i]);
          PLATFORM_LOG(VERB_ALWAYS, "\r\n");
        }
#endif
        err = demoTransceiveBlocking(nfc_SM.output, nfc_SM.output_len, &(nfc_SM.input), &(nfc_SM.input_len), 10000000 );
        if( err != ERR_NONE )
        {
          PLATFORM_LOG(VERB_ERROR, "demoTransceiveBlocking error (0x%X)\r\n", err);
        }
#ifdef ALIRO_APDU_TRACE
        {
          uint16_t _rxlen = (nfc_SM.input_len != NULL) ? *nfc_SM.input_len : 0;
          PLATFORM_LOG(VERB_ALWAYS, "[APDU <] err=0x%X len=%u ", (unsigned)err, (unsigned)_rxlen);
          if (nfc_SM.input != NULL) {
            for (uint16_t _i = 0; _i < _rxlen && _i < 256; _i++)
              PLATFORM_LOG(VERB_ALWAYS, "%02x", nfc_SM.input[_i]);
          }
          PLATFORM_LOG(VERB_ALWAYS, "\r\n");
        }
#endif
      }
      tlw_status = tlw_process_nfc();
    }
    
    if ((nfc_SM.state == TLW_STATE_NFC_ERROR) || ((context->transState != auth1Done) && (context->transState != auth0FastDone) && (context->transState != inStepUp)))
    {
      context->transState = failed;
      PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_RED);PLATFORM_LOG(VERB_ERROR, "\r\nDOOR OPERATION FAILED\r\n");PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_DEFAULT);
      
      TRANSACTION_FAILURE();
    }
    // if ((context->transState != auth1Done) && (context->transState != auth0FastDone))
    // {
    //   PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_RED);PLATFORM_LOG(VERB_ERROR, "DOOR OPERATION FAILED\r\n");PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_DEFAULT);
    // }
    else
    {
      PLATFORM_LOG(VERB_NORMAL, TEXT_COLOR_GREEN);PLATFORM_LOG(VERB_NORMAL, "\r\nAUTHENTICATION OK\r\n");PLATFORM_LOG(VERB_NORMAL, TEXT_COLOR_DEFAULT);
      
      if(/*context->init.RESERVED3 || context->init.NotVerifyKey || */ VerifyEndpointPubKey(context) )
      {   
        PLATFORM_LOG(VERB_NORMAL, TEXT_COLOR_GREEN);PLATFORM_LOG(VERB_NORMAL, "DOOR OPERATION SUCCEEDED\r\n");PLATFORM_LOG(VERB_NORMAL, TEXT_COLOR_DEFAULT);
        if(command == 0x01) // Unlock 0x01, Lock 0x02, Disarm 0x03 ----> Table 8-1 Transaction Codes
        {
          PRINT_TIME_STAMP(DOOR_IS_OPENED_POS);
          TRANSACTION_SUCCESS_OPEN();
          
          command = 0x02;
  //        context->init.cmdParams |= CMD_PARAMS_EXP_FAST_MASK;
        }
        #if 0
          else if(command == 0x02)
          {
            PRINT_TIME_STAMP(DOOR_IS_CLOSED_POS);
            command = 0x01;
    //        context->init.isFast = 0;
            PLATFORM_LOG(VERB_VERBOSE, "        CCCCCCCCCCCCCLLLLLLLLLLL                  OOOOOOOOO        SSSSSSSSSSSSSSS EEEEEEEEEEEEEEEEEEEEEE\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "     CCC::::::::::::CL:::::::::L                OO:::::::::OO    SS:::::::::::::::SE::::::::::::::::::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "   CC:::::::::::::::CL:::::::::L              OO:::::::::::::OO S:::::SSSSSS::::::SE::::::::::::::::::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  C:::::CCCCCCCC::::CLL:::::::LL             O:::::::OOO:::::::OS:::::S     SSSSSSSEE::::::EEEEEEEEE::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, " C:::::C       CCCCCC  L:::::L               O::::::O   O::::::OS:::::S              E:::::E       EEEEEE\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::OS:::::S              E:::::E             \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::O S::::SSSS           E::::::EEEEEEEEEE   \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::O  SS::::::SSSSS      E:::::::::::::::E   \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::O    SSS::::::::SS    E:::::::::::::::E   \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::O       SSSSSS::::S   E::::::EEEEEEEEEE   \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "C:::::C                L:::::L               O:::::O     O:::::O            S:::::S  E:::::E             \r\n");
            PLATFORM_LOG(VERB_VERBOSE, " C:::::C       CCCCCC  L:::::L         LLLLLLO::::::O   O::::::O            S:::::S  E:::::E       EEEEEE\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  C:::::CCCCCCCC::::CLL:::::::LLLLLLLLL:::::LO:::::::OOO:::::::OSSSSSSS     S:::::SEE::::::EEEEEEEE:::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "   CC:::::::::::::::CL::::::::::::::::::::::L OO:::::::::::::OO S::::::SSSSSS:::::SE::::::::::::::::::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "     CCC::::::::::::CL::::::::::::::::::::::L   OO:::::::::OO   S:::::::::::::::SS E::::::::::::::::::::E\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "        CCCCCCCCCCCCCLLLLLLLLLLLLLLLLLLLLLLLL     OOOOOOOOO      SSSSSSSSSSSSSSS   EEEEEEEEEEEEEEEEEEEEEE\r\n");
          }

          else if(context->init.transCode == 0x03)
          {
            PRINT_TIME_STAMP(DOOR_IS_DISARMED_POS);
            context->init.transCode = 0x01;
            context->init.isFast = 0;
            PLATFORM_LOG(VERB_VERBOSE, "DDDDDDDDDDDDD        IIIIIIIIII   SSSSSSSSSSSSSSS                AAA               RRRRRRRRRRRRRRRRR   \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "D::::::::::::DDD     I::::::::I SS:::::::::::::::S              A:::A              R::::::::::::::::R  \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "D:::::::::::::::DD   I::::::::IS:::::SSSSSS::::::S             A:::::A             R::::::RRRRRR:::::R \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "DDD:::::DDDDD:::::D  II::::::IIS:::::S     SSSSSSS            A:::::::A            RR:::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D    D:::::D   I::::I  S:::::S                       A:::::::::A             R::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I  S:::::S                      A:::::A:::::A            R::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I   S::::SSSS                  A:::::A A:::::A           R::::RRRRRR:::::R \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I    SS::::::SSSSS            A:::::A   A:::::A          R:::::::::::::RR  \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I      SSS::::::::SS         A:::::A     A:::::A         R::::RRRRRR:::::R \r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I         SSSSSS::::S       A:::::AAAAAAAAA:::::A        R::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D     D:::::D  I::::I              S:::::S     A:::::::::::::::::::::A       R::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "  D:::::D    D:::::D   I::::I              S:::::S    A:::::AAAAAAAAAAAAA:::::A      R::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "DDD:::::DDDDD:::::D  II::::::IISSSSSSS     S:::::S   A:::::A             A:::::A   RR:::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "D:::::::::::::::DD   I::::::::IS::::::SSSSSS:::::S  A:::::A               A:::::A  R::::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "D::::::::::::DDD     I::::::::IS:::::::::::::::SS  A:::::A                 A:::::A R::::::R     R:::::R\r\n");
            PLATFORM_LOG(VERB_VERBOSE, "DDDDDDDDDDDDD        IIIIIIIIII SSSSSSSSSSSSSSS   AAAAAAA                   AAAAAAARRRRRRRR     RRRRRRR\r\n");
          }

        else
        {
          PRINT_TIME_STAMP(DON_T_KNOW_POS);
          command = 0x01;
          //context->init.cmdParams &= ~CMD_PARAMS_EXP_FAST_MASK;
        }

        #endif
      }
      else
      {

        PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_YELLOW);
        PLATFORM_LOG(VERB_VERBOSE, "ENDPOINT PUBLIC KEY VERIFICATION FAILED\r\n");
        PLATFORM_LOG(VERB_ERROR, TEXT_COLOR_DEFAULT);
        TRANSACTION_FAILURE();
      }
      
    }
    tlw_reload_nfc(context);
    PRINT_TIME_STAMP(ELAPSED_TIME_POS);
    TIME_STAMP_REPORT();

    
    HAL_Delay(1000);

  if(context->init.RESERVED3)
  {
    HAL_Delay(9000);
  }

  PLATFORM_LOG(VERB_VERBOSE, "\r\n-------------End of NFC demoAPDU --------- \r\n");
  AliroPort_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
  AliroPort_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}


/*!
 *****************************************************************************
 * \brief Demo Blocking Transceive 
 *
 * Helper function to send data in a blocking manner via the rfalNfc module 
 *  
 * \warning A protocol transceive handles long timeouts (several seconds), 
 * transmission errors and retransmissions which may lead to a long period of 
 * time where the MCU/CPU is blocked in this method.
 * This is a demo implementation, for a non-blocking usage example please 
 * refer to the Examples available with RFAL
 *
 * \param[in]  txBuf      : data to be transmitted
 * \param[in]  txBufSize  : size of the data to be transmited
 * \param[out] rxData     : location where the received data has been placed
 * \param[out] rcvLen     : number of data bytes received
 * \param[in]  fwt        : FWT to be used (only for RF frame interface, 
 *                                          otherwise use RFAL_FWT_NONE)
 *
 * 
 *  \return ERR_PARAM     : Invalid parameters
 *  \return ERR_TIMEOUT   : Timeout error
 *  \return ERR_FRAMING   : Framing error detected
 *  \return ERR_PROTO     : Protocol error detected
 *  \return ERR_NONE      : No error, activation successful
 * 
 *****************************************************************************
 */
/**
 * @brief Helper function to send data in a blocking manner via the rfalNfc module.
 * @param txBuf Data to be transmitted.
 * @param txBufSize Size of the data to be transmitted.
 * @param rxData Location where the received data has been placed.
 * @param rcvLen Number of data bytes received.
 * @param fwt FWT to be used.
 * @return ReturnCode indicating the result of the operation.
 */
ReturnCode demoTransceiveBlocking( uint8_t *txBuf, uint16_t txBufSize, uint8_t **rxData, uint16_t **rcvLen, uint32_t fwt )
{
  ReturnCode err;
  
  err = rfalNfcDataExchangeStart( txBuf, txBufSize, rxData, rcvLen, fwt );
  if( err == ERR_NONE )
  {
    do{
      rfalNfcWorker();
      err = rfalNfcDataExchangeGetStatus();
      uint8_t temp_state = rfalGetTransceiveState();
      if((temp_state > RFAL_TXRX_STATE_RX_IDLE) && (nfc_SM.callback != NULL))
      {
        PLATFORM_LOG(VERB_INFO, " #\r\n");
        nfc_SM.callback(nfc_SM.ctx);
        PLATFORM_LOG(VERB_INFO, " \r\n#");
        nfc_SM.callback = NULL;
      }
//      PLATFORM_LOG(VERB_INFO, ". %d", temp_state );
      PLATFORM_LOG(VERB_INFO, ".");
    }
    while( err == ERR_BUSY );
    PLATFORM_LOG(VERB_INFO, "\r\n");
  }
  return err;
}




/**
 * @brief Initializes the NFC hardware and configures interrupts.
 */
void AliroNfcHwInit( void )
{
    BSP_NFC0XCOMM_Init();

#ifdef ST25R200
    USR_INT_LINE.Line = USR_INT_LINE_NUM;
    USR_INT_LINE.RisingCallback = st25r200Isr;

    /* Configure interrupt callback */
   (void)HAL_EXTI_GetHandle(&USR_INT_LINE, USR_INT_LINE.Line);
   (void)HAL_EXTI_RegisterCallback(&USR_INT_LINE, HAL_EXTI_RISING_CB_ID, st25r200Isr);
#endif //ST25R200
#ifdef ST25R500
    USR_INT_LINE.Line = USR_INT_LINE_NUM;
    USR_INT_LINE.RisingCallback = st25r500Isr;

    /* Configure interrupt callback */
   (void)HAL_EXTI_GetHandle(&USR_INT_LINE, USR_INT_LINE.Line);
   (void)HAL_EXTI_RegisterCallback(&USR_INT_LINE, HAL_EXTI_RISING_CB_ID, st25r500Isr);
#endif //ST25R500
}



/**
  * @brief      SPI Read and Write byte(s) to device
  * @param[in]  pTxData : Pointer to data buffer to write
  * @param[out] pRxData : Pointer to data buffer for read data
  * @param[in]  Length : number of bytes to write
  * @return     BSP status
  */
int32_t BSP_NFC0XCOMM_SendRecv(const uint8_t * const pTxData, uint8_t * const pRxData, uint16_t Length)
{
  HAL_StatusTypeDef status = HAL_ERROR;
  int32_t ret = BSP_ERROR_NONE;

  if((pTxData != NULL) && (pRxData != NULL))
  {
    status = HAL_SPI_TransmitReceive(&COMM_HANDLE, (uint8_t *)pTxData, (uint8_t *)pRxData, Length, 2000);
  }
  else if ((pTxData != NULL) && (pRxData == NULL))
  {
    status = HAL_SPI_Transmit(&COMM_HANDLE, (uint8_t *)pTxData, Length, 2000);
  }
  else if ((pTxData == NULL) && (pRxData != NULL))
  {
    status = HAL_SPI_Receive(&COMM_HANDLE, (uint8_t *)pRxData, Length, 2000);
  }
  else
  {
  	ret = BSP_ERROR_WRONG_PARAM;
  }

  /* Check the communication status */
  if (status != HAL_OK)
  {
    /* Execute user timeout callback */
    //BSP_SPIx_DeInit();
    ret = BSP_NFC0XCOMM_Init();
  }

  return ret;
}


/* Weak function -----------------------------------------------*/
#ifdef ST25R200
/**
  * @brief  BSP SPI1 callback
  * @param  None
  * @return None
  */
__weak void BSP_NFC0XCOMM_IRQ_Callback(void)
{
  /* Prevent unused argument(s) compilation warning */

  /* This function should be implemented by the user application.
   * It is called into this driver when an event from ST25R200 is triggered.
   */
  st25r200Isr();
}
#endif //ST25R200

__weak ReturnCode demoPropNfcInitialize( void ){ return ERR_REQUEST; }
__weak ReturnCode demoPropNfcTechnologyDetection( void ){ return ERR_REQUEST; }

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
