mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-15 15:46:06 +00:00
feat(core): Introduce NFC tests into prodtest [no changelog]
This commit is contained in:
parent
f75fe14270
commit
34885699a0
@ -26,16 +26,16 @@
|
|||||||
|
|
||||||
#define NFC_MAX_UID_LEN 10
|
#define NFC_MAX_UID_LEN 10
|
||||||
|
|
||||||
typedef enum{
|
typedef enum {
|
||||||
NFC_POLLER_TECH_A = 0x1,
|
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_F = 0x1 << 2,
|
||||||
NFC_POLLER_TECH_V = 0x1 << 3,
|
NFC_POLLER_TECH_V = 0x1 << 3,
|
||||||
NFC_CARD_EMU_TECH_A = 0x1 << 4,
|
NFC_CARD_EMU_TECH_A = 0x1 << 4,
|
||||||
NFC_CARD_EMU_TECH_F = 0x1 << 5,
|
NFC_CARD_EMU_TECH_F = 0x1 << 5,
|
||||||
} nfc_tech_t ;
|
} nfc_tech_t;
|
||||||
|
|
||||||
typedef enum{
|
typedef enum {
|
||||||
NFC_DEV_TYPE_A,
|
NFC_DEV_TYPE_A,
|
||||||
NFC_DEV_TYPE_B,
|
NFC_DEV_TYPE_B,
|
||||||
NFC_DEV_TYPE_F,
|
NFC_DEV_TYPE_F,
|
||||||
@ -45,7 +45,7 @@ typedef enum{
|
|||||||
NFC_DEV_TYPE_UNKNOWN,
|
NFC_DEV_TYPE_UNKNOWN,
|
||||||
} nfc_dev_type_t;
|
} nfc_dev_type_t;
|
||||||
|
|
||||||
typedef enum{
|
typedef enum {
|
||||||
NFC_STATE_IDLE,
|
NFC_STATE_IDLE,
|
||||||
NFC_STATE_ACTIVATED,
|
NFC_STATE_ACTIVATED,
|
||||||
} nfc_event_t;
|
} nfc_event_t;
|
||||||
@ -58,26 +58,47 @@ typedef enum {
|
|||||||
NFC_INITIALIZATION_FAILED,
|
NFC_INITIALIZATION_FAILED,
|
||||||
} nfc_status_t;
|
} nfc_status_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
char uid[NFC_MAX_UID_LEN];
|
char uid[NFC_MAX_UID_LEN];
|
||||||
uint8_t 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();
|
nfc_status_t nfc_init();
|
||||||
|
|
||||||
|
// Deinitialize NFC drive
|
||||||
nfc_status_t nfc_deinit();
|
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_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();
|
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_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();
|
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
|
#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 <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ndef.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ndef_status_t create_ndef_record_uri(uint8_t *bytearray, )
|
// 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
|
while (1) {
|
||||||
if(*buffer == 0x3){
|
parse_ndef_record(buffer, remaining_len,
|
||||||
buffer++;
|
&(message->records[message->records_cnt]));
|
||||||
}else{
|
buffer += message->records[message->records_cnt].record_total_len;
|
||||||
return NDEF_ERROR; // Not a valid TLV structure
|
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 (remaining_len == 0) {
|
||||||
if(*buffer == 0xFF){
|
break;
|
||||||
|
|
||||||
// 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++;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
remaining_len = message->message_total_len;
|
// Check TLV termination character
|
||||||
|
if (*buffer != 0xFE) {
|
||||||
|
return NDEF_ERROR; // Not a valid TLV structure
|
||||||
|
}
|
||||||
|
|
||||||
while(1){
|
return NDEF_OK;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
uint8_t bp = 0;
|
||||||
|
|
||||||
// Check if there is enough items to cover first part of the header revelaing record length
|
// Check if there is enough items to cover first part of the header revelaing
|
||||||
if(len < 3){
|
// record length
|
||||||
return NDEF_ERROR; // Not enough data to parse
|
if (len < 3) {
|
||||||
|
return NDEF_ERROR; // Not enough data to parse
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look at first byte, parse header
|
// Look at first byte, parse header
|
||||||
memcpy(&(rec->header), buffer, 1);
|
memcpy(&(rec->header), buffer, 1);
|
||||||
bp++;
|
bp++;
|
||||||
|
|
||||||
if(rec->header.tnf == 0x00 || rec->header.tnf > 0x06){
|
if (rec->header.tnf == 0x00 || rec->header.tnf > 0x06) {
|
||||||
return NDEF_ERROR; // Empty or non-existing record
|
return NDEF_ERROR; // Empty or non-existing record
|
||||||
}
|
}
|
||||||
|
|
||||||
rec->type_length = buffer[bp++];
|
rec->type_length = buffer[bp++];
|
||||||
|
|
||||||
if(rec->header.sr){
|
if (rec->header.sr) {
|
||||||
rec->payload_length = buffer[bp++];
|
rec->payload_length = buffer[bp++];
|
||||||
}else{
|
} else {
|
||||||
memcpy(&(rec->payload_length), buffer + bp, 4);
|
memcpy(&(rec->payload_length), buffer + bp, 4);
|
||||||
bp += 4;
|
bp += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rec->header.il){
|
if (rec->header.il) {
|
||||||
rec->id_length = buffer[bp++];
|
rec->id_length = buffer[bp++];
|
||||||
}else{
|
} else {
|
||||||
// ID length ommited
|
// ID length ommited
|
||||||
rec->id_length = 0;
|
rec->id_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rec->type_length > 0){
|
if (rec->type_length > 0) {
|
||||||
memcpy(&(rec->type), buffer + bp, rec->type_length);
|
memcpy(&(rec->type), buffer + bp, rec->type_length);
|
||||||
bp += rec->type_length;
|
bp += rec->type_length;
|
||||||
}else{
|
} else {
|
||||||
// Type length ommited
|
// Type length ommited
|
||||||
rec->type = 0;
|
rec->type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rec->id_length > 0){
|
if (rec->id_length > 0) {
|
||||||
memcpy(&(rec->id), buffer + bp, rec->id_length);
|
memcpy(&(rec->id), buffer + bp, rec->id_length);
|
||||||
bp += rec->id_length;
|
bp += rec->id_length;
|
||||||
}else{
|
} else {
|
||||||
// ID length ommited
|
// ID length ommited
|
||||||
rec->id = 0;
|
rec->id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rec->payload_length > 0){
|
if (rec->payload_length > 0) {
|
||||||
memcpy(rec->payload, buffer + bp, rec->payload_length);
|
memcpy(rec->payload, buffer + bp, rec->payload_length);
|
||||||
bp += rec->payload_length;
|
bp += rec->payload_length;
|
||||||
}else{
|
} else {
|
||||||
// Payload length ommited;
|
// Payload length ommited;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec->record_total_len = bp;
|
rec->record_total_len = bp;
|
||||||
|
|
||||||
return NDEF_OK;
|
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
|
#ifndef NDEF_H
|
||||||
#define NDEF_H
|
#define NDEF_H
|
||||||
@ -6,22 +6,21 @@
|
|||||||
#define NDEF_MAX_RECORDS 3
|
#define NDEF_MAX_RECORDS 3
|
||||||
#define NDEF_MAX_RECORD_PAYLOAD_BYTES 50
|
#define NDEF_MAX_RECORD_PAYLOAD_BYTES 50
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
typedef enum{
|
NDEF_OK = 0,
|
||||||
NDEF_OK = 0,
|
NDEF_ERROR = 1,
|
||||||
NDEF_ERROR = 1,
|
|
||||||
} ndef_status_t;
|
} ndef_status_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
uint8_t tnf : 3;
|
uint8_t tnf : 3;
|
||||||
uint8_t il : 1;
|
uint8_t il : 1;
|
||||||
uint8_t sr : 1;
|
uint8_t sr : 1;
|
||||||
uint8_t cf : 1;
|
uint8_t cf : 1;
|
||||||
uint8_t me : 1;
|
uint8_t me : 1;
|
||||||
uint8_t mb : 1;
|
uint8_t mb : 1;
|
||||||
}ndef_record_header_t;
|
} ndef_record_header_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
ndef_record_header_t header;
|
ndef_record_header_t header;
|
||||||
uint8_t type_length;
|
uint8_t type_length;
|
||||||
uint32_t payload_length;
|
uint32_t payload_length;
|
||||||
@ -30,15 +29,18 @@ typedef struct{
|
|||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint8_t payload[NDEF_MAX_RECORD_PAYLOAD_BYTES];
|
uint8_t payload[NDEF_MAX_RECORD_PAYLOAD_BYTES];
|
||||||
uint16_t record_total_len;
|
uint16_t record_total_len;
|
||||||
}ndef_record_t;
|
} ndef_record_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
uint32_t message_total_len;
|
uint32_t message_total_len;
|
||||||
uint8_t records_cnt;
|
uint8_t records_cnt;
|
||||||
ndef_record_t records[NDEF_MAX_RECORDS];
|
ndef_record_t records[NDEF_MAX_RECORDS];
|
||||||
} ndef_message_t;
|
} 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_message(uint8_t *buffer, uint16_t buffer_len,
|
||||||
ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec);
|
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
|
#endif
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
#include <trezor_rtl.h>
|
#include <trezor_rtl.h>
|
||||||
|
|
||||||
#include "../inc/io/nfc.h"
|
#include "../inc/io/nfc.h"
|
||||||
|
#include "card_emulation.h"
|
||||||
|
#include "ndef.h"
|
||||||
#include "nfc_internal.h"
|
#include "nfc_internal.h"
|
||||||
#include "rfal_platform.h"
|
#include "rfal_platform.h"
|
||||||
#include "ndef.h"
|
|
||||||
|
|
||||||
#include "../rfal/include/rfal_isoDep.h"
|
#include "../rfal/include/rfal_isoDep.h"
|
||||||
#include "../rfal/include/rfal_nfc.h"
|
#include "../rfal/include/rfal_nfc.h"
|
||||||
@ -19,15 +20,6 @@
|
|||||||
|
|
||||||
#include "stm32u5xx_hal.h"
|
#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 {
|
typedef struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
// SPI driver
|
// SPI driver
|
||||||
@ -36,8 +28,8 @@ typedef struct {
|
|||||||
void (*nfc_irq_callback)(void);
|
void (*nfc_irq_callback)(void);
|
||||||
|
|
||||||
// Event callbacks
|
// Event callbacks
|
||||||
void(*nfc_state_idle_cb)(void);
|
void (*nfc_state_idle_cb)(void);
|
||||||
void(*nfc_state_activated_cb)(void);
|
void (*nfc_state_activated_cb)(void);
|
||||||
|
|
||||||
EXTI_HandleTypeDef hEXTI;
|
EXTI_HandleTypeDef hEXTI;
|
||||||
|
|
||||||
@ -48,13 +40,13 @@ static st25r3916b_driver_t g_st25r3916b_driver = {
|
|||||||
.initialized = false,
|
.initialized = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
uint8_t UID[7];
|
uint8_t UID[7];
|
||||||
uint8_t BCC[1];
|
uint8_t BCC[1];
|
||||||
uint8_t SYSTEM_AREA[2];
|
uint8_t SYSTEM_AREA[2];
|
||||||
union{
|
union {
|
||||||
uint8_t CC[4];
|
uint8_t CC[4];
|
||||||
struct{
|
struct {
|
||||||
uint8_t CC_MAGIC_NUMBER;
|
uint8_t CC_MAGIC_NUMBER;
|
||||||
uint8_t CC_VERSION;
|
uint8_t CC_VERSION;
|
||||||
uint8_t CC_SIZE;
|
uint8_t CC_SIZE;
|
||||||
@ -63,76 +55,19 @@ typedef struct{
|
|||||||
};
|
};
|
||||||
} nfc_device_header_t2t_t;
|
} 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 LM_SEL_RES \
|
||||||
#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 \
|
|
||||||
0x20U /*!<NFC-A SEL_RES configured for Type 4A Tag Platform */
|
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 */
|
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 */
|
0x12U /*!<NFC-F System Code byte 1 */
|
||||||
#define DEMO_LM_SC_BYTE2 \
|
#define LM_SC_BYTE2 \
|
||||||
0xFCU /*!<NFC-F System Code byte 2 */
|
0xFCU /*!<NFC-F System Code byte 2 */
|
||||||
#define DEMO_LM_PAD0 \
|
#define LM_PAD0 \
|
||||||
0x00U /*!<NFC-F PAD0 */
|
0x00U /*!<NFC-F PAD0 */
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
******************************************************************************
|
|
||||||
* GLOBAL MACROS
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
******************************************************************************
|
|
||||||
* LOCAL VARIABLES
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* P2P communication data */
|
/* P2P communication data */
|
||||||
static uint8_t NFCID3[] = {0x01, 0xFE, 0x03, 0x04, 0x05,
|
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,
|
0x02, 0x07, 0x80, 0x03, 0x02, 0x00, 0x03,
|
||||||
0x04, 0x01, 0x32, 0x07, 0x01, 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 */
|
/* NFC-A CE config */
|
||||||
/* 4-byte UIDs with first byte 0x08 would need random number for the subsequent
|
/* 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
|
* 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
|
* for this demo 7-byte UIDs need a manufacturer ID and need to assure
|
||||||
* uniqueness of the rest.*/
|
* uniqueness of the rest.*/
|
||||||
static uint8_t ceNFCA_NFCID[] = {
|
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,
|
static uint8_t ceNFCA_SENS_RES[] = {0x02,
|
||||||
0x00}; /* SENS_RES / ATQA for 4-byte UID */
|
0x00}; /* SENS_RES / ATQA for 4-byte UID */
|
||||||
static uint8_t ceNFCA_SEL_RES = DEMO_LM_SEL_RES; /* SEL_RES / SAK */
|
static uint8_t ceNFCA_SEL_RES = LM_SEL_RES; /* SEL_RES / SAK */
|
||||||
#endif /* RFAL_SUPPORT_MODE_LISTEN_NFCA */
|
|
||||||
|
|
||||||
static uint8_t ceNFCF_nfcid2[] = {
|
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 */
|
/* 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[] = {
|
static uint8_t ceNFCF_SENSF_RES[] = {
|
||||||
0x01, /* SENSF_RES */
|
0x01, /* SENSF_RES */
|
||||||
0x02, 0xFE, 0x11, 0x22, 0x33,
|
0x02, 0xFE, 0x11, 0x22, 0x33,
|
||||||
0x44, 0x55, 0x66, /* NFCID2 */
|
0x44, 0x55, 0x66, /* NFCID2 */
|
||||||
DEMO_LM_PAD0, DEMO_LM_PAD0, 0x00, 0x00, 0x00,
|
LM_PAD0, LM_PAD0, 0x00, 0x00, 0x00,
|
||||||
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
|
0x7F, 0x7F, 0x00, /* PAD0, PAD1, MRTIcheck, MRTIupdate, PAD2
|
||||||
*/
|
*/
|
||||||
0x00, 0x00}; /* RD */
|
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);
|
|
||||||
|
|
||||||
|
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 4
|
||||||
#define MAX_HEX_STR_LENGTH 512
|
#define MAX_HEX_STR_LENGTH 512
|
||||||
char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];
|
char hexStr[MAX_HEX_STR][MAX_HEX_STR_LENGTH];
|
||||||
uint8_t hexStrIdx = 0;
|
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() {
|
nfc_status_t nfc_init() {
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
@ -299,7 +162,8 @@ nfc_status_t nfc_init() {
|
|||||||
|
|
||||||
drv->hspi.Instance = SPI_INSTANCE_3;
|
drv->hspi.Instance = SPI_INSTANCE_3;
|
||||||
drv->hspi.Init.Mode = SPI_MODE_MASTER;
|
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.DataSize = SPI_DATASIZE_8BIT;
|
||||||
drv->hspi.Init.Direction = SPI_DIRECTION_2LINES;
|
drv->hspi.Init.Direction = SPI_DIRECTION_2LINES;
|
||||||
drv->hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
drv->hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||||
@ -342,7 +206,6 @@ nfc_status_t nfc_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nfc_status_t nfc_deinit() {
|
nfc_status_t nfc_deinit() {
|
||||||
|
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
if (!drv->initialized) {
|
if (!drv->initialized) {
|
||||||
@ -375,39 +238,30 @@ nfc_status_t nfc_deinit() {
|
|||||||
drv->initialized = false;
|
drv->initialized = false;
|
||||||
|
|
||||||
return NFC_OK;
|
return NFC_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfal_callback(rfalNfcState st){
|
void rfal_callback(rfalNfcState st) {
|
||||||
|
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
switch(st){
|
switch (st) {
|
||||||
|
|
||||||
case RFAL_NFC_STATE_IDLE:
|
case RFAL_NFC_STATE_IDLE:
|
||||||
if(drv->nfc_state_idle_cb != NULL){
|
if (drv->nfc_state_idle_cb != NULL) {
|
||||||
drv->nfc_state_idle_cb();
|
drv->nfc_state_idle_cb();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFAL_NFC_STATE_ACTIVATED:
|
case RFAL_NFC_STATE_ACTIVATED:
|
||||||
if(drv->nfc_state_activated_cb != NULL){
|
if (drv->nfc_state_activated_cb != NULL) {
|
||||||
drv->nfc_state_activated_cb();
|
drv->nfc_state_activated_cb();
|
||||||
|
|
||||||
// Deactivate the device imediatly after callback
|
|
||||||
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// State not reported
|
// State not reported
|
||||||
break;
|
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;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
drv->disc_params.devLimit = 1;
|
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.totalDuration = 1000U;
|
||||||
drv->disc_params.notifyCb = rfal_callback;
|
drv->disc_params.notifyCb = rfal_callback;
|
||||||
|
|
||||||
if(drv->initialized == false){
|
if (drv->initialized == false) {
|
||||||
return NFC_NOT_INITIALIZED;
|
return NFC_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,56 +282,54 @@ nfc_status_t nfc_register_tech(nfc_tech_t tech){
|
|||||||
|
|
||||||
// Set general discovery parameters.
|
// 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;
|
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;
|
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;
|
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;
|
drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_V;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tech & NFC_CARD_EMU_TECH_A){
|
if (tech & NFC_CARD_EMU_TECH_A) {
|
||||||
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
|
card_emulation_init(ceNFCF_nfcid2);
|
||||||
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
|
memcpy(drv->disc_params.lmConfigPA.SENS_RES, ceNFCA_SENS_RES,
|
||||||
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
|
RFAL_LM_SENS_RES_LEN); /* Set SENS_RES / ATQA */
|
||||||
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
|
memcpy(drv->disc_params.lmConfigPA.nfcid, ceNFCA_NFCID,
|
||||||
drv->disc_params.lmConfigPA.nfcidLen =
|
RFAL_LM_NFCID_LEN_04); /* Set NFCID / UID */
|
||||||
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
|
drv->disc_params.lmConfigPA.nfcidLen =
|
||||||
drv->disc_params.lmConfigPA.SEL_RES =
|
RFAL_LM_NFCID_LEN_04; /* Set NFCID length to 4 bytes */
|
||||||
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
|
drv->disc_params.lmConfigPA.SEL_RES =
|
||||||
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
|
ceNFCA_SEL_RES; /* Set SEL_RES / SAK */
|
||||||
|
drv->disc_params.techs2Find |= RFAL_NFC_LISTEN_TECH_A;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tech & NFC_CARD_EMU_TECH_F){
|
if (tech & NFC_CARD_EMU_TECH_F) {
|
||||||
|
/* Set configuration for NFC-F CE */
|
||||||
/* Set configuration for NFC-F CE */
|
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
|
||||||
memcpy(drv->disc_params.lmConfigPF.SC, ceNFCF_SC,
|
|
||||||
RFAL_LM_SENSF_SC_LEN); /* Set System Code */
|
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 */
|
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 */
|
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;
|
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;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
switch(event_type){
|
switch (event_type) {
|
||||||
case NFC_STATE_IDLE:
|
case NFC_STATE_IDLE:
|
||||||
drv->nfc_state_idle_cb = cb_fn;
|
drv->nfc_state_idle_cb = cb_fn;
|
||||||
break;
|
break;
|
||||||
@ -489,20 +341,16 @@ nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(v
|
|||||||
}
|
}
|
||||||
|
|
||||||
return NFC_OK;
|
return NFC_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nfc_status_t nfc_unregister_event_callback(){
|
nfc_status_t nfc_unregister_event_callback() {
|
||||||
|
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
drv->disc_params.notifyCb = NULL;
|
drv->disc_params.notifyCb = NULL;
|
||||||
|
|
||||||
return NFC_OK;
|
return NFC_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nfc_status_t nfc_activate_stm(){
|
nfc_status_t nfc_activate_stm() {
|
||||||
|
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
@ -512,11 +360,9 @@ nfc_status_t nfc_activate_stm(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
return NFC_OK;
|
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
|
// In case the NFC state machine is active, deactivate to idle before
|
||||||
// registering a new card emulation technology.
|
// registering a new card emulation technology.
|
||||||
if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) {
|
if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) {
|
||||||
@ -529,15 +375,12 @@ nfc_status_t nfc_deactivate_stm(){
|
|||||||
return NFC_OK;
|
return NFC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nfc_status_t nfc_feed_worker() {
|
nfc_status_t nfc_feed_worker() {
|
||||||
|
|
||||||
static rfalNfcDevice *nfcDevice;
|
static rfalNfcDevice *nfcDevice;
|
||||||
|
|
||||||
rfalNfcWorker(); /* Run RFAL worker periodically */
|
rfalNfcWorker(); /* Run RFAL worker periodically */
|
||||||
|
|
||||||
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
||||||
|
|
||||||
rfalNfcGetActiveDevice(&nfcDevice);
|
rfalNfcGetActiveDevice(&nfcDevice);
|
||||||
|
|
||||||
switch (nfcDevice->type) {
|
switch (nfcDevice->type) {
|
||||||
@ -546,75 +389,32 @@ nfc_status_t nfc_feed_worker() {
|
|||||||
|
|
||||||
switch (nfcDevice->dev.nfca.type) {
|
switch (nfcDevice->dev.nfca.type) {
|
||||||
case RFAL_NFCA_T1T:
|
case RFAL_NFCA_T1T:
|
||||||
vcp_println("ISO14443A/Topaz (NFC-A T1T) TAG found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFAL_NFCA_T4T:
|
case RFAL_NFCA_T4T:
|
||||||
vcp_println("NFCA Passive ISO-DEP device found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFAL_NFCA_T4T_NFCDEP:
|
case RFAL_NFCA_T4T_NFCDEP:
|
||||||
case RFAL_NFCA_NFCDEP:
|
case RFAL_NFCA_NFCDEP:
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_LISTEN_TYPE_NFCB:
|
case RFAL_NFC_LISTEN_TYPE_NFCB:
|
||||||
|
|
||||||
vcp_println("NFC TYPE B card found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_LISTEN_TYPE_NFCF:
|
case RFAL_NFC_LISTEN_TYPE_NFCF:
|
||||||
|
|
||||||
vcp_println("NFC TYPE F card found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_LISTEN_TYPE_NFCV:
|
case RFAL_NFC_LISTEN_TYPE_NFCV:
|
||||||
|
|
||||||
vcp_println("NFC TYPE V card found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_LISTEN_TYPE_ST25TB:
|
case RFAL_NFC_LISTEN_TYPE_ST25TB:
|
||||||
|
|
||||||
vcp_println("ST25TB card found. UID: %s\r\n",
|
|
||||||
hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
@ -623,9 +423,25 @@ nfc_status_t nfc_feed_worker() {
|
|||||||
break;
|
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:
|
case RFAL_NFC_POLL_TYPE_NFCA:
|
||||||
break;
|
|
||||||
case RFAL_NFC_POLL_TYPE_NFCF:
|
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;
|
break;
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
default:
|
default:
|
||||||
@ -633,16 +449,51 @@ nfc_status_t nfc_feed_worker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
|
rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_DISCOVERY);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NFC_OK;
|
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,
|
nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
||||||
uint8_t *rxData, uint16_t *rxDataLen) {
|
uint8_t *rxData, uint16_t *rxDataLen) {
|
||||||
|
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
|
||||||
if (drv->initialized == false) {
|
if (drv->initialized == false) {
|
||||||
@ -654,8 +505,8 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
err = demoTransceiveBlocking((uint8_t *)txData, txDataLen, &rxData, &rxDataLen,
|
err = nfc_transcieve_blocking((uint8_t *)txData, txDataLen, &rxData,
|
||||||
RFAL_FWT_NONE);
|
&rxDataLen, RFAL_FWT_NONE);
|
||||||
|
|
||||||
if (err != RFAL_ERR_NONE) {
|
if (err != RFAL_ERR_NONE) {
|
||||||
return NFC_ERROR;
|
return NFC_ERROR;
|
||||||
@ -664,15 +515,24 @@ nfc_status_t nfc_transceive(const uint8_t *txData, uint16_t txDataLen,
|
|||||||
return NFC_OK;
|
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) {
|
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info) {
|
||||||
|
|
||||||
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
if (rfalNfcIsDevActivated(rfalNfcGetState())) {
|
||||||
|
|
||||||
rfalNfcDevice *nfcDevice;
|
rfalNfcDevice *nfcDevice;
|
||||||
rfalNfcGetActiveDevice(&nfcDevice);
|
rfalNfcGetActiveDevice(&nfcDevice);
|
||||||
|
|
||||||
|
|
||||||
// Resolve device type
|
// Resolve device type
|
||||||
switch (nfcDevice->type) {
|
switch (nfcDevice->type) {
|
||||||
case RFAL_NFC_LISTEN_TYPE_NFCA:
|
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;
|
dev_info->uid_len = nfcDevice->nfcidLen;
|
||||||
|
|
||||||
if(dev_info->uid_len > 10){
|
if (dev_info->uid_len > 10) {
|
||||||
// Unexpected UID length
|
// Unexpected UID length
|
||||||
return NFC_ERROR;
|
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);
|
char *uid_str = hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen);
|
||||||
memcpy(dev_info->uid, uid_str, nfcDevice->nfcidLen);
|
memcpy(dev_info->uid, uid_str, nfcDevice->nfcidLen);
|
||||||
|
|
||||||
|
} else {
|
||||||
}else{
|
|
||||||
|
|
||||||
// No device activated
|
// No device activated
|
||||||
return NFC_ERROR;
|
return NFC_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NFC_OK;
|
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);
|
static ReturnCode nfc_transcieve_blocking(uint8_t *txBuf, uint16_t txBufSize,
|
||||||
hdr.BCC[0] = data[3];
|
uint8_t **rxData, uint16_t **rcvLen,
|
||||||
memcpy(hdr.UID + 3, data+4, 4);
|
uint32_t fwt) {
|
||||||
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) {
|
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
|
|
||||||
err = rfalNfcDataExchangeStart(txBuf, txBufSize, rxData, rcvLen, fwt);
|
err = rfalNfcDataExchangeStart(txBuf, txBufSize, rxData, rcvLen, fwt);
|
||||||
@ -783,6 +602,32 @@ ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize,
|
|||||||
return err;
|
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,
|
HAL_StatusTypeDef nfc_spi_transmit_receive(const uint8_t *txData,
|
||||||
uint8_t *rxData, uint16_t length) {
|
uint8_t *rxData, uint16_t length) {
|
||||||
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
st25r3916b_driver_t *drv = &g_st25r3916b_driver;
|
||||||
|
@ -93,6 +93,7 @@ def configure(
|
|||||||
if "nfc" in features_wanted:
|
if "nfc" in features_wanted:
|
||||||
sources += ["embed/io/nfc/st25r3916b/nfc.c"]
|
sources += ["embed/io/nfc/st25r3916b/nfc.c"]
|
||||||
sources += ["embed/io/nfc/st25r3916b/ndef.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/st25r3916/rfal_rfst25r3916.c"]
|
||||||
sources += ["embed/io/nfc/rfal/source/rfal_analogConfig.c"]
|
sources += ["embed/io/nfc/rfal/source/rfal_analogConfig.c"]
|
||||||
sources += ["embed/io/nfc/rfal/source/rfal_nfc.c"]
|
sources += ["embed/io/nfc/rfal/source/rfal_nfc.c"]
|
||||||
|
Loading…
Reference in New Issue
Block a user