From 8cfd0eab9e5f99a41c2c79ab5c3c0c4afe253555 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 2 Feb 2022 22:59:28 +0300 Subject: [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 --- firmware/targets/f6/furi_hal/furi_hal_nfc.c | 131 +++++++++++++++++++++++ firmware/targets/f7/furi_hal/furi_hal_nfc.c | 131 +++++++++++++++++++++++ firmware/targets/furi_hal_include/furi_hal_nfc.h | 31 ++++++ 3 files changed, 293 insertions(+) mode change 100644 => 100755 firmware/targets/f6/furi_hal/furi_hal_nfc.c mode change 100644 => 100755 firmware/targets/f7/furi_hal/furi_hal_nfc.c (limited to 'firmware') diff --git a/firmware/targets/f6/furi_hal/furi_hal_nfc.c b/firmware/targets/f6/furi_hal/furi_hal_nfc.c old mode 100644 new mode 100755 index be79aca1..c2560b75 --- a/firmware/targets/f6/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f6/furi_hal/furi_hal_nfc.c @@ -1,14 +1,25 @@ #include "furi_hal_nfc.h" #include +#include +#include +#include +#include #define TAG "FuriHalNfc" static const uint32_t clocks_in_ms = 64 * 1000; +osEventFlagsId_t event = NULL; +#define EVENT_FLAG_INTERRUPT (1UL << 0) +#define EVENT_FLAG_STATE_CHANGED (1UL << 1) +#define EVENT_FLAG_STOP (1UL << 2) +#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP) + void furi_hal_nfc_init() { ReturnCode ret = rfalNfcInitialize(); if(ret == ERR_NONE) { furi_hal_nfc_start_sleep(); + event = osEventFlagsNew(NULL); FURI_LOG_I(TAG, "Init OK"); } else { FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); @@ -140,6 +151,126 @@ bool furi_hal_nfc_listen( return true; } +void rfal_interrupt_callback_handler() { + osEventFlagsSet(event, EVENT_FLAG_INTERRUPT); +} + +void rfal_state_changed_callback(void* context) { + osEventFlagsSet(event, EVENT_FLAG_STATE_CHANGED); +} + +void furi_hal_nfc_stop() { + if(event) { + osEventFlagsSet(event, EVENT_FLAG_STOP); + } +} + +bool furi_hal_nfc_emulate_nfca( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak, + FuriHalNfcEmulateCallback callback, + void* context, + uint32_t timeout) { + rfalSetUpperLayerCallback(rfal_interrupt_callback_handler); + rfal_set_state_changed_callback(rfal_state_changed_callback); + + rfalLmConfPA config; + config.nfcidLen = uid_len; + memcpy(config.nfcid, uid, uid_len); + memcpy(config.SENS_RES, atqa, RFAL_LM_SENS_RES_LEN); + config.SEL_RES = sak; + uint8_t buff_rx[256]; + uint16_t buff_rx_size = 256; + uint16_t buff_rx_len = 0; + uint8_t buff_tx[256]; + uint16_t buff_tx_len = 0; + uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT; + + rfalLowPowerModeStop(); + if(rfalListenStart( + RFAL_LM_MASK_NFCA, + &config, + NULL, + NULL, + buff_rx, + rfalConvBytesToBits(buff_rx_size), + &buff_rx_len)) { + rfalListenStop(); + FURI_LOG_E(TAG, "Failed to start listen mode"); + return false; + } + while(true) { + buff_rx_len = 0; + buff_tx_len = 0; + uint32_t flag = osEventFlagsWait(event, EVENT_FLAG_ALL, osFlagsWaitAny, timeout); + if(flag == osErrorTimeout || flag == EVENT_FLAG_STOP) { + break; + } + bool data_received = false; + buff_rx_len = 0; + rfalWorker(); + rfalLmState state = rfalListenGetState(&data_received, NULL); + if(data_received) { + rfalTransceiveBlockingRx(); + if(nfca_emulation_handler(buff_rx, buff_rx_len, buff_tx, &buff_tx_len)) { + if(rfalListenSleepStart( + RFAL_LM_STATE_SLEEP_A, + buff_rx, + rfalConvBytesToBits(buff_rx_size), + &buff_rx_len)) { + FURI_LOG_E(TAG, "Failed to enter sleep mode"); + break; + } else { + continue; + } + } + if(buff_tx_len) { + ReturnCode ret = rfalTransceiveBitsBlockingTx( + buff_tx, + buff_tx_len, + buff_rx, + sizeof(buff_rx), + &buff_rx_len, + data_type, + RFAL_FWT_NONE); + if(ret) { + FURI_LOG_E(TAG, "Tranceive failed with status %d", ret); + break; + } + continue; + } + if((state == RFAL_LM_STATE_ACTIVE_A || state == RFAL_LM_STATE_ACTIVE_Ax)) { + if(callback) { + callback(buff_rx, buff_rx_len, buff_tx, &buff_tx_len, &data_type, context); + } + if(!rfalIsExtFieldOn()) { + break; + } + if(buff_tx_len) { + ReturnCode ret = rfalTransceiveBitsBlockingTx( + buff_tx, + buff_tx_len, + buff_rx, + sizeof(buff_rx), + &buff_rx_len, + data_type, + RFAL_FWT_NONE); + if(ret) { + FURI_LOG_E(TAG, "Tranceive failed with status %d", ret); + continue; + } + } else { + break; + } + } + } + } + rfalListenStop(); + return true; +} + bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c old mode 100644 new mode 100755 index be79aca1..c2560b75 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -1,14 +1,25 @@ #include "furi_hal_nfc.h" #include +#include +#include +#include +#include #define TAG "FuriHalNfc" static const uint32_t clocks_in_ms = 64 * 1000; +osEventFlagsId_t event = NULL; +#define EVENT_FLAG_INTERRUPT (1UL << 0) +#define EVENT_FLAG_STATE_CHANGED (1UL << 1) +#define EVENT_FLAG_STOP (1UL << 2) +#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP) + void furi_hal_nfc_init() { ReturnCode ret = rfalNfcInitialize(); if(ret == ERR_NONE) { furi_hal_nfc_start_sleep(); + event = osEventFlagsNew(NULL); FURI_LOG_I(TAG, "Init OK"); } else { FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); @@ -140,6 +151,126 @@ bool furi_hal_nfc_listen( return true; } +void rfal_interrupt_callback_handler() { + osEventFlagsSet(event, EVENT_FLAG_INTERRUPT); +} + +void rfal_state_changed_callback(void* context) { + osEventFlagsSet(event, EVENT_FLAG_STATE_CHANGED); +} + +void furi_hal_nfc_stop() { + if(event) { + osEventFlagsSet(event, EVENT_FLAG_STOP); + } +} + +bool furi_hal_nfc_emulate_nfca( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak, + FuriHalNfcEmulateCallback callback, + void* context, + uint32_t timeout) { + rfalSetUpperLayerCallback(rfal_interrupt_callback_handler); + rfal_set_state_changed_callback(rfal_state_changed_callback); + + rfalLmConfPA config; + config.nfcidLen = uid_len; + memcpy(config.nfcid, uid, uid_len); + memcpy(config.SENS_RES, atqa, RFAL_LM_SENS_RES_LEN); + config.SEL_RES = sak; + uint8_t buff_rx[256]; + uint16_t buff_rx_size = 256; + uint16_t buff_rx_len = 0; + uint8_t buff_tx[256]; + uint16_t buff_tx_len = 0; + uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT; + + rfalLowPowerModeStop(); + if(rfalListenStart( + RFAL_LM_MASK_NFCA, + &config, + NULL, + NULL, + buff_rx, + rfalConvBytesToBits(buff_rx_size), + &buff_rx_len)) { + rfalListenStop(); + FURI_LOG_E(TAG, "Failed to start listen mode"); + return false; + } + while(true) { + buff_rx_len = 0; + buff_tx_len = 0; + uint32_t flag = osEventFlagsWait(event, EVENT_FLAG_ALL, osFlagsWaitAny, timeout); + if(flag == osErrorTimeout || flag == EVENT_FLAG_STOP) { + break; + } + bool data_received = false; + buff_rx_len = 0; + rfalWorker(); + rfalLmState state = rfalListenGetState(&data_received, NULL); + if(data_received) { + rfalTransceiveBlockingRx(); + if(nfca_emulation_handler(buff_rx, buff_rx_len, buff_tx, &buff_tx_len)) { + if(rfalListenSleepStart( + RFAL_LM_STATE_SLEEP_A, + buff_rx, + rfalConvBytesToBits(buff_rx_size), + &buff_rx_len)) { + FURI_LOG_E(TAG, "Failed to enter sleep mode"); + break; + } else { + continue; + } + } + if(buff_tx_len) { + ReturnCode ret = rfalTransceiveBitsBlockingTx( + buff_tx, + buff_tx_len, + buff_rx, + sizeof(buff_rx), + &buff_rx_len, + data_type, + RFAL_FWT_NONE); + if(ret) { + FURI_LOG_E(TAG, "Tranceive failed with status %d", ret); + break; + } + continue; + } + if((state == RFAL_LM_STATE_ACTIVE_A || state == RFAL_LM_STATE_ACTIVE_Ax)) { + if(callback) { + callback(buff_rx, buff_rx_len, buff_tx, &buff_tx_len, &data_type, context); + } + if(!rfalIsExtFieldOn()) { + break; + } + if(buff_tx_len) { + ReturnCode ret = rfalTransceiveBitsBlockingTx( + buff_tx, + buff_tx_len, + buff_rx, + sizeof(buff_rx), + &buff_rx_len, + data_type, + RFAL_FWT_NONE); + if(ret) { + FURI_LOG_E(TAG, "Tranceive failed with status %d", ret); + continue; + } + } else { + break; + } + } + } + } + rfalListenStop(); + return true; +} + bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 61d95e90..3d0c2024 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -16,6 +16,26 @@ extern "C" { #define FURI_HAL_NFC_UID_MAX_LEN 10 +#define FURI_HAL_NFC_TXRX_DEFAULT \ + ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \ + (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \ + (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + +#define FURI_HAL_NFC_TXRX_RAW \ + ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \ + (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE | \ + (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + +typedef bool (*FuriHalNfcEmulateCallback)( + uint8_t* buff_rx, + uint16_t buff_rx_len, + uint8_t* buff_tx, + uint16_t* buff_tx_len, + uint32_t* flags, + void* context); + /** Init nfc */ void furi_hal_nfc_init(); @@ -76,6 +96,15 @@ bool furi_hal_nfc_listen( bool activate_after_sak, uint32_t timeout); +bool furi_hal_nfc_emulate_nfca( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak, + FuriHalNfcEmulateCallback callback, + void* context, + uint32_t timeout); + /** Get first command from reader after activation in emulation mode * * @param rx_buff pointer to receive buffer @@ -113,6 +142,8 @@ ReturnCode furi_hal_nfc_raw_bitstream_exchange( */ void furi_hal_nfc_deactivate(); +void furi_hal_nfc_stop(); + #ifdef __cplusplus } #endif -- cgit v1.2.3