implement ISO14433-A fully in software for pointless experimenting reasons and improving the DigitalReader / SignalSequence code in performance

This commit is contained in:
g3gg0
2022-11-25 02:46:49 +01:00
parent 674a5c6f48
commit 013e88154f
14 changed files with 427 additions and 183 deletions

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,7.28,, Version,+,7.33,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.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,-,cosl,long double,long double
Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t"
Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" 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_byte,uint8_t,"Crypto1*, uint8_t, int"
Function,-,crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" 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*" 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,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*"
Function,-,difftime,double,"time_t, time_t" Function,-,difftime,double,"time_t, time_t"
Function,-,digital_sequence_add,void,"DigitalSequence*, uint8_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_clear,void,DigitalSequence*
Function,-,digital_sequence_free,void,DigitalSequence* Function,-,digital_sequence_free,void,DigitalSequence*
Function,-,digital_sequence_send,_Bool,"DigitalSequence*, const GpioPin*" Function,-,digital_sequence_send,_Bool,DigitalSequence*
Function,-,digital_sequence_send_signal,_Bool,DigitalSignal*
Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*" Function,-,digital_sequence_set_signal,void,"DigitalSequence*, uint8_t, DigitalSignal*"
Function,-,digital_signal_add,void,"DigitalSignal*, uint32_t" 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_alloc,DigitalSignal*,uint32_t
Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*" Function,-,digital_signal_append,_Bool,"DigitalSignal*, DigitalSignal*"
Function,-,digital_signal_free,void,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_exit_sleep,void,
Function,+,furi_hal_nfc_field_off,void, Function,+,furi_hal_nfc_field_off,void,
Function,+,furi_hal_nfc_field_on,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_init,void,
Function,+,furi_hal_nfc_is_busy,_Bool, Function,+,furi_hal_nfc_is_busy,_Bool,
Function,+,furi_hal_nfc_is_init,_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_alloc,NfcaSignal*,
Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*"
Function,-,nfca_signal_free,void,NfcaSignal* 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_deinit,void,
Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*" Function,-,nfcv_emu_init,void,"FuriHalNfcDevData*, NfcVData*"
Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcDevData*, NfcVData*, uint32_t" Function,-,nfcv_emu_loop,_Bool,"FuriHalNfcDevData*, NfcVData*, uint32_t"
1 entry status name type params
2 Version + 7.28 7.33
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
669 Function - cosl long double long double
670 Function + crc32_calc_buffer uint32_t uint32_t, const void*, size_t
671 Function + crc32_calc_file uint32_t File*, const FileCrcProgressCb, void*
Function - crypto1_bit uint8_t Crypto1*, uint8_t, int
672 Function - crypto1_byte uint8_t Crypto1*, uint8_t, int
673 Function - crypto1_decrypt void Crypto1*, uint8_t*, uint16_t, uint8_t*
674 Function - crypto1_encrypt void Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*
707 Function + dialog_message_show_storage_error void DialogsApp*, const char*
708 Function - difftime double time_t, time_t
709 Function - digital_sequence_add void DigitalSequence*, uint8_t
710 Function - digital_sequence_alloc DigitalSequence* uint32_t uint32_t, const GpioPin*
711 Function - digital_sequence_clear void DigitalSequence*
712 Function - digital_sequence_free void DigitalSequence*
713 Function - digital_sequence_send _Bool DigitalSequence*, const GpioPin* DigitalSequence*
Function - digital_sequence_send_signal _Bool DigitalSignal*
714 Function - digital_sequence_set_signal void DigitalSequence*, uint8_t, DigitalSignal*
715 Function - digital_signal_add void DigitalSignal*, uint32_t
716 Function - digital_signal_add_pulse void DigitalSignal*, uint32_t, _Bool
717 Function - digital_signal_alloc DigitalSignal* uint32_t
718 Function - digital_signal_append _Bool DigitalSignal*, DigitalSignal*
719 Function - digital_signal_free void DigitalSignal*
1165 Function + furi_hal_nfc_exit_sleep void
1166 Function + furi_hal_nfc_field_off void
1167 Function + furi_hal_nfc_field_on void
1168 Function - furi_hal_nfc_gen_bitstream void FuriHalNfcTxRxContext*, uint8_t*, size_t
1169 Function - furi_hal_nfc_init void
1170 Function + furi_hal_nfc_is_busy _Bool
1171 Function + furi_hal_nfc_is_init _Bool
1967 Function - nfca_signal_alloc NfcaSignal*
1968 Function - nfca_signal_encode void NfcaSignal*, uint8_t*, uint16_t, uint8_t*
1969 Function - nfca_signal_free void NfcaSignal*
1970 Function - nfca_trans_rx_continue void NfcaTransRxState*
1971 Function - nfca_trans_rx_deinit void NfcaTransRxState*
1972 Function - nfca_trans_rx_init void NfcaTransRxState*
1973 Function - nfca_trans_rx_loop _Bool NfcaTransRxState*, uint32_t
1974 Function - nfca_trans_rx_pause void NfcaTransRxState*
1975 Function - nfcv_emu_deinit void
1976 Function - nfcv_emu_init void FuriHalNfcDevData*, NfcVData*
1977 Function - nfcv_emu_loop _Bool FuriHalNfcDevData*, NfcVData*, uint32_t

