NFC emulation software tunning (#1341)

* digital_signal: optimize calculationxx
* firmware: add listen start and listen rx
* digital signal: rework with fixed point calculation
* nfc: tune timings
* nfc: fix array overflow
* mifare classic: fix key access
* nfc: rework spi bus access
* nfc: rework listen mode with st25r3916 calls
* digital signal: speed up digital_signal_append()
* digital signal: remove unused profiling
* nfc: clean up code
* nfc: correct sleep state
* nfc: add unit tests
* nfc: fix memory leak in unit test
* digital_signal: remove unused code
* nfc: fix incorrect sak load in pt memory

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
gornekich 2022-07-03 17:51:50 +03:00 committed by GitHub
parent 1975868ed8
commit 5769595e67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 496 additions and 61 deletions

View File

@ -1,6 +1,8 @@
#include "nfc_worker_i.h"
#include <furi_hal.h>
#include <platform.h>
#define TAG "NfcWorker"
/***************************** NFC Worker API *******************************/
@ -495,9 +497,11 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
NfcaSignal* nfca_signal = nfca_signal_alloc();
tx_rx.nfca_signal = nfca_signal;
rfal_platform_spi_acquire();
furi_hal_nfc_listen_start(nfc_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) {
if(furi_hal_nfc_listen(
nfc_data->uid, nfc_data->uid_len, nfc_data->atqa, nfc_data->sak, true, 300)) {
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
mf_classic_emulator(&emulator, &tx_rx);
}
}
@ -510,6 +514,8 @@ void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
}
nfca_signal_free(nfca_signal);
rfal_platform_spi_release();
}
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {

View File

@ -0,0 +1,184 @@
#include <furi.h>
#include <furi_hal.h>
#include <applications/storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <lib/nfc_protocols/nfca.h>
#include <lib/digital_signal/digital_signal.h>
#include <lib/flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/file_stream.h>
#include "../minunit.h"
#define TAG "NfcTest"
#define NFC_TEST_RESOURCES_DIR "/ext/unit_tests/nfc/"
#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc"
#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc"
static const char* nfc_test_file_type = "Flipper NFC test";
static const uint32_t nfc_test_file_version = 1;
#define NFC_TEST_DATA_MAX_LEN 18
#define NFC_TETS_TIMINGS_MAX_LEN 1350
typedef struct {
Storage* storage;
NfcaSignal* signal;
uint32_t test_data_len;
uint8_t test_data[NFC_TEST_DATA_MAX_LEN];
uint32_t test_timings_len;
uint32_t test_timings[NFC_TETS_TIMINGS_MAX_LEN];
} NfcTest;
static NfcTest* nfc_test = NULL;
static void nfc_test_alloc() {
nfc_test = malloc(sizeof(NfcTest));
nfc_test->signal = nfca_signal_alloc();
nfc_test->storage = furi_record_open("storage");
}
static void nfc_test_free() {
furi_assert(nfc_test);
furi_record_close("storage");
nfca_signal_free(nfc_test->signal);
free(nfc_test);
nfc_test = NULL;
}
static bool nfc_test_read_signal_from_file(const char* file_name) {
bool success = false;
FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage);
string_t file_type;
string_init(file_type);
uint32_t file_version = 0;
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_read_header(file, file_type, &file_version)) break;
if(string_cmp_str(file_type, nfc_test_file_type) || file_version != nfc_test_file_version)
break;
if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break;
if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break;
if(!flipper_format_read_hex(
file, "Plain data", nfc_test->test_data, nfc_test->test_data_len))
break;
if(!flipper_format_read_uint32(file, "Timings length", &nfc_test->test_timings_len, 1))
break;
if(nfc_test->test_timings_len > NFC_TETS_TIMINGS_MAX_LEN) break;
if(!flipper_format_read_uint32(
file, "Timings", nfc_test->test_timings, nfc_test->test_timings_len))
break;
success = true;
} while(false);
string_clear(file_type);
flipper_format_free(file);
return success;
}
static bool nfc_test_digital_signal_test_encode(
const char* file_name,
uint32_t encode_max_time,
uint32_t timing_tolerance,
uint32_t timings_sum_tolerance) {
furi_assert(nfc_test);
bool success = false;
uint32_t time = 0;
uint32_t dut_timings_sum = 0;
uint32_t ref_timings_sum = 0;
uint8_t parity[10] = {};
do {
// Read test data
if(!nfc_test_read_signal_from_file(file_name)) break;
// Encode signal
FURI_CRITICAL_ENTER();
time = DWT->CYCCNT;
nfca_signal_encode(
nfc_test->signal, nfc_test->test_data, nfc_test->test_data_len * 8, parity);
digital_signal_prepare_arr(nfc_test->signal->tx_signal);
time = (DWT->CYCCNT - time) / furi_hal_delay_instructions_per_microsecond();
FURI_CRITICAL_EXIT();
// Check timings
if(time > encode_max_time) {
FURI_LOG_E(
TAG, "Encoding time: %d us while accepted value: %d us", time, encode_max_time);
break;
}
// Check data
if(nfc_test->signal->tx_signal->edge_cnt != nfc_test->test_timings_len) {
FURI_LOG_E(TAG, "Not equal timings buffers length");
break;
}
uint32_t timings_diff = 0;
uint32_t* ref = nfc_test->test_timings;
uint32_t* dut = nfc_test->signal->tx_signal->reload_reg_buff;
bool timing_check_success = true;
for(size_t i = 0; i < nfc_test->test_timings_len; i++) {
timings_diff = dut[i] > ref[i] ? dut[i] - ref[i] : ref[i] - dut[i];
dut_timings_sum += dut[i];
ref_timings_sum += ref[i];
if(timings_diff > timing_tolerance) {
FURI_LOG_E(
TAG, "Too big differece in %d timings. Ref: %d, DUT: %d", i, ref[i], dut[i]);
timing_check_success = false;
break;
}
}
if(!timing_check_success) break;
uint32_t sum_diff = dut_timings_sum > ref_timings_sum ? dut_timings_sum - ref_timings_sum :
ref_timings_sum - dut_timings_sum;
if(sum_diff > timings_sum_tolerance) {
FURI_LOG_E(
TAG,
"Too big difference in timings sum. Ref: %d, DUT: %d",
ref_timings_sum,
dut_timings_sum);
break;
}
FURI_LOG_I(TAG, "Encoding time: %d us. Acceptable time: %d us", time, encode_max_time);
FURI_LOG_I(
TAG,
"Timings sum difference: %d [1/64MHZ]. Acceptable difference: %d [1/64MHz]",
sum_diff,
timings_sum_tolerance);
success = true;
} while(false);
return success;
}
MU_TEST(nfc_digital_signal_test) {
mu_assert(
nfc_test_digital_signal_test_encode(
NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_SHORT_FILE, 500, 1, 37),
"NFC short digital signal test failed\r\n");
mu_assert(
nfc_test_digital_signal_test_encode(
NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_LONG_FILE, 2000, 1, 37),
"NFC long digital signal test failed\r\n");
}
MU_TEST_SUITE(nfc) {
nfc_test_alloc();
MU_RUN_TEST(nfc_digital_signal_test);
nfc_test_free();
}
int run_minunit_test_nfc() {
MU_RUN_SUITE(nfc);
return MU_EXIT_CODE;
}

