diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 80d8c6984..676e61b0c 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -14,6 +14,9 @@ #include +#include +#include + static void nfc_cli_print_usage() { printf("Usage:\r\n"); @@ -23,10 +26,6 @@ static void nfc_cli_print_usage() { printf("\temulate\t - emulate predefined nfca card\r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\tfield\t - turn field on\r\n"); - printf("\tst25r_read\t - read ST25R3916 register\r\n"); - printf("\tst25r_write\t - write ST25R3916 register\r\n"); - printf("\tst25r_cmd\t - execute ST25R3916 command\r\n"); - printf("\tst25r_fifo\t - wait for FIFO data\r\n"); } } @@ -111,199 +110,6 @@ static void nfc_cli_field(Cli* cli, FuriString* args) { furi_hal_nfc_sleep(); } -static uint8_t hexdigit(char hex) { - return (hex <= '9') ? hex - '0' : toupper(hex) - 'A' + 10 ; -} - -static uint8_t hexbyte(const char* hex) { - return (hexdigit(*hex) << 4) | hexdigit(*(hex+1)); -} - -static void nfc_cli_st25r_write(Cli* cli, FuriString* args) { - UNUSED(cli); - FuriString* reg = furi_string_alloc(); - FuriString* value = furi_string_alloc(); - - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - if(!args_read_string_and_trim(args, reg) || !args_read_string_and_trim(args, value)) { - printf("You didn't specify and \r\n"); - nfc_cli_print_usage(); - return; - } - - if(furi_string_utf8_length(reg) != 2 || furi_string_utf8_length(value) != 2) { - printf("You didn't specify and as 2-character hex values\r\n"); - nfc_cli_print_usage(); - return; - } - - uint8_t reg_val = hexbyte(furi_string_get_cstr(reg)); - uint8_t value_val = hexbyte(furi_string_get_cstr(value)); - - printf("W %02X <- %02X\r\n", reg_val, value_val); - if(st25r3916WriteRegister(reg_val, value_val) != ERR_NONE) { - printf("Failed to write register\r\n"); - return; - } -} - -static void nfc_cli_st25r_read(Cli* cli, FuriString* args) { - UNUSED(cli); - FuriString* reg = furi_string_alloc(); - - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - if(!args_read_string_and_trim(args, reg)) { - printf("You didn't specify \r\n"); - nfc_cli_print_usage(); - return; - } - - if(furi_string_utf8_length(reg) != 2) { - printf("You didn't specify as 2-character hex value\r\n"); - nfc_cli_print_usage(); - return; - } - - uint8_t reg_val = hexbyte(furi_string_get_cstr(reg)); - uint8_t value_val = 0; - - if(st25r3916ReadRegister(reg_val, &value_val) != ERR_NONE) { - printf("Failed to read register\r\n"); - return; - } - - printf("R %02X -> %02X\r\n", reg_val, value_val); -} - -static void nfc_cli_st25r_cmd(Cli* cli, FuriString* args) { - UNUSED(cli); - FuriString* cmd = furi_string_alloc(); - - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - if(!args_read_string_and_trim(args, cmd)) { - printf("You didn't specify \r\n"); - nfc_cli_print_usage(); - return; - } - - if(furi_string_utf8_length(cmd) != 2) { - printf("You didn't specify as 2-character hex value\r\n"); - nfc_cli_print_usage(); - return; - } - - uint8_t cmd_val = hexbyte(furi_string_get_cstr(cmd)); - - if(st25r3916ExecuteCommand(cmd_val) != ERR_NONE) { - printf("Failed to execute\r\n"); - return; - } - - printf("X %02X\r\n", cmd_val); -} - -static FuriHalNfcTxRxContext tx_rx = {}; - -static void nfc_cli_st25r_fifo(Cli* cli, FuriString* args) { - UNUSED(args); - - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - bool field = false; - - tx_rx.sniff_tx = NULL; - tx_rx.sniff_rx = NULL; - tx_rx.tx_bits = 0; - tx_rx.tx_rx_type = FuriHalNfcTxRxTypeRxRaw; - - rfal_platform_spi_acquire(); - - furi_hal_nfcv_listen_start(); - - printf("Reading FIFO...\r\nPress Ctrl+C to abort\r\n"); - while(!cli_cmd_interrupt_received(cli)) { - - if(st25r3916IsExtFieldOn() && !field) { - printf("Field entered\r\n"); - field = true; - } - if(!st25r3916IsExtFieldOn() && field) { - printf("Field left\r\n"); - field = false; - } - - if(furi_hal_nfc_listen_rx(&tx_rx, 50)) { - for(int pos = 0; pos < tx_rx.rx_bits / 8; pos++) { - printf(" %02X", tx_rx.rx_data[pos]); - } - printf("\r\n"); - } - - furi_delay_ms(50); - } - rfal_platform_spi_release(); -} - - -static void nfc_cli_st25r_trans(Cli* cli, FuriString* args) { - UNUSED(args); - - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - printf("ISO15693 emulator...\r\nPress Ctrl+C to abort\r\n"); - - FuriHalNfcDevData nfc_data = { - .uid = { 0xE0, 0x04, 0x45, 0x03, 0x50, 0x0E, 0x78, 0x36 }, - .uid_len = 8, - .type = FuriHalNfcTypeV, - }; - NfcVData nfcv_data = { - .afi = 0, - .dsfid = 0, - .block_num = 8, - .block_size = 4, - .ic_ref = 3, - .type = NfcVTypeSlixL, - .sub_data.slix_l = { - .key_privacy = { 0x0F, 0x0F, 0x0F, 0x0F }, - .privacy = false - } - }; - - memset(nfcv_data.data, 0xAE, 4 * 8); - - nfcv_emu_init(&nfc_data, &nfcv_data); - while(!cli_cmd_interrupt_received(cli)) { - if(nfcv_emu_loop(&nfc_data, &nfcv_data, 1000)) { - printf("[NfcV-Emu] %s\r\n", nfcv_data.last_command); - } - } - - nfcv_emu_deinit(); -} static void nfc_cli(Cli* cli, FuriString* args, void* context) { UNUSED(context); @@ -329,26 +135,6 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_field(cli, args); break; } - if(furi_string_cmp_str(cmd, "st25r_read") == 0) { - nfc_cli_st25r_read(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "st25r_write") == 0) { - nfc_cli_st25r_write(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "st25r_cmd") == 0) { - nfc_cli_st25r_cmd(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "st25r_fifo") == 0) { - nfc_cli_st25r_fifo(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "st25r_trans") == 0) { - nfc_cli_st25r_trans(cli, args); - break; - } } nfc_cli_print_usage(); diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 0687c1343..6dd29eff5 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -22,6 +22,7 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { signal->edge_cnt = 0; signal->reload_reg_buff = malloc(signal->edges_max_cnt * sizeof(uint32_t)); signal->reload_reg_entries = 0; + signal->reload_reg_remainder = 0; return signal; } @@ -98,10 +99,6 @@ uint32_t digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { void digital_signal_prepare(DigitalSignal* signal) { furi_assert(signal); - if(signal->prepared) { - return; - } - /* set up signal polarities */ uint32_t bit_set = signal->gpio->pin; uint32_t bit_reset = signal->gpio->pin << 16; @@ -115,20 +112,30 @@ void digital_signal_prepare(DigitalSignal* signal) { } /* set up edge timings */ - uint32_t remainder = 0; signal->reload_reg_entries = 0; for(size_t pos = 0; pos < signal->edge_cnt; pos++) { - uint32_t pulse_duration = signal->edge_timings[pos] + remainder; + uint32_t pulse_duration = signal->edge_timings[pos] + signal->reload_reg_remainder; uint32_t pulse_ticks = (pulse_duration + T_TIM_DIV2) / T_TIM; - remainder = pulse_duration - (pulse_ticks * T_TIM); + signal->reload_reg_remainder = pulse_duration - (pulse_ticks * T_TIM); if(pulse_ticks > 1) { signal->reload_reg_buff[signal->reload_reg_entries++] = pulse_ticks - 1; } } +} - signal->prepared = true; + +void digital_signal_stop_dma() { + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); +} + +void digital_signal_stop_timer() { + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); } bool digital_signal_setup_dma(DigitalSignal* signal) { @@ -166,6 +173,8 @@ bool digital_signal_setup_dma(DigitalSignal* signal) { dma_config_timer.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config_timer.Priority = LL_DMA_PRIORITY_HIGH; + digital_signal_stop_dma(); + /* 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); @@ -178,13 +187,14 @@ bool digital_signal_setup_dma(DigitalSignal* signal) { } -void digital_signal_update_dma(DigitalSignal* signal) { +bool digital_signal_update_dma(DigitalSignal* signal) { furi_assert(signal); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_ClearFlag_TC1(DMA1); - LL_DMA_ClearFlag_TC2(DMA1); + if(!signal->reload_reg_entries) { + return false; + } + + digital_signal_stop_dma(); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)signal->gpio_buff); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)signal->reload_reg_buff); @@ -193,18 +203,8 @@ void digital_signal_update_dma(DigitalSignal* signal) { LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); -} -void digital_signal_stop_dma() { - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_ClearFlag_TC1(DMA1); - LL_DMA_ClearFlag_TC2(DMA1); -} - -void digital_signal_stop_timer() { - LL_TIM_DisableCounter(TIM2); - LL_TIM_SetCounter(TIM2, 0); + return true; } void digital_signal_setup_timer() { @@ -231,7 +231,6 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { /* if selected GPIO changed, force reconfiguration of buffers */ if(gpio && (signal->gpio != gpio)) { signal->gpio = gpio; - signal->prepared = false; } /* Configure gpio as output */ @@ -303,7 +302,7 @@ void digital_sequence_add(DigitalSequence* sequence, uint8_t signal_index) { bool digital_sequence_send_signal(DigitalSignal* signal) { furi_assert(signal); - /* the first iteration has to set up the whol machinery */ + /* the first iteration has to set up the whole machinery */ if(!LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1)) { furi_hal_gpio_init(signal->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); @@ -314,12 +313,15 @@ bool digital_sequence_send_signal(DigitalSignal* signal) { digital_signal_setup_timer(); digital_signal_start_timer(); } else { - /* it was already active, wait till DMA is done and the last timer ticks are running */ + /* transfer was already active, wait till DMA is done and the last timer ticks are running */ while(!LL_DMA_IsActiveFlag_TC2(DMA1)) { } /* configure next polarities and timings */ - digital_signal_update_dma(signal); + if(!digital_signal_update_dma(signal)) { + FURI_LOG_D(TAG, "Signal has no entries, aborting"); + return false; + } } return true; @@ -328,9 +330,15 @@ bool digital_sequence_send_signal(DigitalSignal* signal) { bool digital_sequence_send(DigitalSequence* sequence) { furi_assert(sequence); + uint32_t remainder = 0; + for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { DigitalSignal *sig = sequence->signals[sequence->sequence[pos]]; + /* take over previous remainder */ + sig->reload_reg_remainder = remainder; + digital_signal_prepare(sig); + if(!digital_sequence_send_signal(sig)) { digital_signal_stop_timer(); digital_signal_stop_dma(); diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h index 00376466e..583105e47 100644 --- a/lib/digital_signal/digital_signal.h +++ b/lib/digital_signal/digital_signal.h @@ -24,6 +24,7 @@ typedef struct { uint32_t* edge_timings; uint32_t* reload_reg_buff; uint32_t reload_reg_entries; + uint32_t reload_reg_remainder; uint32_t gpio_buff[2]; const GpioPin* gpio; } DigitalSignal; diff --git a/lib/nfc/protocols/nfcv.c b/lib/nfc/protocols/nfcv.c index bce179dba..a806d547c 100644 --- a/lib/nfc/protocols/nfcv.c +++ b/lib/nfc/protocols/nfcv.c @@ -161,6 +161,11 @@ DigitalSignal* nfcv_resp_eof = NULL; DigitalSignal* nfcv_resp_unmod_256 = NULL; DigitalSignal* nfcv_resp_unmod_768 = NULL; +//DigitalSignal* nfcv_signal = NULL; + +//const GpioPin* nfcv_out_io = &gpio_ext_pb2; +const GpioPin* nfcv_out_io = &gpio_spi_r_mosi; + DigitalSequence* nfcv_signal = NULL; #define SIG_SOF 0 @@ -192,6 +197,7 @@ void nfcv_crc(uint8_t* data, uint32_t length, uint8_t* out) { } void nfcv_emu_free() { + //digital_signal_free(nfcv_signal); digital_sequence_free(nfcv_signal); digital_signal_free(nfcv_resp_unmod_256); digital_signal_free(nfcv_resp_pulse_32); @@ -212,8 +218,9 @@ void nfcv_emu_free() { void nfcv_emu_alloc() { if(!nfcv_signal) { + //nfcv_signal = digital_signal_alloc(8192); /* assuming max frame length is 255 bytes */ - nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); + nfcv_signal = digital_sequence_alloc(8 * 255 + 2, nfcv_out_io); } if(!nfcv_resp_unmod_256) { @@ -283,12 +290,11 @@ void nfcv_emu_send_raw(uint8_t* data, uint8_t length) { int bits = length * 8; - furi_hal_gpio_write(&gpio_spi_r_mosi, false); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, true); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, false); + //nfcv_signal->start_level = false; + //nfcv_signal->edge_cnt = 0; + //digital_signal_append(nfcv_signal, nfcv_resp_sof); + digital_sequence_clear(nfcv_signal); digital_sequence_add(nfcv_signal, SIG_SOF); @@ -297,26 +303,17 @@ void nfcv_emu_send_raw(uint8_t* data, uint8_t length) { uint32_t bit_pos = bit_total % 8; uint8_t bit_val = 0x01 << bit_pos; - if(data[byte_pos] & bit_val) { - digital_sequence_add(nfcv_signal, SIG_BIT1); - } else { - digital_sequence_add(nfcv_signal, SIG_BIT0); - } + //digital_signal_append(nfcv_signal, nfcv_resp_one); + digital_sequence_add(nfcv_signal, (data[byte_pos] & bit_val) ? SIG_BIT1 : SIG_BIT0); } + //digital_signal_append(nfcv_signal, nfcv_resp_eof); digital_sequence_add(nfcv_signal, SIG_EOF); - - /* digital signal setup will take some time. win some time by tricking the VCD into thinking that something happens */ - furi_hal_gpio_write(&gpio_spi_r_mosi, false); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, true); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, false); - FURI_CRITICAL_ENTER(); + //digital_signal_send(nfcv_signal, nfcv_out_io); digital_sequence_send(nfcv_signal); FURI_CRITICAL_EXIT(); - furi_hal_gpio_write(&gpio_spi_r_mosi, false); + furi_hal_gpio_write(nfcv_out_io, false); } void nfcv_emu_send(uint8_t* data, uint8_t length) { @@ -579,7 +576,7 @@ void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, ui } if(strlen(nfcv_data->last_command) > 0) { - //FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); } } @@ -594,7 +591,6 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); - FURI_LOG_D(TAG, "Starting NfcV 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], @@ -676,7 +672,6 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti break; case NFCV_FRAME_STATE_CODING_256: - if(periods_previous > periods) { snprintf(reset_reason, sizeof(reset_reason), "1oo256: Missing %lu periods from previous symbol, got %lu", periods_previous, periods); frame_state = NFCV_FRAME_STATE_RESET; @@ -758,13 +753,9 @@ bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t ti } if(frame_state == NFCV_FRAME_STATE_EOF) { + FURI_LOG_D(TAG, "Received valid frame"); + /* we know that this code uses TIM2, so stop pulse reader */ - furi_hal_gpio_write(&gpio_spi_r_mosi, false); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, true); - furi_delay_us(10); - furi_hal_gpio_write(&gpio_spi_r_mosi, false); - pulse_reader_stop(reader_signal); nfcv_emu_handle_packet(nfc_data, nfcv_data, frame_payload, frame_pos); pulse_reader_start(reader_signal);