diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ea96eac8c..bb092b7ff 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,7.28,, +Version,+,7.33,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -669,7 +669,6 @@ Function,-,coshl,long double,long double Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" -Function,-,crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" Function,-,crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" Function,-,crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" Function,-,crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" @@ -708,13 +707,13 @@ Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMes Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" Function,-,difftime,double,"time_t, time_t" Function,-,digital_sequence_add,void,"DigitalSequence*, uint8_t" -Function,-,digital_sequence_alloc,DigitalSequence*,uint32_t +Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" Function,-,digital_sequence_clear,void,DigitalSequence* Function,-,digital_sequence_free,void,DigitalSequence* -Function,-,digital_sequence_send,_Bool,"DigitalSequence*, const GpioPin*" -Function,-,digital_sequence_send_signal,_Bool,DigitalSignal* +Function,-,digital_sequence_send,_Bool,DigitalSequence* Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*" Function,-,digital_signal_add,void,"DigitalSignal*, uint32_t" +Function,-,digital_signal_add_pulse,void,"DigitalSignal*, uint32_t, _Bool" Function,-,digital_signal_alloc,DigitalSignal*,uint32_t Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*" Function,-,digital_signal_free,void,DigitalSignal* @@ -1166,6 +1165,7 @@ Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t Function,+,furi_hal_nfc_exit_sleep,void, Function,+,furi_hal_nfc_field_off,void, Function,+,furi_hal_nfc_field_on,void, +Function,-,furi_hal_nfc_gen_bitstream,void,"FuriHalNfcTxRxContext*, uint8_t*, size_t" Function,-,furi_hal_nfc_init,void, Function,+,furi_hal_nfc_is_busy,_Bool, Function,+,furi_hal_nfc_is_init,_Bool, @@ -1967,6 +1967,11 @@ Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* +Function,-,nfca_trans_rx_continue,void,NfcaTransRxState* +Function,-,nfca_trans_rx_deinit,void,NfcaTransRxState* +Function,-,nfca_trans_rx_init,void,NfcaTransRxState* +Function,-,nfca_trans_rx_loop,_Bool,"NfcaTransRxState*, uint32_t" +Function,-,nfca_trans_rx_pause,void,NfcaTransRxState* Function,-,nfcv_emu_deinit,void, Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*" Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcDevData*, NfcVData*, uint32_t" diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 54a48b429..e18fa3819 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -523,6 +523,7 @@ bool furi_hal_nfc_emulate_nfca( return true; } + static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { furi_assert(tx_rx->nfca_signal); @@ -536,7 +537,7 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ // 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); + digital_sequence_send(tx_rx->nfca_signal->tx_signal); FURI_CRITICAL_EXIT(); // Configure gpio back to SPI and exit transparent @@ -601,6 +602,94 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_ return ret; } +static bool furi_hal_nfc_fully_transparent_raw_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { + furi_assert(tx_rx); + + bool received = false; + + tx_rx->rx_bits = 0; + + if(tx_rx->tx_bits) { + nfca_trans_rx_pause(&tx_rx->nfca_trans_state); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + digital_sequence_send(tx_rx->nfca_signal->tx_signal); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + nfca_trans_rx_continue(&tx_rx->nfca_trans_state); + + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); + } + } + + if(timeout_ms) { + tx_rx->nfca_trans_state.bits_received = 0; + received = nfca_trans_rx_loop(&tx_rx->nfca_trans_state, timeout_ms); + + if(received) { + if(tx_rx->nfca_trans_state.bits_received > 7) { + tx_rx->rx_bits = tx_rx->nfca_trans_state.bits_received/9 * 8; + for(size_t pos = 0; pos < tx_rx->rx_bits/8; pos++) { + tx_rx->rx_data[pos] = tx_rx->nfca_trans_state.frame_data[pos]; + } + } else { + tx_rx->rx_bits = tx_rx->nfca_trans_state.bits_received; + tx_rx->rx_data[0] = tx_rx->nfca_trans_state.frame_data[0] & ~(0xFF << tx_rx->rx_bits); + } + + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context); + } + } + } + + return received; +} + +static bool furi_hal_nfc_fully_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { + furi_assert(tx_rx); + + bool received = false; + + tx_rx->rx_bits = 0; + + if(tx_rx->tx_bits) { + nfca_trans_rx_pause(&tx_rx->nfca_trans_state); + FURI_CRITICAL_ENTER(); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits, tx_rx->tx_parity); + digital_sequence_send(tx_rx->nfca_signal->tx_signal); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + FURI_CRITICAL_EXIT(); + nfca_trans_rx_continue(&tx_rx->nfca_trans_state); + + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(tx_rx->tx_data, tx_rx->tx_bits, false, tx_rx->sniff_context); + } + } + + if(timeout_ms) { + tx_rx->nfca_trans_state.bits_received = 0; + received = nfca_trans_rx_loop(&tx_rx->nfca_trans_state, timeout_ms); + + if(received) { + if(tx_rx->nfca_trans_state.bits_received > 7) { + tx_rx->rx_bits = tx_rx->nfca_trans_state.bits_received/9 * 8; + memcpy(tx_rx->rx_data, tx_rx->nfca_trans_state.frame_data, tx_rx->nfca_trans_state.bits_received/9); + } else { + tx_rx->rx_bits = tx_rx->nfca_trans_state.bits_received; + tx_rx->rx_data[0] = tx_rx->nfca_trans_state.frame_data[0] & ~(0xFF << tx_rx->rx_bits); + } + + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(tx_rx->rx_data, tx_rx->rx_bits, false, tx_rx->sniff_context); + } + } + } + + return received; +} + + static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { uint32_t flags = 0; @@ -674,9 +763,39 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity( return curr_byte * 8; } +static uint8_t furi_hal_nfc_gen_parity(uint8_t value) { + value ^= (value >> 4); + value ^= (value >> 2); + value ^= (value >> 1); + + return (value ^ 1) & 1; +} + +void furi_hal_nfc_gen_bitstream(FuriHalNfcTxRxContext* tx_rx, uint8_t *buffer, size_t len) { + for(size_t pos = 0; pos < len; pos++) { + uint32_t parity_bit_num = pos % 8; + uint8_t bit = furi_hal_nfc_gen_parity(buffer[pos]); + + tx_rx->tx_data[pos] = buffer[pos]; + tx_rx->tx_parity[pos / 8] &= ~(1 << (7 - parity_bit_num)); + tx_rx->tx_parity[pos / 8] |= bit << (7 - parity_bit_num); + } + tx_rx->tx_bits = len * 8; +} + bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { furi_assert(tx_rx); + if(tx_rx->tx_rx_type == FuriHalNfcTxRxFullyRawTransparent) { + return furi_hal_nfc_fully_transparent_raw_tx_rx(tx_rx, timeout_ms); + } + if(tx_rx->tx_rx_type == FuriHalNfcTxRxFullyTransparent) { + return furi_hal_nfc_fully_transparent_tx_rx(tx_rx, timeout_ms); + } + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTransparent) { + return furi_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms); + } + ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; uint8_t temp_tx_buff[FURI_HAL_NFC_DATA_BUFF_SIZE] = {}; @@ -684,9 +803,7 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { uint8_t* temp_rx_buff = NULL; uint16_t* temp_rx_bits = NULL; - if(tx_rx->tx_rx_type == FuriHalNfcTxRxTransparent) { - return furi_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms); - } + //FURI_LOG_D(TAG, "furi_hal_nfc_tx_rx %u", tx_rx->tx_rx_type); // Prepare data for FIFO if necessary uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type); diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 1363a1572..12ce91523 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -14,6 +14,7 @@ extern "C" { #endif #include #include +#include #define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) @@ -46,6 +47,8 @@ typedef enum { FuriHalNfcTxRxTypeRaw, FuriHalNfcTxRxTypeRxRaw, FuriHalNfcTxRxTransparent, + FuriHalNfcTxRxFullyRawTransparent, + FuriHalNfcTxRxFullyTransparent } FuriHalNfcTxRxType; typedef bool (*FuriHalNfcEmulateCallback)( @@ -91,6 +94,8 @@ typedef struct { uint16_t rx_bits; FuriHalNfcTxRxType tx_rx_type; NfcaSignal* nfca_signal; + NfcaTransRxState nfca_trans_state; + bool nfca_trans_initialized; FuriHalNfcTxRxSniffCallback sniff_tx; FuriHalNfcTxRxSniffCallback sniff_rx; @@ -425,6 +430,9 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( void furi_hal_nfc_ll_poll(); + +void furi_hal_nfc_gen_bitstream(FuriHalNfcTxRxContext* tx_rx, uint8_t *buffer, size_t len); + #ifdef __cplusplus } #endif diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 8e6cbae62..c7e8bbca5 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -2,18 +2,16 @@ #include #include -#include -#include #include #define TAG "DigitalSignal" -#pragma GCC optimize("O3,unroll-loops,Ofast") #define F_TIM (64000000.0) #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; @@ -23,6 +21,26 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->reload_reg_entries = 0; signal->reload_reg_remainder = 0; + + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_gpio.NbData = 2; + signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->ARR); + signal->dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + signal->dma_config_timer.Mode = LL_DMA_MODE_NORMAL; + signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + signal->dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; return signal; } @@ -144,7 +162,6 @@ void digital_signal_prepare(DigitalSignal* signal) { } } - static void digital_signal_stop_dma() { LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); @@ -164,39 +181,14 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) { return false; } - LL_DMA_InitTypeDef dma_config_gpio = {}; - LL_DMA_InitTypeDef dma_config_timer = {}; - - dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff; - dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->BSRR); - dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; - dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config_gpio.NbData = 2; - dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; - - // Init timer arr register buffer and DMA channel - dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; - dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->ARR); - dma_config_timer.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dma_config_timer.Mode = LL_DMA_MODE_NORMAL; - dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config_timer.NbData = signal->reload_reg_entries; - dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; - dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; - - digital_signal_stop_dma(); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff; + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->BSRR); + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff; + signal->dma_config_timer.NbData = signal->reload_reg_entries; /* set up DMA channel 1 and 2 for GPIO and timer copy operations */ - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config_gpio); - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config_timer); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &signal->dma_config_gpio); + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer); /* enable both DMA channels */ LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); @@ -251,9 +243,6 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { signal->edge_cnt--; } - - - void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { sequence->signals_size = size; sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); @@ -270,13 +259,8 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { DigitalSequence* sequence = malloc(sizeof(DigitalSequence)); - //gpio = &gpio_ext_pb2; - //furi_hal_gpio_init(&gpio_ext_pb2, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - //furi_hal_gpio_init(&gpio_ext_pc3, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - //furi_hal_gpio_write(&gpio_ext_pb2, false); - //furi_hal_gpio_write(&gpio_ext_pc3, false); - sequence->gpio = gpio; + sequence->bake = false; digital_sequence_alloc_signals(sequence, 32); digital_sequence_alloc_sequence(sequence, size); @@ -380,7 +364,6 @@ static bool digital_sequence_send_signal(DigitalSignal* signal) { digital_signal_setup_timer(); digital_signal_start_timer(); } else { - /* configure next polarities and timings */ digital_signal_update_dma(signal); } @@ -425,6 +408,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { } int32_t remainder = 0; + FURI_CRITICAL_ENTER(); for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { uint8_t signal_index = sequence->sequence[pos]; @@ -432,9 +416,7 @@ bool digital_sequence_send(DigitalSequence* sequence) { if(!sig) { FURI_LOG_D(TAG, "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", signal_index, pos); - digital_signal_stop_timer(); - digital_signal_stop_dma(); - return false; + break; } /* when we are too late more than half a tick, make the first edge temporarily longer */ @@ -461,11 +443,10 @@ bool digital_sequence_send(DigitalSequence* sequence) { bool success = digital_sequence_send_signal(sig); if(!success) { - digital_signal_stop_timer(); - digital_signal_stop_dma(); - return false; + break; } } + FURI_CRITICAL_EXIT(); while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { } diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 189ad9198..4d25b90c2 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -5,6 +5,8 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -27,6 +29,8 @@ typedef struct { uint32_t reload_reg_remainder; uint32_t gpio_buff[2]; const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_gpio; + LL_DMA_InitTypeDef dma_config_timer; } DigitalSignal; typedef struct { diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 1538b2177..eff4d8d39 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -857,6 +857,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { } void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; MfClassicEmulator emulator = { @@ -870,11 +871,67 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { rfal_platform_spi_acquire(); furi_hal_nfc_listen_start(nfc_data); + nfca_trans_rx_init(&tx_rx.nfca_trans_state); + + tx_rx.tx_rx_type = FuriHalNfcTxRxFullyTransparent; + + uint8_t tx_buffer_aticoll[32]; + memcpy(tx_buffer_aticoll, &nfc_data->uid, 4); + nfca_append_crc16(tx_buffer_aticoll, 4); + + uint8_t tx_buffer_ack[8]; + tx_buffer_ack[0] = nfc_data->sak; + nfca_append_crc16(tx_buffer_ack, 1); + while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { - if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { + tx_rx.tx_bits = 0; + tx_rx.rx_bits = 0; + if(furi_hal_nfc_tx_rx(&tx_rx, 300)) { + FURI_LOG_D(TAG, "Command: %02X", tx_rx.rx_data[0]); + + if(tx_rx.rx_bits == 7) { + switch(tx_rx.rx_data[0]) { + /* MAGIC WUPC1 */ + case 0x40: + continue; + + /* WUPA */ + case 0x52: + furi_hal_nfc_gen_bitstream(&tx_rx, nfc_data->atqa, 2); + furi_hal_nfc_tx_rx(&tx_rx, 0); + continue; + } + } + + if(tx_rx.rx_bits >= 16) { + switch(tx_rx.rx_data[0]) { + /* SELECT */ + case 0x93: + switch(tx_rx.rx_data[1]) { + /* ANTICOLL */ + case 0x20: + furi_hal_nfc_gen_bitstream(&tx_rx, tx_buffer_aticoll, 6); + furi_hal_nfc_tx_rx(&tx_rx, 0); + continue; + + /* SELECT UID */ + case 0x70: + furi_hal_nfc_gen_bitstream(&tx_rx, tx_buffer_ack, 3); + furi_hal_nfc_tx_rx(&tx_rx, 0); + continue; + } + break; + + /* HALS */ + case 0x50: + continue; + } + } + mf_classic_emulator(&emulator, &tx_rx); } } + if(emulator.data_changed) { nfc_worker->dev_data->mf_classic_data = emulator.data; if(nfc_worker->callback) { @@ -883,9 +940,12 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { emulator.data_changed = false; } - nfca_signal_free(nfca_signal); + nfca_trans_rx_deinit(&tx_rx.nfca_trans_state); rfal_platform_spi_release(); + + + nfca_signal_free(nfca_signal); } void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index 67fdcdc3d..ef1983e81 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 10a22b033..094ea7507 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -763,6 +763,10 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE]; MfClassicKey access_key = MfClassicKeyA; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; + + FURI_LOG_D(TAG, "Starting mf_classic_emulator"); + // Read command while(!command_processed) { if(!is_encrypted) { @@ -791,7 +795,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } if(plain_data[0] == 0x50 && plain_data[1] == 0x00) { - furi_hal_nfc_listen_sleep(); + //furi_hal_nfc_listen_sleep(); command_processed = true; break; } else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) { @@ -824,7 +828,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ 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 = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; } else { crypto1_encrypt( &emulator->crypto, @@ -834,7 +838,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = sizeof(nt) * 8; - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; } if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { FURI_LOG_E(TAG, "Error in NT exchange?"); @@ -881,7 +885,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = sizeof(responce) * 8; - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; is_encrypted = true; } else if(is_encrypted && plain_data[0] == 0x30) { @@ -912,7 +916,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } else { tx_rx->tx_data[0] = nack; } - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; tx_rx->tx_bits = 4; furi_hal_nfc_tx_rx(tx_rx, 300); break; @@ -928,7 +932,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = 18 * 8; - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; } else if(is_encrypted && plain_data[0] == 0xA0) { uint8_t block = plain_data[1]; if(block > mf_classic_get_total_block_num(emulator->data.type)) { @@ -937,7 +941,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // Send ACK uint8_t ack = 0x0A; crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; tx_rx->tx_bits = 4; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; @@ -972,7 +976,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // Send ACK ack = 0x0A; crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; tx_rx->tx_bits = 4; } else { FURI_LOG_T(TAG, "%02X unknown received", plain_data[0]); @@ -989,7 +993,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ } else { tx_rx->tx_data[0] = nack; } - tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent; tx_rx->tx_bits = 4; furi_hal_nfc_tx_rx(tx_rx, 300); } diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca.c index 6d0fc20b3..328db012b 100644 --- a/lib/nfc/protocols/nfca.c +++ b/lib/nfc/protocols/nfca.c @@ -2,18 +2,27 @@ #include #include #include +#include +#include #define NFCA_CMD_RATS (0xE0U) #define NFCA_CRC_INIT (0x6363) #define NFCA_F_SIG (13560000.0) /* [Hz] NFC frequency */ -#define NFCA_F_SUB (NFCA_F_SIG / 16) /* [Hz] NFC subcarrier frequency fs/16 (847500 Hz) */ +#define NFCA_F_SUB (NFCA_F_SIG/16) /* [Hz] NFC subcarrier frequency fs/16 (847500 Hz) */ #define T_SUB (1000000000000.0f / NFCA_F_SUB) /* [ps] subcarrier period = 1/NFCA_F_SUB (1.18 µs) */ -#define T_SUB_PHASE (T_SUB / 2) /* [ps] a single subcarrier phase (590 µs) */ +#define T_SUB_PHASE (T_SUB/2) /* [ps] a single subcarrier phase (590 µs) */ #define NFCA_SIGNAL_MAX_EDGES (1350) +#define SEQ_SOF 0 +#define SEQ_BIT0 1 +#define SEQ_BIT1 2 +#define SEQ_EOF 3 +#define SEQ_IDLE 4 + + typedef struct { uint8_t cmd; uint8_t param; @@ -65,27 +74,32 @@ bool nfca_emulation_handler( static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) { for(uint8_t i = 0; i < 8; i++) { if(byte & (1 << i)) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1); } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_e); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0); } } if(parity) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1); } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_e); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0); } } static void nfca_add_modulation(DigitalSignal* signal, size_t phases) { for(size_t i = 0; i < phases; i++) { - bool modulated = (i % 2 == 0); - digital_signal_add_pulse(signal, DIGITAL_SIGNAL_PS(T_SUB_PHASE), modulated); + signal->edge_timings[signal->edge_cnt++] = DIGITAL_SIGNAL_PS(T_SUB_PHASE); } } static void nfca_add_silence(DigitalSignal* signal, size_t phases) { - digital_signal_add_pulse(signal, DIGITAL_SIGNAL_PS(phases*T_SUB_PHASE), false); + bool end_level = signal->start_level ^ ((signal->edge_cnt % 2) == 0); + + if((signal->edge_cnt == 0) || end_level) { + signal->edge_timings[signal->edge_cnt++] = DIGITAL_SIGNAL_PS(phases * T_SUB_PHASE); + } else { + signal->edge_timings[signal->edge_cnt - 1] += DIGITAL_SIGNAL_PS(phases * T_SUB_PHASE); + } } NfcaSignal* nfca_signal_alloc() { @@ -97,16 +111,29 @@ NfcaSignal* nfca_signal_alloc() { nfca_signal->seq_f = digital_signal_alloc(10); /* SEQ D has the first half modulated, used as SOF */ + nfca_signal->seq_d->start_level = true; nfca_add_modulation(nfca_signal->seq_d, 8); nfca_add_silence(nfca_signal->seq_d, 8); /* SEQ E has the second half modulated */ + nfca_signal->seq_e->start_level = false; nfca_add_silence(nfca_signal->seq_e, 8); nfca_add_modulation(nfca_signal->seq_e, 8); /* SEQ F is just no modulation, used as EOF */ + nfca_signal->seq_f->start_level = false; nfca_add_silence(nfca_signal->seq_f, 16); - nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES); + + nfca_signal->tx_signal = digital_sequence_alloc(NFCA_SIGNAL_MAX_EDGES, &gpio_spi_r_mosi); + + /* we are dealing with shorter sequences, enable bake-before-sending */ + //nfca_signal->tx_signal->bake = true; + + digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_SOF, nfca_signal->seq_d); + digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_BIT0, nfca_signal->seq_e); + digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_BIT1, nfca_signal->seq_d); + digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_EOF, nfca_signal->seq_f); + digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_IDLE, nfca_signal->seq_f); return nfca_signal; } @@ -117,7 +144,7 @@ void nfca_signal_free(NfcaSignal* nfca_signal) { digital_signal_free(nfca_signal->seq_d); digital_signal_free(nfca_signal->seq_e); digital_signal_free(nfca_signal->seq_f); - digital_signal_free(nfca_signal->tx_signal); + digital_sequence_free(nfca_signal->tx_signal); free(nfca_signal); } @@ -126,21 +153,18 @@ void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, u furi_assert(data); furi_assert(parity); - nfca_signal->tx_signal->edge_cnt = 0; - nfca_signal->tx_signal->start_level = true; + digital_sequence_clear(nfca_signal->tx_signal); - // Start of frame - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d); + /* add some idle bit times before SOF in case the GPIO was active */ + digital_sequence_add(nfca_signal->tx_signal, SEQ_IDLE); + digital_sequence_add(nfca_signal->tx_signal, SEQ_SOF); if(bits < 8) { for(size_t i = 0; i < bits; i++) { if(FURI_BIT(data[0], i)) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1); } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_e); + digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0); } } } else { @@ -148,5 +172,6 @@ void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, u nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07)))); } } - digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); + + digital_sequence_add(nfca_signal->tx_signal, SEQ_EOF); } diff --git a/lib/nfc/protocols/nfca.h b/lib/nfc/protocols/nfca.h index 7acd1fb95..a4928a3eb 100644 --- a/lib/nfc/protocols/nfca.h +++ b/lib/nfc/protocols/nfca.h @@ -9,7 +9,7 @@ typedef struct { DigitalSignal* seq_d; /* sequence D, modulation with subcarrier during first half */ DigitalSignal* seq_e; /* sequence E, modulation with subcarrier during second half */ DigitalSignal* seq_f; /* sequence F, no modulation at all */ - DigitalSignal* tx_signal; + DigitalSequence* tx_signal; } NfcaSignal; uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len); @@ -27,3 +27,4 @@ NfcaSignal* nfca_signal_alloc(); void nfca_signal_free(NfcaSignal* nfca_signal); void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity); + diff --git a/lib/nfc/protocols/nfca_emu.c b/lib/nfc/protocols/nfca_trans_rx.c similarity index 58% rename from lib/nfc/protocols/nfca_emu.c rename to lib/nfc/protocols/nfca_trans_rx.c index 6040bad14..3f8047272 100644 --- a/lib/nfc/protocols/nfca_emu.c +++ b/lib/nfc/protocols/nfca_trans_rx.c @@ -10,16 +10,13 @@ #include #include -#include "nfca_emu.h" +#include "nfca_trans_rx.h" -#define TAG "NfcA-emu" +#define TAG "NfcA-trans-rx" - - -void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data) { - //nfca_emu_alloc(); - rfal_platform_spi_acquire(); +void nfca_trans_rx_init(NfcaTransRxState *state) { + FURI_LOG_D(TAG, "Starting NfcA transparent rx"); st25r3916ExecuteCommand(ST25R3916_CMD_STOP); st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3); @@ -28,11 +25,6 @@ void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data) { furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); - FURI_LOG_D(TAG, "Starting NfcA emulation"); - FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X", - nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], - nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]); - /* allocate a 512 edge buffer, more than enough */ state->reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512); /* timebase shall be 1 ns */ @@ -46,20 +38,30 @@ void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data) { state->valid_frame = false; } -void nfca_emu_deinit(NfcaEmuState *state) { +void nfca_trans_rx_deinit(NfcaTransRxState *state) { furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); - rfal_platform_spi_release(); pulse_reader_free(state->reader_signal); } +void nfca_trans_rx_pause(NfcaTransRxState *state) { + pulse_reader_stop(state->reader_signal); +} -void nfca_bit_received(NfcaEmuState *state, uint8_t bit) { +void nfca_trans_rx_continue(NfcaTransRxState *state) { + pulse_reader_start(state->reader_signal); +} + +static void nfca_bit_received(NfcaTransRxState *state, uint8_t bit) { /* According to ISO14443-3 short frames have 7 bits and standard 9 bits per byte, where the 9th bit is odd parity. Data is transmitted LSB first. */ uint32_t byte_num = (state->bits_received / 9); uint32_t bit_num = (state->bits_received % 9); + if(byte_num >= NFCA_FRAME_LENGTH) { + return; + } + if(bit_num == 8) { uint32_t parity_value = 1 << (state->bits_received / 9); state->parity_bits &= ~parity_value; @@ -74,94 +76,97 @@ void nfca_bit_received(NfcaEmuState *state, uint8_t bit) { } -bool nfca_emu_loop(NfcaEmuState *state, FuriHalNfcDevData* nfc_data, uint32_t timeout_ms) { - furi_assert(nfc_data); +bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms) { + furi_assert(state); - bool ret = false; + state->valid_frame = false; + state->have_sof = false; + state->bits_received = 0; - while(!ret) { - uint32_t timeout_ns = timeout_ms * 1000; - uint32_t timeout = state->have_sof ? (4 * NFCA_TB) : timeout_ns; - uint32_t nsec = pulse_reader_receive(state->reader_signal, timeout); + bool done = false; + uint32_t timeout_us = timeout_ms * 1000; - bool eof = state->have_sof && nsec > 2*NFCA_TB; + while(!done) { + uint32_t nsec = pulse_reader_receive(state->reader_signal, timeout_us); - if(nsec != PULSE_READER_NO_EDGE) { - FURI_LOG_T(TAG, "pulse: %lu ns, frametime now: %ld", nsec, state->frame_time); + bool eof = state->have_sof && (nsec >= (2 * NFCA_TB)); + bool lost_pulse = false; + + if(state->have_sof && nsec == PULSE_READER_LOST_EDGE) { + nsec = NFCA_T1; + lost_pulse = true; + } else if(nsec == PULSE_READER_NO_EDGE) { + done = true; } if(IS_T1(nsec) || eof) { - FURI_LOG_T(TAG, " T1 pulse"); - + timeout_us = (3 * NFCA_TB) / 1000; if(!state->have_sof) { - FURI_LOG_T(TAG, " SOF"); state->frame_time = -(NFCA_TB - nsec); state->have_sof = true; state->valid_frame = false; state->bits_received = 0; + state->debug_pos = 0; + if(lost_pulse) { + state->frame_time -= nsec; + } continue; } if(state->frame_time > NFCA_TB_MIN) { - FURI_LOG_T(TAG, " Y"); state->frame_time -= NFCA_TB; nfca_bit_received(state, 0); } if(IS_ZERO(state->frame_time)) { - FURI_LOG_T(TAG, " Z"); state->frame_time = -(NFCA_TB - nsec); nfca_bit_received(state, 0); } else if(IS_TX(state->frame_time)) { - FURI_LOG_T(TAG, " X"); state->frame_time = -(NFCA_TX - nsec); nfca_bit_received(state, 1); } else { if(eof) { - FURI_LOG_T(TAG, " EOF"); state->have_sof = false; state->valid_frame = true; - ret = true; + done = true; } else { - FURI_LOG_D(TAG, " unexpected: %ld", state->frame_time); } } - - } else { if(!state->have_sof) { - state->frame_time = 0; + if(IS_TB(nsec)) { + state->frame_time = 0; + state->have_sof = true; + state->valid_frame = false; + state->bits_received = 0; + state->debug_pos = 0; + if(lost_pulse) { + state->frame_time -= nsec; + } + continue; + } else { + state->frame_time = 0; + } } else { state->frame_time += nsec; - FURI_LOG_T(TAG, " non-T1 pulse"); } } + + if(lost_pulse) { + state->frame_time -= nsec; + } } - if(ret) { - + if(state->valid_frame) { if(state->bits_received > 7) { /* a last 0-bit will look like a missing bit */ if((state->bits_received % 9) == 8) { nfca_bit_received(state, 0); state->bits_received++; } - FURI_LOG_D(TAG, "Received standard frame: %d bits (%d byte)", state->bits_received, state->bits_received/9); - - for(size_t pos = 0; pos < state->bits_received / 9; pos++) { - FURI_LOG_D(TAG, " 0x%02X", state->frame_data[pos]); - } - } else { - FURI_LOG_D(TAG, "Received short frame: %d bits", state->bits_received); - FURI_LOG_D(TAG, " 0x%02X", state->frame_data[0] & 0x7F); } - - /* we know that this code uses TIM2, so stop pulse reader */ - //pulse_reader_stop(state->reader_signal); - //nfcv_emu_handle_packet(nfc_data, nfcv_data, frame_payload, frame_pos); - //pulse_reader_start(state->reader_signal); } - return ret; + return state->valid_frame; } diff --git a/lib/nfc/protocols/nfca_emu.h b/lib/nfc/protocols/nfca_trans_rx.h similarity index 61% rename from lib/nfc/protocols/nfca_emu.h rename to lib/nfc/protocols/nfca_trans_rx.h index 8fc769da5..d9c5f9513 100644 --- a/lib/nfc/protocols/nfca_emu.h +++ b/lib/nfc/protocols/nfca_trans_rx.h @@ -12,6 +12,7 @@ /* assume fc/128 */ #define NFCA_FC (13560000.0f) /* MHz */ #define NFCA_FC_K ((uint32_t)(NFCA_FC/1000)) /* kHz */ +#define NFCA_T1 (28.0f / NFCA_FC * 1000000000) #define NFCA_T1_MIN (24.0f / NFCA_FC * 1000000000) #define NFCA_T1_MAX (41.0f / NFCA_FC * 1000000000) #define NFCA_TX (64.0f / NFCA_FC * 1000000000) /* 4.7198 µs */ @@ -21,15 +22,16 @@ #define NFCA_TB_MIN (0.80f * NFCA_TB) #define NFCA_TB_MAX (1.20f * NFCA_TB) -#define IS_T1(x) ((x)>=NFCA_T1_MIN && (x)<=NFCA_T1_MAX) -#define IS_TX(x) ((x)>=NFCA_TX_MIN && (x)<=NFCA_TX_MAX) -#define IS_TB(x) ((x)>=NFCA_TB_MIN && (x)<=NFCA_TB_MAX) -#define IS_ZERO(x) ((x)>=-NFCA_T1_MIN/2 && (x)<=NFCA_T1_MIN/2) +#define IS_T1(x) ((x)>=NFCA_T1_MIN && (x)<=NFCA_T1_MAX) +#define IS_TX(x) ((x)>=NFCA_TX_MIN && (x)<=NFCA_TX_MAX) +#define IS_TB(x) ((x)>=NFCA_TB_MIN && (x)<=NFCA_TB_MAX) +#define IS_ZERO(x) ((x)>=-NFCA_T1_MIN/2 && (x)<=NFCA_T1_MIN/2) #define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) #define DIGITAL_SIGNAL_UNIT_US (100000.0f) #define NFCA_FRAME_LENGTH 32 +#define NFCA_DEBUG_LENGTH 128 typedef struct { @@ -38,10 +40,15 @@ typedef struct { int32_t frame_time; size_t bits_received; uint8_t frame_data[NFCA_FRAME_LENGTH]; + uint32_t debug_buffer[NFCA_DEBUG_LENGTH]; + size_t debug_pos; uint32_t parity_bits; PulseReader *reader_signal; -} NfcaEmuState; +} NfcaTransRxState; -bool nfca_emu_loop(NfcaEmuState *state, FuriHalNfcDevData* nfc_data, uint32_t timeout_ms); -void nfca_emu_deinit(NfcaEmuState *state); -void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data); +bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms); +void nfca_trans_rx_deinit(NfcaTransRxState *state); +void nfca_trans_rx_init(NfcaTransRxState *state); + +void nfca_trans_rx_pause(NfcaTransRxState *state); +void nfca_trans_rx_continue(NfcaTransRxState *state); \ No newline at end of file diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index c5729c42a..f829bf831 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -2,10 +2,6 @@ #include #include #include -#include -#include -#include -#include #include "pulse_reader.h" @@ -36,6 +32,7 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { PulseReader* signal = malloc(sizeof(PulseReader)); signal->timer_buffer = malloc(size * sizeof(uint32_t)); + signal->gpio_buffer = malloc(size * sizeof(uint32_t)); signal->dma_channel = LL_DMA_CHANNEL_4; signal->gpio = gpio; signal->size = size; @@ -45,6 +42,26 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) { pulse_reader_set_timebase(signal, PulseReaderUnit64MHz); pulse_reader_set_bittime(signal, 1); + signal->dma_config_timer.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_timer.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT); + signal->dma_config_timer.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_timer.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t) signal->timer_buffer; + signal->dma_config_timer.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_timer.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_timer.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_timer.Priority = LL_DMA_PRIORITY_VERYHIGH; + + signal->dma_config_gpio.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; + signal->dma_config_gpio.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + signal->dma_config_gpio.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + signal->dma_config_gpio.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + signal->dma_config_gpio.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + signal->dma_config_gpio.Mode = LL_DMA_MODE_CIRCULAR; + signal->dma_config_gpio.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ + signal->dma_config_gpio.Priority = LL_DMA_PRIORITY_VERYHIGH; + return signal; } @@ -75,6 +92,7 @@ void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) { void pulse_reader_free(PulseReader* signal) { free(signal->timer_buffer); + free(signal->gpio_buffer); free(signal); } @@ -85,32 +103,21 @@ uint32_t pulse_reader_samples(PulseReader* signal) { } void pulse_reader_stop(PulseReader* signal) { - LL_DMA_DisableChannel(DMA1, signal->dma_channel); + LL_DMA_DisableChannel(DMA1, signal->dma_channel+1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); } void pulse_reader_start(PulseReader* signal) { - - memset(signal->timer_buffer, 0x00, signal->size * sizeof(uint32_t)); - /* configure DMA to read from a timer peripheral */ - LL_DMA_InitTypeDef dma_config = {}; - dma_config.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT); - dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; - dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; - dma_config.MemoryOrM2MDstAddress = (uint32_t) signal->timer_buffer; - dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - dma_config.Mode = LL_DMA_MODE_CIRCULAR; - dma_config.NbData = signal->size; /* executes LL_DMA_SetDataLength */ - dma_config.PeriphRequest = LL_DMAMUX_REQ_GENERATOR0; /* executes LL_DMA_SetPeriphRequest */ - dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + signal->dma_config_timer.NbData = signal->size; + + signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->IDR); + signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buffer; + signal->dma_config_gpio.NbData = signal->size; /* start counter */ - LL_TIM_DisableCounter(TIM2); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); @@ -118,8 +125,6 @@ void pulse_reader_start(PulseReader* signal) { LL_TIM_SetCounter(TIM2, 0); LL_TIM_EnableCounter(TIM2); - /* make sure request generation is disabled before modifying registers */ - LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); /* generator 0 gets fed by EXTI_LINEn */ LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); /* trigger on rising edge of the interrupt */ @@ -134,11 +139,13 @@ void pulse_reader_start(PulseReader* signal) { signal->pos = 0; signal->start_level = furi_hal_gpio_read(signal->gpio); signal->timer_value = TIM2->CNT; + signal->gpio_mask = signal->gpio->pin; /* now set up DMA with these settings */ - LL_DMA_DisableChannel(DMA1, signal->dma_channel); - LL_DMA_Init(DMA1, signal->dma_channel, &dma_config); + LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer); + LL_DMA_Init(DMA1, signal->dma_channel+1, &signal->dma_config_gpio); LL_DMA_EnableChannel(DMA1, signal->dma_channel); + LL_DMA_EnableChannel(DMA1, signal->dma_channel+1); } uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { @@ -154,8 +161,17 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { if(dma_pos != signal->pos) { uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value; + uint32_t last_gpio_value = signal->gpio_value; + signal->gpio_value = signal->gpio_buffer[signal->pos]; + + /* check if the GPIO really toggled. if not, we lost an edge :( */ + if(((last_gpio_value ^ signal->gpio_value) & signal->gpio_mask) != signal->gpio_mask) { + signal->gpio_value ^= signal->gpio_mask; + return PULSE_READER_LOST_EDGE; + } signal->timer_value = signal->timer_buffer[signal->pos]; + signal->pos++; signal->pos %= signal->size; @@ -183,7 +199,7 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { return PULSE_READER_NO_EDGE; } - furi_delay_ms(0); + //furi_delay_ms(0); } while(true); } diff --git a/lib/pulse_reader/pulse_reader.h b/lib/pulse_reader/pulse_reader.h index a53e666b0..886c9d9e7 100644 --- a/lib/pulse_reader/pulse_reader.h +++ b/lib/pulse_reader/pulse_reader.h @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -10,8 +14,9 @@ extern "C" { #endif -#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL -#define F_TIM2 64000000UL +#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL +#define PULSE_READER_LOST_EDGE 0xFFFFFFFEUL +#define F_TIM2 64000000UL /** * unit of the edge durations to return @@ -27,14 +32,19 @@ typedef enum { typedef struct { bool start_level; uint32_t* timer_buffer; + uint32_t* gpio_buffer; uint32_t size; uint32_t pos; uint32_t timer_value; + uint32_t gpio_value; + uint32_t gpio_mask; uint32_t unit_multiplier; uint32_t unit_divider; uint32_t bit_time; uint32_t dma_channel; const GpioPin* gpio; + LL_DMA_InitTypeDef dma_config_timer; + LL_DMA_InitTypeDef dma_config_gpio; } PulseReader;