View File

@ -19,6 +19,7 @@ int run_minunit_test_stream();
int run_minunit_test_storage();
int run_minunit_test_subghz();
int run_minunit_test_dirwalk();
int run_minunit_test_nfc();
void minunit_print_progress(void) {
static char progress[] = {'\\', '|', '/', '-'};
@ -67,6 +68,7 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) {
test_result |= run_minunit_test_infrared_decoder_encoder();
test_result |= run_minunit_test_rpc();
test_result |= run_minunit_test_subghz();
test_result |= run_minunit_test_nfc();
cycle_counter = (furi_hal_get_tick() - cycle_counter);

View File

@ -0,0 +1,6 @@
Filetype: Flipper NFC test
Version: 1
Data length: 18
Plain data: f1 99 41 43 a1 2f 23 01 de f3 c5 8d 91 4b 1e 50 4a c9
Timings length: 1304
Timings: 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 640 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 641 37 36 37 37 37 36 37 37 37 36 37 37 37 37 36 641 37 37 36 37 37 37 36 37 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 0

View File

@ -0,0 +1,6 @@
Filetype: Flipper NFC test
Version: 1
Data length: 4
Plain data: 14 d8 a0 c9
Timings length: 296
Timings: 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 339 37 37 36 37 37 37 36 339 37 37 37 36 37 37 37 338 37 37 37 36 37 37 37 338 37 37 37 37 36 37 37 339 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 641 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 339 37 37 36 37 37 37 37 640 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 339 36 37 37 37 36 37 37 339 37 36 37 37 37 36 37 339 37 36 37 37 37 36 37 339 37 37 36 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 641 36 37 37 37 36 37 37 37 36 37 37 37 36 37 37 641 37 36 37 37 37 36 37 339 37 36 37 37 37 37 36 37 37 37 36 37 37 37 36 641 37 37 36 37 37 37 37 338 37 37 37 36 37 37 37 36 37 37 37 36 37 37 37 339 36 37 37 37 36 37 37 641 36 37 37 37 37 36 37 0

View File

@ -8,6 +8,9 @@
#include <lib/digital_signal/digital_signal.h>
#include <furi_hal_delay.h>
#include <furi_hal_spi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_resources.h>
#define TAG "FuriHalNfc"
@ -19,6 +22,8 @@ osEventFlagsId_t event = NULL;
#define EVENT_FLAG_STOP (1UL << 2)
#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP)
#define FURI_HAL_NFC_UID_INCOMPLETE (0x04)
void furi_hal_nfc_init() {
ReturnCode ret = rfalNfcInitialize();
if(ret == ERR_NONE) {
@ -243,6 +248,108 @@ bool furi_hal_nfc_listen(
return true;
}
static void furi_hal_nfc_read_fifo(uint8_t* data, uint16_t* bits) {
uint8_t fifo_status[2];
uint8_t rx_buff[64];
st25r3916ReadMultipleRegisters(
ST25R3916_REG_FIFO_STATUS1, fifo_status, ST25R3916_FIFO_STATUS_LEN);
uint16_t rx_bytes =
((((uint16_t)fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >>
ST25R3916_REG_FIFO_STATUS2_fifo_b_shift)
<< 8);
rx_bytes |= (((uint16_t)fifo_status[0]) & 0x00FFU);
st25r3916ReadFifo(rx_buff, rx_bytes);
memcpy(data, rx_buff, rx_bytes);
*bits = rx_bytes * 8;
}
void furi_hal_nfc_listen_sleep() {
st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SLEEP);
}
bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms) {
furi_assert(tx_rx);
// Wait for interrupts
uint32_t start = osKernelGetTickCount();
bool data_received = false;
while(true) {
if(furi_hal_gpio_read(&gpio_nfc_irq_rfid_pull) == true) {
st25r3916CheckForReceivedInterrupts();
if(st25r3916GetInterrupt(ST25R3916_IRQ_MASK_RXE)) {
furi_hal_nfc_read_fifo(tx_rx->rx_data, &tx_rx->rx_bits);
data_received = true;
break;
}
continue;
}
if(osKernelGetTickCount() - start > timeout_ms) {
FURI_LOG_D(TAG, "Interrupt waiting timeout");
break;
}
}
return data_received;
}
void furi_hal_nfc_listen_start(FuriHalNfcDevData* nfc_data) {
furi_assert(nfc_data);
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh);
// Clear interrupts
st25r3916ClearInterrupts();
// Mask all interrupts
st25r3916DisableInterrupts(ST25R3916_IRQ_MASK_ALL);
// RESET
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
// Setup registers
st25r3916WriteRegister(
ST25R3916_REG_OP_CONTROL,
ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
st25r3916WriteRegister(
ST25R3916_REG_MODE,
ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0);
st25r3916WriteRegister(
ST25R3916_REG_PASSIVE_TARGET,
ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 |
ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r);
st25r3916WriteRegister(ST25R3916_REG_MASK_RX_TIMER, 0x02);
// Mask interrupts
uint32_t clear_irq_mask =
(ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_RXE_PTA | ST25R3916_IRQ_MASK_WU_A_X |
ST25R3916_IRQ_MASK_WU_A);
st25r3916EnableInterrupts(clear_irq_mask);
// Set 4 or 7 bytes UID
if(nfc_data->uid_len == 4) {
st25r3916ChangeRegisterBits(
ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_4bytes);
} else {
st25r3916ChangeRegisterBits(
ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_id_mask, ST25R3916_REG_AUX_nfc_id_7bytes);
}
// Write PT Memory
uint8_t pt_memory[15] = {};
memcpy(pt_memory, nfc_data->uid, nfc_data->uid_len);
pt_memory[10] = nfc_data->atqa[0];
pt_memory[11] = nfc_data->atqa[1];
if(nfc_data->uid_len == 4) {
pt_memory[12] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE;
} else {
pt_memory[12] = nfc_data->sak | FURI_HAL_NFC_UID_INCOMPLETE;
}
pt_memory[13] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE;
pt_memory[14] = nfc_data->sak & ~FURI_HAL_NFC_UID_INCOMPLETE;
st25r3916WritePTMem(pt_memory, sizeof(pt_memory));
// Go to sence
st25r3916ExecuteCommand(ST25R3916_CMD_GOTO_SENSE);
}
void rfal_interrupt_callback_handler() {
osEventFlagsSet(event, EVENT_FLAG_INTERRUPT);
}
@ -369,23 +476,18 @@ bool furi_hal_nfc_emulate_nfca(
static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
furi_assert(tx_rx->nfca_signal);
platformDisableIrqCallback();
bool ret = false;
// Start transparent mode
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
// Reconfigure gpio
// Reconfigure gpio for Transparent mode
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
furi_hal_gpio_init(&gpio_spi_r_sck, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_init(&gpio_spi_r_miso, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_init(&gpio_nfc_cs, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_init(&gpio_spi_r_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
furi_hal_gpio_write(&gpio_spi_r_mosi, false);
// Send signal
FURI_CRITICAL_ENTER();
nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits, tx_rx->tx_parity);
digital_signal_send(tx_rx->nfca_signal->tx_signal, &gpio_spi_r_mosi);
FURI_CRITICAL_EXIT();
furi_hal_gpio_write(&gpio_spi_r_mosi, false);
// Configure gpio back to SPI and exit transparent
@ -443,7 +545,6 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
}
st25r3916ClearInterrupts();
platformEnableIrqCallback();
return ret;
}

View File

@ -188,6 +188,72 @@ inline static void furi_hal_spi_bus_r_handle_event_callback(
}
}
inline static void furi_hal_spi_bus_nfc_handle_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event,
const LL_SPI_InitTypeDef* preset) {
if(event == FuriHalSpiBusHandleEventInit) {
// Configure GPIOs in normal SPI mode
furi_hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
furi_hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
furi_hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
furi_hal_gpio_write(handle->cs, true);
furi_hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
} else if(event == FuriHalSpiBusHandleEventDeinit) {
// Configure GPIOs for st25r3916 Transparent mode
furi_hal_gpio_init(handle->sck, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_init(handle->miso, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_init(handle->cs, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_gpio_write(handle->mosi, false);
furi_hal_gpio_init(handle->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
} else if(event == FuriHalSpiBusHandleEventActivate) {
LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
LL_SPI_Enable(handle->bus->spi);
furi_hal_gpio_init_ex(
handle->miso,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
furi_hal_gpio_init_ex(
handle->mosi,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
furi_hal_gpio_init_ex(
handle->sck,
GpioModeAltFunctionPushPull,
GpioPullNo,
GpioSpeedVeryHigh,
GpioAltFn5SPI1);
} else if(event == FuriHalSpiBusHandleEventDeactivate) {
furi_hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
LL_SPI_Disable(handle->bus->spi);
}
}
static void furi_hal_spi_bus_handle_subghz_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
@ -206,7 +272,7 @@ FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
static void furi_hal_spi_bus_handle_nfc_event_callback(
FuriHalSpiBusHandle* handle,
FuriHalSpiBusHandleEvent event) {
furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
furi_hal_spi_bus_nfc_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
}
FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {

View File

@ -163,6 +163,39 @@ bool furi_hal_nfc_listen(
bool activate_after_sak,
uint32_t timeout);
/** Start Target Listen mode
* @note RFAL free implementation
*
* @param nfc_data FuriHalNfcDevData instance
*/
void furi_hal_nfc_listen_start(FuriHalNfcDevData* nfc_data);
/** Read data in Target Listen mode
* @note Must be called only after furi_hal_nfc_listen_start()
*
* @param tx_rx FuriHalNfcTxRxContext instance
* @param timeout_ms timeout im ms
*
* @return true on not empty receive
*/
bool furi_hal_nfc_listen_rx(FuriHalNfcTxRxContext* tx_rx, uint32_t timeout_ms);
/** Set Target in Sleep state */
void furi_hal_nfc_listen_sleep();
/** Emulate NFC-A Target
* @note RFAL based implementation
*
* @param uid NFC-A UID
* @param uid_len NFC-A UID length
* @param atqa NFC-A ATQA
* @param sak NFC-A SAK
* @param callback FuriHalNfcEmulateCallback instance
* @param context pointer to context for callback
* @param timeout timeout in ms
*
* @return true on success
*/
bool furi_hal_nfc_emulate_nfca(
uint8_t* uid,
uint8_t uid_len,

View File

@ -6,11 +6,13 @@
typedef struct {
FuriThread* thread;
volatile PlatformIrqCallback callback;
bool need_spi_lock;
} RfalPlatform;
static volatile RfalPlatform rfal_platform = {
.thread = NULL,
.callback = NULL,
.need_spi_lock = true,
};
void nfc_isr(void* _ctx) {
@ -71,10 +73,30 @@ bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len) {
return ret;
}
void platformProtectST25RComm() {
// Until we completely remove RFAL, NFC works with SPI from rfal_platform_irq_thread and nfc_worker
// threads. Some nfc features already stop using RFAL and work with SPI from nfc_worker only.
// rfal_platform_spi_acquire() and rfal_platform_spi_release() functions are used to lock SPI for a
// long term without locking it for each SPI transaction. This is needed for time critical communications.
void rfal_platform_spi_acquire() {
platformDisableIrqCallback();
rfal_platform.need_spi_lock = false;
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
}
void rfal_platform_spi_release() {
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
rfal_platform.need_spi_lock = true;
platformEnableIrqCallback();
}
void platformProtectST25RComm() {
if(rfal_platform.need_spi_lock) {
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
}
}
void platformUnprotectST25RComm() {
if(rfal_platform.need_spi_lock) {
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
}
}

View File

@ -19,6 +19,8 @@ void platformDisableIrqCallback();
bool platformSpiTxRx(const uint8_t* txBuf, uint8_t* rxBuf, uint16_t len);
void platformProtectST25RComm();
void platformUnprotectST25RComm();
void rfal_platform_spi_acquire();
void rfal_platform_spi_release();
#define ST25R_SS_PIN NFC_CS_Pin
#define ST25R_SS_PORT NFC_CS_GPIO_Port

View File

@ -5,14 +5,17 @@
#include <stm32wbxx_ll_tim.h>
#include <math.h>
#pragma GCC optimize("O3,unroll-loops,Ofast")
#define F_TIM (64000000.0)
#define T_TIM (1.0 / F_TIM)
#define T_TIM 1562 //15.625 ns *100
#define T_TIM_DIV2 781 //15.625 ns / 2 *100
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
DigitalSignal* signal = malloc(sizeof(DigitalSignal));
signal->start_level = true;
signal->edges_max_cnt = max_edges_cnt;
signal->edge_timings = malloc(max_edges_cnt * sizeof(float));
signal->edge_timings = malloc(max_edges_cnt * sizeof(uint32_t));
signal->reload_reg_buff = malloc(max_edges_cnt * sizeof(uint32_t));
signal->edge_cnt = 0;
@ -48,10 +51,10 @@ bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) {
signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0];
}
}
memcpy(
&signal_a->edge_timings[signal_a->edge_cnt],
&signal_b->edge_timings[start_copy],
(signal_b->edge_cnt - start_copy) * sizeof(float));
for(size_t i = 0; i < signal_b->edge_cnt - start_copy; i++) {
signal_a->edge_timings[signal_a->edge_cnt + i] = signal_b->edge_timings[start_copy + i];
}
signal_a->edge_cnt += signal_b->edge_cnt - start_copy;
return true;
@ -69,34 +72,33 @@ uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) {
return signal->edge_cnt;
}
float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
furi_assert(signal);
furi_assert(edge_num < signal->edge_cnt);
return signal->edge_timings[edge_num];
}
static void digital_signal_prepare_arr(DigitalSignal* signal) {
float t_signal = 0;
float t_current = 0;
float r = 0;
float r_int = 0;
float r_dec = 0;
void digital_signal_prepare_arr(DigitalSignal* signal) {
uint32_t t_signal_rest = signal->edge_timings[0];
uint32_t r_count_tick_arr = 0;
uint32_t r_rest_div = 0;
for(size_t i = 0; i < signal->edge_cnt - 1; i++) {
t_signal += signal->edge_timings[i];
r = (t_signal - t_current) / T_TIM;
r_dec = modff(r, &r_int);
if(r_dec < 0.5f) {
signal->reload_reg_buff[i] = (uint32_t)r_int - 1;
r_count_tick_arr = t_signal_rest / T_TIM;
r_rest_div = t_signal_rest % T_TIM;
t_signal_rest = signal->edge_timings[i + 1] + r_rest_div;
if(r_rest_div < T_TIM_DIV2) {
signal->reload_reg_buff[i] = r_count_tick_arr - 1;
} else {
signal->reload_reg_buff[i] = (uint32_t)r_int;
signal->reload_reg_buff[i] = r_count_tick_arr;
t_signal_rest -= T_TIM;
}
t_current += (signal->reload_reg_buff[i] + 1) * T_TIM;
}
}
bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
furi_assert(signal);
furi_assert(gpio);
@ -168,6 +170,4 @@ bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
LL_TIM_SetCounter(TIM2, 0);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
return true;
}

View File

@ -10,7 +10,7 @@ typedef struct {
bool start_level;
uint32_t edge_cnt;
uint32_t edges_max_cnt;
float* edge_timings;
uint32_t* edge_timings;
uint32_t* reload_reg_buff;
} DigitalSignal;
@ -20,10 +20,12 @@ void digital_signal_free(DigitalSignal* signal);
bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b);
void digital_signal_prepare_arr(DigitalSignal* signal);
bool digital_signal_get_start_level(DigitalSignal* signal);
uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal);
float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num);
uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num);
bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio);
void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio);

View File

@ -537,25 +537,23 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
// Read command
while(!command_processed) {
if(!is_encrypted) {
// Read first frame
tx_rx->tx_bits = 0;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
}
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) {
FURI_LOG_D(
TAG, "Error in tx rx. Tx :%d bits, Rx: %d bits", tx_rx->tx_bits, tx_rx->rx_bits);
break;
}
if(!is_encrypted) {
memcpy(plain_data, tx_rx->rx_data, tx_rx->rx_bits / 8);
} else {
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) {
FURI_LOG_D(
TAG,
"Error in tx rx. Tx :%d bits, Rx: %d bits",
tx_rx->tx_bits,
tx_rx->rx_bits);
break;
}
mf_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data);
}
// TODO Check crc
if(plain_data[0] == 0x50 && plain_data[1] == 00) {
if(plain_data[0] == 0x50 && plain_data[1] == 0x00) {
FURI_LOG_T(TAG, "Halt received");
furi_hal_nfc_listen_sleep();
command_processed = true;
break;
} else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) {
@ -564,11 +562,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
uint8_t sector_trailer_block = mf_classic_get_sector_trailer(block);
MfClassicSectorTrailer* sector_trailer =
(MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value;
if(plain_data[0] == 0x61) {
key = nfc_util_bytes2num(sector_trailer->key_b, 6);
if(plain_data[0] == 0x60) {
key = nfc_util_bytes2num(sector_trailer->key_a, 6);
access_key = MfClassicKeyA;
} else {
key = nfc_util_bytes2num(sector_trailer->key_a, 6);
key = nfc_util_bytes2num(sector_trailer->key_b, 6);
access_key = MfClassicKeyB;
}
@ -581,8 +579,12 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
if(!is_encrypted) {
crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0);
memcpy(tx_rx->tx_data, nt, sizeof(nt));
tx_rx->tx_parity[0] = 0;
for(size_t i = 0; i < sizeof(nt); i++) {
tx_rx->tx_parity[0] |= nfc_util_odd_parity8(nt[i]) << (7 - i);
}
tx_rx->tx_bits = sizeof(nt) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxRaw;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
} else {
mf_crypto1_encrypt(
&emulator->crypto,

View File

@ -8,7 +8,10 @@
#define NFCA_CRC_INIT (0x6363)
#define NFCA_F_SIG (13560000.0)
#define NFCA_T_SIG (1.0 / NFCA_F_SIG)
#define T_SIG 7374 //73.746ns*100
#define T_SIG_x8 58992 //T_SIG*8
#define T_SIG_x8_x8 471936 //T_SIG*8*8
#define T_SIG_x8_x9 530928 //T_SIG*8*9
#define NFCA_SIGNAL_MAX_EDGES (1350)
@ -64,15 +67,15 @@ static void nfca_add_bit(DigitalSignal* signal, bool bit) {
if(bit) {
signal->start_level = true;
for(size_t i = 0; i < 7; i++) {
signal->edge_timings[i] = 8 * NFCA_T_SIG;
signal->edge_timings[i] = T_SIG_x8;
}
signal->edge_timings[7] = 9 * 8 * NFCA_T_SIG;
signal->edge_timings[7] = T_SIG_x8_x9;
signal->edge_cnt = 8;
} else {
signal->start_level = false;
signal->edge_timings[0] = 8 * 8 * NFCA_T_SIG;
signal->edge_timings[0] = T_SIG_x8_x8;
for(size_t i = 1; i < 9; i++) {
signal->edge_timings[i] = 8 * NFCA_T_SIG;
signal->edge_timings[i] = T_SIG_x8;
}
signal->edge_cnt = 9;
}