mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-22 12:32:02 +00:00
feat(core): Introduce NFC tests into prodtest [no changelog]
This commit is contained in:
parent
fe64689992
commit
2686b8a033
@ -26,16 +26,16 @@
|
||||
|
||||
#define NFC_MAX_UID_LEN 10
|
||||
|
||||
typedef enum{
|
||||
typedef enum {
|
||||
NFC_POLLER_TECH_A = 0x1,
|
||||
NFC_POLLER_TECH_B = 0x1 << 1 ,
|
||||
NFC_POLLER_TECH_B = 0x1 << 1,
|
||||
NFC_POLLER_TECH_F = 0x1 << 2,
|
||||
NFC_POLLER_TECH_V = 0x1 << 3,
|
||||
NFC_CARD_EMU_TECH_A = 0x1 << 4,
|
||||
NFC_CARD_EMU_TECH_F = 0x1 << 5,
|
||||
} nfc_tech_t ;
|
||||
} nfc_tech_t;
|
||||
|
||||
typedef enum{
|
||||
typedef enum {
|
||||
NFC_DEV_TYPE_A,
|
||||
NFC_DEV_TYPE_B,
|
||||
NFC_DEV_TYPE_F,
|
||||
@ -45,7 +45,7 @@ typedef enum{
|
||||
NFC_DEV_TYPE_UNKNOWN,
|
||||
} nfc_dev_type_t;
|
||||
|
||||
typedef enum{
|
||||
typedef enum {
|
||||
NFC_STATE_IDLE,
|
||||
NFC_STATE_ACTIVATED,
|
||||
} nfc_event_t;
|
||||
@ -58,26 +58,47 @@ typedef enum {
|
||||
NFC_INITIALIZATION_FAILED,
|
||||
} nfc_status_t;
|
||||
|
||||
typedef struct{
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
char uid[NFC_MAX_UID_LEN];
|
||||
uint8_t uid_len;
|
||||
}nfc_dev_info_t;
|
||||
} nfc_dev_info_t;
|
||||
|
||||
// Initialize NFC driver including supportive RFAL middlewere
|
||||
nfc_status_t nfc_init();
|
||||
|
||||
// Deinitialize NFC drive
|
||||
nfc_status_t nfc_deinit();
|
||||
|
||||
// Register NFC technology (or several) to be explored by NFC state machine
|
||||
// use this function before activating the state machine with nfc_activate_stm()
|
||||
nfc_status_t nfc_register_tech(nfc_tech_t tech);
|
||||
|
||||
nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(void));
|
||||
// Register event callbacks to be called with state machine, this function is
|
||||
// used when user need to further interact (read/write) with the connected NFC
|
||||
// device
|
||||
nfc_status_t nfc_register_event_callback(nfc_event_t event_type,
|
||||
void (*cb_fn)(void));
|
||||
|
||||
// Activate the NFC RFAL state machine which will explore the registered
|
||||
// technologies State machine handles the low level NFC protocols of registered
|
||||
// technologies and provide the user with the activated device information. With
|
||||
// activated, user have to constantly run NFC workerwith nfc_feed_worker() to
|
||||
// activly loop the state machine.
|
||||
nfc_status_t nfc_activate_stm();
|
||||
|
||||
// Deactivate the NFC RFAL state machine (put in IDLE state).
|
||||
nfc_status_t nfc_deactivate_stm();
|
||||
|
||||
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);
|
||||
|
||||
// Calls NFC RFAL worker which service the NFC statemachine exploring the
|
||||
// registered technologies. this function has to be actively called in loop
|
||||
// (main NFC poll function).
|
||||
nfc_status_t nfc_feed_worker();
|
||||
|
||||
// Read the general device information of the activated NFC device.
|
||||
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);
|
||||
|
||||
// Write the NDFE message with the trezor.io URI to the activated NFC device.
|
||||
nfc_status_t nfc_def_write_ndef_uri();
|
||||
|
||||
#endif // TREZORHAL_NFC_H
|
||||
|
653
core/embed/io/nfc/st25r3916b/card_emulation.c
Normal file
653
core/embed/io/nfc/st25r3916b/card_emulation.c
Normal file
@ -0,0 +1,653 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file card_emulation.c
|
||||
* @author MMY Application Team
|
||||
* @brief Body function to manage card emul mode
|
||||
******************************************************************************
|
||||
** This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* COPYRIGHT(c) 2018 STMicroelectronics
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "card_emulation.h"
|
||||
#include "rfal_nfca.h"
|
||||
#include "rfal_nfcf.h"
|
||||
#include "rfal_rf.h"
|
||||
|
||||
/** @addtogroup X-CUBE-NFC6_Applications
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup CardEmulation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup CE_CardEmul
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/** @defgroup CE_CardEmul_Private_Typedef
|
||||
* @{
|
||||
*/
|
||||
enum States {
|
||||
STATE_IDLE = 0, /*!< Emulated Tag state idle */
|
||||
STATE_APP_SELECTED = 1, /*!< Emulated Tag state application selected */
|
||||
STATE_CC_SELECTED = 2, /*!< Emulated Tag state CCFile selected */
|
||||
STATE_FID_SELECTED = 3, /*!< Emulated Tag state FileID selected */
|
||||
};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/** @defgroup CE_CardEmul_Private_Define
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define NDEF_SIZE 2048 /*!< Max NDEF size emulated. Range: 0005h - 7FFFh */
|
||||
#define T4T_CLA_00 0x00 /*!< CLA value for type 4 command */
|
||||
#define T4T_INS_SELECT \
|
||||
0xA4 /*!< INS value for select command */
|
||||
#define T4T_INS_READ \
|
||||
0xB0 /*!< INS value for reabbinary command */
|
||||
#define T4T_INS_UPDATE \
|
||||
0xD6 /*!< INS value for update command */
|
||||
#define FID_CC 0xE103 /*!< File ID number for CCFile */
|
||||
#define FID_NDEF 0x0001 /*!< File ID number for NDEF file */
|
||||
#define T3T_BLOCK_SIZE \
|
||||
0x10 /*!< Block size in Type 3 Tag */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/** @defgroup CE_CardEmul_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
static uint8_t gNfcfNfcid[RFAL_NFCF_NFCID2_LEN];
|
||||
static uint8_t ndefFile[NDEF_SIZE]; /*!< Buffer to store NDEF File */
|
||||
static int8_t nState = STATE_IDLE; /*!< Type 4 tag emulation status */
|
||||
static int32_t nSelectedIdx = -1; /*!< current file selected */
|
||||
static int32_t nFiles = 2; /*!< Number of file emulated */
|
||||
|
||||
/**
|
||||
* CCLEN : Indicates the size of this CC File <BR>
|
||||
* T4T_VNo : Indicates the Mapping Version <BR>
|
||||
* MLe high : Max R-APDU size <BR>
|
||||
* MLc high : Max C-APDU size <BR>
|
||||
* NDEF FCI T: Indicates the NDEF-File_Ctrl_TLV <BR>
|
||||
* NDEF FCI L: The length of the V-field <BR>
|
||||
* NDEF FCI V1: NDEF File Identifier <BR>
|
||||
* NDEF FCI V2: NDEF File size <BR>
|
||||
* NDEF FCI V3: NDEF Read AC <BR>
|
||||
* NDEF FCI V4: NDEF Write AC <BR>
|
||||
*/
|
||||
static uint8_t ccfile[] = {
|
||||
0x00,
|
||||
0x0F, /* CCLEN */
|
||||
0x20, /* T4T_VNo */
|
||||
0x00,
|
||||
0x7F, /* MLe */
|
||||
0x00,
|
||||
0x7F, /* MLc */
|
||||
0x04, /* T */
|
||||
0x06, /* L */
|
||||
(FID_NDEF & 0xFF00) >> 8,
|
||||
(FID_NDEF & 0x00FF), /* V1 */
|
||||
(NDEF_SIZE & 0xFF00) >> 8,
|
||||
(NDEF_SIZE & 0x00FF), /* V2 */
|
||||
0x00, /* V3 */
|
||||
0x00 /* V4 */
|
||||
};
|
||||
|
||||
static uint32_t pdwFileSize[] = {sizeof(ccfile),
|
||||
NDEF_SIZE}; /*!< Current emulated files size */
|
||||
|
||||
/**
|
||||
* NDEF length <BR>
|
||||
* NDEF Header: MB,ME,SR,Well known Type <BR>
|
||||
* NDEF type length <BR>
|
||||
* NDEF payload length <BR>
|
||||
* NDEF Type : URI <BR>
|
||||
* NDEF URI abreviation field : http://www. <BR>
|
||||
* NDEF URI string : st.com/st25-demo <BR>
|
||||
*/
|
||||
static const uint8_t ndef_uri[] = {
|
||||
0x00, 0x15, /* NDEF length */
|
||||
0xD1, /* NDEF Header */
|
||||
0x01, /* NDEF type length */
|
||||
0x11, /* NDEF payload length */
|
||||
0x55, /* NDEF Type */
|
||||
0x01, /* NDEF URI abreviation field */
|
||||
0x74, 0x72, 0x65, 0x7A, 0x6F, 0x72, 0x2E, 0x69, 0x6F}; /* NDEF URI string */
|
||||
|
||||
__WEAK const uint8_t *NdefFile = ndef_uri;
|
||||
__WEAK uint32_t NdefFileLen = sizeof(ndef_uri);
|
||||
|
||||
/**
|
||||
* Ver : Indicates the NDEF mapping version <BR>
|
||||
* Nbr : Indicates the number of blocks that can be read <BR>
|
||||
* Nbw : Indicates the number of blocks that can be written <BR>
|
||||
* NmaxB : Indicates the maximum number of blocks available for NDEF data <BR>
|
||||
* WriteFlag : Indicates whether a previous NDEF write procedure has finished or
|
||||
* not <BR> RWFlag : Indicates data can be updated or not <BR> Ln : Is the size
|
||||
* of the actual stored NDEF data in bytes <BR> Checksum : allows the
|
||||
* Reader/Writer to check whether the Attribute Data are correct <BR>
|
||||
*/
|
||||
static uint8_t InformationBlock[] = {
|
||||
0x10, /* Ver */
|
||||
0x08, /* Nbr */
|
||||
0x08, /* Nbw */
|
||||
0x00, 0x0F, /* NmaxB */
|
||||
0x00, 0x00, 0x00, 0x00, /* RFU */
|
||||
0x00, /* WriteFlag */
|
||||
0x01, /* RWFlag */
|
||||
0x00, 0x00, 0x15, /* Ln */
|
||||
0x00, 0x45 /* Checksum */
|
||||
};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/** @defgroup CE_CardEmul_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Compare 2 commands supplied in parameters
|
||||
*
|
||||
* @param[in] cmd : pointer to the received command.
|
||||
* @param[in] find : pointer to the avalaible command.
|
||||
* @param[in] len : length of the available command.
|
||||
*
|
||||
* @retval True : Same command.
|
||||
* @retval False : Different command.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static bool cmdCompare(uint8_t *cmd, uint8_t *find, uint16_t len) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (!memcmp(&cmd[i], find, len)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Manage the T4T Select answer to the reader
|
||||
*
|
||||
* @param[in] cmdData : pointer to the received command.
|
||||
* @param[out] rspData : pointer to the answer to send.
|
||||
*
|
||||
* @return Answer size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static uint16_t card_emulation_t4t_select(uint8_t *cmdData, uint8_t *rspData) {
|
||||
bool success = false;
|
||||
/*
|
||||
* Cmd: CLA(1) | INS(1) | P1(1) | P2(1) | Lc(1) | Data(n) | [Le(1)]
|
||||
* Rsp: [FCI(n)] | SW12
|
||||
*
|
||||
* Select App by Name NDEF: 00 A4 04 00 07 D2 76 00 00 85 01 01 00
|
||||
* Select App by Name NDEF 4 ST: 00 A4 04 00 07 A0 00 00 00 03 00 00 00
|
||||
* Select CC FID: 00 A4 00 0C 02 xx xx
|
||||
* Select NDEF FID: 00 A4 00 0C 02 xx xx
|
||||
*/
|
||||
|
||||
uint8_t aid[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
|
||||
uint8_t fidCC[] = {FID_CC >> 8, FID_CC & 0xFF};
|
||||
uint8_t fidNDEF[] = {FID_NDEF >> 8, FID_NDEF & 0xFF};
|
||||
uint8_t selectFileId[] = {0xA4, 0x00, 0x0C, 0x02, 0x00, 0x01};
|
||||
|
||||
if (cmdCompare(cmdData, aid, sizeof(aid))) { /* Select Appli */
|
||||
nState = STATE_APP_SELECTED;
|
||||
success = true;
|
||||
} else if ((nState >= STATE_APP_SELECTED) &&
|
||||
cmdCompare(cmdData, fidCC, sizeof(fidCC))) { /* Select CC */
|
||||
nState = STATE_CC_SELECTED;
|
||||
nSelectedIdx = 0;
|
||||
success = true;
|
||||
} else if ((nState >= STATE_APP_SELECTED) &&
|
||||
(cmdCompare(cmdData, fidNDEF, sizeof(fidNDEF)) ||
|
||||
cmdCompare(cmdData, selectFileId,
|
||||
sizeof(selectFileId)))) { /* Select NDEF */
|
||||
nState = STATE_FID_SELECTED;
|
||||
nSelectedIdx = 1;
|
||||
success = true;
|
||||
} else {
|
||||
nState = STATE_IDLE;
|
||||
}
|
||||
|
||||
rspData[0] = (success ? (char)0x90 : 0x6A);
|
||||
rspData[1] = (success ? (char)0x00 : 0x82);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Manage the T4T Read answer to the reader
|
||||
*
|
||||
* @param[in] cmdData : pointer to the received command.
|
||||
* @param[out] rspData : pointer to the answer to send.
|
||||
* @param[in] rspDataLen : size of the answer buffer.
|
||||
*
|
||||
* @return Answer size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static uint16_t card_emulation_t4t_read(uint8_t *cmdData, uint8_t *rspData,
|
||||
uint16_t rspDataLen) {
|
||||
/*
|
||||
* Cmd: CLA(1) | INS(1) | P1(1).. offset inside file high | P2(1).. offset
|
||||
* inside file high | Le(1).. nBytes to read Rsp: BytesRead | SW12
|
||||
*/
|
||||
unsigned short offset = (cmdData[2] << 8) | cmdData[3];
|
||||
unsigned short toRead = cmdData[4];
|
||||
uint8_t *ppbMemory;
|
||||
|
||||
if (rspDataLen < 2) {
|
||||
// platformErrorHandle(); /* Must ensure appropriate buffer */
|
||||
}
|
||||
|
||||
/* Any file selected */
|
||||
if (nSelectedIdx < 0 || nSelectedIdx >= nFiles) {
|
||||
rspData[0] = ((char)0x6A);
|
||||
rspData[1] = ((char)0x82);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* offset + length exceed file size */
|
||||
if ((unsigned long)(offset + toRead) > pdwFileSize[nSelectedIdx]) {
|
||||
toRead = pdwFileSize[nSelectedIdx] - offset;
|
||||
}
|
||||
|
||||
if (rspDataLen < (toRead + 2)) {
|
||||
rspData[0] = ((char)0x6F);
|
||||
rspData[1] = ((char)0x00);
|
||||
return 2;
|
||||
}
|
||||
|
||||
ppbMemory = (nSelectedIdx == 0 ? ccfile : ndefFile);
|
||||
/* read data */
|
||||
memcpy(rspData, &ppbMemory[offset], toRead);
|
||||
|
||||
rspData[toRead] = ((char)0x90);
|
||||
rspData[toRead + 1] = ((char)0x00);
|
||||
return toRead + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Manage the T4T Update answer to the reader
|
||||
*
|
||||
* @param[in] cmdData : pointer to the received command.
|
||||
* @param[in] rspData : pointer to the answer to send.
|
||||
*
|
||||
* @return Answer size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static uint16_t card_emulation_t4t_update(uint8_t *cmdData, uint8_t *rspData) {
|
||||
uint32_t offset = (cmdData[2] << 8) | cmdData[3];
|
||||
uint32_t length = cmdData[4];
|
||||
|
||||
if (nSelectedIdx != 1) {
|
||||
rspData[0] = ((char)0x6A);
|
||||
rspData[1] = ((char)0x82);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((unsigned long)(offset + length) > pdwFileSize[nSelectedIdx]) {
|
||||
rspData[0] = ((char)0x62);
|
||||
rspData[1] = ((char)0x82);
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy((ndefFile + offset), &cmdData[5], length);
|
||||
|
||||
rspData[0] = ((char)0x90);
|
||||
rspData[1] = ((char)0x00);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Manage the T4T Read answer to the reader
|
||||
*
|
||||
* @param[in] cmdData : pointer to the received command.
|
||||
* @param[out] rspData : pointer to the answer to send.
|
||||
* @param[in] rspDataLen : size of the answer buffer.
|
||||
*
|
||||
* @return Answer size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static uint16_t card_emulation_t3t_check(uint8_t *cmdData, uint8_t *rspData,
|
||||
uint16_t rspDataLen) {
|
||||
/*
|
||||
* Cmd: cmd | NFCID2 | NoS | Service code list | NoB | Block list
|
||||
* Rsp: rsp | NFCID2 | Status Flag 1 | Status Flag 2 | NoB | Block Data
|
||||
*/
|
||||
uint8_t *block;
|
||||
uint16_t blocknb[256];
|
||||
uint32_t idx = 0;
|
||||
uint32_t cnt = 0;
|
||||
uint32_t nbmax = 0;
|
||||
|
||||
/* Command response */
|
||||
rspData[idx++] = RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION + 1;
|
||||
|
||||
/* NFCID 2 bytes */
|
||||
if (memcmp(gNfcfNfcid, &cmdData[RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN],
|
||||
RFAL_NFCF_NFCID2_LEN) == 0) {
|
||||
memcpy(&rspData[idx], &gNfcfNfcid, RFAL_NFCF_NFCID2_LEN);
|
||||
idx += RFAL_NFCF_NFCID2_LEN;
|
||||
} else {
|
||||
/* If NFCID2 in command is different, no answer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for command errors */
|
||||
if ((cmdData[10] != 1) || ((cmdData[11] != 0x09) && (cmdData[11] != 0x0B)) ||
|
||||
(cmdData[13] == 0) || (cmdData[13] > InformationBlock[1])) {
|
||||
rspData[idx++] = 0xFF;
|
||||
rspData[idx++] = 0xFF;
|
||||
return idx;
|
||||
} else {
|
||||
rspData[idx++] = 0x00;
|
||||
rspData[idx++] = 0x00;
|
||||
}
|
||||
|
||||
/* Verify CHECK response length */
|
||||
if (rspDataLen < (11 + (cmdData[13] * T3T_BLOCK_SIZE))) {
|
||||
// platformErrorHandle(); /* Must ensure appropriate buffer */
|
||||
}
|
||||
|
||||
/* Nob */
|
||||
rspData[idx++] = cmdData[13];
|
||||
|
||||
/* Retrieving block to read */
|
||||
block = &cmdData[14];
|
||||
for (cnt = 0; cnt < cmdData[13]; cnt++) {
|
||||
/* TS T3T 5.6.1.5 Service Code List Order value SHALL be between 0 and NoS-1
|
||||
*/
|
||||
if (((*block) & 0x0F) >= cmdData[10]) {
|
||||
rspData[idx - 3] = 0xFF;
|
||||
rspData[idx - 2] = 0x80; /* TS T3T table 13 - proprietary value to
|
||||
indicate specific error conditions.*/
|
||||
return (idx - 1);
|
||||
}
|
||||
/* Check block list element size */
|
||||
if (*block & 0x80) {
|
||||
/* 2-byte Block List element */
|
||||
blocknb[cnt] = *(block + 1);
|
||||
block += 2;
|
||||
} else {
|
||||
/* 3-byte Block List element */
|
||||
blocknb[cnt] = *(block + 2); /* Little Endian Format */
|
||||
blocknb[cnt] <<= 8;
|
||||
blocknb[cnt] |= *(block + 1);
|
||||
block += 3;
|
||||
}
|
||||
|
||||
/* Return error if Blocknb > NmaxB */
|
||||
nbmax = InformationBlock[3];
|
||||
nbmax = (nbmax << 8) | InformationBlock[4];
|
||||
if (blocknb[cnt] > nbmax) {
|
||||
rspData[idx - 3] = 0xFF;
|
||||
rspData[idx - 2] = 0x70;
|
||||
return (idx - 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < cmdData[13]; cnt++) {
|
||||
if (blocknb[cnt] == 0x0000) {
|
||||
/* Read information block */
|
||||
memcpy(&rspData[idx], InformationBlock, sizeof(InformationBlock));
|
||||
idx += sizeof(InformationBlock);
|
||||
} else {
|
||||
/* Read ndef block */
|
||||
memcpy(&rspData[idx],
|
||||
&ndefFile[2 + ((blocknb[cnt] - 1) * T3T_BLOCK_SIZE)],
|
||||
T3T_BLOCK_SIZE);
|
||||
idx += T3T_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Manage the T3T Update answer to the reader
|
||||
*
|
||||
* @param[in] cmdData : pointer to the received command.
|
||||
* @param[in] rspData : pointer to the answer to send.
|
||||
*
|
||||
* @return Answer size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
static uint16_t card_emulation_t3t_update(uint8_t *cmdData, uint8_t *rspData) {
|
||||
/*
|
||||
* Cmd: cmd | NFCID2 | NoS | Service code list | NoB | Block list | Block Data
|
||||
* Rsp: rsp | NFCID2 | Status Flag 1 | Status Flag 2
|
||||
*/
|
||||
uint8_t *block;
|
||||
uint16_t blocknb[256];
|
||||
uint32_t idx = 0;
|
||||
uint32_t cnt = 0;
|
||||
uint32_t nbmax = 0;
|
||||
|
||||
/* Command response */
|
||||
rspData[idx++] = RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION + 1;
|
||||
|
||||
/* NFCID 2 bytes */
|
||||
if (memcmp(gNfcfNfcid, &cmdData[RFAL_NFCF_LENGTH_LEN + RFAL_NFCF_CMD_LEN],
|
||||
RFAL_NFCF_NFCID2_LEN) == 0) {
|
||||
memcpy(&rspData[idx], gNfcfNfcid, RFAL_NFCF_NFCID2_LEN);
|
||||
idx += RFAL_NFCF_NFCID2_LEN;
|
||||
} else {
|
||||
/* If NFCID2 in command is different, no answer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for command errors */
|
||||
if ((cmdData[10] != 1) || (cmdData[11] != 0x09) || (cmdData[13] == 0) ||
|
||||
(cmdData[13] > InformationBlock[2])) {
|
||||
rspData[idx++] = 0xFF;
|
||||
rspData[idx++] = 0xFF;
|
||||
return idx;
|
||||
} else {
|
||||
rspData[idx++] = 0x00;
|
||||
rspData[idx++] = 0x00;
|
||||
}
|
||||
|
||||
/* Retrieving block to read */
|
||||
block = &cmdData[14];
|
||||
for (cnt = 0; cnt < cmdData[13]; cnt++) {
|
||||
/* Check block list element size */
|
||||
if (*block & 0x80) {
|
||||
/* 2-byte Block List element */
|
||||
blocknb[cnt] = *(block + 1);
|
||||
block += 2;
|
||||
} else {
|
||||
/* 3-byte Block List element */
|
||||
blocknb[cnt] = *(block + 2); /* Little Endian Format */
|
||||
blocknb[cnt] <<= 8;
|
||||
blocknb[cnt] |= *(block + 1);
|
||||
block += 3;
|
||||
}
|
||||
/* Return error if Blocknb > NmaxB */
|
||||
nbmax = InformationBlock[3];
|
||||
nbmax = (nbmax << 8) | InformationBlock[4];
|
||||
if (blocknb[cnt] > nbmax) {
|
||||
rspData[idx - 2] = 0xFF;
|
||||
rspData[idx - 1] = 0x70;
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < cmdData[13]; cnt++) {
|
||||
if (blocknb[cnt] == 0x0000) {
|
||||
/* Write information block */
|
||||
memcpy(InformationBlock, block, T3T_BLOCK_SIZE);
|
||||
block += T3T_BLOCK_SIZE;
|
||||
} else {
|
||||
/* Read ndef block */
|
||||
memcpy(&ndefFile[2 + ((blocknb[cnt] - 1) * T3T_BLOCK_SIZE)], block,
|
||||
T3T_BLOCK_SIZE);
|
||||
block += T3T_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Status flag answer */
|
||||
rspData[idx++] = 0x00;
|
||||
rspData[idx++] = 0x00;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief card emulation initialize
|
||||
*
|
||||
* Initializes the CE mode
|
||||
*
|
||||
* @param[in] nfcfNfcid : The NFCID to be used in T3T CE.
|
||||
*
|
||||
* @return None
|
||||
*****************************************************************************
|
||||
*/
|
||||
void card_emulation_init(uint8_t *nfcfNfcid) {
|
||||
if (nfcfNfcid != NULL) {
|
||||
memcpy(gNfcfNfcid, nfcfNfcid, RFAL_NFCF_NFCID2_LEN);
|
||||
}
|
||||
|
||||
memcpy(ndefFile, (uint8_t *)NdefFile, NdefFileLen);
|
||||
|
||||
/* Update AIB Ln with actual NDEF length */
|
||||
InformationBlock[12] = NdefFile[0];
|
||||
InformationBlock[13] = NdefFile[1];
|
||||
uint16_t checksum = 0;
|
||||
for (int i = 0; i < 14; i++) {
|
||||
checksum += InformationBlock[i];
|
||||
}
|
||||
InformationBlock[14] = checksum >> 8;
|
||||
InformationBlock[15] = checksum & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Demo CE T4T
|
||||
*
|
||||
* Parses the received command and computes the response to be sent back to
|
||||
* the Reader
|
||||
*
|
||||
* @param[in] rxData : pointer to the received command.
|
||||
* @param[in] rxDataLen : length of the received command.
|
||||
* @param[in] txBuf : pointer to where the response will be placed.
|
||||
* @param[in] txBufLen : size of txBuf.
|
||||
*
|
||||
* @return Response size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
uint16_t card_emulation_t4t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
|
||||
uint16_t txBufLen) {
|
||||
if ((txBuf == NULL) || (txBufLen < 2)) {
|
||||
// platformErrorHandle(); /* Must ensure appropriate buffer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((rxData != NULL) && (rxDataLen >= 4)) {
|
||||
if (rxData[0] == T4T_CLA_00) {
|
||||
switch (rxData[1]) {
|
||||
case T4T_INS_SELECT:
|
||||
return card_emulation_t4t_select(rxData, txBuf);
|
||||
|
||||
case T4T_INS_READ:
|
||||
return card_emulation_t4t_read(rxData, txBuf, txBufLen);
|
||||
|
||||
case T4T_INS_UPDATE:
|
||||
return card_emulation_t4t_update(rxData, txBuf);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Function not supported ... */
|
||||
txBuf[0] = ((char)0x68);
|
||||
txBuf[1] = ((char)0x00);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
*****************************************************************************
|
||||
* @brief Demo CE T3T
|
||||
*
|
||||
* Parses the received command and computes the response to be sent back to
|
||||
* the Reader
|
||||
*
|
||||
* @param[in] rxData : pointer to the received command.
|
||||
* @param[in] rxDataLen : length of the received command.
|
||||
* @param[in] txBuf : pointer to where the response will be placed.
|
||||
* @param[in] txBufLen : size of txBuf.
|
||||
*
|
||||
* @return Response size.
|
||||
*****************************************************************************
|
||||
*/
|
||||
uint16_t card_emulation_t3t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
|
||||
uint16_t txBufLen) {
|
||||
if ((txBuf == NULL) || (txBufLen < 11)) {
|
||||
// platformErrorHandle(); /* Must ensure appropriate buffer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((rxData != NULL) && (rxDataLen >= 4)) {
|
||||
switch (rxData[1]) {
|
||||
case RFAL_NFCF_CMD_READ_WITHOUT_ENCRYPTION:
|
||||
return card_emulation_t3t_check(rxData, txBuf, txBufLen);
|
||||
|
||||
case RFAL_NFCF_CMD_WRITE_WITHOUT_ENCRYPTION:
|
||||
return card_emulation_t3t_update(rxData, txBuf);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function not supported ... */
|
||||
txBuf[0] = ((char)0xFF);
|
||||
txBuf[1] = ((char)0xFF);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
105
core/embed/io/nfc/st25r3916b/card_emulation.h
Normal file
105
core/embed/io/nfc/st25r3916b/card_emulation.h
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file card_emulation.h
|
||||
* @author MMY Application Team
|
||||
* @brief Implementation of Common CardEmulation parts
|
||||
******************************************************************************
|
||||
** This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* COPYRIGHT(c) 2018 STMicroelectronics
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef DEMO_CE_H
|
||||
#define DEMO_CE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @addtogroup X-CUBE-NFC6_Applications
|
||||
* @brief Sample applications for X-NUCLEO-NFC06A1 STM32 expansion boards.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup CardEmulation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup CE_CardEmul
|
||||
* @brief Card Emulation management functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* T3T Information Block Bytes offset */
|
||||
#define T3T_INFBLK_VER_OFFSET 0
|
||||
#define T3T_INFBLK_NBR_OFFSET 1
|
||||
#define T3T_INFBLK_NBW_OFFSET 2
|
||||
#define T3T_INFBLK_NMAXB_OFFSET 3
|
||||
#define T3T_INFBLK_WRITEFLAG_OFFSET 9
|
||||
#define T3T_INFBLK_RWFLAG_OFFSET 10
|
||||
#define T3T_INFBLK_LN_OFFSET 11
|
||||
#define T3T_INFBCK_CHECKSUM_OFFSET 14
|
||||
|
||||
/* T3T Information Block WriteFlag values */
|
||||
#define T3T_WRITEFLAG_OFF 0x00
|
||||
#define T3T_WRITEFLAG_ON 0x0F
|
||||
|
||||
/* T3T COMMAND OFFSET */
|
||||
#define T3T_CHECK_RESP_CMD_OFFSET 0
|
||||
#define T3T_CHECK_RESP_NFCID2_OFFSET 1
|
||||
#define T3T_CHECK_RESP_SF1_OFFSET 9
|
||||
#define T3T_CHECK_RESP_SF2_OFFSET 10
|
||||
#define T3T_CHECK_RESP_NOB_OFFSET 11
|
||||
#define T3T_CHECK_RESP_DATA_OFFSET 12
|
||||
#define T3T_UPDATE_RESP_CMD_OFFSET 0
|
||||
#define T3T_UPDATE_RESP_NFCID2_OFFSET 1
|
||||
#define T3T_UPDATE_RESP_SF1_OFFSET 9
|
||||
#define T3T_UPDATE_RESP_SF2_OFFSET 10
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
/** @defgroup CE_CardEmul_Exported_functions
|
||||
* @{
|
||||
*/
|
||||
void card_emulation_init(uint8_t *nfcfNfcid);
|
||||
uint16_t card_emulation_t3t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
|
||||
uint16_t txBufLen);
|
||||
uint16_t card_emulation_t4t(uint8_t *rxData, uint16_t rxDataLen, uint8_t *txBuf,
|
||||
uint16_t txBufLen);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DEMO_CE_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2018 STMicroelectronics *****END OF FILE****/
|
@ -1,132 +1,166 @@
|
||||
|
||||
|
||||
#include "ndef.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "ndef.h"
|
||||
|
||||
|
||||
|
||||
// ndef_status_t create_ndef_record_uri(uint8_t *bytearray, )
|
||||
|
||||
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len,
|
||||
ndef_message_t *message) {
|
||||
memset(message, 0, sizeof(ndef_message_t));
|
||||
|
||||
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message){
|
||||
uint16_t remaining_len = buffer_len;
|
||||
|
||||
// Indicate TLV header
|
||||
if (*buffer == 0x3) {
|
||||
buffer++;
|
||||
} else {
|
||||
return NDEF_ERROR; // Not a valid TLV structure
|
||||
}
|
||||
|
||||
memset(message, 0, sizeof(ndef_message_t));
|
||||
// TLV length
|
||||
if (*buffer == 0xFF) {
|
||||
// TLV 3 byte length format
|
||||
buffer++;
|
||||
message->message_total_len = (int16_t)(buffer[0] << 8 | buffer[1]);
|
||||
buffer = buffer + 2;
|
||||
|
||||
uint16_t remaining_len = buffer_len;
|
||||
} else {
|
||||
message->message_total_len = *buffer;
|
||||
buffer++;
|
||||
}
|
||||
|
||||
remaining_len = message->message_total_len;
|
||||
|
||||
// Indicate TLV header
|
||||
if(*buffer == 0x3){
|
||||
buffer++;
|
||||
}else{
|
||||
return NDEF_ERROR; // Not a valid TLV structure
|
||||
while (1) {
|
||||
parse_ndef_record(buffer, remaining_len,
|
||||
&(message->records[message->records_cnt]));
|
||||
buffer += message->records[message->records_cnt].record_total_len;
|
||||
remaining_len -= message->records[message->records_cnt].record_total_len;
|
||||
message->records_cnt++;
|
||||
|
||||
if (message->records_cnt >= NDEF_MAX_RECORDS) {
|
||||
break; // Max records reached
|
||||
}
|
||||
|
||||
// TLV length
|
||||
if(*buffer == 0xFF){
|
||||
|
||||
// TLV 3 byte length format
|
||||
buffer++;
|
||||
message->message_total_len = (int16_t) (buffer[0] << 8 | buffer[1]);
|
||||
buffer = buffer + 2;
|
||||
|
||||
}else{
|
||||
|
||||
message->message_total_len = *buffer;
|
||||
buffer++;
|
||||
|
||||
if (remaining_len == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
remaining_len = message->message_total_len;
|
||||
// Check TLV termination character
|
||||
if (*buffer != 0xFE) {
|
||||
return NDEF_ERROR; // Not a valid TLV structure
|
||||
}
|
||||
|
||||
while(1){
|
||||
|
||||
parse_ndef_record(buffer, remaining_len , &(message->records[message->records_cnt]));
|
||||
buffer += message->records[message->records_cnt].record_total_len;
|
||||
remaining_len -= message->records[message->records_cnt].record_total_len;
|
||||
message->records_cnt++;
|
||||
|
||||
if(message->records_cnt >= NDEF_MAX_RECORDS){
|
||||
break; // Max records reached
|
||||
}
|
||||
|
||||
if(remaining_len == 0){
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check TLV termination character
|
||||
if(*buffer != 0xFE){
|
||||
return NDEF_ERROR; // Not a valid TLV structure
|
||||
}
|
||||
|
||||
return NDEF_OK;
|
||||
return NDEF_OK;
|
||||
}
|
||||
|
||||
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec){
|
||||
|
||||
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len,
|
||||
ndef_record_t *rec) {
|
||||
uint8_t bp = 0;
|
||||
|
||||
// Check if there is enough items to cover first part of the header revelaing record length
|
||||
if(len < 3){
|
||||
return NDEF_ERROR; // Not enough data to parse
|
||||
// Check if there is enough items to cover first part of the header revelaing
|
||||
// record length
|
||||
if (len < 3) {
|
||||
return NDEF_ERROR; // Not enough data to parse
|
||||
}
|
||||
|
||||
// Look at first byte, parse header
|
||||
memcpy(&(rec->header), buffer, 1);
|
||||
bp++;
|
||||
|
||||
if(rec->header.tnf == 0x00 || rec->header.tnf > 0x06){
|
||||
return NDEF_ERROR; // Empty or non-existing record
|
||||
if (rec->header.tnf == 0x00 || rec->header.tnf > 0x06) {
|
||||
return NDEF_ERROR; // Empty or non-existing record
|
||||
}
|
||||
|
||||
rec->type_length = buffer[bp++];
|
||||
|
||||
if(rec->header.sr){
|
||||
if (rec->header.sr) {
|
||||
rec->payload_length = buffer[bp++];
|
||||
}else{
|
||||
} else {
|
||||
memcpy(&(rec->payload_length), buffer + bp, 4);
|
||||
bp += 4;
|
||||
}
|
||||
|
||||
if(rec->header.il){
|
||||
if (rec->header.il) {
|
||||
rec->id_length = buffer[bp++];
|
||||
}else{
|
||||
} else {
|
||||
// ID length ommited
|
||||
rec->id_length = 0;
|
||||
}
|
||||
|
||||
if(rec->type_length > 0){
|
||||
if (rec->type_length > 0) {
|
||||
memcpy(&(rec->type), buffer + bp, rec->type_length);
|
||||
bp += rec->type_length;
|
||||
}else{
|
||||
} else {
|
||||
// Type length ommited
|
||||
rec->type = 0;
|
||||
}
|
||||
|
||||
if(rec->id_length > 0){
|
||||
if (rec->id_length > 0) {
|
||||
memcpy(&(rec->id), buffer + bp, rec->id_length);
|
||||
bp += rec->id_length;
|
||||
}else{
|
||||
} else {
|
||||
// ID length ommited
|
||||
rec->id = 0;
|
||||
}
|
||||
|
||||
if(rec->payload_length > 0){
|
||||
if (rec->payload_length > 0) {
|
||||
memcpy(rec->payload, buffer + bp, rec->payload_length);
|
||||
bp += rec->payload_length;
|
||||
}else{
|
||||
} else {
|
||||
// Payload length ommited;
|
||||
}
|
||||
|
||||
rec->record_total_len = bp;
|
||||
|
||||
return NDEF_OK;
|
||||
|
||||
}
|
||||
|
||||
uint16_t create_ndef_uri(const char *uri, uint8_t *buffer) {
|
||||
*buffer = 0x3; // TLV header
|
||||
buffer++;
|
||||
|
||||
uint16_t uri_len = strlen(uri);
|
||||
|
||||
// NDEF message length
|
||||
*buffer = uri_len + 5; // uri + record header;
|
||||
buffer++;
|
||||
|
||||
// ndef_record_header_t hdr = {
|
||||
// .tnf = 0x01,
|
||||
// .il = 0,
|
||||
// .sr = 1,
|
||||
// .cf = 0,
|
||||
// .me = 1,
|
||||
// .mb = 1,
|
||||
// };
|
||||
|
||||
*buffer = 0xD1; // NDEF record Header
|
||||
buffer++;
|
||||
|
||||
*buffer = 0x1; // Type length
|
||||
buffer++;
|
||||
|
||||
*buffer = uri_len; // Payload length
|
||||
buffer++;
|
||||
|
||||
*buffer = 0x55; // URI type
|
||||
buffer++;
|
||||
|
||||
*buffer = 0x1; // URI abreviation
|
||||
buffer++;
|
||||
|
||||
for (uint8_t i = 0; i < uri_len; i++) {
|
||||
*buffer = uri[i];
|
||||
buffer++;
|
||||
}
|
||||
|
||||
// memcpy(buffer, uri, uri_len);
|
||||
|
||||
*buffer = 0xFE; // TLV termination
|
||||
|
||||
return uri_len + 7; // return buffer len
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef NDEF_H
|
||||
#define NDEF_H
|
||||
@ -6,22 +6,21 @@
|
||||
#define NDEF_MAX_RECORDS 3
|
||||
#define NDEF_MAX_RECORD_PAYLOAD_BYTES 50
|
||||
|
||||
|
||||
typedef enum{
|
||||
NDEF_OK = 0,
|
||||
NDEF_ERROR = 1,
|
||||
typedef enum {
|
||||
NDEF_OK = 0,
|
||||
NDEF_ERROR = 1,
|
||||
} ndef_status_t;
|
||||
|
||||
typedef struct{
|
||||
typedef struct {
|
||||
uint8_t tnf : 3;
|
||||
uint8_t il : 1;
|
||||
uint8_t sr : 1;
|
||||
uint8_t cf : 1;
|
||||
uint8_t me : 1;
|
||||
uint8_t mb : 1;
|
||||
}ndef_record_header_t;
|
||||
uint8_t il : 1;
|
||||
uint8_t sr : 1;
|
||||
uint8_t cf : 1;
|
||||
uint8_t me : 1;
|
||||
uint8_t mb : 1;
|
||||
} ndef_record_header_t;
|
||||
|
||||
typedef struct{
|
||||
typedef struct {
|
||||
ndef_record_header_t header;
|
||||
uint8_t type_length;
|
||||
uint32_t payload_length;
|
||||
@ -30,15 +29,18 @@ typedef struct{
|
||||
uint8_t id;
|
||||
uint8_t payload[NDEF_MAX_RECORD_PAYLOAD_BYTES];
|
||||
uint16_t record_total_len;
|
||||
}ndef_record_t;
|
||||
} ndef_record_t;
|
||||
|
||||
typedef struct{
|
||||
uint32_t message_total_len;
|
||||
uint8_t records_cnt;
|
||||
ndef_record_t records[NDEF_MAX_RECORDS];
|
||||
typedef struct {
|
||||
uint32_t message_total_len;
|
||||
uint8_t records_cnt;
|
||||
ndef_record_t records[NDEF_MAX_RECORDS];
|
||||
} ndef_message_t;
|
||||
|
||||
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message);
|
||||
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec);
|
||||
ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len,
|
||||
ndef_message_t *message);
|
||||
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len,
|
||||
ndef_record_t *rec);
|
||||
uint16_t create_ndef_uri(const char *uri, uint8_t *buffer);
|
||||
|
||||
#endif
|
||||
|
@ -5,9 +5,10 @@
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include "../inc/io/nfc.h"
|
||||
#include "card_emulation.h"
|
||||
#include "ndef.h"
|
||||
#include "nfc_internal.h"
|
||||
#include "rfal_platform.h"
|
||||
#include "ndef.h"
|
||||
|
||||
#include "../rfal/include/rfal_isoDep.h"
|
||||
#include "../rfal/include/rfal_nfc.h"
|
||||
@ -19,15 +20,6 @@
|
||||
|
||||
#include "stm32u5xx_hal.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
// SPI driver
|
||||
@ -36,8 +28,8 @@ typedef struct {
|
||||
void (*nfc_irq_callback)(void);
|
||||
|
||||
// Event callbacks
|
||||
void(*nfc_state_idle_cb)(void);
|
||||
void(*nfc_state_activated_cb)(void);
|
||||
void (*nfc_state_idle_cb)(void);
|
||||
void (*nfc_state_activated_cb)(void);
|
||||
|
||||
EXTI_HandleTypeDef hEXTI;
|
||||
|
||||
@ -48,13 +40,13 @@ static st25r3916b_driver_t g_st25r3916b_driver = {
|
||||
.initialized = false,
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
typedef struct {
|
||||
uint8_t UID[7];
|
||||
uint8_t BCC[1];
|
||||
uint8_t SYSTEM_AREA[2];
|
||||
union{
|
||||
union {
|
||||
uint8_t CC[4];
|
||||
struct{
|
||||
struct {
|
||||
uint8_t CC_MAGIC_NUMBER;
|
||||
uint8_t CC_VERSION;
|
||||
uint8_t CC_SIZE;
|
||||
@ -63,76 +55,19 @@ typedef struct{
|
||||
};
|
||||
} nfc_device_header_t2t_t;
|
||||
|
||||
static void parse_tag_header(uint8_t *data, uint16_t dataLen);
|
||||
// static void parse_tag_header(uint8_t *data, uint16_t dataLen);
|
||||
static char *hex2Str(unsigned char *data, size_t dataLen);
|
||||
|
||||
/* Definition of possible states the demo state machine could have */
|
||||
#define DEMO_ST_CE_NOTINIT 0 /*!< Demo State: Not initialized */
|
||||
#define DEMO_ST_CE_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
|
||||
#define DEMO_ST_CE_DISCOVERY 2 /*!< Demo State: Discovery */
|
||||
#define DEMO_ST_CE_TAG_OPERATION 3 /*!< Demo State: Discovery */
|
||||
|
||||
/* 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 DEMO_NFCV_BLOCK_LEN 4 /*!< NFCV Block len */
|
||||
#define DEMO_NFCV_USE_SELECT_MODE \
|
||||
false /*!< NFCV demonstrate select mode */
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* GLOBAL DEFINES
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Definition of possible states the demo state machine could have */
|
||||
#define DEMO_ST_NOTINIT 0 /*!< Demo State: Not initialized | Stopped */
|
||||
#define DEMO_ST_START_DISCOVERY 1 /*!< Demo State: Start Discovery */
|
||||
#define DEMO_ST_DISCOVERY 2 /*!< Demo State: Discovery */
|
||||
|
||||
#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 \
|
||||
#define LM_SEL_RES \
|
||||
0x20U /*!<NFC-A SEL_RES configured for Type 4A Tag Platform */
|
||||
#define DEMO_LM_NFCID2_BYTE1 \
|
||||
#define LM_NFCID2_BYTE1 \
|
||||
0x02U /*!<NFC-F SENSF_RES configured for Type 3 Tag Platform */
|
||||
#define DEMO_LM_SC_BYTE1 \
|
||||
#define LM_SC_BYTE1 \
|
||||
0x12U /*!<NFC-F System Code byte 1 */
|
||||
#define DEMO_LM_SC_BYTE2 \
|
||||
#define LM_SC_BYTE2 \
|
||||
0xFCU /*!<NFC-F System Code byte 2 */
|
||||
#define DEMO_LM_PAD0 \
|
||||
#define LM_PAD0 \
|
||||
0x00U /*!<NFC-F PAD0 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* GLOBAL MACROS
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* LOCAL VARIABLES
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* P2P communication data */
|
||||
static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05,
|
||||
@ -141,113 +76,41 @@ static uint8_t GB[] = {0x46, 0x66, 0x6d, 0x01, 0x01, 0x11, 0x02,
|
||||
0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03,
|
||||
0x04, 0x01, 0x32, 0x07, 0x01, 0x03};
|
||||
|
||||
/* APDUs communication data */
|
||||
#if RFAL_FEATURE_ISO_DEP_POLL
|
||||
static uint8_t ndefSelectApp[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
|
||||
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
static uint8_t ccSelectFile[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
|
||||
static uint8_t readBinary[] = {0x00, 0xB0, 0x00, 0x00, 0x0F};
|
||||
|
||||
/* For a Payment application a Select PPSE would be needed:
|
||||
ppseSelectApp[] = { 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x32, 0x50, 0x41, 0x59,
|
||||
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 } */
|
||||
#endif /* RFAL_FEATURE_ISO_DEP_POLL */
|
||||
|
||||
#if RFAL_FEATURE_NFC_DEP
|
||||
/* 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 uint8_t ndefUriSTcom[] = {
|
||||
0x13, 0x20, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x19, 0xc1, 0x01, 0x00,
|
||||
0x00, 0x00, 0x12, 0x55, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
|
||||
0x77, 0x77, 0x77, 0x2e, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d};
|
||||
#endif /* RFAL_FEATURE_NFC_DEP */
|
||||
|
||||
#if RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE
|
||||
#if RFAL_SUPPORT_MODE_LISTEN_NFCA
|
||||
/* NFC-A CE config */
|
||||
/* 4-byte UIDs with first byte 0x08 would need random number for the subsequent
|
||||
* 3 bytes. 4-byte UIDs with first byte 0x*F are Fixed number, not unique, use
|
||||
* for this demo 7-byte UIDs need a manufacturer ID and need to assure
|
||||
* uniqueness of the rest.*/
|
||||
static uint8_t ceNFCA_NFCID[] = {
|
||||
0x5F, 'S', 'T', 'M'}; /* =_STM, 5F 53 54 4D NFCID1 / UID (4 bytes) */
|
||||
0x1, 0x2, 0x3, 0x4}; /* =_STM, 5F 53 54 4D NFCID1 / UID (4 bytes) */
|
||||
static uint8_t ceNFCA_SENS_RES[] = {0x02,
|
||||
0x00}; /* SENS_RES / ATQA for 4-byte UID */
|
||||
static uint8_t ceNFCA_SEL_RES = DEMO_LM_SEL_RES; /* SEL_RES / SAK */
|
||||
#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCA */
|
||||
0x00}; /* SENS_RES / ATQA for 4-byte UID */
|
||||
static uint8_t ceNFCA_SEL_RES = LM_SEL_RES; /* SEL_RES / SAK */
|
||||
|
||||
static uint8_t ceNFCF_nfcid2[] = {
|
||||
DEMO_LM_NFCID2_BYTE1, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
LM_NFCID2_BYTE1, 0xFE, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
|
||||
|
||||
#if RFAL_SUPPORT_MODE_LISTEN_NFCF
|
||||
/* NFC-F CE config */
|
||||
static uint8_t ceNFCF_SC[] = {DEMO_LM_SC_BYTE1, DEMO_LM_SC_BYTE2};
|
||||
static uint8_t ceNFCF_SC[] = {LM_SC_BYTE1, LM_SC_BYTE2};
|
||||
static uint8_t ceNFCF_SENSF_RES[] = {
|
||||
0x01, /* SENSF_RES */
|
||||
0x02, 0xFE, 0x11, 0x22, 0x33,
|
||||
0x44, 0x55, 0x66, /* NFCID2 */
|
||||
DEMO_LM_PAD0, DEMO_LM_PAD0, 0x00, 0x00, 0x00,
|
||||
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
|
||||
*/
|
||||
0x00, 0x00}; /* RD */
|
||||
#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCF */
|
||||
#endif /* RFAL_SUPPORT_CE && RFAL_FEATURE_LISTEN_MODE */
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* LOCAL VARIABLES
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
// static void demoNotif(rfalNfcState st);
|
||||
// static bool demoInit();
|
||||
// static void demoCycle();
|
||||
// static void demoP2P(rfalNfcDevice *nfcDev);
|
||||
// static void demoAPDU(void);
|
||||
// static void demoNfcv(rfalNfcvListenDevice *nfcvDev);
|
||||
// static void demoNfcf(rfalNfcfListenDevice *nfcfDev);
|
||||
// static void demoT2t(void);
|
||||
// static void demoCE(rfalNfcDevice *nfcDev);
|
||||
ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||
uint8_t **rxBuf, uint16_t **rcvLen,
|
||||
uint32_t fwt);
|
||||
0x02, 0xFE, 0x11, 0x22, 0x33,
|
||||
0x44, 0x55, 0x66, /* NFCID2 */
|
||||
LM_PAD0, LM_PAD0, 0x00, 0x00, 0x00,
|
||||
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
|
||||
*/
|
||||
0x00, 0x00}; /* RD */
|
||||
|
||||
static ReturnCode nfc_transcieve_blocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||
uint8_t **rxBuf, uint16_t **rcvLen,
|
||||
uint32_t fwt);
|
||||
static void nfc_card_emulator_loop(rfalNfcDevice *nfcDev);
|
||||
|
||||
#define MAX_HEX_STR 4
|
||||
#define MAX_HEX_STR_LENGTH 512
|
||||
char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];
|
||||
uint8_t hexStrIdx = 0;
|
||||
|
||||
char *hex2Str(unsigned char *data, size_t dataLen) {
|
||||
{
|
||||
unsigned char *pin = data;
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
char *pout = hexStr[hexStrIdx];
|
||||
uint8_t i = 0;
|
||||
uint8_t idx = hexStrIdx;
|
||||
if (dataLen == 0) {
|
||||
pout[0] = 0;
|
||||
} else {
|
||||
for (; i < dataLen - 1; ++i) {
|
||||
*pout++ = hex[(*pin >> 4) & 0xF];
|
||||
*pout++ = hex[(*pin++) & 0xF];
|
||||
}
|
||||
*pout++ = hex[(*pin >> 4) & 0xF];
|
||||
*pout++ = hex[(*pin) & 0xF];
|
||||
*pout = 0;
|
||||
}
|
||||
|
||||
hexStrIdx++;
|
||||
hexStrIdx %= MAX_HEX_STR;
|
||||
|
||||
return hexStr[idx];
|
||||
}
|
||||
}
|
||||
|
||||
nfc_status_t nfc_init() {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
@ -299,7 +162,8 @@ nfc_status_t nfc_init() {
|
||||
|
||||
drv->hspi.Instance = SPI_INSTANCE_3;
|
||||
drv->hspi.Init.Mode = SPI_MODE_MASTER;
|
||||
drv->hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; // TODO: Calculate frequency precisly.
|
||||
drv->hspi.Init.BaudRatePrescaler =
|
||||
SPI_BAUDRATEPRESCALER_32; // TODO: Calculate frequency precisly.
|
||||
drv->hspi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
drv->hspi.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
drv->hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
@ -342,7 +206,6 @@ nfc_status_t nfc_init() {
|
||||
}
|
||||
|
||||
nfc_status_t nfc_deinit() {
|
||||
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
@ -375,39 +238,30 @@ nfc_status_t nfc_deinit() {
|
||||
drv->initialized = false;
|
||||
|
||||
return NFC_OK;
|
||||
|
||||
}
|
||||
|
||||
void rfal_callback(rfalNfcState st){
|
||||
|
||||
void rfal_callback(rfalNfcState st) {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
switch(st){
|
||||
|
||||
switch (st) {
|
||||
case RFAL_NFC_STATE_IDLE:
|
||||
if(drv->nfc_state_idle_cb != NULL){
|
||||
if (drv->nfc_state_idle_cb != NULL) {
|
||||
drv->nfc_state_idle_cb();
|
||||
}
|
||||
break;
|
||||
|
||||
case RFAL_NFC_STATE_ACTIVATED:
|
||||
if(drv->nfc_state_activated_cb != NULL){
|
||||
if (drv->nfc_state_activated_cb != NULL) {
|
||||
drv->nfc_state_activated_cb();
|
||||
|
||||
// Deactivate the device imediatly after callback
|
||||
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// State not reported
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nfc_status_t nfc_register_tech(nfc_tech_t tech){
|
||||
|
||||
nfc_status_t nfc_register_tech(nfc_tech_t tech) {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
drv->disc_params.devLimit = 1;
|
||||
@ -418,7 +272,7 @@ nfc_status_t nfc_register_tech(nfc_tech_t tech){
|
||||
drv->disc_params.totalDuration = 1000U;
|
||||
drv->disc_params.notifyCb = rfal_callback;
|
||||
|
||||
if(drv->initialized == false){
|
||||
if (drv->initialized == false) {
|
||||
return NFC_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
@ -428,56 +282,54 @@ nfc_status_t nfc_register_tech(nfc_tech_t tech){
|
||||
|
||||
// Set general discovery parameters.
|
||||
|
||||
if(tech & NFC_POLLER_TECH_A){
|
||||
if (tech & NFC_POLLER_TECH_A) {
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_A;
|
||||
}
|
||||
|
||||
if(tech & NFC_POLLER_TECH_B){
|
||||
if (tech & NFC_POLLER_TECH_B) {
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_B;
|
||||
}
|
||||
|
||||
if(tech & NFC_POLLER_TECH_F){
|
||||
if (tech & NFC_POLLER_TECH_F) {
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_F;
|
||||
}
|
||||
|
||||
if(tech & NFC_POLLER_TECH_V){
|
||||
if (tech & NFC_POLLER_TECH_V) {
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_V;
|
||||
}
|
||||
|
||||
if(tech & NFC_CARD_EMU_TECH_A){
|
||||
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
|
||||
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
|
||||
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
|
||||
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
|
||||
drv->disc_params.lmConfigPA.nfcidLen =
|
||||
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
|
||||
drv->disc_params.lmConfigPA.SEL_RES =
|
||||
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
|
||||
if (tech & NFC_CARD_EMU_TECH_A) {
|
||||
card_emulation_init(ceNFCF_nfcid2);
|
||||
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
|
||||
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
|
||||
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
|
||||
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
|
||||
drv->disc_params.lmConfigPA.nfcidLen =
|
||||
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
|
||||
drv->disc_params.lmConfigPA.SEL_RES =
|
||||
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
|
||||
}
|
||||
|
||||
if(tech & NFC_CARD_EMU_TECH_F){
|
||||
|
||||
/* Set configuration for NFC-F CE */
|
||||
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
|
||||
if (tech & NFC_CARD_EMU_TECH_F) {
|
||||
/* Set configuration for NFC-F CE */
|
||||
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
|
||||
RFAL_LM_SENSF_SC_LEN); /* Set System Code */
|
||||
memcpy(&ceNFCF_SENSF_RES[RFAL_NFCF_CMD_LEN], ceNFCF_nfcid2,
|
||||
memcpy(&ceNFCF_SENSF_RES[RFAL_NFCF_CMD_LEN], ceNFCF_nfcid2,
|
||||
RFAL_NFCID2_LEN); /* Load NFCID2 on SENSF_RES */
|
||||
memcpy(drv->disc_params.lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES,
|
||||
memcpy(drv->disc_params.lmConfigPF.SENSF_RES, ceNFCF_SENSF_RES,
|
||||
RFAL_LM_SENSF_RES_LEN); /* Set SENSF_RES / Poll Response */
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_F;
|
||||
|
||||
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_F;
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
|
||||
}
|
||||
|
||||
nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(void)){
|
||||
|
||||
nfc_status_t nfc_register_event_callback(nfc_event_t event_type,
|
||||
void (*cb_fn)(void)) {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
switch(event_type){
|
||||
switch (event_type) {
|
||||
case NFC_STATE_IDLE:
|
||||
drv->nfc_state_idle_cb = cb_fn;
|
||||
break;
|
||||
@ -489,20 +341,16 @@ nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(v
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
|
||||
}
|
||||
|
||||
nfc_status_t nfc_unregister_event_callback(){
|
||||
|
||||
nfc_status_t nfc_unregister_event_callback() {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
drv->disc_params.notifyCb = NULL;
|
||||
|
||||
return NFC_OK;
|
||||
|
||||
}
|
||||
|
||||
nfc_status_t nfc_activate_stm(){
|
||||
|
||||
nfc_status_t nfc_activate_stm() {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
ReturnCode err;
|
||||
@ -512,11 +360,9 @@ nfc_status_t nfc_activate_stm(){
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
|
||||
}
|
||||
|
||||
nfc_status_t nfc_deactivate_stm(){
|
||||
|
||||
nfc_status_t nfc_deactivate_stm() {
|
||||
// In case the NFC state machine is active, deactivate to idle before
|
||||
// registering a new card emulation technology.
|
||||
if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) {
|
||||
@ -529,15 +375,12 @@ nfc_status_t nfc_deactivate_stm(){
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
|
||||
nfc_status_t nfc_feed_worker() {
|
||||
|
||||
static rfalNfcDevice *nfcDevice;
|
||||
|
||||
rfalNfcWorker(); /* Run RFAL worker periodically */
|
||||
|
||||
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
||||
|
||||
rfalNfcGetActiveDevice(&nfcDevice);
|
||||
|
||||
switch (nfcDevice->type) {
|
||||
@ -546,75 +389,32 @@ nfc_status_t nfc_feed_worker() {
|
||||
|
||||
switch (nfcDevice->dev.nfca.type) {
|
||||
case RFAL_NFCA_T1T:
|
||||
vcp_println("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
break;
|
||||
|
||||
case RFAL_NFCA_T4T:
|
||||
vcp_println("NFCA Passive ISO-DEP device found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
break;
|
||||
|
||||
case RFAL_NFCA_T4T_NFCDEP:
|
||||
case RFAL_NFCA_NFCDEP:
|
||||
break;
|
||||
default:
|
||||
vcp_println("ISO14443A/NFC-A card found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
ReturnCode err;
|
||||
uint16_t rcvLen;
|
||||
uint8_t blockNum = 0;
|
||||
uint8_t rxBuf[16];
|
||||
|
||||
vcp_println("Tag ID len: %d", nfcDevice->nfcidLen);
|
||||
|
||||
// Read first 16 bytes (1st block)
|
||||
err = rfalT2TPollerRead(0, rxBuf, sizeof(rxBuf), &rcvLen);
|
||||
parse_tag_header(rxBuf, sizeof(rxBuf));
|
||||
|
||||
uint8_t memory_area_data[160] = {0};
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
err = rfalT2TPollerRead(4+i*4, memory_area_data+i*16, 16 , &rcvLen);
|
||||
}
|
||||
|
||||
ndef_message_t ndef_message;
|
||||
parse_ndef_message(memory_area_data, 160, &ndef_message);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
case RFAL_NFC_LISTEN_TYPE_NFCB:
|
||||
|
||||
vcp_println("NFC TYPE B card found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
case RFAL_NFC_LISTEN_TYPE_NFCF:
|
||||
|
||||
vcp_println("NFC TYPE F card found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
case RFAL_NFC_LISTEN_TYPE_NFCV:
|
||||
|
||||
vcp_println("NFC TYPE V card found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
case RFAL_NFC_LISTEN_TYPE_ST25TB:
|
||||
|
||||
vcp_println("ST25TB card found. UID: %s\r\n",
|
||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
@ -623,9 +423,25 @@ nfc_status_t nfc_feed_worker() {
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
|
||||
/*******************************************************************************/
|
||||
|
||||
// Card emulators need to promptly respond to the reader commands, so when
|
||||
// activated rfal worker is called seveal times untill back to back
|
||||
// communication with the reader is completed. This may prolong the
|
||||
// run_feed_worker service time compared to standard reader mode.
|
||||
case RFAL_NFC_POLL_TYPE_NFCA:
|
||||
break;
|
||||
case RFAL_NFC_POLL_TYPE_NFCF:
|
||||
|
||||
if (nfcDevice->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
|
||||
// not supported yet
|
||||
} else {
|
||||
nfc_card_emulator_loop(nfcDevice);
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
break;
|
||||
/*******************************************************************************/
|
||||
default:
|
||||
@ -633,16 +449,51 @@ nfc_status_t nfc_feed_worker() {
|
||||
}
|
||||
|
||||
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
|
||||
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
static void nfc_card_emulator_loop(rfalNfcDevice *nfcDev) {
|
||||
ReturnCode err = RFAL_ERR_INTERNAL;
|
||||
uint8_t *rxData;
|
||||
uint16_t *rcvLen;
|
||||
uint8_t txBuf[150];
|
||||
uint16_t txLen;
|
||||
|
||||
do {
|
||||
rfalNfcWorker();
|
||||
|
||||
switch (rfalNfcGetState()) {
|
||||
case RFAL_NFC_STATE_ACTIVATED:
|
||||
err = nfc_transcieve_blocking(NULL, 0, &rxData, &rcvLen, 0);
|
||||
break;
|
||||
|
||||
case RFAL_NFC_STATE_DATAEXCHANGE:
|
||||
case RFAL_NFC_STATE_DATAEXCHANGE_DONE:
|
||||
|
||||
txLen = ((nfcDev->type == RFAL_NFC_POLL_TYPE_NFCA)
|
||||
? card_emulation_t4t(rxData, *rcvLen, txBuf, sizeof(txBuf))
|
||||
: rfalConvBytesToBits(card_emulation_t3t(
|
||||
rxData, rfalConvBitsToBytes(*rcvLen), txBuf,
|
||||
sizeof(txBuf))));
|
||||
|
||||
err = nfc_transcieve_blocking(txBuf, txLen, &rxData, &rcvLen,
|
||||
RFAL_FWT_NONE);
|
||||
break;
|
||||
|
||||
case RFAL_NFC_STATE_START_DISCOVERY:
|
||||
return;
|
||||
|
||||
case RFAL_NFC_STATE_LISTEN_SLEEP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while ((err == RFAL_ERR_NONE) || (err == RFAL_ERR_SLEEP_REQ));
|
||||
}
|
||||
|
||||
nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
||||
uint8_t *rxData, uint16_t *rxDataLen) {
|
||||
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
||||
if (drv->initialized == false) {
|
||||
@ -654,8 +505,8 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
||||
}
|
||||
|
||||
ReturnCode err;
|
||||
err = demoTransceiveBlocking((uint8_t *)txData, txDataLen, &rxData, &rxDataLen,
|
||||
RFAL_FWT_NONE);
|
||||
err = nfc_transcieve_blocking((uint8_t *)txData, txDataLen, &rxData,
|
||||
&rxDataLen, RFAL_FWT_NONE);
|
||||
|
||||
if (err != RFAL_ERR_NONE) {
|
||||
return NFC_ERROR;
|
||||
@ -664,15 +515,24 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
nfc_status_t nfc_def_write_ndef_uri() {
|
||||
// NDEF message
|
||||
uint8_t ndef_message[128] = {0};
|
||||
|
||||
uint16_t buffer_len = create_ndef_uri("trezor.io/", ndef_message);
|
||||
|
||||
for (uint8_t i = 0; i < buffer_len / 4; i++) {
|
||||
rfalT2TPollerWrite(4 + i, ndef_message + i * 4);
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
|
||||
|
||||
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
||||
|
||||
rfalNfcDevice *nfcDevice;
|
||||
rfalNfcGetActiveDevice(&nfcDevice);
|
||||
|
||||
|
||||
// Resolve device type
|
||||
switch (nfcDevice->type) {
|
||||
case RFAL_NFC_LISTEN_TYPE_NFCA:
|
||||
@ -700,7 +560,7 @@ nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
|
||||
|
||||
dev_info->uid_len = nfcDevice->nfcidLen;
|
||||
|
||||
if(dev_info->uid_len > 10){
|
||||
if (dev_info->uid_len > 10) {
|
||||
// Unexpected UID length
|
||||
return NFC_ERROR;
|
||||
}
|
||||
@ -708,69 +568,28 @@ nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
|
||||
char *uid_str = hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen);
|
||||
memcpy(dev_info->uid, uid_str, nfcDevice->nfcidLen);
|
||||
|
||||
|
||||
}else{
|
||||
|
||||
} else {
|
||||
// No device activated
|
||||
return NFC_ERROR;
|
||||
|
||||
}
|
||||
|
||||
return NFC_OK;
|
||||
}
|
||||
|
||||
// static void parse_tag_header(uint8_t *data, uint16_t dataLen) {
|
||||
// nfc_device_header_t2t_t hdr;
|
||||
|
||||
static void parse_tag_header(uint8_t *data, uint16_t dataLen){
|
||||
// memcpy(hdr.UID, data, 3);
|
||||
// hdr.BCC[0] = data[3];
|
||||
// memcpy(hdr.UID + 3, data + 4, 4);
|
||||
// memcpy(hdr.SYSTEM_AREA, data + 8, 2);
|
||||
// memcpy(hdr.CC, data + 12, 4);
|
||||
|
||||
nfc_device_header_t2t_t hdr;
|
||||
// }
|
||||
|
||||
memcpy(hdr.UID, data, 3);
|
||||
hdr.BCC[0] = data[3];
|
||||
memcpy(hdr.UID + 3, data+4, 4);
|
||||
memcpy(hdr.SYSTEM_AREA, data+8, 2);
|
||||
memcpy(hdr.CC, data+12, 4);
|
||||
|
||||
// vcp_println("UID: %s", hex2Str(hdr.t2t.UID, sizeof(hdr.t2t.UID)));
|
||||
// vcp_println("BCC: %s (%s)", hex2Str(hdr.t2t.BCC, sizeof(hdr.t2t.BCC)), (0x88 == (hdr.t2t.UID[0] ^ hdr.t2t.UID[1] ^ hdr.t2t.UID[2] ^ hdr.t2t.BCC[0]))? " CHECKSUM PASSED" : "CHECKSUM FAILED");
|
||||
// vcp_println("SYSTEM_AREA: %s", hex2Str(hdr.t2t.SYSTEM_AREA, sizeof(hdr.t2t.SYSTEM_AREA)));
|
||||
// vcp_println("CC: %s", hex2Str(hdr.t2t.CC, sizeof(hdr.t2t.CC)));
|
||||
// vcp_println(" -> CC_MAGIC_NUMBER: %02X", hdr.t2t.CC_MAGIC_NUMBER);
|
||||
// vcp_println(" -> CC_VERSION: %02X", hdr.t2t.CC_VERSION);
|
||||
// vcp_println(" -> CC_SIZE: %02X (%d bytes)", hdr.t2t.CC_SIZE, hdr.t2t.CC_SIZE*8);
|
||||
// vcp_println(" -> CC_ACCESS_CONDITION: %02X", hdr.t2t.CC_ACCESS_CONDITION);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
*****************************************************************************
|
||||
* \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 RFAL_ERR_PARAM : Invalid parameters
|
||||
* \return RFAL_ERR_TIMEOUT : Timeout error
|
||||
* \return RFAL_ERR_FRAMING : Framing error detected
|
||||
* \return RFAL_ERR_PROTO : Protocol error detected
|
||||
* \return RFAL_ERR_NONE : No error, activation successful
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||
uint8_t **rxData, uint16_t **rcvLen,
|
||||
uint32_t fwt) {
|
||||
static ReturnCode nfc_transcieve_blocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||
uint8_t **rxData, uint16_t **rcvLen,
|
||||
uint32_t fwt) {
|
||||
ReturnCode err;
|
||||
|
||||
err = rfalNfcDataExchangeStart(txBuf, txBufSize, rxData, rcvLen, fwt);
|
||||
@ -783,6 +602,32 @@ ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *hex2Str(unsigned char *data, size_t dataLen) {
|
||||
{
|
||||
unsigned char *pin = data;
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
char *pout = hexStr[hexStrIdx];
|
||||
uint8_t i = 0;
|
||||
uint8_t idx = hexStrIdx;
|
||||
if (dataLen == 0) {
|
||||
pout[0] = 0;
|
||||
} else {
|
||||
for (; i < dataLen - 1; ++i) {
|
||||
*pout++ = hex[(*pin >> 4) & 0xF];
|
||||
*pout++ = hex[(*pin++) & 0xF];
|
||||
}
|
||||
*pout++ = hex[(*pin >> 4) & 0xF];
|
||||
*pout++ = hex[(*pin) & 0xF];
|
||||
*pout = 0;
|
||||
}
|
||||
|
||||
hexStrIdx++;
|
||||
hexStrIdx %= MAX_HEX_STR;
|
||||
|
||||
return hexStr[idx];
|
||||
}
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef nfc_spi_transmit_receive(const uint8_t *txData,
|
||||
uint8_t *rxData, uint16_t length) {
|
||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||
|
@ -94,6 +94,7 @@ def configure(
|
||||
if "nfc" in features_wanted:
|
||||
sources += ["embed/io/nfc/st25r3916b/nfc.c"]
|
||||
sources += ["embed/io/nfc/st25r3916b/ndef.c"]
|
||||
sources += ["embed/io/nfc/st25r3916b/card_emulation.c"]
|
||||
sources += ["embed/io/nfc/rfal/source/st25r3916/rfal_rfst25r3916.c"]
|
||||
sources += ["embed/io/nfc/rfal/source/rfal_analogConfig.c"]
|
||||
sources += ["embed/io/nfc/rfal/source/rfal_nfc.c"]
|
||||
|
Loading…
Reference in New Issue
Block a user