mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 16:18:35 -07:00
implement ISO14433-A fully in software for pointless experimenting reasons and improving the DigitalReader / SignalSequence code in performance
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
|
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user