diff --git a/core/embed/io/nfc/inc/io/nfc.h b/core/embed/io/nfc/inc/io/nfc.h index 51953a963d..20230386bd 100644 --- a/core/embed/io/nfc/inc/io/nfc.h +++ b/core/embed/io/nfc/inc/io/nfc.h @@ -22,18 +22,33 @@ #include #include +#include "ndef.h" -typedef enum { - NFC_CARD_EMU_TECH_A, - NFC_CARD_EMU_TECH_V, -} nfc_card_emul_tech_t; +#define NFC_MAX_UID_LEN 10 -typedef enum { - NFC_POLLER_TECH_A, - NFC_POLLER_TECH_B, - NFC_POLLER_TECH_F, - NFC_POLLER_TECH_V, -} nfc_poller_tech_t; +typedef enum{ + NFC_POLLER_TECH_A = 0x1, + 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 ; + +typedef enum{ + NFC_DEV_TYPE_A, + NFC_DEV_TYPE_B, + NFC_DEV_TYPE_F, + NFC_DEV_TYPE_V, + NFC_DEV_TYPE_ST25TB, + NFC_DEV_TYPE_AP2P, + NFC_DEV_TYPE_UNKNOWN, +} nfc_dev_type_t; + +typedef enum{ + NFC_STATE_IDLE, + NFC_STATE_ACTIVATED, +} nfc_event_t; typedef enum { NFC_OK, @@ -43,14 +58,26 @@ typedef enum { NFC_INITIALIZATION_FAILED, } nfc_status_t; +typedef struct{ + uint8_t type; + char uid[NFC_MAX_UID_LEN]; + uint8_t uid_len; +}nfc_dev_info_t; + nfc_status_t nfc_init(); nfc_status_t nfc_deinit(); -nfc_status_t nfc_register_card_emu(nfc_card_emul_tech_t tech); +nfc_status_t nfc_register_tech(nfc_tech_t tech); -nfc_status_t nfc_register_poller(nfc_poller_tech_t tech); +nfc_status_t nfc_register_event_callback(nfc_event_t event_type, void (*cb_fn)(void)); -nfc_status_t nfc_run_worker(); +nfc_status_t nfc_activate_stm(); + +nfc_status_t nfc_deactivate_stm(); + +nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info); + +nfc_status_t nfc_feed_worker(); #endif // TREZORHAL_NFC_H diff --git a/core/embed/io/nfc/st25r3916b/ndef.c b/core/embed/io/nfc/st25r3916b/ndef.c index ee10eb45b4..4b6f49c7fc 100644 --- a/core/embed/io/nfc/st25r3916b/ndef.c +++ b/core/embed/io/nfc/st25r3916b/ndef.c @@ -4,27 +4,67 @@ #include #include "ndef.h" -// ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message){ -// memset(message, 0, sizeof(ndef_message_t)); -// uint16_t offset = 0; -// uint16_t remainin_len = buffer_len +// ndef_status_t create_ndef_record_uri(uint8_t *bytearray, ) -// while(1){ -// ndef_record_t record; -// parse_ndef_record(buffer + offset, remainin_len , &record); -// offset += record.payload_length; +ndef_status_t parse_ndef_message(uint8_t *buffer, uint16_t buffer_len ,ndef_message_t *message){ -// message->records_cnt++; -// if(message->records_cnt >= NDEF_MAX_RECORDS){ -// break; // Max records reached -// } -// } -// return NDEF_OK; -// } + memset(message, 0, sizeof(ndef_message_t)); + + uint16_t remaining_len = buffer_len; + + + // Indicate TLV header + if(*buffer == 0x3){ + buffer++; + }else{ + return NDEF_ERROR; // Not a valid TLV structure + } + + // 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++; + + } + + remaining_len = message->message_total_len; + + 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; +} ndef_status_t parse_ndef_record(uint8_t *buffer, uint16_t len, ndef_record_t *rec){ diff --git a/core/embed/io/nfc/st25r3916b/ndef.h b/core/embed/io/nfc/st25r3916b/ndef.h index c5e78438a5..4a76caf4b9 100644 --- a/core/embed/io/nfc/st25r3916b/ndef.h +++ b/core/embed/io/nfc/st25r3916b/ndef.h @@ -1,8 +1,12 @@ +#ifndef NDEF_H +#define NDEF_H + #define NDEF_MAX_RECORDS 3 #define NDEF_MAX_RECORD_PAYLOAD_BYTES 50 + typedef enum{ NDEF_OK = 0, NDEF_ERROR = 1, @@ -29,10 +33,12 @@ typedef struct{ }ndef_record_t; 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_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); +#endif diff --git a/core/embed/io/nfc/st25r3916b/nfc.c b/core/embed/io/nfc/st25r3916b/nfc.c index 5223503e71..54090848ad 100644 --- a/core/embed/io/nfc/st25r3916b/nfc.c +++ b/core/embed/io/nfc/st25r3916b/nfc.c @@ -34,6 +34,11 @@ typedef struct { SPI_HandleTypeDef hspi; // NFC IRQ pin callback void (*nfc_irq_callback)(void); + + // Event callbacks + void(*nfc_state_idle_cb)(void); + void(*nfc_state_activated_cb)(void); + EXTI_HandleTypeDef hEXTI; rfalNfcDiscoverParam disc_params; @@ -43,6 +48,21 @@ static st25r3916b_driver_t g_st25r3916b_driver = { .initialized = false, }; +typedef struct{ + uint8_t UID[7]; + uint8_t BCC[1]; + uint8_t SYSTEM_AREA[2]; + union{ + uint8_t CC[4]; + struct{ + uint8_t CC_MAGIC_NUMBER; + uint8_t CC_VERSION; + uint8_t CC_SIZE; + uint8_t CC_ACCESS_CONDITION; + }; + }; +} nfc_device_header_t2t_t; + static void parse_tag_header(uint8_t *data, uint16_t dataLen); /* Definition of possible states the demo state machine could have */ @@ -66,8 +86,6 @@ static void parse_tag_header(uint8_t *data, uint16_t dataLen); ****************************************************************************** */ - - /* 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 */ @@ -199,14 +217,11 @@ ReturnCode demoTransceiveBlocking(uint8_t *txBuf, uint16_t txBufSize, uint32_t fwt); - #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; @@ -233,21 +248,6 @@ char *hex2Str(unsigned char *data, size_t dataLen) { } } -typedef struct{ - uint8_t UID[7]; - uint8_t BCC[1]; - uint8_t SYSTEM_AREA[2]; - union{ - uint8_t CC[4]; - struct{ - uint8_t CC_MAGIC_NUMBER; - uint8_t CC_VERSION; - uint8_t CC_SIZE; - uint8_t CC_ACCESS_CONDITION; - }; - }; -} type2_header_t; - nfc_status_t nfc_init() { st25r3916b_driver_t *drv = &g_st25r3916b_driver; @@ -299,8 +299,7 @@ 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; @@ -343,6 +342,7 @@ nfc_status_t nfc_init() { } nfc_status_t nfc_deinit() { + st25r3916b_driver_t *drv = &g_st25r3916b_driver; if (!drv->initialized) { @@ -375,29 +375,76 @@ nfc_status_t nfc_deinit() { drv->initialized = false; return NFC_OK; + } -nfc_status_t nfc_register_card_emu(nfc_card_emul_tech_t tech) { +void rfal_callback(rfalNfcState st){ + st25r3916b_driver_t *drv = &g_st25r3916b_driver; - // In case the NFC state machine is active, deactivate to idle before - // registering a new card emulation technology. - if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) { - rfalNfcDeactivate(RFAL_NFC_DEACTIVATE_IDLE); - do { - rfalNfcWorker(); - } while (rfalNfcGetState() != RFAL_NFC_STATE_IDLE); + switch(st){ + + case RFAL_NFC_STATE_IDLE: + 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){ + 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){ + + st25r3916b_driver_t *drv = &g_st25r3916b_driver; + drv->disc_params.devLimit = 1; memcpy(&drv->disc_params.nfcid3, NFCID3, sizeof(NFCID3)); memcpy(&drv->disc_params.GB, GB, sizeof(GB)); drv->disc_params.GBLen = sizeof(GB); drv->disc_params.p2pNfcaPrio = true; drv->disc_params.totalDuration = 1000U; + drv->disc_params.notifyCb = rfal_callback; - switch (tech) { - case NFC_CARD_EMU_TECH_A: + if(drv->initialized == false){ + return NFC_NOT_INITIALIZED; + } + + if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) { + return NFC_ERROR; + } + + // Set general discovery parameters. + + if(tech & NFC_POLLER_TECH_A){ + drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_A; + } + + if(tech & NFC_POLLER_TECH_B){ + drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_B; + } + + if(tech & NFC_POLLER_TECH_F){ + drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_F; + } + + 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, @@ -407,19 +454,68 @@ nfc_status_t nfc_register_card_emu(nfc_card_emul_tech_t tech) { 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, + RFAL_LM_SENSF_SC_LEN); /* Set System Code */ + 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, + RFAL_LM_SENSF_RES_LEN); /* Set SENSF_RES / Poll Response */ + 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)){ + + st25r3916b_driver_t *drv = &g_st25r3916b_driver; + + switch(event_type){ + case NFC_STATE_IDLE: + drv->nfc_state_idle_cb = cb_fn; break; - case NFC_CARD_EMU_TECH_V: - drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_V; + case NFC_STATE_ACTIVATED: + drv->nfc_state_activated_cb = cb_fn; break; default: return NFC_ERROR; } return NFC_OK; + } -nfc_status_t nfc_register_poller(nfc_poller_tech_t tech) { +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(){ + + st25r3916b_driver_t *drv = &g_st25r3916b_driver; + + ReturnCode err; + err = rfalNfcDiscover(&(drv->disc_params)); + if (err != RFAL_ERR_NONE) { + return NFC_ERROR; + } + + return NFC_OK; + +} + +nfc_status_t nfc_deactivate_stm(){ // In case the NFC state machine is active, deactivate to idle before // registering a new card emulation technology. @@ -430,45 +526,18 @@ nfc_status_t nfc_register_poller(nfc_poller_tech_t tech) { } while (rfalNfcGetState() != RFAL_NFC_STATE_IDLE); } - drv->disc_params.devLimit = 1; - memcpy(&drv->disc_params.nfcid3, NFCID3, sizeof(NFCID3)); - memcpy(&drv->disc_params.GB, GB, sizeof(GB)); - drv->disc_params.GBLen = sizeof(GB); - drv->disc_params.p2pNfcaPrio = true; - drv->disc_params.totalDuration = 1000U; - - switch (tech) { - case NFC_POLLER_TECH_A: - drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_A; - break; - case NFC_POLLER_TECH_B: - drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_B; - break; - case NFC_POLLER_TECH_F: - drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_F; - break; - case NFC_POLLER_TECH_V: - drv->disc_params.techs2Find |= RFAL_NFC_POLL_TECH_V; - break; - default: - return NFC_ERROR; - } - - ReturnCode err; - err = rfalNfcDiscover(&drv->disc_params); - if (err != RFAL_ERR_NONE) { - return NFC_ERROR; - } - return NFC_OK; } -nfc_status_t nfc_run_worker() { + +nfc_status_t nfc_feed_worker() { + static rfalNfcDevice *nfcDevice; rfalNfcWorker(); /* Run RFAL worker periodically */ if (rfalNfcIsDevActivated(rfalNfcGetState())) { + rfalNfcGetActiveDevice(&nfcDevice); switch (nfcDevice->type) { @@ -511,14 +580,8 @@ nfc_status_t nfc_run_worker() { err = rfalT2TPollerRead(4+i*4, memory_area_data+i*16, 16 , &rcvLen); } - ndef_record_t record; - parse_ndef_record(memory_area_data+2, 160, &record); - vcp_println("Record payload: %s", record.payload); - - - - - + ndef_message_t ndef_message; + parse_ndef_message(memory_area_data, 160, &ndef_message); break; } @@ -577,10 +640,89 @@ nfc_status_t nfc_run_worker() { } +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) { + return NFC_NOT_INITIALIZED; + } + + if (rfalNfcGetState() != RFAL_NFC_STATE_IDLE) { + return NFC_ERROR; + } + + ReturnCode err; + err = demoTransceiveBlocking((uint8_t *)txData, txDataLen, &rxData, &rxDataLen, + RFAL_FWT_NONE); + + if (err != RFAL_ERR_NONE) { + return NFC_ERROR; + } + + 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: + dev_info->type = NFC_DEV_TYPE_A; + break; + case RFAL_NFC_LISTEN_TYPE_NFCB: + dev_info->type = NFC_DEV_TYPE_B; + break; + case RFAL_NFC_LISTEN_TYPE_NFCF: + dev_info->type = NFC_DEV_TYPE_F; + break; + case RFAL_NFC_LISTEN_TYPE_NFCV: + dev_info->type = NFC_DEV_TYPE_V; + break; + case RFAL_NFC_LISTEN_TYPE_ST25TB: + dev_info->type = NFC_DEV_TYPE_ST25TB; + break; + case RFAL_NFC_LISTEN_TYPE_AP2P: + dev_info->type = NFC_DEV_TYPE_AP2P; + break; + default: + dev_info->type = NFC_DEV_TYPE_UNKNOWN; + break; + } + + dev_info->uid_len = nfcDevice->nfcidLen; + + if(dev_info->uid_len > 10){ + // Unexpected UID length + return NFC_ERROR; + } + + char *uid_str = hex2Str(nfcDevice->nfcid, nfcDevice->nfcidLen); + memcpy(dev_info->uid, uid_str, nfcDevice->nfcidLen); + + + }else{ + + // No device activated + return NFC_ERROR; + + } + + return NFC_OK; +} + static void parse_tag_header(uint8_t *data, uint16_t dataLen){ - type2_header_t hdr; + nfc_device_header_t2t_t hdr; memcpy(hdr.UID, data, 3); hdr.BCC[0] = data[3]; @@ -588,18 +730,17 @@ static void parse_tag_header(uint8_t *data, uint16_t dataLen){ memcpy(hdr.SYSTEM_AREA, data+8, 2); memcpy(hdr.CC, data+12, 4); - vcp_println("UID: %s", hex2Str(hdr.UID, sizeof(hdr.UID))); - vcp_println("BCC: %s (%s)", hex2Str(hdr.BCC, sizeof(hdr.BCC)), (0x88 == (hdr.UID[0] ^ hdr.UID[1] ^ hdr.UID[2] ^ hdr.BCC[0]))? " CHECKSUM PASSED" : "CHECKSUM FAILED"); - vcp_println("SYSTEM_AREA: %s", hex2Str(hdr.SYSTEM_AREA, sizeof(hdr.SYSTEM_AREA))); - vcp_println("CC: %s", hex2Str(hdr.CC, sizeof(hdr.CC))); - vcp_println(" -> CC_MAGIC_NUMBER: %02X", hdr.CC_MAGIC_NUMBER); - vcp_println(" -> CC_VERSION: %02X", hdr.CC_VERSION); - vcp_println(" -> CC_SIZE: %02X (%d bytes)", hdr.CC_SIZE, hdr.CC_SIZE*8); - vcp_println(" -> CC_ACCESS_CONDITION: %02X", hdr.CC_ACCESS_CONDITION); + // 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