From 1d4ce4e78ac4f1339379352d9dd6cd4e318642f8 Mon Sep 17 00:00:00 2001 From: "g3gg0.de" Date: Sat, 4 Feb 2023 01:43:04 +0100 Subject: [PATCH] scale NfcV frequency a bit, add echo mode, fix signal level at the end --- lib/nfc/protocols/nfcv.c | 118 ++++++++++++++++++++++++++++++--------- lib/nfc/protocols/nfcv.h | 9 ++- 2 files changed, 100 insertions(+), 27 deletions(-) diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index e18552340..e7b6c761a 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -270,16 +270,12 @@ bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_ return false; } success &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); - for(size_t i = 0; i < slowdown * 24; i++) { + for(size_t i = 0; i < slowdown * 23; i++) { success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); } - for(size_t i = 0; i < slowdown * 3; i++) { - success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); - } - /* add extra silence */ - success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_unmod); - if(!success) { - return false; + /* we don't want to add the last level as we just want a transition to "unmodulated" again */ + for(size_t i = 0; i < slowdown; i++) { + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_half_pulse); } } return success; @@ -327,6 +323,18 @@ bool nfcv_emu_alloc(NfcVData* nfcv_data) { nfcv_data->emu_air.nfcv_resp_pulse->edge_cnt = 2; } + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + /* modulated fc/32 or fc/8 pulse as building block */ + nfcv_data->emu_air.nfcv_resp_half_pulse = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + return false; + } + nfcv_data->emu_air.nfcv_resp_half_pulse->start_level = true; + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_cnt = 1; + } + bool success = true; success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); @@ -387,6 +395,9 @@ void nfcv_emu_free(NfcVData* nfcv_data) { if(nfcv_data->emu_air.nfcv_resp_pulse) { digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); } + if(nfcv_data->emu_air.nfcv_resp_half_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_half_pulse); + } if(nfcv_data->emu_air.nfcv_signal) { digital_sequence_free(nfcv_data->emu_air.nfcv_signal); } @@ -397,6 +408,7 @@ void nfcv_emu_free(NfcVData* nfcv_data) { nfcv_data->frame = NULL; nfcv_data->emu_air.nfcv_resp_unmod = NULL; nfcv_data->emu_air.nfcv_resp_pulse = NULL; + nfcv_data->emu_air.nfcv_resp_half_pulse = NULL; nfcv_data->emu_air.nfcv_signal = NULL; nfcv_data->emu_air.reader_signal = NULL; @@ -490,6 +502,18 @@ void nfcv_emu_handle_packet( return; } + if(nfcv_data->echo_mode) { + nfcv_emu_send( + tx_rx, + nfcv_data, + nfcv_data->frame, + nfcv_data->frame_length, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + return; + } + /* parse the frame data for the upcoming part 3 handling */ ctx->flags = nfcv_data->frame[0]; ctx->command = nfcv_data->frame[1]; @@ -500,7 +524,7 @@ void nfcv_emu_handle_packet( ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0); ctx->response_flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof; - ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4130); + ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4380); if(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) { ctx->response_flags |= NfcVSendFlagsHighRate; @@ -509,6 +533,11 @@ void nfcv_emu_handle_packet( ctx->response_flags |= NfcVSendFlagsTwoSubcarrier; } + if(ctx->payload_offset + 2 > nfcv_data->frame_length) { + FURI_LOG_D(TAG, "command 0x%02X, but packet is too short", ctx->command); + return; + } + /* standard behavior is implemented */ if(ctx->addressed) { uint8_t* address = &nfcv_data->frame[ctx->address_offset]; @@ -681,11 +710,7 @@ void nfcv_emu_handle_packet( blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; } - if(block + blocks > nfcv_data->block_num) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - nfcv_emu_send( - tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); - } else { + if(block + blocks <= nfcv_data->block_num) { uint8_t buffer_pos = 0; ctx->response_buffer[buffer_pos++] = ISO15693_NOERROR; @@ -719,31 +744,30 @@ void nfcv_emu_handle_packet( case ISO15693_WRITE_MULTI_BLOCK: case ISO15693_WRITEBLOCK: { - uint8_t block = nfcv_data->frame[ctx->payload_offset]; uint8_t blocks = 1; - uint8_t data_pos = 1; + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t data_pos = ctx->payload_offset + 1; if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { - blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + blocks = nfcv_data->frame[data_pos] + 1; data_pos++; } - uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos]; + uint8_t* data = &nfcv_data->frame[data_pos]; uint32_t data_len = nfcv_data->block_size * blocks; - if(block + blocks > nfcv_data->block_num || - ctx->payload_offset + data_len + 2 > nfcv_data->frame_length) { - ctx->response_buffer[0] = ISO15693_ERROR_CMD_NOT_REC; - } else { + if((block + blocks) <= nfcv_data->block_num && + (data_pos + data_len + 2) == nfcv_data->frame_length) { ctx->response_buffer[0] = ISO15693_NOERROR; memcpy( &nfcv_data->data[nfcv_data->block_size * block], - &nfcv_data->frame[ctx->payload_offset + data_pos], + &nfcv_data->frame[data_pos], data_len); nfcv_data->modified = true; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); } - nfcv_emu_send( - tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) { snprintf( @@ -782,6 +806,27 @@ void nfcv_emu_handle_packet( break; } + case ISO15693_CUST_ECHO_MODE: { + ctx->response_buffer[0] = ISO15693_NOERROR; + nfcv_data->echo_mode = true; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO mode"); + break; + } + + case ISO15693_CUST_ECHO_DATA: { + nfcv_emu_send( + tx_rx, + nfcv_data, + &nfcv_data->frame[ctx->payload_offset], + nfcv_data->frame_length - ctx->payload_offset - 2, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + break; + } + default: snprintf( nfcv_data->last_command, @@ -1112,6 +1157,8 @@ bool nfcv_emu_loop( uint32_t byte_value = 0; uint32_t bits_received = 0; uint32_t timeout = timeout_ms * 1000; + uint32_t sof_timestamp = 0; + uint32_t eof_timestamp = 0; bool wait_for_pulse = false; if(!nfcv_data->ready) { @@ -1153,6 +1200,7 @@ bool nfcv_emu_loop( frame_state = NFCV_FRAME_STATE_SOF2; } else { frame_state = NFCV_FRAME_STATE_SOF1; + sof_timestamp = timestamp; break; } break; @@ -1186,6 +1234,7 @@ bool nfcv_emu_loop( break; } else if(periods == 2) { frame_state = NFCV_FRAME_STATE_EOF; + eof_timestamp = timestamp; break; } @@ -1226,6 +1275,7 @@ bool nfcv_emu_loop( periods_previous = 0; } else if(periods == 2) { frame_state = NFCV_FRAME_STATE_EOF; + eof_timestamp = timestamp; break; } else { frame_state = NFCV_FRAME_STATE_RESET; @@ -1259,6 +1309,24 @@ bool nfcv_emu_loop( tx_rx->sniff_rx(nfcv_data->frame, frame_pos * 8, false, tx_rx->sniff_context); } nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + + + /* determine readers fc by analyzing transmission duration */ + uint32_t duration = eof_timestamp - sof_timestamp; + float fc_1024 = (4.0f * duration) / (4 * (frame_pos * 4 + 1) + 1); + /* it should be 1024/fc in 64MHz ticks */ + float fact = fc_1024 / ((1000000.0f * 64.0f * 1024.0f) / NFCV_FC); + FURI_LOG_D(TAG, "1024/fc: %f -> %f %%", fc_1024, fact * 100); +#if 0 + if(fact > 0.99f && fact < 1.01f) { + static float avg_err = 0.0f; + + avg_err = (avg_err * 15.0f + (fact - 1.0f)) / 16.0f; + FURI_LOG_D(TAG, " ==> set %f %%", (1.0f + avg_err) * 100); + digital_sequence_timebase_correction(nfcv_data->emu_air.nfcv_signal, 1.0f + avg_err); + } +#endif + pulse_reader_start(nfcv_data->emu_air.reader_signal); ret = true; } else { diff --git a/lib/nfc/protocols/nfcv.h b/lib/nfc/protocols/nfcv.h index f1d6e0127..56e37f525 100644 --- a/lib/nfc/protocols/nfcv.h +++ b/lib/nfc/protocols/nfcv.h @@ -12,7 +12,7 @@ extern "C" { #endif -#define NFCV_FC (13560000.0f) /* MHz */ +#define NFCV_FC (13560000.0f / 0.9998f) /* MHz */ #define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */ #define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */ @@ -37,7 +37,7 @@ extern "C" { /* helpers to calculate the send time based on DWT->CYCCNT */ #define NFCV_FDT_USEC(usec) (usec * 64) -#define NFCV_FDT_FC(ticks) (ticks * 6400 / 1356) +#define NFCV_FDT_FC(ticks) ((ticks)*6400 / 1356) #define NFCV_FRAME_STATE_SOF1 0 #define NFCV_FRAME_STATE_SOF2 1 @@ -73,6 +73,9 @@ extern "C" { #define ISO15693_GET_SYSTEM_INFO 0x2B #define ISO15693_READ_MULTI_SECSTATUS 0x2C +#define ISO15693_CUST_ECHO_MODE 0xDE +#define ISO15693_CUST_ECHO_DATA 0xDF + /* ISO15693 RESPONSE ERROR CODES */ #define ISO15693_NOERROR 0x00 #define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported @@ -139,6 +142,7 @@ typedef struct { typedef struct { PulseReader* reader_signal; DigitalSignal* nfcv_resp_pulse; /* pulse length, fc/32 */ + DigitalSignal* nfcv_resp_half_pulse; /* half pulse length, fc/32 */ DigitalSignal* nfcv_resp_unmod; /* unmodulated length 256/fc */ NfcVEmuAirSignals signals_high; NfcVEmuAirSignals signals_low; @@ -185,6 +189,7 @@ typedef struct { bool modified; bool ready; + bool echo_mode; /* specfic variant infos */ NfcVSubtype sub_type;