2022-04-28 02:04:02 +02:00

1104 lines
46 KiB
C

/******************************************************************************
* \attention
*
* <h2><center>&copy; COPYRIGHT 2019 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.
*
******************************************************************************/
/*! \file
*
* \author
*
* \brief Demo application
*
* This demo shows how to poll for several types of NFC cards/devices and how
* to exchange data with these devices, using the RFAL library.
*
* This demo does not fully implement the activities according to the standards,
* it performs the required to communicate with a card/device and retrieve
* its UID. Also blocking methods are used for data exchange which may lead to
* long periods of blocking CPU/MCU.
* For standard compliant example please refer to the Examples provided
* with the RFAL library.
*
*/
/*
******************************************************************************
* INCLUDES
******************************************************************************
*/
#include "demo.h"
#include "utils.h"
#include "rfal_nfc.h"
#include "ndef_poller.h"
#include "ndef_t2t.h"
#include "ndef_t4t.h"
#include "ndef_t5t.h"
#include "ndef_message.h"
#include "ndef_types_rtd.h"
#include "ndef_dump.h"
/*
******************************************************************************
* GLOBAL DEFINES
******************************************************************************
*/
/* Definition of possible states the demo state machine could have */
#define DEMO_ST_NOTINIT 0 /*!< Demo State: Not initialized */
#define DEMO_ST_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
#define DEMO_ST_DISCOVERY 2 /*!< Demo State: Discovery */
#define NDEF_DEMO_READ 0U /*!< NDEF menu read */
#define NDEF_DEMO_WRITE_MSG1 1U /*!< NDEF menu write 1 record */
#define NDEF_DEMO_WRITE_MSG2 2U /*!< NDEF menu write 2 records */
#define NDEF_DEMO_FORMAT_TAG 3U /*!< NDEF menu format tag */
#if NDEF_FEATURE_ALL
#define NDEF_DEMO_MAX_FEATURES 4U /*!< Number of menu items */
#else
#define NDEF_DEMO_MAX_FEATURES 1U /*!< Number of menu items */
#endif /* NDEF_FEATURE_ALL */
#define NDEF_WRITE_FORMAT_TIMEOUT 10000U /*!< When write or format mode is selected, demo returns back to read mode after a timeout */
#define NDEF_LED_BLINK_DURATION 250U /*!< Led blink duration */
#define DEMO_RAW_MESSAGE_BUF_LEN 8192 /*!< Raw message buffer len */
#define DEMO_ST_MANUFACTURER_ID 0x02U /*!< ST Manufacturer ID */
/*
******************************************************************************
* LOCAL 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};
#if defined(ST25R3916) && defined(RFAL_FEATURE_LISTEN_MODE)
/* NFC-A CE config */
static uint8_t ceNFCA_NFCID[] = {0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; /* NFCID / UID (7 bytes) */
static uint8_t ceNFCA_SENS_RES[] = {0x44, 0x00}; /* SENS_RES / ATQA */
static uint8_t ceNFCA_SEL_RES = 0x20; /* SEL_RES / SAK */
/* NFC-F CE config */
static uint8_t ceNFCF_nfcid2[] = {0x02, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
static uint8_t ceNFCF_SC[] = {0x12, 0xFC};
static uint8_t ceNFCF_SENSF_RES[] = {0x01, /* SENSF_RES */
0x02, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, /* NFCID2 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x00, /* PAD0, PAD01, MRTIcheck, MRTIupdate, PAD2 */
0x00, 0x00 }; /* RD */
#endif /* RFAL_FEATURE_LISTEN_MODE */
/* P2P communication data */
static uint8_t ndefLLCPSYMM[] = {0x00, 0x00};
static uint8_t ndefInit[] = {0x05, 0x20, 0x06, 0x0F, 0x75, 0x72, 0x6E, 0x3A, 0x6E, 0x66, 0x63, 0x3A, 0x73, 0x6E, 0x3A, 0x73, 0x6E, 0x65, 0x70, 0x02, 0x02, 0x07, 0x80, 0x05, 0x01, 0x02};
static const uint8_t ndefSnepPrefix[] = { 0x13, 0x20, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00 };
static const uint8_t URL[] = "st.com";
static ndefConstBuffer bufURL = { URL, sizeof(URL) - 1 };
static uint8_t ndefUriBuffer[255];
static uint8_t *ndefStates[] =
{
(uint8_t *)"INVALID",
(uint8_t *)"INITIALIZED",
(uint8_t *)"READ/WRITE",
(uint8_t *)"READ-ONLY"
};
static const uint8_t *ndefDemoFeatureDescription[NDEF_DEMO_MAX_FEATURES] =
{
(uint8_t *)"1. Tap a tag to read its content",
#if NDEF_FEATURE_ALL
(uint8_t *)"2. Present a tag to write a Text record",
(uint8_t *)"3. Present a tag to write a URI record and an Android Application record",
(uint8_t *)"4. Present an ST tag to format",
#endif /* NDEF_FEATURE_ALL */
};
#if NDEF_FEATURE_ALL
static uint8_t ndefURI[] = "st.com";
static uint8_t ndefTEXT[] = "Welcome to ST NDEF demo";
static uint8_t ndefTextLangCode[] = "en";
static uint8_t ndefAndroidPackName[] = "com.st.st25nfc";
#endif /* NDEF_FEATURE_ALL */
/*
******************************************************************************
* LOCAL VARIABLES
******************************************************************************
*/
static rfalNfcDiscoverParam discParam;
static uint8_t state = DEMO_ST_NOTINIT;
static ndefContext ndefCtx;
static uint8_t ndefDemoFeature = NDEF_DEMO_READ;
static uint8_t ndefDemoPrevFeature = 0xFF;
static bool verbose = false;
static uint8_t rawMessageBuf[DEMO_RAW_MESSAGE_BUF_LEN];
static uint32_t timer;
static uint32_t timerLed;
static bool ledOn;
/*
******************************************************************************
* LOCAL FUNCTION PROTOTYPES
******************************************************************************
*/
static void demoNdef(rfalNfcDevice *nfcDevice);
static void ndefCCDump(ndefContext *ctx);
static void ndefDumpSysInfo(ndefContext *ctx);
#if NDEF_FEATURE_ALL
static bool ndefIsSTTag(ndefContext *ctx);
static void LedNotificationWriteDone(void);
#endif /* NDEF_FEATURE_ALL */
static void demoP2P( void );
ReturnCode demoTransceiveBlocking( uint8_t *txBuf, uint16_t txBufSize, uint8_t **rxBuf, uint16_t **rcvLen, uint32_t fwt );
static void ledsOn(void);
static void ledsOff(void);
/*!
*****************************************************************************
* \brief Check user button
*
* This function check whethe the user button has been pressed
*****************************************************************************
*/
static void checkUserButton(void)
{
/* Check if USER button is pressed */
if( platformGpioIsLow(PLATFORM_USER_BUTTON_PORT, PLATFORM_USER_BUTTON_PIN))
{
ndefDemoFeature++;
ndefDemoFeature %= NDEF_DEMO_MAX_FEATURES;
ledsOff();
ndefDemoPrevFeature = ndefDemoFeature;
platformLog("%s\r\n", ndefDemoFeatureDescription[ndefDemoFeature]);
/* Debounce button */
while( platformGpioIsLow(PLATFORM_USER_BUTTON_PORT, PLATFORM_USER_BUTTON_PIN) );
if( ndefDemoFeature != NDEF_DEMO_READ )
{
timer = platformTimerCreate(NDEF_WRITE_FORMAT_TIMEOUT);
timerLed = platformTimerCreate(NDEF_LED_BLINK_DURATION);
}
}
}
/*!
*****************************************************************************
* \brief Show usage
*
* This function displays usage information
*****************************************************************************
*/
static void ndefShowDemoUsage()
{
#if NDEF_FEATURE_ALL
uint32_t i;
platformLog("Use the User button to cycle among the different modes:\r\n");
for (i = 0; i < SIZEOF_ARRAY(ndefDemoFeatureDescription); i++)
{
platformLog("%s\r\n", ndefDemoFeatureDescription[i]);
}
platformLog("In Write or Format mode (menu 2, 3 or 4), the demo returns to Read mode (menu 1) if no tag detected after %d seconds\r\n\n", NDEF_WRITE_FORMAT_TIMEOUT/1000);
#endif /* NDEF_FEATURE_ALL */
}
/*!
*****************************************************************************
* \brief Demo Ini
*
* This function Initializes the required layers for the demo
*
* \return true : Initialization ok
* \return false : Initialization failed
*****************************************************************************
*/
bool demoIni( void )
{
ReturnCode err;
#if defined(STM32L476xx)
if( (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) != 0)
{
verbose = true;
}
#endif
ndefShowDemoUsage();
err = rfalNfcInitialize();
if( err == ERR_NONE )
{
discParam.compMode = RFAL_COMPLIANCE_MODE_NFC;
discParam.devLimit = 1U;
discParam.nfcfBR = RFAL_BR_212;
discParam.ap2pBR = RFAL_BR_424;
ST_MEMCPY( &discParam.nfcid3, NFCID3, sizeof(NFCID3) );
ST_MEMCPY( &discParam.GB, GB, sizeof(GB) );
discParam.GBLen = sizeof(GB);
discParam.notifyCb = NULL;
discParam.totalDuration = 1000U;
discParam.wakeupEnabled = false;
discParam.wakeupConfigDefault = true;
discParam.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_ST25TB );
#if defined(ST25R3911) || defined(ST25R3916)
discParam.techs2Find |= RFAL_NFC_POLL_TECH_AP2P;
#endif /* ST25R3911 || ST25R3916 */
#if defined(ST25R3916)
/* Set configuration for NFC-A CE */
ST_MEMCPY( discParam.lmConfigPA.SENS_RES, ceNFCA_SENS_RES, RFAL_LM_SENS_RES_LEN ); /* Set SENS_RES / ATQA */
ST_MEMCPY( discParam.lmConfigPA.nfcid, ceNFCA_NFCID, RFAL_NFCID2_LEN ); /* Set NFCID / UID */
discParam.lmConfigPA.nfcidLen = RFAL_LM_NFCID_LEN_07; /* Set NFCID length to 7 bytes */
discParam.lmConfigPA.SEL_RES = ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
/* Set configuration for NFC-F CE */
ST_MEMCPY( discParam.lmConfigPF.SC, ceNFCF_SC, RFAL_LM_SENSF_SC_LEN ); /* Set System Code */
ST_MEMCPY( &ceNFCF_SENSF_RES[RFAL_NFCF_LENGTH_LEN], ceNFCF_nfcid2, RFAL_LM_SENSF_RES_LEN ); /* Load NFCID2 on SENSF_RES */
ST_MEMCPY( discParam.lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES, RFAL_LM_SENSF_RES_LEN ); /* Set SENSF_RES / Poll Response */
discParam.techs2Find |= ( RFAL_NFC_LISTEN_TECH_A | RFAL_NFC_LISTEN_TECH_F );
#endif /* ST25R3916 */
state = DEMO_ST_START_DISCOVERY;
return true;
}
return false;
}
/*!
*****************************************************************************
* \brief Demo Cycle
*
* This function executes the demo state machine.
* It must be called periodically
*****************************************************************************
*/
void demoCycle( void )
{
static rfalNfcDevice *nfcDevice;
rfalNfcaSensRes sensRes;
rfalNfcaSelRes selRes;
rfalNfcbSensbRes sensbRes;
uint8_t sensbResLen;
uint8_t devCnt = 0;
rfalFeliCaPollRes cardList[1];
uint8_t collisions = 0U;
rfalNfcfSensfRes* sensfRes;
rfalNfcvInventoryRes invRes;
uint16_t rcvdLen;
rfalNfcWorker(); /* Run RFAL worker periodically */
if( (ndefDemoFeature != NDEF_DEMO_READ) && (platformTimerIsExpired(timer)) )
{
platformLog("Timer expired, back to Read mode...\r\n");
ndefDemoFeature = NDEF_DEMO_READ;
}
if( ndefDemoFeature != ndefDemoPrevFeature )
{
ndefDemoPrevFeature = ndefDemoFeature;
platformLog("%s\r\n", ndefDemoFeatureDescription[ndefDemoFeature]);
}
if( ndefDemoFeature != NDEF_DEMO_READ )
{
if( platformTimerIsExpired(timerLed) )
{
timerLed = platformTimerCreate(NDEF_LED_BLINK_DURATION);
ledOn = !ledOn;
}
if( ledOn )
{
ledsOn();
}
else
{
ledsOff();
}
}
checkUserButton();
switch( state )
{
/*******************************************************************************/
case DEMO_ST_START_DISCOVERY:
ledsOff();
rfalNfcDeactivate( false );
rfalNfcDiscover( &discParam );
state = DEMO_ST_DISCOVERY;
break;
/*******************************************************************************/
case DEMO_ST_DISCOVERY:
if( rfalNfcIsDevActivated( rfalNfcGetState() ) )
{
rfalNfcGetActiveDevice( &nfcDevice );
ledsOff();
platformDelay(50);
ndefDemoPrevFeature = 0xFF; /* Force the display of the prompt */
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:
platformLog("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
rfalNfcaPollerSleep();
break;
case RFAL_NFCA_T4T:
platformLog("NFCA Passive ISO-DEP device found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
demoNdef(nfcDevice);
rfalIsoDepDeselect();
break;
case RFAL_NFCA_T4T_NFCDEP:
case RFAL_NFCA_NFCDEP:
platformLog("NFCA Passive P2P device found. NFCID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
demoP2P();
break;
default:
platformLog("ISO14443A/NFC-A card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
demoNdef(nfcDevice);
rfalNfcaPollerSleep();
break;
}
/* Loop until tag is removed from the field */
platformLog("Operation completed\r\nTag can be removed from the field\r\n");
rfalNfcaPollerInitialize();
while( rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_WUPA, &sensRes) == ERR_NONE )
{
if( ((nfcDevice->dev.nfca.type == RFAL_NFCA_T1T) && (!rfalNfcaIsSensResT1T(&sensRes ))) ||
((nfcDevice->dev.nfca.type != RFAL_NFCA_T1T) && (rfalNfcaPollerSelect(nfcDevice->dev.nfca.nfcId1, nfcDevice->dev.nfca.nfcId1Len, &selRes) != ERR_NONE)) )
{
break;
}
rfalNfcaPollerSleep();
platformDelay(130);
}
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCB:
platformLog("ISO14443B/NFC-B card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
platformLedOn(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
if( rfalNfcbIsIsoDepSupported( &nfcDevice->dev.nfcb ) )
{
demoNdef(nfcDevice);
rfalIsoDepDeselect();
}
else
{
rfalNfcbPollerSleep(nfcDevice->dev.nfcb.sensbRes.nfcid0);
}
/* Loop until tag is removed from the field */
platformLog("Operation completed\r\nTag can be removed from the field\r\n");
rfalNfcbPollerInitialize();
while( rfalNfcbPollerCheckPresence(RFAL_NFCB_SENS_CMD_ALLB_REQ, RFAL_NFCB_SLOT_NUM_1, &sensbRes, &sensbResLen) == ERR_NONE )
{
if( ST_BYTECMP(sensbRes.nfcid0, nfcDevice->dev.nfcb.sensbRes.nfcid0, RFAL_NFCB_NFCID0_LEN) != 0 )
{
break;
}
rfalNfcbPollerSleep(nfcDevice->dev.nfcb.sensbRes.nfcid0);
platformDelay(130);
}
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCF:
if( rfalNfcfIsNfcDepSupported( &nfcDevice->dev.nfcf ) )
{
platformLog("NFCF Passive P2P device found. NFCID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ) );
demoP2P();
}
else
{
platformLog("Felica/NFC-F card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ));
demoNdef(nfcDevice);
}
platformLedOn(PLATFORM_LED_F_PORT, PLATFORM_LED_F_PIN);
/* Loop until tag is removed from the field */
platformLog("Operation completed\r\nTag can be removed from the field\r\n");
devCnt = 1;
rfalNfcfPollerInitialize( RFAL_BR_212 );
while (rfalNfcfPollerPoll( RFAL_FELICA_1_SLOT, RFAL_NFCF_SYSTEMCODE, RFAL_FELICA_POLL_RC_NO_REQUEST, cardList, &devCnt, &collisions ) == ERR_NONE)
{
/* Skip the length field byte */
sensfRes = (rfalNfcfSensfRes*)&((uint8_t *)cardList)[1];
if( ST_BYTECMP(sensfRes->NFCID2, nfcDevice->dev.nfcf.sensfRes.NFCID2, RFAL_NFCF_NFCID2_LEN) != 0 )
{
break;
}
platformDelay(130);
}
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_NFCV:
{
uint8_t devUID[RFAL_NFCV_UID_LEN];
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 */
platformLog("ISO15693/NFC-V card found. UID: %s\r\n", hex2Str(devUID, RFAL_NFCV_UID_LEN));
platformLedOn(PLATFORM_LED_V_PORT, PLATFORM_LED_V_PIN);
demoNdef(nfcDevice);
/* Loop until tag is removed from the field */
platformLog("Operation completed\r\nTag can be removed from the field\r\n");
rfalNfcvPollerInitialize();
while (rfalNfcvPollerInventory( RFAL_NFCV_NUM_SLOTS_1, RFAL_NFCV_UID_LEN * 8U, nfcDevice->dev.nfcv.InvRes.UID, &invRes, &rcvdLen) == ERR_NONE)
{
platformDelay(130);
}
}
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_ST25TB:
platformLog("ST25TB card found. UID: %s\r\n", hex2Str( nfcDevice->nfcid, nfcDevice->nfcidLen ));
platformLedOn(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
break;
/*******************************************************************************/
case RFAL_NFC_LISTEN_TYPE_AP2P:
platformLog("NFC Active P2P device found. NFCID3: %s\r\n", hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
platformLedOn(PLATFORM_LED_AP2P_PORT, PLATFORM_LED_AP2P_PIN);
demoP2P();
break;
/*******************************************************************************/
default:
break;
}
rfalNfcDeactivate( false );
platformDelay( 500 );
state = DEMO_ST_START_DISCOVERY;
}
break;
/*******************************************************************************/
case DEMO_ST_NOTINIT:
default:
break;
}
}
/*!
*****************************************************************************
* \brief Demo P2P Exchange
*
* Sends a NDEF URI record 'http://www.ST.com' via NFC-DEP (P2P) protocol.
*
* This method sends a set of static predefined frames which tries to establish
* a LLCP connection, followed by the NDEF record, and then keeps sending
* LLCP SYMM packets to maintain the connection.
*
*
*****************************************************************************
*/
void demoP2P( void )
{
uint16_t *rxLen;
uint8_t *rxData;
ReturnCode err;
ndefBuffer bufPayload;
ndefMessage message;
ndefRecord record;
ndefType uri;
platformLog(" Initalize device .. ");
err = demoTransceiveBlocking( ndefInit, sizeof(ndefInit), &rxData, &rxLen, RFAL_FWT_NONE);
if( err != ERR_NONE )
{
platformLog("failed.");
return;
}
platformLog("succeeded.\r\n");
err = ndefRtdUri(&uri, NDEF_URI_PREFIX_HTTP_WWW, &bufURL);
err |= ndefRtdUriToRecord(&uri, &record);
err |= ndefMessageInit(&message);
err |= ndefMessageAppend(&message, &record); /* To get MB and ME bits set */
/* Build the SNEP buffer made of the prefix, the length byte and the record */
ST_MEMCPY(ndefUriBuffer, ndefSnepPrefix, sizeof(ndefSnepPrefix));
/* Skip 1 byte for length byte */
bufPayload.buffer = ndefUriBuffer + sizeof(ndefSnepPrefix) + 1;
bufPayload.length = sizeof(ndefUriBuffer) - sizeof(ndefSnepPrefix);
err |= ndefMessageEncode(&message, &bufPayload);
ndefUriBuffer[sizeof(ndefSnepPrefix)] = bufPayload.length;
bufPayload.buffer = ndefUriBuffer;
bufPayload.length = sizeof(ndefSnepPrefix) + 1 + bufPayload.length;
if( err != ERR_NONE )
{
platformLog("NDEF message creation failed\r\n", err);
return;
}
ndefBufferDump("URL converted to SNEP:\r\n", (ndefConstBuffer*)&bufPayload, true);
platformLog(" Push NDEF Uri: www.ST.com .. ");
err = demoTransceiveBlocking(bufPayload.buffer, bufPayload.length, &rxData, &rxLen, RFAL_FWT_NONE);
if( err != ERR_NONE )
{
platformLog("failed.");
return;
}
platformLog("succeeded.\r\n");
platformLog(" Device present, maintaining connection ");
while(err == ERR_NONE)
{
err = demoTransceiveBlocking( ndefLLCPSYMM, sizeof(ndefLLCPSYMM), &rxData, &rxLen, RFAL_FWT_NONE);
platformLog(".");
platformDelay(50);
}
platformLog("\r\n Device removed.\r\n");
}
/*!
*****************************************************************************
* \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
*
*****************************************************************************
*/
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();
}
while( err == ERR_BUSY );
}
return err;
}
static void demoNdef(rfalNfcDevice *pNfcDevice)
{
ReturnCode err;
ndefMessage message;
uint32_t rawMessageLen;
ndefInfo info;
ndefBuffer bufRawMessage;
ndefConstBuffer bufConstRawMessage;
#if NDEF_FEATURE_ALL
ndefRecord record1;
ndefRecord record2;
ndefType text;
ndefType uri;
ndefType aar;
ndefConstBuffer8 bufTextLangCode;
ndefConstBuffer bufTextLangText;
ndefConstBuffer bufUri;
ndefConstBuffer bufAndroidPackName;
#endif /* NDEF_FEATURE_ALL */
/*
* Perform NDEF Context Initialization
*/
err = ndefPollerContextInitialization(&ndefCtx, pNfcDevice);
if( err != ERR_NONE )
{
platformLog("NDEF NOT DETECTED (ndefPollerContextInitialization returns %d)\r\n", err);
return;
}
if( verbose & (pNfcDevice->type == RFAL_NFC_LISTEN_TYPE_NFCV) )
{
ndefDumpSysInfo(&ndefCtx);
}
/*
* Perform NDEF Detect procedure
*/
err = ndefPollerNdefDetect(&ndefCtx, &info);
if( err != ERR_NONE )
{
platformLog("NDEF NOT DETECTED (ndefPollerNdefDetect returns %d)\r\n", err);
if( ndefDemoFeature != NDEF_DEMO_FORMAT_TAG)
{
return;
}
}
else
{
platformLog("%s NDEF detected.\r\n", ndefStates[info.state]);
ndefCCDump(&ndefCtx);
if( verbose )
{
platformLog("NDEF Len: %d, Offset=%d\r\n", ndefCtx.messageLen, ndefCtx.messageOffset);
}
}
switch( ndefDemoFeature )
{
/*
* Demonstrate how to read the NDEF message from the Tag
*/
case NDEF_DEMO_READ:
if( info.state == NDEF_STATE_INITIALIZED )
{
/* Nothing to read... */
return;
}
err = ndefPollerReadRawMessage(&ndefCtx, rawMessageBuf, sizeof(rawMessageBuf), &rawMessageLen);
if( err != ERR_NONE )
{
platformLog("NDEF message cannot be read (ndefPollerReadRawMessage returns %d)\r\n", err);
return;
}
if( verbose )
{
bufRawMessage.buffer = rawMessageBuf;
bufRawMessage.length = rawMessageLen;
ndefBufferDump(" NDEF Content", (ndefConstBuffer*)&bufRawMessage, verbose);
}
bufConstRawMessage.buffer = rawMessageBuf;
bufConstRawMessage.length = rawMessageLen;
err = ndefMessageDecode(&bufConstRawMessage, &message);
if( err != ERR_NONE )
{
platformLog("NDEF message cannot be decoded (ndefMessageDecode returns %d)\r\n", err);
return;
}
err = ndefMessageDump(&message, verbose);
if( err != ERR_NONE )
{
platformLog("NDEF message cannot be displayed (ndefMessageDump returns %d)\r\n", err);
return;
}
break;
#if NDEF_FEATURE_ALL
/*
* Demonstrate how to encode a text record and write the message to the tag
*/
case NDEF_DEMO_WRITE_MSG1:
ndefDemoFeature = NDEF_DEMO_READ; /* returns to READ mode after write */
err = ndefMessageInit(&message); /* Initialize message structure */
bufTextLangCode.buffer = ndefTextLangCode;
bufTextLangCode.length = strlen((char *)ndefTextLangCode);
bufTextLangText.buffer = ndefTEXT;
bufTextLangText.length = strlen((char *)ndefTEXT);
err |= ndefRtdText(&text, TEXT_ENCODING_UTF8, &bufTextLangCode, &bufTextLangText); /* Initialize Text type structure */
err |= ndefRtdTextToRecord(&text, &record1); /* Encode Text Record */
err |= ndefMessageAppend(&message, &record1); /* Append Text record to message */
if( err != ERR_NONE )
{
platformLog("Message creation failed\r\n", err);
return;
}
err = ndefPollerWriteMessage(&ndefCtx, &message); /* Write message */
if( err != ERR_NONE )
{
platformLog("Message cannot be written (ndefPollerWriteMessage return %d)\r\n", err);
return;
}
platformLog("Wrote 1 record to the Tag\r\n");
if( verbose )
{
/* Dump raw message */
bufRawMessage.buffer = rawMessageBuf;
bufRawMessage.length = sizeof(rawMessageBuf);
err = ndefMessageEncode(&message, &bufRawMessage);
if( err == ERR_NONE )
{
ndefBufferDump("Raw message", (ndefConstBuffer*)&bufRawMessage, verbose);
}
}
LedNotificationWriteDone();
break;
/*
* Demonstrate how to encode a URI record and a AAR record, how to encode the message to a raw buffer and then how to write the raw buffer
*/
case NDEF_DEMO_WRITE_MSG2:
ndefDemoFeature = NDEF_DEMO_READ; /* returns to READ mode after write */
err = ndefMessageInit(&message); /* Initialize message structure */
bufUri.buffer = ndefURI;
bufUri.length = strlen((char *)ndefURI);
err |= ndefRtdUri(&uri, NDEF_URI_PREFIX_HTTP_WWW, &bufUri); /* Initialize URI type structure */
err |= ndefRtdUriToRecord(&uri, &record1); /* Encode URI Record */
bufAndroidPackName.buffer = ndefAndroidPackName;
bufAndroidPackName.length = sizeof(ndefAndroidPackName) - 1U;
err |= ndefRtdAar(&aar, &bufAndroidPackName); /* Initialize AAR type structure */
err |= ndefRtdAarToRecord(&aar, &record2); /* Encode AAR record */
err |= ndefMessageAppend(&message, &record1); /* Append URI to message */
err |= ndefMessageAppend(&message, &record2); /* Append AAR to message (record #2 is an example of preformatted record) */
bufRawMessage.buffer = rawMessageBuf;
bufRawMessage.length = sizeof(rawMessageBuf);
err |= ndefMessageEncode(&message, &bufRawMessage); /* Encode the message to the raw buffer */
if( err != ERR_NONE )
{
platformLog("Raw message creation failed\r\n", err);
return;
}
err = ndefPollerWriteRawMessage(&ndefCtx, bufRawMessage.buffer, bufRawMessage.length);
if( err != ERR_NONE )
{
platformLog("Message cannot be written (ndefPollerWriteRawMessage return %d)\r\n", err);
return;
}
platformLog("Wrote 2 records to the Tag\r\n");
if( verbose )
{
/* Dump raw message */
ndefBufferDump("Raw message", (ndefConstBuffer*)&bufRawMessage, verbose);
}
LedNotificationWriteDone();
break;
/*
* Demonstrate how to format a Tag
*/
case NDEF_DEMO_FORMAT_TAG:
ndefDemoFeature = NDEF_DEMO_READ;
if( !ndefIsSTTag(&ndefCtx) )
{
platformLog("Manufacturer ID not found or not an ST tag. Format aborted \r\n");
return;
}
platformLog("Formatting Tag...\r\n");
/* Format Tag */
err = ndefPollerTagFormat(&ndefCtx, NULL, 0);
if( err != ERR_NONE )
{
platformLog("Tag cannot be formatted (ndefPollerTagFormat returns %d)\r\n", err);
return;
}
platformLog("Tag formatted\r\n");
LedNotificationWriteDone();
break;
#endif /* NDEF_FEATURE_ALL */
default:
ndefDemoFeature = NDEF_DEMO_READ;
break;
}
return;
}
static void ndefT2TCCDump(ndefContext *ctx)
{
ndefConstBuffer bufCcBuf;
platformLog(" * Magic: %2.2Xh Version: %d.%d Size: %d (%d bytes) \r\n * readAccess: %2.2xh writeAccess: %2.2xh \r\n", ctx->cc.t2t.magicNumber, ctx->cc.t2t.majorVersion, ctx->cc.t2t.minorVersion, ctx->cc.t2t.size, ctx->cc.t2t.size * 8U, ctx->cc.t2t.readAccess, ctx->cc.t2t.writeAccess);
bufCcBuf.buffer = ctx->ccBuf;
bufCcBuf.length = 4;
ndefBufferDump(" CC Raw Data", &bufCcBuf, verbose);
}
static void ndefT3TAIBDump(ndefContext *ctx)
{
ndefConstBuffer bufCcBuf;
platformLog(" * Version: %d.%d Size: %d (%d bytes) NbR: %d NbW: %d\r\n * WriteFlag: %2.2xh RWFlag: %2.2xh \r\n", ctx->cc.t3t.majorVersion, ctx->cc.t3t.minorVersion, ctx->cc.t3t.nMaxB, ctx->cc.t3t.nMaxB * 16U, ctx->cc.t3t.nbR, ctx->cc.t3t.nbW, ctx->cc.t3t.writeFlag, ctx->cc.t3t.rwFlag);
bufCcBuf.buffer = ctx->ccBuf;
bufCcBuf.length = 16;
ndefBufferDump(" CC Raw Data", &bufCcBuf, verbose);
}
static void ndefT4TCCDump(ndefContext *ctx)
{
ndefConstBuffer bufCcBuf;
platformLog(" * CCLEN: %d T4T_VNo: %xh MLe: %d MLc: %d FileId: %2.2x%2.2xh FileSize: %d\r\n * readAccess: %2.2xh writeAccess: %2.2xh\r\n", ctx->cc.t4t.ccLen, ctx->cc.t4t.vNo, ctx->cc.t4t.mLe, ctx->cc.t4t.mLc, ctx->cc.t4t.fileId[0], ctx->cc.t4t.fileId[1],ctx->cc.t4t.fileSize, ctx->cc.t4t.readAccess, ctx->cc.t4t.writeAccess);
bufCcBuf.buffer = ctx->ccBuf;
bufCcBuf.length = ctx->cc.t4t.ccLen;
ndefBufferDump(" CC File Raw Data", &bufCcBuf, verbose);
}
static void ndefT5TCCDump(ndefContext *ctx)
{
ndefConstBuffer bufCcBuf;
platformLog(" * Block Length: %d\r\n", ctx->subCtx.t5t.blockLen);
platformLog(" * %d bytes CC\r\n * Magic: %2.2Xh Version: %d.%d MLEN: %d (%d bytes) \r\n * readAccess: %2.2xh writeAccess: %2.2xh \r\n", ctx->cc.t5t.ccLen, ctx->cc.t5t.magicNumber, ctx->cc.t5t.majorVersion, ctx->cc.t5t.minorVersion, ctx->cc.t5t.memoryLen, ctx->cc.t5t.memoryLen * 8U, ctx->cc.t5t.readAccess, ctx->cc.t5t.writeAccess);
platformLog(" * [%c] Special Frame\r\n", ctx->cc.t5t.specialFrame ? 'X' : ' ');
platformLog(" * [%c] Multiple block Read\r\n", ctx->cc.t5t.multipleBlockRead ? 'X' : ' ');
platformLog(" * [%c] Lock Block\r\n", ctx->cc.t5t.lockBlock ? 'X' : ' ');
bufCcBuf.buffer = ctx->ccBuf;
bufCcBuf.length = ctx->cc.t5t.ccLen;
ndefBufferDump(" CC Raw Data", &bufCcBuf, verbose);
}
static void ndefCCDump(ndefContext *ctx)
{
if( (ctx == NULL) || !verbose)
{
return;
}
platformLog("%s", (ctx->device.type == RFAL_NFC_LISTEN_TYPE_NFCF) ? "NDEF Attribute Information Block\r\n" : "NDEF Capability Container\r\n");
switch( ctx->device.type )
{
case RFAL_NFC_LISTEN_TYPE_NFCA:
switch( ctx->device.dev.nfca.type )
{
case RFAL_NFCA_T2T:
ndefT2TCCDump(ctx);
break;
case RFAL_NFCA_T4T:
ndefT4TCCDump(ctx);
break;
default:
break;
}
break;
case RFAL_NFC_LISTEN_TYPE_NFCB:
ndefT4TCCDump(ctx);
break;
case RFAL_NFC_LISTEN_TYPE_NFCF:
ndefT3TAIBDump(ctx);
break;
case RFAL_NFC_LISTEN_TYPE_NFCV:
ndefT5TCCDump(ctx);
break;
default:
break;
}
}
static void ndefDumpSysInfo(ndefContext *ctx)
{
ndefSystemInformation *sysInfo;
if( (ctx == NULL) || !verbose)
{
return;
}
if( !ctx->subCtx.t5t.sysInfoSupported )
{
return;
}
sysInfo = &ctx->subCtx.t5t.sysInfo;
platformLog("System Information\r\n");
platformLog(" * %d byte(s) memory addressing\r\n", ndefT5TSysInfoMOIValue(sysInfo->infoFlags) + 1);
if( ndefT5TSysInfoDFSIDPresent(sysInfo->infoFlags) )
{
platformLog(" * DFSID=%2.2Xh\r\n", sysInfo->DFSID);
}
if( ndefT5TSysInfoAFIPresent(sysInfo->infoFlags) )
{
platformLog(" * AFI=%2.2Xh\r\n", sysInfo->AFI);
}
if( ndefT5TSysInfoMemSizePresent(sysInfo->infoFlags) )
{
platformLog(" * %d blocks, %d bytes per block\r\n", sysInfo->numberOfBlock, sysInfo->blockSize);
}
if( ndefT5TSysInfoICRefPresent(sysInfo->infoFlags) )
{
platformLog(" * ICRef=%2.2xh\r\n", sysInfo->ICRef);
}
if( ndefT5TSysInfoCmdListPresent(sysInfo->infoFlags) )
{
platformLog(" * [%c] ReadSingleBlock \r\n", ndefT5TSysInfoReadSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] WriteSingleBlock \r\n", ndefT5TSysInfoWriteSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] LockSingleBlock \r\n", ndefT5TSysInfoLockSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ReadMultipleBlocks \r\n", ndefT5TSysInfoReadMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] WriteMultipleBlocks \r\n", ndefT5TSysInfoWriteMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] Select \r\n", ndefT5TSysInfoSelectSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ResetToReady \r\n", ndefT5TSysInfoResetToReadySupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] GetMultipleBlockSecStatus \r\n", ndefT5TSysInfoGetMultipleBlockSecStatusSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] WriteAFI \r\n", ndefT5TSysInfoWriteAFISupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] LockAFI \r\n", ndefT5TSysInfoLockAFISupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] WriteDSFID \r\n", ndefT5TSysInfoWriteDSFIDSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] LockDSFID \r\n", ndefT5TSysInfoLockDSFIDSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] GetSystemInformation \r\n", ndefT5TSysInfoGetSystemInformationSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] CustomCmds \r\n", ndefT5TSysInfoCustomCmdsSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] FastReadMultipleBlocks \r\n", ndefT5TSysInfoFastReadMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtReadSingleBlock \r\n", ndefT5TSysInfoExtReadSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtWriteSingleBlock \r\n", ndefT5TSysInfoExtWriteSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtLockSingleBlock \r\n", ndefT5TSysInfoExtLockSingleBlockSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtReadMultipleBlocks \r\n", ndefT5TSysInfoExtReadMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtWriteMultipleBlocks \r\n", ndefT5TSysInfoExtWriteMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] ExtGetMultipleBlockSecStatus \r\n", ndefT5TSysInfoExtGetMultipleBlockSecStatusSupported(sysInfo->supportedCmd) ? 'X' : ' ');
platformLog(" * [%c] FastExtendedReadMultipleBlocks \r\n", ndefT5TSysInfoFastExtendedReadMultipleBlocksSupported(sysInfo->supportedCmd) ? 'X' : ' ');
}
return;
}
#if NDEF_FEATURE_ALL
static bool ndefIsSTTag(ndefContext *ctx)
{
bool ret = false;
#if defined(STM32L476xx) //FIXME: temporary code to enable format tag from any manufacturer
if( (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) != 0)
{
ret = true;
}
#endif
if( ctx == NULL )
{
return ret;
}
switch (ctx->device.type)
{
case RFAL_NFC_LISTEN_TYPE_NFCA:
if( (ctx->device.dev.nfca.nfcId1Len != 4) && (ctx->device.dev.nfca.nfcId1[0] == 0x02 ) )
{
ret = true;
}
break;
case RFAL_NFC_LISTEN_TYPE_NFCF:
break;
case RFAL_NFC_LISTEN_TYPE_NFCB:
break;
case RFAL_NFC_LISTEN_TYPE_NFCV:
if( ctx->device.dev.nfcv.InvRes.UID[6] == 0x02 )
{
ret = true;
}
break;
default:
break;
}
return (ret);
}
#endif /* NDEF_FEATURE_ALL */
#if NDEF_FEATURE_ALL
static void LedNotificationWriteDone(void)
{
uint32_t i;
for (i = 0; i < 3; i++)
{
ledsOn();
platformDelay(100);
ledsOff();
platformDelay(100);
}
}
static void ledsOn(void)
{
platformLedOn(PLATFORM_LED_A_PORT, PLATFORM_LED_A_PIN);
platformLedOn(PLATFORM_LED_B_PORT, PLATFORM_LED_B_PIN);
platformLedOn(PLATFORM_LED_F_PORT, PLATFORM_LED_F_PIN);
platformLedOn(PLATFORM_LED_V_PORT, PLATFORM_LED_V_PIN);
platformLedOn(PLATFORM_LED_AP2P_PORT, PLATFORM_LED_AP2P_PIN);
platformLedOn(PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN);
}
static void ledsOff(void)
{
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);
platformLedOff(PLATFORM_LED_FIELD_PORT, PLATFORM_LED_FIELD_PIN);
}
#endif /* NDEF_FEATURE_ALL */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/