View File

@@ -523,6 +523,7 @@ bool furi_hal_nfc_emulate_nfca(
return true; return true;
} }
static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
furi_assert(tx_rx->nfca_signal); furi_assert(tx_rx->nfca_signal);
@@ -536,7 +537,7 @@ static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_
// Send signal // Send signal
FURI_CRITICAL_ENTER(); FURI_CRITICAL_ENTER();
nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits, tx_rx->tx_parity); 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(); FURI_CRITICAL_EXIT();
// Configure gpio back to SPI and exit transparent // 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; 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) { static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) {
uint32_t flags = 0; uint32_t flags = 0;
@@ -674,9 +763,39 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity(
return curr_byte * 8; 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) { bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
furi_assert(tx_rx); 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; ReturnCode ret;
rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
uint8_t temp_tx_buff[FURI_HAL_NFC_DATA_BUFF_SIZE] = {}; 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; uint8_t* temp_rx_buff = NULL;
uint16_t* temp_rx_bits = NULL; uint16_t* temp_rx_bits = NULL;
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTransparent) { //FURI_LOG_D(TAG, "furi_hal_nfc_tx_rx %u", tx_rx->tx_rx_type);
return furi_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms);
}
// Prepare data for FIFO if necessary // Prepare data for FIFO if necessary
uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type); uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type);

View File

