[FL-2198], [FL-2161] NFC emulation refactoring (#968)
* rfal: add state changed callback * furi_hal_nfc: add NFC-A emulation API * nfc: add emulation logger, refactor scenes * elements: fix text_box element * gui: fix text box module * nfc: remove unnecessary buffers * nfc: introduce emulation callback concept * nfc: format sources * bt settings: fix incorrect scene switch * bt settings: format sources * Debug: fix x2d import for python 3 * Gui: rename method name widget_clear to widget_reset * nfc: add nfca emulation handler * nfc: add global custom events enum * nfc: UID emulation Data -> Log * furi_hal_nfc: fix incorrect timings * u2f, badusb: widget_clear() -> widget_reset() Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -545,10 +545,13 @@ typedef struct {
|
||||
typedef void (*rfalUpperLayerCallback)(void);
|
||||
|
||||
/*! Callback to be executed before a Transceive */
|
||||
typedef void (*rfalPreTxRxCallback)(void);
|
||||
typedef void (*rfalPreTxRxCallback)(void* context);
|
||||
|
||||
/*! Callback to be executed after a Transceive */
|
||||
typedef void (*rfalPostTxRxCallback)(void);
|
||||
typedef void (*rfalPostTxRxCallback)(void* context);
|
||||
|
||||
/** Callback to be executed on each RFAL state change */
|
||||
typedef void (*RfalStateChangedCallback)(void* context);
|
||||
|
||||
/*******************************************************************************/
|
||||
/* ISO14443A */
|
||||
@@ -819,6 +822,19 @@ void rfalSetPreTxRxCallback(rfalPreTxRxCallback pFunc);
|
||||
*/
|
||||
void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc);
|
||||
|
||||
/** Set RFAL state changed callback
|
||||
*
|
||||
* @param cb RfalStateChangedCallback instance
|
||||
* @param ctx pointer to context
|
||||
*/
|
||||
void rfal_set_state_changed_callback(RfalStateChangedCallback callback);
|
||||
|
||||
/** Set callback context
|
||||
*
|
||||
* @param ctx pointer to context
|
||||
*/
|
||||
void rfal_set_callback_context(void* context);
|
||||
|
||||
/*!
|
||||
*****************************************************************************
|
||||
* \brief RFAL Deinitialize
|
||||
@@ -1480,6 +1496,15 @@ ReturnCode rfalTransceiveBlockingTxRx(
|
||||
uint32_t flags,
|
||||
uint32_t fwt);
|
||||
|
||||
ReturnCode rfalTransceiveBitsBlockingTx(
|
||||
uint8_t* txBuf,
|
||||
uint16_t txBufLen,
|
||||
uint8_t* rxBuf,
|
||||
uint16_t rxBufLen,
|
||||
uint16_t* actLen,
|
||||
uint32_t flags,
|
||||
uint32_t fwt);
|
||||
|
||||
/*****************************************************************************
|
||||
* Listen Mode *
|
||||
*****************************************************************************/
|
||||
|
||||
@@ -130,6 +130,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
rfalPreTxRxCallback preTxRx; /*!< RFAL's Pre TxRx callback */
|
||||
rfalPostTxRxCallback postTxRx; /*!< RFAL's Post TxRx callback */
|
||||
RfalStateChangedCallback state_changed_cb;
|
||||
void* ctx;
|
||||
} rfalCallbacks;
|
||||
|
||||
/*! Struct that holds counters to control the FIFO on Tx and Rx */
|
||||
@@ -595,6 +597,8 @@ ReturnCode rfalInitialize(void) {
|
||||
|
||||
gRFAL.callbacks.preTxRx = NULL;
|
||||
gRFAL.callbacks.postTxRx = NULL;
|
||||
gRFAL.callbacks.state_changed_cb = NULL;
|
||||
gRFAL.callbacks.ctx = NULL;
|
||||
|
||||
#if RFAL_FEATURE_NFCV
|
||||
/* Initialize NFC-V Data */
|
||||
@@ -669,6 +673,14 @@ void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc) {
|
||||
gRFAL.callbacks.postTxRx = pFunc;
|
||||
}
|
||||
|
||||
void rfal_set_state_changed_callback(RfalStateChangedCallback callback) {
|
||||
gRFAL.callbacks.state_changed_cb = callback;
|
||||
}
|
||||
|
||||
void rfal_set_callback_context(void* context) {
|
||||
gRFAL.callbacks.ctx = context;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
ReturnCode rfalDeinitialize(void) {
|
||||
/* Deinitialize chip */
|
||||
@@ -1520,6 +1532,30 @@ ReturnCode rfalTransceiveBlockingTx(
|
||||
return rfalTransceiveRunBlockingTx();
|
||||
}
|
||||
|
||||
ReturnCode rfalTransceiveBitsBlockingTx(
|
||||
uint8_t* txBuf,
|
||||
uint16_t txBufLen,
|
||||
uint8_t* rxBuf,
|
||||
uint16_t rxBufLen,
|
||||
uint16_t* actLen,
|
||||
uint32_t flags,
|
||||
uint32_t fwt) {
|
||||
ReturnCode ret;
|
||||
rfalTransceiveContext ctx = {
|
||||
.rxBuf = rxBuf,
|
||||
.rxBufLen = rxBufLen,
|
||||
.rxRcvdLen = actLen,
|
||||
.txBuf = txBuf,
|
||||
.txBufLen = txBufLen,
|
||||
.flags = flags,
|
||||
.fwt = fwt,
|
||||
};
|
||||
|
||||
EXIT_ON_ERR(ret, rfalStartTransceive(&ctx));
|
||||
|
||||
return rfalTransceiveRunBlockingTx();
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
static ReturnCode rfalTransceiveRunBlockingTx(void) {
|
||||
ReturnCode ret;
|
||||
@@ -1797,7 +1833,7 @@ static void rfalCleanupTransceive(void) {
|
||||
/* Execute Post Transceive Callback */
|
||||
/*******************************************************************************/
|
||||
if(gRFAL.callbacks.postTxRx != NULL) {
|
||||
gRFAL.callbacks.postTxRx();
|
||||
gRFAL.callbacks.postTxRx(gRFAL.callbacks.ctx);
|
||||
}
|
||||
/*******************************************************************************/
|
||||
}
|
||||
@@ -1838,7 +1874,7 @@ static void rfalPrepareTransceive(void) {
|
||||
/* Execute Pre Transceive Callback */
|
||||
/*******************************************************************************/
|
||||
if(gRFAL.callbacks.preTxRx != NULL) {
|
||||
gRFAL.callbacks.preTxRx();
|
||||
gRFAL.callbacks.preTxRx(gRFAL.callbacks.ctx);
|
||||
}
|
||||
/*******************************************************************************/
|
||||
|
||||
@@ -4164,6 +4200,11 @@ ReturnCode rfalListenSetState(rfalLmState newSt) {
|
||||
|
||||
gRFAL.Lm.state = newState;
|
||||
|
||||
// Call callback on state change
|
||||
if(gRFAL.callbacks.state_changed_cb) {
|
||||
gRFAL.callbacks.state_changed_cb(gRFAL.callbacks.ctx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "mifare_ultralight.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal_nfc.h>
|
||||
|
||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
||||
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
||||
@@ -154,6 +156,7 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data)
|
||||
mf_ul_emulate->data = *data;
|
||||
mf_ul_emulate->auth_data = NULL;
|
||||
mf_ul_emulate->data_changed = false;
|
||||
mf_ul_emulate->comp_write_cmd_started = false;
|
||||
if(data->version.storage_size == 0) {
|
||||
mf_ul_emulate->data.type = MfUltralightTypeUnknown;
|
||||
mf_ul_emulate->support_fast_read = false;
|
||||
@@ -197,11 +200,15 @@ void mf_ul_protect_auth_data_on_read_command(
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t mf_ul_prepare_emulation_response(
|
||||
bool mf_ul_prepare_emulation_response(
|
||||
uint8_t* buff_rx,
|
||||
uint16_t len_rx,
|
||||
uint16_t buff_rx_len,
|
||||
uint8_t* buff_tx,
|
||||
MifareUlDevice* mf_ul_emulate) {
|
||||
uint16_t* buff_tx_len,
|
||||
uint32_t* data_type,
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
MifareUlDevice* mf_ul_emulate = context;
|
||||
uint8_t cmd = buff_rx[0];
|
||||
uint16_t page_num = mf_ul_emulate->data.data_size / 4;
|
||||
uint16_t tx_bytes = 0;
|
||||
@@ -211,12 +218,13 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
// Check composite commands
|
||||
if(mf_ul_emulate->comp_write_cmd_started) {
|
||||
// Compatibility write is the only one composit command
|
||||
if(len_rx == 16) {
|
||||
if(buff_rx_len == 16) {
|
||||
memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4);
|
||||
mf_ul_emulate->data_changed = true;
|
||||
// Send ACK message
|
||||
buff_tx[0] = 0x0A;
|
||||
tx_bits = 4;
|
||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||
command_parsed = true;
|
||||
}
|
||||
mf_ul_emulate->comp_write_cmd_started = false;
|
||||
@@ -224,6 +232,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) {
|
||||
tx_bytes = sizeof(mf_ul_emulate->data.version);
|
||||
memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes);
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_READ_CMD) {
|
||||
@@ -243,6 +252,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
}
|
||||
mf_ul_protect_auth_data_on_read_command(
|
||||
buff_tx, start_page, (start_page + 4), mf_ul_emulate);
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_FAST_READ_CMD) {
|
||||
@@ -254,6 +264,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
|
||||
mf_ul_protect_auth_data_on_read_command(
|
||||
buff_tx, start_page, end_page, mf_ul_emulate);
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
}
|
||||
@@ -265,6 +276,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
// ACK
|
||||
buff_tx[0] = 0x0A;
|
||||
tx_bits = 4;
|
||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_COMP_WRITE) {
|
||||
@@ -275,6 +287,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
// ACK
|
||||
buff_tx[0] = 0x0A;
|
||||
tx_bits = 4;
|
||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_READ_CNT) {
|
||||
@@ -284,6 +297,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
|
||||
buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
|
||||
tx_bytes = 3;
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_INC_CNT) {
|
||||
@@ -295,6 +309,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
// ACK
|
||||
buff_tx[0] = 0x0A;
|
||||
tx_bits = 4;
|
||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_AUTH) {
|
||||
@@ -303,11 +318,13 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0];
|
||||
buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1];
|
||||
tx_bytes = 2;
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
} else if(!mf_ul_emulate->auth_data->pack.value) {
|
||||
buff_tx[0] = 0x80;
|
||||
buff_tx[1] = 0x80;
|
||||
tx_bytes = 2;
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
}
|
||||
@@ -316,6 +333,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
if(buff_rx[1] == 0x00) {
|
||||
tx_bytes = sizeof(mf_ul_emulate->data.signature);
|
||||
memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes);
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_CHECK_TEARING) {
|
||||
@@ -323,6 +341,7 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
if(cnt_num < 3) {
|
||||
buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
|
||||
tx_bytes = 1;
|
||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||
command_parsed = true;
|
||||
}
|
||||
} else if(cmd == MF_UL_HALT_START) {
|
||||
@@ -334,10 +353,12 @@ uint16_t mf_ul_prepare_emulation_response(
|
||||
// Send NACK
|
||||
buff_tx[0] = 0x00;
|
||||
tx_bits = 4;
|
||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||
}
|
||||
// Return tx buffer size in bits
|
||||
if(tx_bytes) {
|
||||
tx_bits = tx_bytes * 8;
|
||||
}
|
||||
return tx_bits;
|
||||
*buff_tx_len = tx_bits;
|
||||
return tx_bits > 0;
|
||||
}
|
||||
|
||||
@@ -116,8 +116,10 @@ void mf_ul_parse_fast_read_response(
|
||||
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
|
||||
|
||||
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
|
||||
uint16_t mf_ul_prepare_emulation_response(
|
||||
bool mf_ul_prepare_emulation_response(
|
||||
uint8_t* buff_rx,
|
||||
uint16_t len_rx,
|
||||
uint16_t buff_rx_len,
|
||||
uint8_t* buff_tx,
|
||||
MifareUlDevice* mf_ul_emulate);
|
||||
uint16_t* buff_tx_len,
|
||||
uint32_t* data_type,
|
||||
void* context);
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#include "nfca.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NFCA_CMD_RATS (0xE0U)
|
||||
|
||||
typedef struct {
|
||||
uint8_t cmd;
|
||||
uint8_t param;
|
||||
} nfca_cmd_rats;
|
||||
|
||||
static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00};
|
||||
|
||||
static uint8_t nfca_sleep_req[] = {0x50, 0x00};
|
||||
|
||||
bool nfca_emulation_handler(
|
||||
uint8_t* buff_rx,
|
||||
uint16_t buff_rx_len,
|
||||
uint8_t* buff_tx,
|
||||
uint16_t* buff_tx_len) {
|
||||
bool sleep = false;
|
||||
uint8_t rx_bytes = buff_rx_len / 8;
|
||||
|
||||
if(rx_bytes == sizeof(nfca_sleep_req) && !memcmp(buff_rx, nfca_sleep_req, rx_bytes)) {
|
||||
sleep = true;
|
||||
} else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) {
|
||||
memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats));
|
||||
*buff_tx_len = sizeof(nfca_default_ats) * 8;
|
||||
}
|
||||
|
||||
return sleep;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool nfca_emulation_handler(
|
||||
uint8_t* buff_rx,
|
||||
uint16_t buff_rx_len,
|
||||
uint8_t* buff_tx,
|
||||
uint16_t* buff_tx_len);
|
||||
Reference in New Issue
Block a user