2023-02-09 01:51 AM
Hi,
I have downloaded en.x-cube-nfc5 project from:
st(site)/en/ecosystems/x-nucleo-nfc05a1_html
I have connected the X-NUCLEO-NFC05A1 Shield to one of my lab boards, based on STM32F103.
I managed to make the whole thing work with this example: ndef_example_read.c (see below)
I even managed to read one of my tags (NFC type 4A)
I have ST25R3911B-DISCO board too as an example
I run it with "NFC Type 4A - NDEF Message user interface"
there are two options in the supplied ST Windows software:
Present Read Password for read NDEF message
Present Write Password for write NDEF message
and with those options I can read or write my tags with a 16Bytes password length.
I need to do the same with my board (the one with STM32F103), directly connected to the ST25r3911b, and so far I can't find how to define and send those read / write passwords.
ndef_example_read.c:
#include "utils.h"
#include "rfal_nfc.h"
#include "ndef_poller.h"
#include "ndef_message.h"
#include "ndef_types_rtd.h"
#include "ndef_types_mime.h"
#define DEMO_RAW_MESSAGE_BUF_LEN 8192 /*!< raw message buffer size */
static rfalNfcDevice *nfcDevice;
static rfalNfcDiscoverParam discParam =
{
.compMode = RFAL_COMPLIANCE_MODE_NFC,
.devLimit = 1U,
.nfcfBR = RFAL_BR_212,
.ap2pBR = RFAL_BR_424,
.nfcid3 = NULL,
.GB = NULL,
.GBLen = 0,
.notifyCb = NULL,
.totalDuration = 1000U,
.wakeupEnabled = false,
.wakeupConfigDefault = true,
.techs2Find = ( RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | RFAL_NFC_POLL_TECH_V )
};
static ndefContext ndefCtx;
static uint8_t rawMessageBuf[DEMO_RAW_MESSAGE_BUF_LEN];
void ndefExampleParseMessage(uint8_t* rawMsgBuf, uint32_t rawMsgLen);
void ndefExampleParseRecord(ndefRecord *record);
void ndefExamplePrintString(const uint8_t* str, uint32_t strLen);
void ndefExampleRead( void )
{
ReturnCode err;
uint32_t rawMessageLen;
/*
* RFAL Init
*/
err = rfalNfcInitialize();
if( err != ERR_NONE )
{
platformLog("rfalNfcInitialize return %d\r\n", err);
return;
}
rfalNfcDeactivate( false );
rfalNfcDiscover( &discParam );
/*
* Read loop
*/
while (1)
{
rfalNfcWorker();
if( rfalNfcIsDevActivated(rfalNfcGetState()) )
{
/*
* Retrieve NFC device
*/
rfalNfcGetActiveDevice(&nfcDevice);
/*
* Perform NDEF Context Initialization
*/
err = ndefPollerContextInitialization(&ndefCtx, nfcDevice);
if( err != ERR_NONE )
{
platformLog("NDEF NOT DETECTED (ndefPollerContextInitialization returns %d)\r\n", err);
return;
}
/*
* Perform NDEF Detect procedure
*/
err = ndefPollerNdefDetect(&ndefCtx, NULL);
if( err != ERR_NONE )
{
platformLog("NDEF NOT DETECTED (ndefPollerNdefDetect returns %d)\r\n", err);
return;
}
/*
* Perform NDEF read procedure
*/
err = ndefPollerReadRawMessage(&ndefCtx, rawMessageBuf, sizeof(rawMessageBuf), &rawMessageLen);
if( err != ERR_NONE )
{
platformLog("NDEF message cannot be read (ndefPollerReadRawMessage returns %d)\r\n", err);
return;
}
platformLog("NDEF Read successful\r\n");
/*
* Parse message content
*/
ndefExampleParseMessage(rawMessageBuf, rawMessageLen);
return;
}
}
}
Solved! Go to Solution.
2023-02-14 07:06 AM
Thank you a lot
I finished writing my code, I made a few little changes in additions to yours @Brian TIDAL_O :
I add 2 function call, that get the read pass arr and the write pass arr, from my code:
GetReadPassword_p();
GetWritePassword_p();
I also added:
ret = ndefT4TPollerManageAccessRight(ctx, false); // write password
at the end of the call to gives access to write too
The file ndef_t4t.c looks like that now:
/*******************************************************************************/
static ReturnCode ndefT4TPollerComposeVerify( rfalIsoDepApduBufFormat *cApduBuf, bool read, const uint8_t* pwd, uint8_t pwdLen, uint16_t *cApduLen )
{
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h D6h [Offset] len Data - */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = 0x20;
cAPDU.P1 = 0x00;
cAPDU.P2 = (read ? 0x01U : 0x02U);
cAPDU.Lc = pwdLen;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if( pwdLen > 0U )
{
ST_MEMCPY( cAPDU.cApduBuf->apdu, pwd, pwdLen );
}
return rfalT4TPollerComposeCAPDU( &cAPDU );
}
/*******************************************************************************/
static ReturnCode ndefT4TPollerVerify(ndefContext *ctx, bool read, const uint8_t *pwd)
{
ReturnCode ret;
rfalIsoDepApduTxRxParam isoDepAPDU;
if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( !read && (pwd == NULL) )
{
return ERR_PARAM;
}
ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU);
ret = ndefT4TPollerComposeVerify(isoDepAPDU.txBuf, read, pwd, (pwd == NULL) ? 0x00 : 0x10, &isoDepAPDU.txBufLen);
if( ret == ERR_NONE )
{
ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU);
}
return ret;
}
/*******************************************************************************/
static ReturnCode ndefT4TPollerManageAccessRight(ndefContext *ctx, bool read)
{
uint8_t* readpwd = GetReadPassword_p();
uint8_t* writepwd = GetWritePassword_p();
if(read)
return ndefT4TPollerVerify(ctx, read, readpwd);
return ndefT4TPollerVerify(ctx, read, writepwd);
}
/*******************************************************************************/
ReturnCode ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)
{
ReturnCode ret;
uint8_t* nLen;
uint8_t nlenLen;
if( info != NULL )
{
info->state = NDEF_STATE_INVALID;
info->majorVersion = 0U;
info->minorVersion = 0U;
info->areaLen = 0U;
info->areaAvalableSpaceLen = 0U;
info->messageLen = 0U;
}
if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )
{
return ERR_PARAM;
}
ctx->state = NDEF_STATE_INVALID;
/* Select NDEF Tag application TS T4T v1.0 7.2.1.1 */
ret = ndefT4TPollerSelectNdefTagApplication(ctx);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.2 */
return ret;
}
/* TS T4T v1.0 7.2.1.3 and following */
ret = ndefT4TReadAndParseCCFile(ctx);
if( ret != ERR_NONE )
{
return ret;
}
nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN;
/* TS T4T v1.0 7.2.1.7 verify file READ access */
if( !(ndefT4TIsReadAccessGranted(ctx->cc.t4t.readAccess)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.8 */
return ERR_REQUEST;
}
/* File size need at least be enough to store NLEN or ENLEN */
if( ctx->cc.t4t.fileSize < nlenLen)
{
return ERR_REQUEST;
}
/* Select NDEF File TS T4T v1.0 7.2.1.9 */
ret = ndefT4TPollerSelectFile(ctx, ctx->cc.t4t.fileId);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.10 */
return ret;
}
/* READ Access right management */
ret = ndefT4TPollerManageAccessRight(ctx, true); // read password
if( ret != ERR_NONE )
{
return ret;
}
/* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */
ret = ndefT4TPollerReadBinary(ctx, 0U, nlenLen);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ret;
}
nLen = ctx->subCtx.t4t.rApduBuf.apdu;
ctx->messageLen = (nlenLen == NDEF_T4T_ENLEN_LEN) ? GETU32(&nLen[0]) : (uint32_t)ndefBytes2Uint16(nLen[0], nLen[1]);
ctx->messageOffset = nlenLen;
ctx->areaLen = ctx->cc.t4t.fileSize;
if ( (ctx->messageLen > (ctx->cc.t4t.fileSize - nlenLen)) || ((ctx->messageLen > 0U) && (ctx->messageLen < NDEF_T4T_MIN_NLEN)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ERR_REQUEST;
}
if( ctx->messageLen == 0U )
{
if( !(ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ERR_REQUEST;
}
ctx->state = NDEF_STATE_INITIALIZED;
}
else
{
ctx->state = (ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY;
}
if( info != NULL )
{
info->state = ctx->state;
info->majorVersion = ndefMajorVersion(ctx->cc.t4t.vNo);
info->minorVersion = ndefMinorVersion(ctx->cc.t4t.vNo);
info->areaLen = ctx->areaLen;
info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset;
info->messageLen = ctx->messageLen;
}
ret = ndefT4TPollerManageAccessRight(ctx, false); // write password
if( ret != ERR_NONE )
{
return ret;
}
return ERR_NONE;
}
2023-02-09 02:04 AM
Hi Nathanael,
you will find an rfalST25xVPollerPresentPassword() API in rfal_st25xv.c. See https://community.st.com/s/question/0D53W000004m5e4SAA/can-anyone-provide-an-example-of-api-rfalst25xvpollerreadmessage for a code example.
Basically, you should add the call to this API before ndefPollerContextInitialization.
If this answers to your question, would you please "select as best answer". Otherwise feel free to ask more information.
Rgds
BT
2023-02-09 02:38 AM
I already found this post and this function.
is not working, rfalST25xVPollerPresentPassword() can get a password of more than 8 Bytes
and i need to present the ndef password of 16 Bytes
I tried to change the #define RFAL_ST25xV_PWD_LEN 8U to 16U
but its not working
2023-02-09 04:15 AM
Hi Nathanael,
it seems you are using a Type 4A tag. My previous answer is related to a Type V tag. Sorry for the confusion. Can you confirm you are using a ST25TA tag?
If you are using a ST25TA tag, basically you have to send a Verify command. This should be done after selecting the NDEF file. I would suggest to modify the ndefT4TPollerNdefDetect() just after the NDEF file select command (see comment /* Select NDEF File TS T4T v1.0 7.2.1.9 */ and ndefT4TPollerSelectFile() call in ndefT4TPollerNdefDetect).
As there is no API to send the verify command, you'll have to compose the APDU and to send it. I would suggest to get inspiration from one of the existing command (such as ndefT4TPollerReadBinary) to compose the APU and then you just need to use ndefT4TTransceiveTxRx to transmit it.
Feel free to share your modifications if you face some issue.
Rgds
BT
2023-02-09 04:29 AM
Hi Brian,
Thanks for your reply.
As a beginner, I assume that my knowledge is still limited.
Any chance to ask you to prepare an example code for what you suggest?
Regards,
Nathaniel
2023-02-14 06:20 AM
Sample code sent in private message to issue a Verify command before reading the NDEF file
2023-02-14 07:06 AM
Thank you a lot
I finished writing my code, I made a few little changes in additions to yours @Brian TIDAL_O :
I add 2 function call, that get the read pass arr and the write pass arr, from my code:
GetReadPassword_p();
GetWritePassword_p();
I also added:
ret = ndefT4TPollerManageAccessRight(ctx, false); // write password
at the end of the call to gives access to write too
The file ndef_t4t.c looks like that now:
/*******************************************************************************/
static ReturnCode ndefT4TPollerComposeVerify( rfalIsoDepApduBufFormat *cApduBuf, bool read, const uint8_t* pwd, uint8_t pwdLen, uint16_t *cApduLen )
{
rfalT4tCApduParam cAPDU;
/* CLA INS P1 P2 Lc Data Le */
/* 00h D6h [Offset] len Data - */
cAPDU.CLA = RFAL_T4T_CLA;
cAPDU.INS = 0x20;
cAPDU.P1 = 0x00;
cAPDU.P2 = (read ? 0x01U : 0x02U);
cAPDU.Lc = pwdLen;
cAPDU.LcFlag = true;
cAPDU.LeFlag = false;
cAPDU.cApduBuf = cApduBuf;
cAPDU.cApduLen = cApduLen;
if( pwdLen > 0U )
{
ST_MEMCPY( cAPDU.cApduBuf->apdu, pwd, pwdLen );
}
return rfalT4TPollerComposeCAPDU( &cAPDU );
}
/*******************************************************************************/
static ReturnCode ndefT4TPollerVerify(ndefContext *ctx, bool read, const uint8_t *pwd)
{
ReturnCode ret;
rfalIsoDepApduTxRxParam isoDepAPDU;
if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )
{
return ERR_PARAM;
}
if( !read && (pwd == NULL) )
{
return ERR_PARAM;
}
ndefT4TInitializeIsoDepTxRxParam(ctx, &isoDepAPDU);
ret = ndefT4TPollerComposeVerify(isoDepAPDU.txBuf, read, pwd, (pwd == NULL) ? 0x00 : 0x10, &isoDepAPDU.txBufLen);
if( ret == ERR_NONE )
{
ret = ndefT4TTransceiveTxRx(ctx, &isoDepAPDU);
}
return ret;
}
/*******************************************************************************/
static ReturnCode ndefT4TPollerManageAccessRight(ndefContext *ctx, bool read)
{
uint8_t* readpwd = GetReadPassword_p();
uint8_t* writepwd = GetWritePassword_p();
if(read)
return ndefT4TPollerVerify(ctx, read, readpwd);
return ndefT4TPollerVerify(ctx, read, writepwd);
}
/*******************************************************************************/
ReturnCode ndefT4TPollerNdefDetect(ndefContext *ctx, ndefInfo *info)
{
ReturnCode ret;
uint8_t* nLen;
uint8_t nlenLen;
if( info != NULL )
{
info->state = NDEF_STATE_INVALID;
info->majorVersion = 0U;
info->minorVersion = 0U;
info->areaLen = 0U;
info->areaAvalableSpaceLen = 0U;
info->messageLen = 0U;
}
if( (ctx == NULL) || !ndefT4TisT4TDevice(&ctx->device) )
{
return ERR_PARAM;
}
ctx->state = NDEF_STATE_INVALID;
/* Select NDEF Tag application TS T4T v1.0 7.2.1.1 */
ret = ndefT4TPollerSelectNdefTagApplication(ctx);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.2 */
return ret;
}
/* TS T4T v1.0 7.2.1.3 and following */
ret = ndefT4TReadAndParseCCFile(ctx);
if( ret != ERR_NONE )
{
return ret;
}
nlenLen = ( ndefMajorVersion(ctx->cc.t4t.vNo) == ndefMajorVersion(NDEF_T4T_MAPPING_VERSION_3_0) ) ? NDEF_T4T_ENLEN_LEN : NDEF_T4T_NLEN_LEN;
/* TS T4T v1.0 7.2.1.7 verify file READ access */
if( !(ndefT4TIsReadAccessGranted(ctx->cc.t4t.readAccess)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.8 */
return ERR_REQUEST;
}
/* File size need at least be enough to store NLEN or ENLEN */
if( ctx->cc.t4t.fileSize < nlenLen)
{
return ERR_REQUEST;
}
/* Select NDEF File TS T4T v1.0 7.2.1.9 */
ret = ndefT4TPollerSelectFile(ctx, ctx->cc.t4t.fileId);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.10 */
return ret;
}
/* READ Access right management */
ret = ndefT4TPollerManageAccessRight(ctx, true); // read password
if( ret != ERR_NONE )
{
return ret;
}
/* Read NLEN/ENLEN TS T4T v1.0 7.2.1.11 */
ret = ndefT4TPollerReadBinary(ctx, 0U, nlenLen);
if( ret != ERR_NONE )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ret;
}
nLen = ctx->subCtx.t4t.rApduBuf.apdu;
ctx->messageLen = (nlenLen == NDEF_T4T_ENLEN_LEN) ? GETU32(&nLen[0]) : (uint32_t)ndefBytes2Uint16(nLen[0], nLen[1]);
ctx->messageOffset = nlenLen;
ctx->areaLen = ctx->cc.t4t.fileSize;
if ( (ctx->messageLen > (ctx->cc.t4t.fileSize - nlenLen)) || ((ctx->messageLen > 0U) && (ctx->messageLen < NDEF_T4T_MIN_NLEN)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ERR_REQUEST;
}
if( ctx->messageLen == 0U )
{
if( !(ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) )
{
/* Conclude procedure TS T4T v1.0 7.2.1.11 */
return ERR_REQUEST;
}
ctx->state = NDEF_STATE_INITIALIZED;
}
else
{
ctx->state = (ndefT4TIsWriteAccessGranted(ctx->cc.t4t.writeAccess)) ? NDEF_STATE_READWRITE : NDEF_STATE_READONLY;
}
if( info != NULL )
{
info->state = ctx->state;
info->majorVersion = ndefMajorVersion(ctx->cc.t4t.vNo);
info->minorVersion = ndefMinorVersion(ctx->cc.t4t.vNo);
info->areaLen = ctx->areaLen;
info->areaAvalableSpaceLen = ctx->areaLen - ctx->messageOffset;
info->messageLen = ctx->messageLen;
}
ret = ndefT4TPollerManageAccessRight(ctx, false); // write password
if( ret != ERR_NONE )
{
return ret;
}
return ERR_NONE;
}