@@ -14,6 +14,7 @@ extern "C" {
#endif #endif
#include <rfal_nfc.h> #include <rfal_nfc.h>
#include <lib/nfc/protocols/nfca.h> #include <lib/nfc/protocols/nfca.h>
#include <lib/nfc/protocols/nfca_trans_rx.h>
#define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_UID_MAX_LEN 10
#define FURI_HAL_NFC_DATA_BUFF_SIZE (512) #define FURI_HAL_NFC_DATA_BUFF_SIZE (512)
@@ -46,6 +47,8 @@ typedef enum {
FuriHalNfcTxRxTypeRaw, FuriHalNfcTxRxTypeRaw,
FuriHalNfcTxRxTypeRxRaw, FuriHalNfcTxRxTypeRxRaw,
FuriHalNfcTxRxTransparent, FuriHalNfcTxRxTransparent,
FuriHalNfcTxRxFullyRawTransparent,
FuriHalNfcTxRxFullyTransparent
} FuriHalNfcTxRxType; } FuriHalNfcTxRxType;
typedef bool (*FuriHalNfcEmulateCallback)( typedef bool (*FuriHalNfcEmulateCallback)(
@@ -91,6 +94,8 @@ typedef struct {
uint16_t rx_bits; uint16_t rx_bits;
FuriHalNfcTxRxType tx_rx_type; FuriHalNfcTxRxType tx_rx_type;
NfcaSignal* nfca_signal; NfcaSignal* nfca_signal;
NfcaTransRxState nfca_trans_state;
bool nfca_trans_initialized;
FuriHalNfcTxRxSniffCallback sniff_tx; FuriHalNfcTxRxSniffCallback sniff_tx;
FuriHalNfcTxRxSniffCallback sniff_rx; FuriHalNfcTxRxSniffCallback sniff_rx;
@@ -425,6 +430,9 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits(
void furi_hal_nfc_ll_poll(); void furi_hal_nfc_ll_poll();
void furi_hal_nfc_gen_bitstream(FuriHalNfcTxRxContext* tx_rx, uint8_t *buffer, size_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -2,18 +2,16 @@
#include <furi.h> #include <furi.h>
#include <furi_hal_resources.h> #include <furi_hal_resources.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_tim.h>
#include <math.h> #include <math.h>
#define TAG "DigitalSignal" #define TAG "DigitalSignal"
#pragma GCC optimize("O3,unroll-loops,Ofast")
#define F_TIM (64000000.0) #define F_TIM (64000000.0)
#define T_TIM 1562 /* 15.625 ns *100 */ #define T_TIM 1562 /* 15.625 ns *100 */
#define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ #define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */
DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
DigitalSignal* signal = malloc(sizeof(DigitalSignal)); DigitalSignal* signal = malloc(sizeof(DigitalSignal));
signal->start_level = true; signal->start_level = true;
@@ -24,6 +22,26 @@ DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
signal->reload_reg_entries = 0; signal->reload_reg_entries = 0;
signal->reload_reg_remainder = 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; return signal;
} }
@@ -144,7 +162,6 @@ void digital_signal_prepare(DigitalSignal* signal) {
} }
} }
static void digital_signal_stop_dma() { static void digital_signal_stop_dma() {
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
@@ -164,39 +181,14 @@ static bool digital_signal_setup_dma(DigitalSignal* signal) {
return false; return false;
} }
LL_DMA_InitTypeDef dma_config_gpio = {}; signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff;
LL_DMA_InitTypeDef dma_config_timer = {}; signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->BSRR);
signal->dma_config_timer.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buff; signal->dma_config_timer.NbData = signal->reload_reg_entries;
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();
/* set up DMA channel 1 and 2 for GPIO and timer copy operations */ /* 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_1, &signal->dma_config_gpio);
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config_timer); LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &signal->dma_config_timer);
/* enable both DMA channels */ /* enable both DMA channels */
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
@@ -251,9 +243,6 @@ void digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
signal->edge_cnt--; signal->edge_cnt--;
} }
void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) { void digital_sequence_alloc_signals(DigitalSequence* sequence, uint32_t size) {
sequence->signals_size = size; sequence->signals_size = size;
sequence->signals = malloc(sequence->signals_size * sizeof(DigitalSignal*)); 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)); 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->gpio = gpio;
sequence->bake = false;
digital_sequence_alloc_signals(sequence, 32); digital_sequence_alloc_signals(sequence, 32);
digital_sequence_alloc_sequence(sequence, size); digital_sequence_alloc_sequence(sequence, size);
@@ -380,7 +364,6 @@ static bool digital_sequence_send_signal(DigitalSignal* signal) {
digital_signal_setup_timer(); digital_signal_setup_timer();
digital_signal_start_timer(); digital_signal_start_timer();
} else { } else {
/* configure next polarities and timings */ /* configure next polarities and timings */
digital_signal_update_dma(signal); digital_signal_update_dma(signal);
} }
@@ -425,6 +408,7 @@ bool digital_sequence_send(DigitalSequence* sequence) {
} }
int32_t remainder = 0; int32_t remainder = 0;
FURI_CRITICAL_ENTER();
for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) { for(uint32_t pos = 0; pos < sequence->sequence_used; pos++) {
uint8_t signal_index = sequence->sequence[pos]; uint8_t signal_index = sequence->sequence[pos];
@@ -432,9 +416,7 @@ bool digital_sequence_send(DigitalSequence* sequence) {
if(!sig) { if(!sig) {
FURI_LOG_D(TAG, "digital_sequence_send: Signal at index %u, used at pos %lu is NULL, aborting", signal_index, pos); 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(); break;
digital_signal_stop_dma();
return false;
} }
/* when we are too late more than half a tick, make the first edge temporarily longer */ /* 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); bool success = digital_sequence_send_signal(sig);
if(!success) { if(!success) {
digital_signal_stop_timer(); break;
digital_signal_stop_dma();
return false;
} }
} }
FURI_CRITICAL_EXIT();
while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) { while(LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2)) {
} }

View File

@@ -5,6 +5,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <furi_hal_gpio.h> #include <furi_hal_gpio.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_tim.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -27,6 +29,8 @@ typedef struct {
uint32_t reload_reg_remainder; uint32_t reload_reg_remainder;
uint32_t gpio_buff[2]; uint32_t gpio_buff[2];
const GpioPin* gpio; const GpioPin* gpio;
LL_DMA_InitTypeDef dma_config_gpio;
LL_DMA_InitTypeDef dma_config_timer;
} DigitalSignal; } DigitalSignal;
typedef struct { typedef struct {

View File

@@ -857,6 +857,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) {
} }
void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {}; FuriHalNfcTxRxContext tx_rx = {};
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
MfClassicEmulator emulator = { MfClassicEmulator emulator = {
@@ -870,11 +871,67 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
rfal_platform_spi_acquire(); rfal_platform_spi_acquire();
furi_hal_nfc_listen_start(nfc_data); 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) { 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); mf_classic_emulator(&emulator, &tx_rx);
} }
} }
if(emulator.data_changed) { if(emulator.data_changed) {
nfc_worker->dev_data->mf_classic_data = emulator.data; nfc_worker->dev_data->mf_classic_data = emulator.data;
if(nfc_worker->callback) { if(nfc_worker->callback) {
@@ -883,9 +940,12 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
emulator.data_changed = false; emulator.data_changed = false;
} }
nfca_signal_free(nfca_signal); nfca_trans_rx_deinit(&tx_rx.nfca_trans_state);
rfal_platform_spi_release(); rfal_platform_spi_release();
nfca_signal_free(nfca_signal);
} }
void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) {

View File

@@ -12,6 +12,7 @@
#include <lib/nfc/protocols/mifare_classic.h> #include <lib/nfc/protocols/mifare_classic.h>
#include <lib/nfc/protocols/mifare_desfire.h> #include <lib/nfc/protocols/mifare_desfire.h>
#include <lib/nfc/protocols/nfca.h> #include <lib/nfc/protocols/nfca.h>
#include <lib/nfc/protocols/nfca_trans_rx.h>
#include <lib/nfc/protocols/nfcv.h> #include <lib/nfc/protocols/nfcv.h>
#include <lib/nfc/protocols/slix.h> #include <lib/nfc/protocols/slix.h>
#include <lib/nfc/helpers/reader_analyzer.h> #include <lib/nfc/helpers/reader_analyzer.h>

View File

@@ -763,6 +763,10 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE]; uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE];
MfClassicKey access_key = MfClassicKeyA; MfClassicKey access_key = MfClassicKeyA;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
FURI_LOG_D(TAG, "Starting mf_classic_emulator");
// Read command // Read command
while(!command_processed) { while(!command_processed) {
if(!is_encrypted) { if(!is_encrypted) {
@@ -791,7 +795,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
} }
if(plain_data[0] == 0x50 && plain_data[1] == 0x00) { if(plain_data[0] == 0x50 && plain_data[1] == 0x00) {
furi_hal_nfc_listen_sleep(); //furi_hal_nfc_listen_sleep();
command_processed = true; command_processed = true;
break; break;
} else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) { } 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_parity[0] |= nfc_util_odd_parity8(nt[i]) << (7 - i);
} }
tx_rx->tx_bits = sizeof(nt) * 8; tx_rx->tx_bits = sizeof(nt) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
} else { } else {
crypto1_encrypt( crypto1_encrypt(
&emulator->crypto, &emulator->crypto,
@@ -834,7 +838,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
tx_rx->tx_data, tx_rx->tx_data,
tx_rx->tx_parity); tx_rx->tx_parity);
tx_rx->tx_bits = sizeof(nt) * 8; 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)) { if(!furi_hal_nfc_tx_rx(tx_rx, 500)) {
FURI_LOG_E(TAG, "Error in NT exchange?"); 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_data,
tx_rx->tx_parity); tx_rx->tx_parity);
tx_rx->tx_bits = sizeof(responce) * 8; tx_rx->tx_bits = sizeof(responce) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
is_encrypted = true; is_encrypted = true;
} else if(is_encrypted && plain_data[0] == 0x30) { } else if(is_encrypted && plain_data[0] == 0x30) {
@@ -912,7 +916,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
} else { } else {
tx_rx->tx_data[0] = nack; tx_rx->tx_data[0] = nack;
} }
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_bits = 4; tx_rx->tx_bits = 4;
furi_hal_nfc_tx_rx(tx_rx, 300); furi_hal_nfc_tx_rx(tx_rx, 300);
break; break;
@@ -928,7 +932,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
tx_rx->tx_data, tx_rx->tx_data,
tx_rx->tx_parity); tx_rx->tx_parity);
tx_rx->tx_bits = 18 * 8; 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) { } else if(is_encrypted && plain_data[0] == 0xA0) {
uint8_t block = plain_data[1]; uint8_t block = plain_data[1];
if(block > mf_classic_get_total_block_num(emulator->data.type)) { 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 // Send ACK
uint8_t ack = 0x0A; uint8_t ack = 0x0A;
crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); 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; tx_rx->tx_bits = 4;
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
@@ -972,7 +976,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
// Send ACK // Send ACK
ack = 0x0A; ack = 0x0A;
crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); 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; tx_rx->tx_bits = 4;
} else { } else {
FURI_LOG_T(TAG, "%02X unknown received", plain_data[0]); FURI_LOG_T(TAG, "%02X unknown received", plain_data[0]);
@@ -989,7 +993,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
} else { } else {
tx_rx->tx_data[0] = nack; tx_rx->tx_data[0] = nack;
} }
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_bits = 4; tx_rx->tx_bits = 4;
furi_hal_nfc_tx_rx(tx_rx, 300); furi_hal_nfc_tx_rx(tx_rx, 300);
} }

View File

@@ -2,18 +2,27 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <furi.h> #include <furi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_resources.h>
#define NFCA_CMD_RATS (0xE0U) #define NFCA_CMD_RATS (0xE0U)
#define NFCA_CRC_INIT (0x6363) #define NFCA_CRC_INIT (0x6363)
#define NFCA_F_SIG (13560000.0) /* [Hz] NFC frequency */ #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 (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 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 { typedef struct {
uint8_t cmd; uint8_t cmd;
uint8_t param; uint8_t param;
@@ -65,27 +74,32 @@ bool nfca_emulation_handler(
static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) { static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) {
for(uint8_t i = 0; i < 8; i++) { for(uint8_t i = 0; i < 8; i++) {
if(byte & (1 << 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 { } else {
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_e); digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0);
} }
} }
if(parity) { if(parity) {
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d); digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1);
} else { } 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) { static void nfca_add_modulation(DigitalSignal* signal, size_t phases) {
for(size_t i = 0; i < phases; i++) { for(size_t i = 0; i < phases; i++) {
bool modulated = (i % 2 == 0); signal->edge_timings[signal->edge_cnt++] = DIGITAL_SIGNAL_PS(T_SUB_PHASE);
digital_signal_add_pulse(signal, DIGITAL_SIGNAL_PS(T_SUB_PHASE), modulated);
} }
} }
static void nfca_add_silence(DigitalSignal* signal, size_t phases) { 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() { NfcaSignal* nfca_signal_alloc() {
@@ -97,16 +111,29 @@ NfcaSignal* nfca_signal_alloc() {
nfca_signal->seq_f = digital_signal_alloc(10); nfca_signal->seq_f = digital_signal_alloc(10);
/* SEQ D has the first half modulated, used as SOF */ /* 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_modulation(nfca_signal->seq_d, 8);
nfca_add_silence(nfca_signal->seq_d, 8); nfca_add_silence(nfca_signal->seq_d, 8);
/* SEQ E has the second half modulated */ /* SEQ E has the second half modulated */
nfca_signal->seq_e->start_level = false;
nfca_add_silence(nfca_signal->seq_e, 8); nfca_add_silence(nfca_signal->seq_e, 8);
nfca_add_modulation(nfca_signal->seq_e, 8); nfca_add_modulation(nfca_signal->seq_e, 8);
/* SEQ F is just no modulation, used as EOF */ /* 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_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; 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_d);
digital_signal_free(nfca_signal->seq_e); digital_signal_free(nfca_signal->seq_e);
digital_signal_free(nfca_signal->seq_f); digital_signal_free(nfca_signal->seq_f);
digital_signal_free(nfca_signal->tx_signal); digital_sequence_free(nfca_signal->tx_signal);
free(nfca_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(data);
furi_assert(parity); furi_assert(parity);
nfca_signal->tx_signal->edge_cnt = 0; digital_sequence_clear(nfca_signal->tx_signal);
nfca_signal->tx_signal->start_level = true;
// Start of frame /* add some idle bit times before SOF in case the GPIO was active */
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); digital_sequence_add(nfca_signal->tx_signal, SEQ_IDLE);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f); digital_sequence_add(nfca_signal->tx_signal, SEQ_SOF);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_f);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_d);
if(bits < 8) { if(bits < 8) {
for(size_t i = 0; i < bits; i++) { for(size_t i = 0; i < bits; i++) {
if(FURI_BIT(data[0], 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 { } else {
digital_signal_append(nfca_signal->tx_signal, nfca_signal->seq_e); digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0);
} }
} }
} else { } 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)))); 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);
} }

