mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-30 02:18:11 -07:00
NFC refactoring (#3050)
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring. Starring: - @gornekich - NFC refactoring project lead, architect, senior developer - @gsurkov - architect, senior developer - @RebornedBrain - senior developer Supporting roles: - @skotopes, @DrZlo13, @hedger - general architecture advisors, code review - @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance Special thanks: @bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
This commit is contained in:
+649
@@ -0,0 +1,649 @@
|
||||
#ifndef FW_CFG_unit_tests
|
||||
|
||||
#include "nfc.h"
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
#include <furi/furi.h>
|
||||
|
||||
#define TAG "Nfc"
|
||||
|
||||
#define NFC_MAX_BUFFER_SIZE (256)
|
||||
|
||||
typedef enum {
|
||||
NfcStateIdle,
|
||||
NfcStateRunning,
|
||||
} NfcState;
|
||||
|
||||
typedef enum {
|
||||
NfcPollerStateStart,
|
||||
NfcPollerStateReady,
|
||||
NfcPollerStateReset,
|
||||
NfcPollerStateStop,
|
||||
|
||||
NfcPollerStateNum,
|
||||
} NfcPollerState;
|
||||
|
||||
typedef enum {
|
||||
NfcCommStateIdle,
|
||||
NfcCommStateWaitBlockTxTimer,
|
||||
NfcCommStateReadyTx,
|
||||
NfcCommStateWaitTxEnd,
|
||||
NfcCommStateWaitRxStart,
|
||||
NfcCommStateWaitRxEnd,
|
||||
NfcCommStateFailed,
|
||||
} NfcCommState;
|
||||
|
||||
typedef enum {
|
||||
NfcConfigurationStateIdle,
|
||||
NfcConfigurationStateDone,
|
||||
} NfcConfigurationState;
|
||||
|
||||
struct Nfc {
|
||||
NfcState state;
|
||||
NfcPollerState poller_state;
|
||||
NfcCommState comm_state;
|
||||
NfcConfigurationState config_state;
|
||||
NfcMode mode;
|
||||
|
||||
uint32_t fdt_listen_fc;
|
||||
uint32_t mask_rx_time_fc;
|
||||
uint32_t fdt_poll_fc;
|
||||
uint32_t fdt_poll_poll_us;
|
||||
uint32_t guard_time_us;
|
||||
NfcEventCallback callback;
|
||||
void* context;
|
||||
|
||||
uint8_t tx_buffer[NFC_MAX_BUFFER_SIZE];
|
||||
size_t tx_bits;
|
||||
uint8_t rx_buffer[NFC_MAX_BUFFER_SIZE];
|
||||
size_t rx_bits;
|
||||
|
||||
FuriThread* worker_thread;
|
||||
};
|
||||
|
||||
typedef bool (*NfcWorkerPollerStateHandler)(Nfc* instance);
|
||||
|
||||
static const FuriHalNfcTech nfc_tech_table[NfcModeNum][NfcTechNum] = {
|
||||
[NfcModePoller] =
|
||||
{
|
||||
[NfcTechIso14443a] = FuriHalNfcTechIso14443a,
|
||||
[NfcTechIso14443b] = FuriHalNfcTechIso14443b,
|
||||
[NfcTechIso15693] = FuriHalNfcTechIso15693,
|
||||
[NfcTechFelica] = FuriHalNfcTechFelica,
|
||||
},
|
||||
[NfcModeListener] =
|
||||
{
|
||||
[NfcTechIso14443a] = FuriHalNfcTechIso14443a,
|
||||
[NfcTechIso14443b] = FuriHalNfcTechInvalid,
|
||||
[NfcTechIso15693] = FuriHalNfcTechIso15693,
|
||||
[NfcTechFelica] = FuriHalNfcTechInvalid,
|
||||
},
|
||||
};
|
||||
|
||||
static NfcError nfc_process_hal_error(FuriHalNfcError error) {
|
||||
NfcError ret = NfcErrorNone;
|
||||
|
||||
switch(error) {
|
||||
case FuriHalNfcErrorNone:
|
||||
ret = NfcErrorNone;
|
||||
break;
|
||||
case FuriHalNfcErrorIncompleteFrame:
|
||||
ret = NfcErrorIncompleteFrame;
|
||||
break;
|
||||
case FuriHalNfcErrorDataFormat:
|
||||
ret = NfcErrorDataFormat;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = NfcErrorInternal;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t nfc_worker_listener(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* instance = context;
|
||||
furi_assert(instance->callback);
|
||||
furi_assert(instance->config_state == NfcConfigurationStateDone);
|
||||
|
||||
instance->state = NfcStateRunning;
|
||||
|
||||
furi_hal_nfc_event_start();
|
||||
|
||||
NfcEventData event_data = {};
|
||||
event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
|
||||
NfcEvent nfc_event = {.data = event_data};
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
while(true) {
|
||||
FuriHalNfcEvent event = furi_hal_nfc_listener_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventAbortRequest) {
|
||||
nfc_event.type = NfcEventTypeUserAbort;
|
||||
instance->callback(nfc_event, instance->context);
|
||||
break;
|
||||
}
|
||||
if(event & FuriHalNfcEventFieldOn) {
|
||||
nfc_event.type = NfcEventTypeFieldOn;
|
||||
instance->callback(nfc_event, instance->context);
|
||||
}
|
||||
if(event & FuriHalNfcEventFieldOff) {
|
||||
nfc_event.type = NfcEventTypeFieldOff;
|
||||
instance->callback(nfc_event, instance->context);
|
||||
furi_hal_nfc_listener_idle();
|
||||
}
|
||||
if(event & FuriHalNfcEventListenerActive) {
|
||||
nfc_event.type = NfcEventTypeListenerActivated;
|
||||
instance->callback(nfc_event, instance->context);
|
||||
}
|
||||
if(event & FuriHalNfcEventRxEnd) {
|
||||
furi_hal_nfc_timer_block_tx_start(instance->fdt_listen_fc);
|
||||
|
||||
nfc_event.type = NfcEventTypeRxEnd;
|
||||
furi_hal_nfc_listener_rx(
|
||||
instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
|
||||
bit_buffer_copy_bits(event_data.buffer, instance->rx_buffer, instance->rx_bits);
|
||||
command = instance->callback(nfc_event, instance->context);
|
||||
if(command == NfcCommandStop) {
|
||||
break;
|
||||
} else if(command == NfcCommandReset) {
|
||||
furi_hal_nfc_listener_enable_rx();
|
||||
} else if(command == NfcCommandSleep) {
|
||||
furi_hal_nfc_listener_sleep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_nfc_reset_mode();
|
||||
instance->config_state = NfcConfigurationStateIdle;
|
||||
|
||||
bit_buffer_free(event_data.buffer);
|
||||
furi_hal_nfc_low_power_mode_start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool nfc_worker_poller_start_handler(Nfc* instance) {
|
||||
furi_hal_nfc_poller_field_on();
|
||||
if(instance->guard_time_us) {
|
||||
furi_hal_nfc_timer_block_tx_start_us(instance->guard_time_us);
|
||||
FuriHalNfcEvent event = furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
furi_assert(event & FuriHalNfcEventTimerBlockTxExpired);
|
||||
}
|
||||
instance->poller_state = NfcPollerStateReady;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_poller_ready_handler(Nfc* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
NfcEvent event = {.type = NfcEventTypePollerReady};
|
||||
command = instance->callback(event, instance->context);
|
||||
if(command == NfcCommandReset) {
|
||||
instance->poller_state = NfcPollerStateReset;
|
||||
} else if(command == NfcCommandStop) {
|
||||
instance->poller_state = NfcPollerStateStop;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_poller_reset_handler(Nfc* instance) {
|
||||
furi_hal_nfc_low_power_mode_start();
|
||||
furi_delay_ms(100);
|
||||
furi_hal_nfc_low_power_mode_stop();
|
||||
instance->poller_state = NfcPollerStateStart;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nfc_worker_poller_stop_handler(Nfc* instance) {
|
||||
furi_hal_nfc_reset_mode();
|
||||
instance->config_state = NfcConfigurationStateIdle;
|
||||
|
||||
furi_hal_nfc_low_power_mode_start();
|
||||
// Wait after field is off some time to reset tag power
|
||||
furi_delay_ms(10);
|
||||
instance->poller_state = NfcPollerStateStart;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const NfcWorkerPollerStateHandler nfc_worker_poller_state_handlers[NfcPollerStateNum] = {
|
||||
[NfcPollerStateStart] = nfc_worker_poller_start_handler,
|
||||
[NfcPollerStateReady] = nfc_worker_poller_ready_handler,
|
||||
[NfcPollerStateReset] = nfc_worker_poller_reset_handler,
|
||||
[NfcPollerStateStop] = nfc_worker_poller_stop_handler,
|
||||
};
|
||||
|
||||
static int32_t nfc_worker_poller(void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
Nfc* instance = context;
|
||||
furi_assert(instance->callback);
|
||||
instance->state = NfcStateRunning;
|
||||
instance->poller_state = NfcPollerStateStart;
|
||||
|
||||
furi_hal_nfc_event_start();
|
||||
|
||||
bool exit = false;
|
||||
while(!exit) {
|
||||
exit = nfc_worker_poller_state_handlers[instance->poller_state](instance);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Nfc* nfc_alloc() {
|
||||
furi_check(furi_hal_nfc_acquire() == FuriHalNfcErrorNone);
|
||||
|
||||
Nfc* instance = malloc(sizeof(Nfc));
|
||||
instance->state = NfcStateIdle;
|
||||
instance->comm_state = NfcCommStateIdle;
|
||||
instance->config_state = NfcConfigurationStateIdle;
|
||||
|
||||
instance->worker_thread = furi_thread_alloc();
|
||||
furi_thread_set_name(instance->worker_thread, "NfcWorker");
|
||||
furi_thread_set_context(instance->worker_thread, instance);
|
||||
furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest);
|
||||
furi_thread_set_stack_size(instance->worker_thread, 8 * 1024);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_free(Nfc* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->state == NfcStateIdle);
|
||||
|
||||
furi_thread_free(instance->worker_thread);
|
||||
free(instance);
|
||||
|
||||
furi_hal_nfc_release();
|
||||
}
|
||||
|
||||
void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech) {
|
||||
furi_assert(instance);
|
||||
furi_assert(mode < NfcModeNum);
|
||||
furi_assert(tech < NfcTechNum);
|
||||
furi_assert(instance->config_state == NfcConfigurationStateIdle);
|
||||
|
||||
FuriHalNfcTech hal_tech = nfc_tech_table[mode][tech];
|
||||
if(hal_tech == FuriHalNfcTechInvalid) {
|
||||
furi_crash("Unsupported mode for given tech");
|
||||
}
|
||||
FuriHalNfcMode hal_mode = (mode == NfcModePoller) ? FuriHalNfcModePoller :
|
||||
FuriHalNfcModeListener;
|
||||
furi_hal_nfc_low_power_mode_stop();
|
||||
furi_hal_nfc_set_mode(hal_mode, hal_tech);
|
||||
|
||||
instance->mode = mode;
|
||||
instance->config_state = NfcConfigurationStateDone;
|
||||
}
|
||||
|
||||
void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) {
|
||||
furi_assert(instance);
|
||||
instance->fdt_poll_fc = fdt_poll_fc;
|
||||
}
|
||||
|
||||
void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc) {
|
||||
furi_assert(instance);
|
||||
instance->fdt_listen_fc = fdt_listen_fc;
|
||||
}
|
||||
|
||||
void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us) {
|
||||
furi_assert(instance);
|
||||
instance->fdt_poll_poll_us = fdt_poll_poll_us;
|
||||
}
|
||||
|
||||
void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) {
|
||||
furi_assert(instance);
|
||||
instance->guard_time_us = guard_time_us;
|
||||
}
|
||||
|
||||
void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) {
|
||||
furi_assert(instance);
|
||||
instance->mask_rx_time_fc = mask_rx_time_fc;
|
||||
}
|
||||
|
||||
void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->worker_thread);
|
||||
furi_assert(callback);
|
||||
furi_assert(instance->config_state == NfcConfigurationStateDone);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
if(instance->mode == NfcModePoller) {
|
||||
furi_thread_set_callback(instance->worker_thread, nfc_worker_poller);
|
||||
} else {
|
||||
furi_thread_set_callback(instance->worker_thread, nfc_worker_listener);
|
||||
}
|
||||
instance->comm_state = NfcCommStateIdle;
|
||||
furi_thread_start(instance->worker_thread);
|
||||
}
|
||||
|
||||
void nfc_stop(Nfc* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->state == NfcStateRunning);
|
||||
|
||||
if(instance->mode == NfcModeListener) {
|
||||
furi_hal_nfc_abort();
|
||||
}
|
||||
furi_thread_join(instance->worker_thread);
|
||||
|
||||
instance->state = NfcStateIdle;
|
||||
}
|
||||
|
||||
NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
}
|
||||
|
||||
FuriHalNfcError error =
|
||||
furi_hal_nfc_listener_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in listener TX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) {
|
||||
FuriHalNfcEvent event = 0;
|
||||
NfcError error = NfcErrorNone;
|
||||
|
||||
while(true) {
|
||||
event = furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventTimerBlockTxExpired) {
|
||||
if(instance->comm_state == NfcCommStateWaitBlockTxTimer) {
|
||||
instance->comm_state = NfcCommStateReadyTx;
|
||||
}
|
||||
}
|
||||
if(event & FuriHalNfcEventTxEnd) {
|
||||
if(instance->comm_state == NfcCommStateWaitTxEnd) {
|
||||
if(fwt_fc) {
|
||||
furi_hal_nfc_timer_fwt_start(fwt_fc);
|
||||
}
|
||||
furi_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us);
|
||||
instance->comm_state = NfcCommStateWaitRxStart;
|
||||
}
|
||||
}
|
||||
if(event & FuriHalNfcEventRxStart) {
|
||||
if(instance->comm_state == NfcCommStateWaitRxStart) {
|
||||
furi_hal_nfc_timer_block_tx_stop();
|
||||
furi_hal_nfc_timer_fwt_stop();
|
||||
instance->comm_state = NfcCommStateWaitRxEnd;
|
||||
}
|
||||
}
|
||||
if(event & FuriHalNfcEventRxEnd) {
|
||||
furi_hal_nfc_timer_block_tx_start(instance->fdt_poll_fc);
|
||||
furi_hal_nfc_timer_fwt_stop();
|
||||
instance->comm_state = NfcCommStateWaitBlockTxTimer;
|
||||
break;
|
||||
}
|
||||
if(event & FuriHalNfcEventTimerFwtExpired) {
|
||||
if(instance->comm_state == NfcCommStateWaitRxStart) {
|
||||
error = NfcErrorTimeout;
|
||||
FURI_LOG_D(TAG, "FWT Timeout");
|
||||
if(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
instance->comm_state = NfcCommStateWaitBlockTxTimer;
|
||||
} else {
|
||||
instance->comm_state = NfcCommStateReadyTx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
NfcError nfc_iso14443a_poller_trx_custom_parity(
|
||||
Nfc* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
|
||||
furi_assert(instance->poller_state == NfcPollerStateReady);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
FuriHalNfcError error = FuriHalNfcErrorNone;
|
||||
do {
|
||||
furi_hal_nfc_trx_reset();
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
FuriHalNfcEvent event =
|
||||
furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventTimerBlockTxExpired) break;
|
||||
}
|
||||
bit_buffer_write_bytes_with_parity(
|
||||
tx_buffer, instance->tx_buffer, sizeof(instance->tx_buffer), &instance->tx_bits);
|
||||
error =
|
||||
furi_hal_nfc_iso14443a_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller TX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
instance->comm_state = NfcCommStateWaitTxEnd;
|
||||
ret = nfc_poller_trx_state_machine(instance, fwt);
|
||||
if(ret != NfcErrorNone) {
|
||||
FURI_LOG_T(TAG, "Failed TRX state machine");
|
||||
break;
|
||||
}
|
||||
|
||||
error = furi_hal_nfc_poller_rx(
|
||||
instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller RX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
if(instance->rx_bits >= 9) {
|
||||
if((instance->rx_bits % 9) != 0) {
|
||||
ret = NfcErrorDataFormat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bit_buffer_copy_bytes_with_parity(rx_buffer, instance->rx_buffer, instance->rx_bits);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NfcError
|
||||
nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
|
||||
furi_assert(instance->poller_state == NfcPollerStateReady);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
FuriHalNfcError error = FuriHalNfcErrorNone;
|
||||
do {
|
||||
furi_hal_nfc_trx_reset();
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
FuriHalNfcEvent event =
|
||||
furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventTimerBlockTxExpired) break;
|
||||
}
|
||||
error =
|
||||
furi_hal_nfc_poller_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller TX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
instance->comm_state = NfcCommStateWaitTxEnd;
|
||||
ret = nfc_poller_trx_state_machine(instance, fwt);
|
||||
if(ret != NfcErrorNone) {
|
||||
FURI_LOG_T(TAG, "Failed TRX state machine");
|
||||
break;
|
||||
}
|
||||
|
||||
error = furi_hal_nfc_poller_rx(
|
||||
instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller RX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
|
||||
bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NfcError nfc_iso14443a_listener_set_col_res_data(
|
||||
Nfc* instance,
|
||||
uint8_t* uid,
|
||||
uint8_t uid_len,
|
||||
uint8_t* atqa,
|
||||
uint8_t sak) {
|
||||
furi_assert(instance);
|
||||
|
||||
FuriHalNfcError error =
|
||||
furi_hal_nfc_iso14443a_listener_set_col_res_data(uid, uid_len, atqa, sak);
|
||||
instance->comm_state = NfcCommStateIdle;
|
||||
return nfc_process_hal_error(error);
|
||||
}
|
||||
|
||||
NfcError nfc_iso14443a_poller_trx_short_frame(
|
||||
Nfc* instance,
|
||||
NfcIso14443aShortFrame frame,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt) {
|
||||
furi_assert(instance);
|
||||
furi_assert(rx_buffer);
|
||||
|
||||
FuriHalNfcaShortFrame short_frame = (frame == NfcIso14443aShortFrameAllReqa) ?
|
||||
FuriHalNfcaShortFrameAllReq :
|
||||
FuriHalNfcaShortFrameSensReq;
|
||||
|
||||
furi_assert(instance->poller_state == NfcPollerStateReady);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
FuriHalNfcError error = FuriHalNfcErrorNone;
|
||||
do {
|
||||
furi_hal_nfc_trx_reset();
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
FuriHalNfcEvent event =
|
||||
furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventTimerBlockTxExpired) break;
|
||||
}
|
||||
error = furi_hal_nfc_iso14443a_poller_trx_short_frame(short_frame);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller TX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
instance->comm_state = NfcCommStateWaitTxEnd;
|
||||
ret = nfc_poller_trx_state_machine(instance, fwt);
|
||||
if(ret != NfcErrorNone) {
|
||||
FURI_LOG_T(TAG, "Failed TRX state machine");
|
||||
break;
|
||||
}
|
||||
|
||||
error = furi_hal_nfc_poller_rx(
|
||||
instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller RX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
|
||||
bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NfcError nfc_iso14443a_poller_trx_sdd_frame(
|
||||
Nfc* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(rx_buffer);
|
||||
|
||||
furi_assert(instance->poller_state == NfcPollerStateReady);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
FuriHalNfcError error = FuriHalNfcErrorNone;
|
||||
do {
|
||||
furi_hal_nfc_trx_reset();
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
FuriHalNfcEvent event =
|
||||
furi_hal_nfc_poller_wait_event(FURI_HAL_NFC_EVENT_WAIT_FOREVER);
|
||||
if(event & FuriHalNfcEventTimerBlockTxExpired) break;
|
||||
}
|
||||
error = furi_hal_nfc_iso14443a_tx_sdd_frame(
|
||||
bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer));
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller TX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
instance->comm_state = NfcCommStateWaitTxEnd;
|
||||
ret = nfc_poller_trx_state_machine(instance, fwt);
|
||||
if(ret != NfcErrorNone) {
|
||||
FURI_LOG_T(TAG, "Failed TRX state machine");
|
||||
break;
|
||||
}
|
||||
|
||||
error = furi_hal_nfc_poller_rx(
|
||||
instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits);
|
||||
if(error != FuriHalNfcErrorNone) {
|
||||
FURI_LOG_D(TAG, "Failed in poller RX");
|
||||
ret = nfc_process_hal_error(error);
|
||||
break;
|
||||
}
|
||||
|
||||
bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits);
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
|
||||
NfcError ret = NfcErrorNone;
|
||||
FuriHalNfcError error = FuriHalNfcErrorNone;
|
||||
|
||||
const uint8_t* tx_data = bit_buffer_get_data(tx_buffer);
|
||||
const uint8_t* tx_parity = bit_buffer_get_parity(tx_buffer);
|
||||
size_t tx_bits = bit_buffer_get_size(tx_buffer);
|
||||
|
||||
error = furi_hal_nfc_iso14443a_listener_tx_custom_parity(tx_data, tx_parity, tx_bits);
|
||||
ret = nfc_process_hal_error(error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
while(furi_hal_nfc_timer_block_tx_is_running()) {
|
||||
}
|
||||
|
||||
FuriHalNfcError error = furi_hal_nfc_iso15693_listener_tx_sof();
|
||||
NfcError ret = nfc_process_hal_error(error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // APP_UNIT_TESTS
|
||||
Reference in New Issue
Block a user