#ifndef APP_UNIT_TESTS
#include "nfc.h"
#include <f_hal_nfc.h>
#include <furi/furi.h>
#define TAG "Nfc"
#define NFC_MAX_BUFFER_SIZE (256)
typedef enum {
NfcStateIdle,
NfcStateChipSleep,
NfcStateChipActive,
NfcStateConfigured,
NfcStateFieldOn,
NfcStateFieldOff,
NfcStateListenStarted,
NfcStatePollerReady,
NfcStatePollerReset,
} NfcState;
typedef enum {
NfcCommStateIdle,
NfcCommStateWaitBlockTxTimer,
NfcCommStateReadyTx,
NfcCommStateWaitTxEnd,
NfcCommStateWaitRxStart,
NfcCommStateWaitRxEnd,
NfcCommStateFailed,
} NfcCommState;
struct Nfc {
NfcState state;
NfcCommState comm_state;
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;
FuriThread* worker_thread;
};
static NfcError nfc_process_hal_error(FHalNfcError error) {
NfcError err = NfcErrorNone;
if(error == FHalNfcErrorNone) {
err = NfcErrorNone;
} else if(error == FHalNfcErrorChipCommunication) {
err = NfcErrorInternal;
}
return err;
}
static int32_t nfc_worker_listener(void* context) {
furi_assert(context);
Nfc* instance = context;
furi_assert(instance->callback);
uint8_t* rx_data = malloc(NFC_MAX_BUFFER_SIZE);
uint16_t rx_bits = 0;
f_hal_nfc_low_power_mode_stop();
NfcEvent nfc_event = {.type = NfcEventTypeConfigureRequest};
instance->callback(nfc_event, instance->context);
f_hal_nfc_listen_start();
instance->state = NfcStateListenStarted;
f_hal_nfc_event_start();
while(true) {
FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER);
if(event & FHalNfcEventAbortRequest) {
FURI_LOG_D(TAG, "Abort request received");
nfc_event.type = NfcEventTypeUserAbort;
instance->callback(nfc_event, instance->context);
break;
}
if(event & FHalNfcEventFieldOn) {
nfc_event.type = NfcEventTypeFieldOn;
instance->callback(nfc_event, instance->context);
}
if(event & FHalNfcEventFieldOff) {
FURI_LOG_T(TAG, "Field off");
nfc_event.type = NfcEventTypeFieldOff;
instance->callback(nfc_event, instance->context);
f_hal_nfc_listener_sleep();
}
if(event & FHalNfcEventListenerActive) {
f_hal_nfc_listener_disable_auto_col_res();
nfc_event.type = NfcEventTypeListenerActivated;
instance->callback(nfc_event, instance->context);
}
if(event & FHalNfcEventRxEnd) {
nfc_event.type = NfcEventTypeRxEnd;
f_hal_nfc_poller_rx(rx_data, sizeof(rx_data), &rx_bits);
nfc_event.data.rx_data = rx_data;
nfc_event.data.rx_bits = rx_bits;
// TODO start block TX timer
instance->callback(nfc_event, instance->context);
}
}
nfc_event.type = NfcEventTypeReset;
instance->callback(nfc_event, instance->context);
nfc_config(instance, NfcModeIdle);
f_hal_nfc_low_power_mode_start();
free(rx_data);
return 0;
}
static int32_t nfc_worker_poller(void* context) {
furi_assert(context);
Nfc* instance = context;
furi_assert(instance->state == NfcStateConfigured);
furi_assert(instance->callback);
instance->state = NfcStateIdle;
NfcEvent nfc_event = {};
NfcCommand cmd = NfcCommandContinue;
f_hal_nfc_event_start();
while(true) {
if(instance->state == NfcStateIdle) {
f_hal_nfc_low_power_mode_stop();
instance->state = NfcStateChipActive;
} else if(instance->state == NfcStateChipSleep) {
f_hal_nfc_low_power_mode_stop();
instance->state = NfcStateChipActive;
} else if(instance->state == NfcStateChipActive) {
nfc_event.type = NfcEventTypeConfigureRequest;
cmd = instance->callback(nfc_event, instance->context);
if(cmd == NfcCommandReset) {
instance->state = NfcStatePollerReset;
} else if(cmd == NfcCommandStop) {
nfc_config(instance, NfcModeIdle);
nfc_event.type = NfcEventTypeReset;
instance->callback(nfc_event, instance->context);
f_hal_nfc_low_power_mode_start();
break;
} else {
instance->state = NfcStateConfigured;
}
} else if(instance->state == NfcStateConfigured) {
f_hal_nfc_poller_field_on();
instance->state = NfcStateFieldOn;
if(instance->guard_time_us) {
f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us);
FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER);
furi_assert(event & FHalNfcEventTimerBlockTxExpired);
}
instance->state = NfcStatePollerReady;
} else if(instance->state == NfcStatePollerReady) {
nfc_event.type = NfcEventTypePollerReady;
cmd = instance->callback(nfc_event, instance->context);
if(cmd == NfcCommandReset) {
instance->state = NfcStatePollerReset;
} else if(cmd == NfcCommandStop) {
nfc_config(instance, NfcModeIdle);
nfc_event.type = NfcEventTypeReset;
instance->callback(nfc_event, instance->context);
f_hal_nfc_low_power_mode_start();
break;
}
} else if(instance->state == NfcStatePollerReset) {
nfc_config(instance, NfcModeIdle);
nfc_event.type = NfcEventTypeReset;
cmd = instance->callback(nfc_event, instance->context);
f_hal_nfc_low_power_mode_start();
if(cmd == NfcCommandStop) {
break;
}
// Delay to power off target nfc device
furi_delay_ms(100);
instance->state = NfcStateChipSleep;
}
}
instance->state = NfcStateChipSleep;
return 0;
}
Nfc* nfc_alloc() {
furi_assert(f_hal_nfc_acquire() == FHalNfcErrorNone);
Nfc* instance = malloc(sizeof(Nfc));
instance->state = NfcStateIdle;
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);
// TODO REWORK!!!
if(instance->state == NfcStateListenStarted) {
f_hal_nfc_abort();
furi_thread_join(instance->worker_thread);
}
furi_thread_free(instance->worker_thread);
f_hal_nfc_low_power_mode_start();
free(instance);
f_hal_nfc_release();
}
void nfc_config(Nfc* instance, NfcMode mode) {
furi_assert(instance);
if(mode == NfcModeIdle) {
f_hal_nfc_reset_mode();
} else if(mode == NfcModeNfcaPoller) {
f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106);
} else if(mode == NfcModeNfcaListener) {
f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106);
}
}
NfcError nfc_listener_set_col_res_data(
Nfc* instance,
uint8_t* uid,
uint8_t uid_len,
uint8_t* atqa,
uint8_t sak) {
furi_assert(instance);
FHalNfcError error = furi_hal_nfca_set_col_res_data(uid, uid_len, atqa, sak);
instance->comm_state = NfcCommStateIdle;
return nfc_process_hal_error(error);
}
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_poller(Nfc* instance, NfcEventCallback callback, void* context) {
furi_assert(instance);
furi_assert(instance->worker_thread);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
furi_thread_set_callback(instance->worker_thread, nfc_worker_poller);
furi_thread_start(instance->worker_thread);
instance->comm_state = NfcCommStateIdle;
}
void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) {
furi_assert(instance);
furi_assert(instance->worker_thread);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
furi_thread_set_callback(instance->worker_thread, nfc_worker_listener);
furi_thread_start(instance->worker_thread);
instance->comm_state = NfcCommStateIdle;
}
void nfc_listener_abort(Nfc* instance) {
furi_assert(instance);
f_hal_nfc_abort();
furi_thread_join(instance->worker_thread);
}
void nfc_stop(Nfc* instance) {
furi_assert(instance);
furi_thread_join(instance->worker_thread);
}
NfcError nfc_listener_sleep(Nfc* instance) {
furi_assert(instance);
furi_assert(instance->state == NfcStateListenStarted);
f_hal_nfc_listener_sleep();
return NfcErrorNone;
}
NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) {
furi_assert(instance);
furi_assert(tx_data);
NfcError ret = NfcErrorNone;
FHalNfcError error = f_hal_nfc_listener_tx(tx_data, tx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(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) {
FHalNfcEvent event = 0;
NfcError error = NfcErrorNone;
while(true) {
event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER);
if(event & FHalNfcEventTimerBlockTxExpired) {
if(instance->comm_state == NfcCommStateWaitBlockTxTimer) {
instance->comm_state = NfcCommStateReadyTx;
}
}
if(event & FHalNfcEventTxEnd) {
if(instance->comm_state == NfcCommStateWaitTxEnd) {
if(fwt_fc) {
f_hal_nfc_timer_fwt_start(fwt_fc);
}
f_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us);
instance->comm_state = NfcCommStateWaitRxStart;
}
}
if(event & FHalNfcEventRxStart) {
if(instance->comm_state == NfcCommStateWaitRxStart) {
f_hal_nfc_timer_block_tx_stop();
f_hal_nfc_timer_fwt_stop();
instance->comm_state = NfcCommStateWaitRxEnd;
}
}
if(event & FHalNfcEventRxEnd) {
f_hal_nfc_timer_block_tx_start(instance->fdt_poll_fc);
f_hal_nfc_timer_fwt_stop();
instance->comm_state = NfcCommStateWaitBlockTxTimer;
break;
}
if(event & FHalNfcEventTimerFwtExpired) {
if(instance->comm_state == NfcCommStateWaitRxStart) {
error = NfcErrorTimeout;
FURI_LOG_W(TAG, "FWT Timeout");
if(f_hal_nfc_timer_block_tx_is_running()) {
instance->comm_state = NfcCommStateWaitBlockTxTimer;
} else {
instance->comm_state = NfcCommStateReadyTx;
}
break;
}
}
}
return error;
}
static NfcError nfc_poller_prepare_trx(Nfc* instance) {
furi_assert(instance);
furi_assert(instance->state == NfcStateIdle);
FHalNfcError error = FHalNfcErrorNone;
NfcError ret = NfcErrorNone;
FHalNfcEvent event = 0;
do {
if(instance->state == NfcStateConfigured) {
error = f_hal_nfc_low_power_mode_stop();
if(error != FHalNfcErrorNone) break;
instance->state = NfcStateChipActive;
}
if(instance->state == NfcStateChipActive) {
error = f_hal_nfc_poller_field_on();
if(error != FHalNfcErrorNone) break;
instance->state = NfcStateFieldOn;
if(instance->guard_time_us) {
f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us);
instance->comm_state = NfcCommStateWaitBlockTxTimer;
event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER);
if(event & FHalNfcEventTimerBlockTxExpired) {
f_hal_nfc_set_mask_receive_timer(instance->mask_rx_time_fc);
instance->comm_state = NfcCommStateReadyTx;
} else {
FURI_LOG_D(TAG, "Unexpected event in tx rx prepare %d", event);
instance->comm_state = NfcCommStateFailed;
}
}
}
} while(false);
ret = nfc_process_hal_error(error);
// Reset FIFO, prepare TX, setup Mask rx timer
f_hal_nfc_trx_reset();
return ret;
}
NfcError nfc_trx_custom_parity(
Nfc* instance,
uint8_t* tx_data,
uint16_t tx_bits,
uint8_t* rx_data,
uint16_t rx_data_size,
uint16_t* rx_bits,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_data);
furi_assert(rx_data);
furi_assert(rx_bits);
furi_assert(instance->state == NfcStateFieldOn);
NfcError ret = NfcErrorNone;
FHalNfcError error = FHalNfcErrorNone;
do {
ret = nfc_poller_prepare_trx(instance);
if(ret != NfcErrorNone) {
FURI_LOG_E(TAG, "Failed in prepare tx rx");
break;
}
error = f_hal_nfc_poller_tx_custom_parity(tx_data, tx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(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_E(TAG, "Failed TRX state machine");
break;
}
error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(TAG, "Failed in poller RX");
ret = nfc_process_hal_error(error);
break;
}
} while(false);
return ret;
}
NfcError nfc_trx(
Nfc* instance,
uint8_t* tx_data,
uint16_t tx_bits,
uint8_t* rx_data,
uint16_t rx_data_size,
uint16_t* rx_bits,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_data);
furi_assert(rx_data);
furi_assert(rx_bits);
furi_assert(instance->state == NfcStateFieldOn);
NfcError ret = NfcErrorNone;
FHalNfcError error = FHalNfcErrorNone;
do {
ret = nfc_poller_prepare_trx(instance);
if(ret != NfcErrorNone) {
FURI_LOG_E(TAG, "Failed in prepare tx rx");
break;
}
error = f_hal_nfc_poller_tx(tx_data, tx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(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_E(TAG, "Failed TRX state machine");
break;
}
error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(TAG, "Failed in poller RX");
ret = nfc_process_hal_error(error);
break;
}
} while(false);
return ret;
}
NfcError nfc_iso13444a_short_frame(
Nfc* instance,
NfcIso14443aShortFrame frame,
uint8_t* rx_data,
uint16_t rx_data_size,
uint16_t* rx_bits,
uint32_t fwt) {
furi_assert(instance);
furi_assert(rx_data);
furi_assert(rx_bits);
FHalNfcaShortFrame short_frame = (frame == NfcIso14443aShortFrameAllReqa) ?
FHalNfcaShortFrameAllReq :
FHalNfcaShortFrameSensReq;
furi_assert(instance->state == NfcStateFieldOn);
NfcError ret = NfcErrorNone;
FHalNfcError error = FHalNfcErrorNone;
do {
ret = nfc_poller_prepare_trx(instance);
if(ret != NfcErrorNone) {
FURI_LOG_E(TAG, "Failed in prepare tx rx");
break;
}
error = f_hal_nfca_send_short_frame(short_frame);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(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_E(TAG, "Failed TRX state machine");
break;
}
error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(TAG, "Failed in poller RX");
ret = nfc_process_hal_error(error);
break;
}
} while(false);
return ret;
}
NfcError nfc_iso13444a_sdd_frame(
Nfc* instance,
uint8_t* tx_data,
uint16_t tx_bits,
uint8_t* rx_data,
uint16_t rx_data_size,
uint16_t* rx_bits,
uint32_t fwt) {
furi_assert(instance);
furi_assert(instance->state == NfcStateFieldOn);
NfcError ret = NfcErrorNone;
FHalNfcError error = FHalNfcErrorNone;
do {
ret = nfc_poller_prepare_trx(instance);
if(ret != NfcErrorNone) {
FURI_LOG_E(TAG, "Failed in prepare tx rx");
break;
}
error = f_hal_nfca_send_sdd_frame(tx_data, tx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(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_E(TAG, "Failed TRX state machine");
break;
}
error = f_hal_nfca_receive_sdd_frame(rx_data, rx_data_size, rx_bits);
if(error != FHalNfcErrorNone) {
FURI_LOG_E(TAG, "Failed in poller RX");
ret = nfc_process_hal_error(error);
break;
}
} while(false);
return ret;
}
#endif // APP_UNIT_TESTS
↑ V579 The f_hal_nfc_poller_rx function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the second argument.