View File

@@ -9,7 +9,7 @@ typedef struct {
DigitalSignal* seq_d; /* sequence D, modulation with subcarrier during first half */ DigitalSignal* seq_d; /* sequence D, modulation with subcarrier during first half */
DigitalSignal* seq_e; /* sequence E, modulation with subcarrier during second half */ DigitalSignal* seq_e; /* sequence E, modulation with subcarrier during second half */
DigitalSignal* seq_f; /* sequence F, no modulation at all */ DigitalSignal* seq_f; /* sequence F, no modulation at all */
DigitalSignal* tx_signal; DigitalSequence* tx_signal;
} NfcaSignal; } NfcaSignal;
uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len); 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_free(NfcaSignal* nfca_signal);
void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity); void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity);

View File

@@ -10,16 +10,13 @@
#include <st25r3916.h> #include <st25r3916.h>
#include <st25r3916_irq.h> #include <st25r3916_irq.h>
#include "nfca_emu.h" #include "nfca_trans_rx.h"
#define TAG "NfcA-emu" #define TAG "NfcA-trans-rx"
void nfca_trans_rx_init(NfcaTransRxState *state) {
FURI_LOG_D(TAG, "Starting NfcA transparent rx");
void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data) {
//nfca_emu_alloc();
rfal_platform_spi_acquire();
st25r3916ExecuteCommand(ST25R3916_CMD_STOP); st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3); 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_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 */ /* allocate a 512 edge buffer, more than enough */
state->reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512); state->reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512);
/* timebase shall be 1 ns */ /* timebase shall be 1 ns */
@@ -46,20 +38,30 @@ void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data) {
state->valid_frame = false; 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); furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
rfal_platform_spi_release();
pulse_reader_free(state->reader_signal); 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, /* 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. */ where the 9th bit is odd parity. Data is transmitted LSB first. */
uint32_t byte_num = (state->bits_received / 9); uint32_t byte_num = (state->bits_received / 9);
uint32_t bit_num = (state->bits_received % 9); uint32_t bit_num = (state->bits_received % 9);
if(byte_num >= NFCA_FRAME_LENGTH) {
return;
}
if(bit_num == 8) { if(bit_num == 8) {
uint32_t parity_value = 1 << (state->bits_received / 9); uint32_t parity_value = 1 << (state->bits_received / 9);
state->parity_bits &= ~parity_value; 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) { bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms) {
furi_assert(nfc_data); furi_assert(state);
bool ret = false; state->valid_frame = false;
state->have_sof = false;
state->bits_received = 0;
while(!ret) { bool done = false;
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);
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) { bool eof = state->have_sof && (nsec >= (2 * NFCA_TB));
FURI_LOG_T(TAG, "pulse: %lu ns, frametime now: %ld", nsec, state->frame_time); 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) { if(IS_T1(nsec) || eof) {
FURI_LOG_T(TAG, " T1 pulse"); timeout_us = (3 * NFCA_TB) / 1000;
if(!state->have_sof) { if(!state->have_sof) {
FURI_LOG_T(TAG, " SOF");
state->frame_time = -(NFCA_TB - nsec); state->frame_time = -(NFCA_TB - nsec);
state->have_sof = true; state->have_sof = true;
state->valid_frame = false; state->valid_frame = false;
state->bits_received = 0; state->bits_received = 0;
state->debug_pos = 0;
if(lost_pulse) {
state->frame_time -= nsec;
}
continue; continue;
} }
if(state->frame_time > NFCA_TB_MIN) { if(state->frame_time > NFCA_TB_MIN) {
FURI_LOG_T(TAG, " Y");
state->frame_time -= NFCA_TB; state->frame_time -= NFCA_TB;
nfca_bit_received(state, 0); nfca_bit_received(state, 0);
} }
if(IS_ZERO(state->frame_time)) { if(IS_ZERO(state->frame_time)) {
FURI_LOG_T(TAG, " Z");
state->frame_time = -(NFCA_TB - nsec); state->frame_time = -(NFCA_TB - nsec);
nfca_bit_received(state, 0); nfca_bit_received(state, 0);
} else if(IS_TX(state->frame_time)) { } else if(IS_TX(state->frame_time)) {
FURI_LOG_T(TAG, " X");
state->frame_time = -(NFCA_TX - nsec); state->frame_time = -(NFCA_TX - nsec);
nfca_bit_received(state, 1); nfca_bit_received(state, 1);
} else { } else {
if(eof) { if(eof) {
FURI_LOG_T(TAG, " EOF");
state->have_sof = false; state->have_sof = false;
state->valid_frame = true; state->valid_frame = true;
ret = true; done = true;
} else { } else {
FURI_LOG_D(TAG, " unexpected: %ld", state->frame_time);
} }
} }
} else { } else {
if(!state->have_sof) { 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 { } else {
state->frame_time += nsec; 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) { if(state->bits_received > 7) {
/* a last 0-bit will look like a missing bit */ /* a last 0-bit will look like a missing bit */
if((state->bits_received % 9) == 8) { if((state->bits_received % 9) == 8) {
nfca_bit_received(state, 0); nfca_bit_received(state, 0);
state->bits_received++; 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;
} }

View File

@@ -12,6 +12,7 @@
/* assume fc/128 */ /* assume fc/128 */
#define NFCA_FC (13560000.0f) /* MHz */ #define NFCA_FC (13560000.0f) /* MHz */
#define NFCA_FC_K ((uint32_t)(NFCA_FC/1000)) /* kHz */ #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_MIN (24.0f / NFCA_FC * 1000000000)
#define NFCA_T1_MAX (41.0f / NFCA_FC * 1000000000) #define NFCA_T1_MAX (41.0f / NFCA_FC * 1000000000)
#define NFCA_TX (64.0f / NFCA_FC * 1000000000) /* 4.7198 µs */ #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_MIN (0.80f * NFCA_TB)
#define NFCA_TB_MAX (1.20f * NFCA_TB) #define NFCA_TB_MAX (1.20f * NFCA_TB)
#define IS_T1(x) ((x)>=NFCA_T1_MIN && (x)<=NFCA_T1_MAX) #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_TX(x) ((x)>=NFCA_TX_MIN && (x)<=NFCA_TX_MAX)
#define IS_TB(x) ((x)>=NFCA_TB_MIN && (x)<=NFCA_TB_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_ZERO(x) ((x)>=-NFCA_T1_MIN/2 && (x)<=NFCA_T1_MIN/2)
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) #define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
#define DIGITAL_SIGNAL_UNIT_US (100000.0f) #define DIGITAL_SIGNAL_UNIT_US (100000.0f)
#define NFCA_FRAME_LENGTH 32 #define NFCA_FRAME_LENGTH 32
#define NFCA_DEBUG_LENGTH 128
typedef struct { typedef struct {
@@ -38,10 +40,15 @@ typedef struct {
int32_t frame_time; int32_t frame_time;
size_t bits_received; size_t bits_received;
uint8_t frame_data[NFCA_FRAME_LENGTH]; uint8_t frame_data[NFCA_FRAME_LENGTH];
uint32_t debug_buffer[NFCA_DEBUG_LENGTH];
size_t debug_pos;
uint32_t parity_bits; uint32_t parity_bits;
PulseReader *reader_signal; PulseReader *reader_signal;
} NfcaEmuState; } NfcaTransRxState;
bool nfca_emu_loop(NfcaEmuState *state, FuriHalNfcDevData* nfc_data, uint32_t timeout_ms); bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms);
void nfca_emu_deinit(NfcaEmuState *state); void nfca_trans_rx_deinit(NfcaTransRxState *state);
void nfca_emu_init(NfcaEmuState *state, FuriHalNfcDevData* nfc_data); void nfca_trans_rx_init(NfcaTransRxState *state);
void nfca_trans_rx_pause(NfcaTransRxState *state);
void nfca_trans_rx_continue(NfcaTransRxState *state);

View File

@@ -2,10 +2,6 @@
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <furi_hal_gpio.h> #include <furi_hal_gpio.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_dmamux.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_exti.h>
#include "pulse_reader.h" #include "pulse_reader.h"
@@ -36,6 +32,7 @@ PulseReader* pulse_reader_alloc(const GpioPin* gpio, uint32_t size) {
PulseReader* signal = malloc(sizeof(PulseReader)); PulseReader* signal = malloc(sizeof(PulseReader));
signal->timer_buffer = malloc(size * sizeof(uint32_t)); signal->timer_buffer = malloc(size * sizeof(uint32_t));
signal->gpio_buffer = malloc(size * sizeof(uint32_t));
signal->dma_channel = LL_DMA_CHANNEL_4; signal->dma_channel = LL_DMA_CHANNEL_4;
signal->gpio = gpio; signal->gpio = gpio;
signal->size = size; 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_timebase(signal, PulseReaderUnit64MHz);
pulse_reader_set_bittime(signal, 1); 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; return signal;
} }
@@ -75,6 +92,7 @@ void pulse_reader_set_bittime(PulseReader* signal, uint32_t bit_time) {
void pulse_reader_free(PulseReader* signal) { void pulse_reader_free(PulseReader* signal) {
free(signal->timer_buffer); free(signal->timer_buffer);
free(signal->gpio_buffer);
free(signal); free(signal);
} }
@@ -85,32 +103,21 @@ uint32_t pulse_reader_samples(PulseReader* signal) {
} }
void pulse_reader_stop(PulseReader* signal) { void pulse_reader_stop(PulseReader* signal) {
LL_DMA_DisableChannel(DMA1, signal->dma_channel); 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_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0);
LL_TIM_DisableCounter(TIM2); LL_TIM_DisableCounter(TIM2);
} }
void pulse_reader_start(PulseReader* signal) { void pulse_reader_start(PulseReader* signal) {
memset(signal->timer_buffer, 0x00, signal->size * sizeof(uint32_t));
/* configure DMA to read from a timer peripheral */ /* configure DMA to read from a timer peripheral */
LL_DMA_InitTypeDef dma_config = {}; signal->dma_config_timer.NbData = signal->size;
dma_config.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) &(TIM2->CNT); signal->dma_config_gpio.PeriphOrM2MSrcAddress = (uint32_t) &(signal->gpio->port->IDR);
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t) signal->gpio_buffer;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; signal->dma_config_gpio.NbData = signal->size;
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;
/* start counter */ /* start counter */
LL_TIM_DisableCounter(TIM2);
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetPrescaler(TIM2, 0); LL_TIM_SetPrescaler(TIM2, 0);
@@ -118,8 +125,6 @@ void pulse_reader_start(PulseReader* signal) {
LL_TIM_SetCounter(TIM2, 0); LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2); 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 */ /* generator 0 gets fed by EXTI_LINEn */
LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin)); LL_DMAMUX_SetRequestSignalID(NULL, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(signal->gpio->pin));
/* trigger on rising edge of the interrupt */ /* trigger on rising edge of the interrupt */
@@ -134,11 +139,13 @@ void pulse_reader_start(PulseReader* signal) {
signal->pos = 0; signal->pos = 0;
signal->start_level = furi_hal_gpio_read(signal->gpio); signal->start_level = furi_hal_gpio_read(signal->gpio);
signal->timer_value = TIM2->CNT; signal->timer_value = TIM2->CNT;
signal->gpio_mask = signal->gpio->pin;
/* now set up DMA with these settings */ /* now set up DMA with these settings */
LL_DMA_DisableChannel(DMA1, signal->dma_channel); LL_DMA_Init(DMA1, signal->dma_channel, &signal->dma_config_timer);
LL_DMA_Init(DMA1, signal->dma_channel, &dma_config); 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);
LL_DMA_EnableChannel(DMA1, signal->dma_channel+1);
} }
uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) { 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) { if(dma_pos != signal->pos) {
uint32_t delta = signal->timer_buffer[signal->pos] - signal->timer_value; 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->timer_value = signal->timer_buffer[signal->pos];
signal->pos++; signal->pos++;
signal->pos %= signal->size; signal->pos %= signal->size;
@@ -183,7 +199,7 @@ uint32_t pulse_reader_receive(PulseReader* signal, int timeout_us) {
return PULSE_READER_NO_EDGE; return PULSE_READER_NO_EDGE;
} }
furi_delay_ms(0); //furi_delay_ms(0);
} while(true); } while(true);
} }

View File

@@ -3,6 +3,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stm32wbxx_ll_dma.h>
#include <stm32wbxx_ll_dmamux.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_exti.h>
#include <furi_hal_gpio.h> #include <furi_hal_gpio.h>
@@ -10,8 +14,9 @@
extern "C" { extern "C" {
#endif #endif
#define PULSE_READER_NO_EDGE 0xFFFFFFFFUL #define PULSE_READER_NO_EDGE 0xFFFFFFFFUL
#define F_TIM2 64000000UL #define PULSE_READER_LOST_EDGE 0xFFFFFFFEUL
#define F_TIM2 64000000UL
/** /**
* unit of the edge durations to return * unit of the edge durations to return
@@ -27,14 +32,19 @@ typedef enum {
typedef struct { typedef struct {
bool start_level; bool start_level;
uint32_t* timer_buffer; uint32_t* timer_buffer;
uint32_t* gpio_buffer;
uint32_t size; uint32_t size;
uint32_t pos; uint32_t pos;
uint32_t timer_value; uint32_t timer_value;
uint32_t gpio_value;
uint32_t gpio_mask;
uint32_t unit_multiplier; uint32_t unit_multiplier;
uint32_t unit_divider; uint32_t unit_divider;
uint32_t bit_time; uint32_t bit_time;
uint32_t dma_channel; uint32_t dma_channel;
const GpioPin* gpio; const GpioPin* gpio;
LL_DMA_InitTypeDef dma_config_timer;
LL_DMA_InitTypeDef dma_config_gpio;
} PulseReader; } PulseReader;