mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-22 21:01:40 +03:00
917410a0a8
* fbt: reworking targets & assets handling WIP * fbt: dist fixes * fbt: moved SD card resources to owning apps * unit_tests: moved resources to app folder * github: updated unit_tests paths * github: packaging fixes * unit_tests: fixes * fbt: assets: internal cleanup * fbt: reworked assets handling * github: unit_tests: reintroducing fixes * minor cleanup * fbt: naming changes to reflect private nature of scons tools * fbt: resources: fixed dist archive paths * docs: updated paths * docs: updated more paths * docs: included "resources" parameter in app manifest docs; updated assets readme * updated gitignore for assets * github: updated action versions * unit_tests: restored timeout; scripts: assets: logging changes * gh: don't upload desktop animations for unit test run Co-authored-by: あく <alleteam@gmail.com>
622 lines
21 KiB
C
622 lines
21 KiB
C
#include "furi_hal_nfc_i.h"
|
|
#include "furi_hal_nfc_tech_i.h"
|
|
|
|
#include <lib/drivers/st25r3916.h>
|
|
|
|
#include <furi.h>
|
|
#include <furi_hal_spi.h>
|
|
|
|
#define TAG "FuriHalNfc"
|
|
|
|
const FuriHalNfcTechBase* furi_hal_nfc_tech[FuriHalNfcTechNum] = {
|
|
[FuriHalNfcTechIso14443a] = &furi_hal_nfc_iso14443a,
|
|
[FuriHalNfcTechIso14443b] = &furi_hal_nfc_iso14443b,
|
|
[FuriHalNfcTechIso15693] = &furi_hal_nfc_iso15693,
|
|
[FuriHalNfcTechFelica] = &furi_hal_nfc_felica,
|
|
// Add new technologies here
|
|
};
|
|
|
|
FuriHalNfc furi_hal_nfc;
|
|
|
|
static FuriHalNfcError furi_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
furi_hal_nfc_event_start();
|
|
|
|
if(!st25r3916_check_reg(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
ST25R3916_REG_OP_CONTROL_en,
|
|
ST25R3916_REG_OP_CONTROL_en)) {
|
|
st25r3916_mask_irq(handle, ~ST25R3916_IRQ_MASK_OSC);
|
|
st25r3916_set_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en);
|
|
furi_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_OSC, 10);
|
|
}
|
|
// Disable IRQs
|
|
st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL);
|
|
|
|
bool osc_on = st25r3916_check_reg(
|
|
handle,
|
|
ST25R3916_REG_AUX_DISPLAY,
|
|
ST25R3916_REG_AUX_DISPLAY_osc_ok,
|
|
ST25R3916_REG_AUX_DISPLAY_osc_ok);
|
|
if(!osc_on) {
|
|
error = FuriHalNfcErrorOscillator;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_is_hal_ready() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
|
|
do {
|
|
error = furi_hal_nfc_acquire();
|
|
if(error != FuriHalNfcErrorNone) break;
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
uint8_t chip_id = 0;
|
|
st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id);
|
|
if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) !=
|
|
ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) {
|
|
FURI_LOG_E(TAG, "Wrong chip id");
|
|
error = FuriHalNfcErrorCommunication;
|
|
}
|
|
|
|
furi_hal_nfc_release();
|
|
} while(false);
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_init() {
|
|
furi_assert(furi_hal_nfc.mutex == NULL);
|
|
|
|
furi_hal_nfc.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
|
|
furi_hal_nfc_event_init();
|
|
furi_hal_nfc_event_start();
|
|
|
|
do {
|
|
error = furi_hal_nfc_acquire();
|
|
if(error != FuriHalNfcErrorNone) {
|
|
furi_hal_nfc_low_power_mode_start();
|
|
}
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
// Set default state
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_SET_DEFAULT);
|
|
// Increase IO driver strength of MISO and IRQ
|
|
st25r3916_write_reg(handle, ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_io_drv_lvl);
|
|
// Check chip ID
|
|
uint8_t chip_id = 0;
|
|
st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id);
|
|
if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) !=
|
|
ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) {
|
|
FURI_LOG_E(TAG, "Wrong chip id");
|
|
error = FuriHalNfcErrorCommunication;
|
|
furi_hal_nfc_low_power_mode_start();
|
|
furi_hal_nfc_release();
|
|
break;
|
|
}
|
|
// Clear interrupts
|
|
st25r3916_get_irq(handle);
|
|
// Mask all interrupts
|
|
st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL);
|
|
// Enable interrupts
|
|
furi_hal_nfc_init_gpio_isr();
|
|
// Disable internal overheat protection
|
|
st25r3916_change_test_reg_bits(handle, 0x04, 0x10, 0x10);
|
|
|
|
error = furi_hal_nfc_turn_on_osc(handle);
|
|
if(error != FuriHalNfcErrorNone) {
|
|
furi_hal_nfc_low_power_mode_start();
|
|
furi_hal_nfc_release();
|
|
break;
|
|
}
|
|
|
|
// Measure voltage
|
|
// Set measure power supply voltage source
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_REGULATOR_CONTROL,
|
|
ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask,
|
|
ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd);
|
|
// Enable timer and interrupt register
|
|
st25r3916_mask_irq(handle, ~ST25R3916_IRQ_MASK_DCT);
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_MEASURE_VDD);
|
|
furi_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_DCT, 100);
|
|
st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL);
|
|
uint8_t ad_res = 0;
|
|
st25r3916_read_reg(handle, ST25R3916_REG_AD_RESULT, &ad_res);
|
|
uint16_t mV = ((uint16_t)ad_res) * 23U;
|
|
mV += (((((uint16_t)ad_res) * 4U) + 5U) / 10U);
|
|
|
|
if(mV < 3600) {
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_IO_CONF2,
|
|
ST25R3916_REG_IO_CONF2_sup3V,
|
|
ST25R3916_REG_IO_CONF2_sup3V_3V);
|
|
} else {
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_IO_CONF2,
|
|
ST25R3916_REG_IO_CONF2_sup3V,
|
|
ST25R3916_REG_IO_CONF2_sup3V_5V);
|
|
}
|
|
|
|
// Disable MCU CLK
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_IO_CONF1,
|
|
ST25R3916_REG_IO_CONF1_out_cl_mask | ST25R3916_REG_IO_CONF1_lf_clk_off,
|
|
0x07);
|
|
// Disable MISO pull-down
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_IO_CONF2,
|
|
ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2,
|
|
0x00);
|
|
// Set tx driver resistance to 1 Om
|
|
st25r3916_change_reg_bits(
|
|
handle, ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_d_res_mask, 0x00);
|
|
// Use minimum non-overlap
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_RES_AM_MOD,
|
|
ST25R3916_REG_RES_AM_MOD_fa3_f,
|
|
ST25R3916_REG_RES_AM_MOD_fa3_f);
|
|
|
|
// Set activation threashold
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV);
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask,
|
|
ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV);
|
|
// Set deactivation threashold
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV);
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask,
|
|
ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV);
|
|
// Enable external load modulation
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_AUX_MOD,
|
|
ST25R3916_REG_AUX_MOD_lm_ext,
|
|
ST25R3916_REG_AUX_MOD_lm_ext);
|
|
// Enable internal load modulation
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_AUX_MOD,
|
|
ST25R3916_REG_AUX_MOD_lm_dri,
|
|
ST25R3916_REG_AUX_MOD_lm_dri);
|
|
// Adjust FDT
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_PASSIVE_TARGET,
|
|
ST25R3916_REG_PASSIVE_TARGET_fdel_mask,
|
|
(5U << ST25R3916_REG_PASSIVE_TARGET_fdel_shift));
|
|
// Reduce RFO resistance in Modulated state
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_PT_MOD,
|
|
ST25R3916_REG_PT_MOD_ptm_res_mask | ST25R3916_REG_PT_MOD_pt_res_mask,
|
|
0x0f);
|
|
// Enable RX start on first 4 bits
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_EMD_SUP_CONF,
|
|
ST25R3916_REG_EMD_SUP_CONF_rx_start_emv,
|
|
ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on);
|
|
// Set antena tunning
|
|
st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_A, 0xff, 0x82);
|
|
st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_B, 0xff, 0x82);
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
ST25R3916_REG_OP_CONTROL_en_fd_mask,
|
|
ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
|
|
|
|
// Perform calibration
|
|
if(st25r3916_check_reg(
|
|
handle,
|
|
ST25R3916_REG_REGULATOR_CONTROL,
|
|
ST25R3916_REG_REGULATOR_CONTROL_reg_s,
|
|
0x00)) {
|
|
FURI_LOG_I(TAG, "Adjusting regulators");
|
|
// Reset logic
|
|
st25r3916_set_reg_bits(
|
|
handle, ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
|
|
st25r3916_clear_reg_bits(
|
|
handle, ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s);
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_ADJUST_REGULATORS);
|
|
furi_delay_ms(6);
|
|
}
|
|
|
|
furi_hal_nfc_low_power_mode_start();
|
|
furi_hal_nfc_release();
|
|
} while(false);
|
|
|
|
return error;
|
|
}
|
|
|
|
static bool furi_hal_nfc_is_mine() {
|
|
return (furi_mutex_get_owner(furi_hal_nfc.mutex) == furi_thread_get_current_id());
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_acquire() {
|
|
furi_check(furi_hal_nfc.mutex);
|
|
|
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
|
|
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
if(furi_mutex_acquire(furi_hal_nfc.mutex, 100) != FuriStatusOk) {
|
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
|
|
error = FuriHalNfcErrorBusy;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_release() {
|
|
furi_check(furi_hal_nfc.mutex);
|
|
furi_check(furi_hal_nfc_is_mine());
|
|
furi_check(furi_mutex_release(furi_hal_nfc.mutex) == FuriStatusOk);
|
|
|
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
|
|
|
|
return FuriHalNfcErrorNone;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_low_power_mode_start() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP);
|
|
st25r3916_clear_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
(ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en |
|
|
ST25R3916_REG_OP_CONTROL_wu | ST25R3916_REG_OP_CONTROL_tx_en |
|
|
ST25R3916_REG_OP_CONTROL_en_fd_mask));
|
|
furi_hal_nfc_deinit_gpio_isr();
|
|
furi_hal_nfc_timers_deinit();
|
|
furi_hal_nfc_event_stop();
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_low_power_mode_stop() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
do {
|
|
furi_hal_nfc_init_gpio_isr();
|
|
furi_hal_nfc_timers_init();
|
|
error = furi_hal_nfc_turn_on_osc(handle);
|
|
if(error != FuriHalNfcErrorNone) break;
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
ST25R3916_REG_OP_CONTROL_en_fd_mask,
|
|
ST25R3916_REG_OP_CONTROL_en_fd_auto_efd);
|
|
|
|
} while(false);
|
|
|
|
return error;
|
|
}
|
|
|
|
static FuriHalNfcError furi_hal_nfc_poller_init_common(FuriHalSpiBusHandle* handle) {
|
|
// Disable wake up
|
|
st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu);
|
|
// Enable correlator
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_AUX,
|
|
ST25R3916_REG_AUX_dis_corr,
|
|
ST25R3916_REG_AUX_dis_corr_correlator);
|
|
|
|
st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_A, 0xff, 0x82);
|
|
st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82);
|
|
|
|
st25r3916_write_reg(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0x00);
|
|
st25r3916_write_reg(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0x00);
|
|
st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0x00);
|
|
st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0x00);
|
|
|
|
return FuriHalNfcErrorNone;
|
|
}
|
|
|
|
static FuriHalNfcError furi_hal_nfc_listener_init_common(FuriHalSpiBusHandle* handle) {
|
|
UNUSED(handle);
|
|
// No common listener configuration
|
|
return FuriHalNfcErrorNone;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_set_mode(FuriHalNfcMode mode, FuriHalNfcTech tech) {
|
|
furi_assert(mode < FuriHalNfcModeNum);
|
|
furi_assert(tech < FuriHalNfcTechNum);
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
|
|
if(mode == FuriHalNfcModePoller) {
|
|
do {
|
|
error = furi_hal_nfc_poller_init_common(handle);
|
|
if(error != FuriHalNfcErrorNone) break;
|
|
error = furi_hal_nfc_tech[tech]->poller.init(handle);
|
|
} while(false);
|
|
|
|
} else if(mode == FuriHalNfcModeListener) {
|
|
do {
|
|
error = furi_hal_nfc_listener_init_common(handle);
|
|
if(error != FuriHalNfcErrorNone) break;
|
|
error = furi_hal_nfc_tech[tech]->listener.init(handle);
|
|
} while(false);
|
|
}
|
|
|
|
furi_hal_nfc.mode = mode;
|
|
furi_hal_nfc.tech = tech;
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_reset_mode() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP);
|
|
|
|
const FuriHalNfcMode mode = furi_hal_nfc.mode;
|
|
const FuriHalNfcTech tech = furi_hal_nfc.tech;
|
|
if(mode == FuriHalNfcModePoller) {
|
|
error = furi_hal_nfc_tech[tech]->poller.deinit(handle);
|
|
} else if(mode == FuriHalNfcModeListener) {
|
|
error = furi_hal_nfc_tech[tech]->listener.deinit(handle);
|
|
}
|
|
// Set default value in mode register
|
|
st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0);
|
|
st25r3916_write_reg(handle, ST25R3916_REG_STREAM_MODE, 0);
|
|
st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx);
|
|
st25r3916_clear_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_BIT_RATE,
|
|
ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask);
|
|
|
|
// Write default values
|
|
st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, 0);
|
|
st25r3916_write_reg(
|
|
handle,
|
|
ST25R3916_REG_RX_CONF2,
|
|
ST25R3916_REG_RX_CONF2_sqm_dyn | ST25R3916_REG_RX_CONF2_agc_en |
|
|
ST25R3916_REG_RX_CONF2_agc_m);
|
|
|
|
st25r3916_write_reg(
|
|
handle,
|
|
ST25R3916_REG_CORR_CONF1,
|
|
ST25R3916_REG_CORR_CONF1_corr_s7 | ST25R3916_REG_CORR_CONF1_corr_s4 |
|
|
ST25R3916_REG_CORR_CONF1_corr_s1 | ST25R3916_REG_CORR_CONF1_corr_s0);
|
|
st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0);
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_field_detect_start() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_write_reg(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask);
|
|
st25r3916_write_reg(
|
|
handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om0);
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_field_detect_stop() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_clear_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
(ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask));
|
|
|
|
return error;
|
|
}
|
|
|
|
bool furi_hal_nfc_field_is_present() {
|
|
bool is_present = false;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
if(st25r3916_check_reg(
|
|
handle,
|
|
ST25R3916_REG_AUX_DISPLAY,
|
|
ST25R3916_REG_AUX_DISPLAY_efd_o,
|
|
ST25R3916_REG_AUX_DISPLAY_efd_o)) {
|
|
is_present = true;
|
|
}
|
|
|
|
return is_present;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_poller_field_on() {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
if(!st25r3916_check_reg(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
ST25R3916_REG_OP_CONTROL_tx_en,
|
|
ST25R3916_REG_OP_CONTROL_tx_en)) {
|
|
// Set min guard time
|
|
st25r3916_write_reg(handle, ST25R3916_REG_FIELD_ON_GT, 0);
|
|
// Enable tx rx
|
|
st25r3916_set_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_OP_CONTROL,
|
|
(ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en));
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_poller_tx_common(
|
|
FuriHalSpiBusHandle* handle,
|
|
const uint8_t* tx_data,
|
|
size_t tx_bits) {
|
|
furi_assert(tx_data);
|
|
|
|
FuriHalNfcError err = FuriHalNfcErrorNone;
|
|
|
|
// Prepare tx
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO);
|
|
st25r3916_clear_reg_bits(
|
|
handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv);
|
|
st25r3916_change_reg_bits(
|
|
handle,
|
|
ST25R3916_REG_ISO14443A_NFC,
|
|
(ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par),
|
|
(ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off));
|
|
uint32_t interrupts =
|
|
(ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS |
|
|
ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC |
|
|
ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE);
|
|
// Clear interrupts
|
|
st25r3916_get_irq(handle);
|
|
// Enable interrupts
|
|
st25r3916_mask_irq(handle, ~interrupts);
|
|
|
|
st25r3916_write_fifo(handle, tx_data, tx_bits);
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC);
|
|
|
|
return err;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_common_fifo_tx(
|
|
FuriHalSpiBusHandle* handle,
|
|
const uint8_t* tx_data,
|
|
size_t tx_bits) {
|
|
FuriHalNfcError err = FuriHalNfcErrorNone;
|
|
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO);
|
|
st25r3916_write_fifo(handle, tx_data, tx_bits);
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC);
|
|
|
|
return err;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModePoller);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->poller.tx(handle, tx_data, tx_bits);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModePoller);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->poller.rx(handle, rx_data, rx_data_size, rx_bits);
|
|
}
|
|
|
|
FuriHalNfcEvent furi_hal_nfc_poller_wait_event(uint32_t timeout_ms) {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModePoller);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->poller.wait_event(timeout_ms);
|
|
}
|
|
|
|
FuriHalNfcEvent furi_hal_nfc_listener_wait_event(uint32_t timeout_ms) {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModeListener);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->listener.wait_event(timeout_ms);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) {
|
|
furi_assert(tx_data);
|
|
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModeListener);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->listener.tx(handle, tx_data, tx_bits);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_common_fifo_rx(
|
|
FuriHalSpiBusHandle* handle,
|
|
uint8_t* rx_data,
|
|
size_t rx_data_size,
|
|
size_t* rx_bits) {
|
|
FuriHalNfcError error = FuriHalNfcErrorNone;
|
|
|
|
if(!st25r3916_read_fifo(handle, rx_data, rx_data_size, rx_bits)) {
|
|
error = FuriHalNfcErrorBufferOverflow;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_listener_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) {
|
|
furi_assert(rx_data);
|
|
furi_assert(rx_bits);
|
|
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModeListener);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->listener.rx(
|
|
handle, rx_data, rx_data_size, rx_bits);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_trx_reset() {
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP);
|
|
|
|
return FuriHalNfcErrorNone;
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_listener_sleep() {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModeListener);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->listener.sleep(handle);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_listener_idle() {
|
|
furi_assert(furi_hal_nfc.mode == FuriHalNfcModeListener);
|
|
furi_assert(furi_hal_nfc.tech < FuriHalNfcTechNum);
|
|
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
return furi_hal_nfc_tech[furi_hal_nfc.tech]->listener.idle(handle);
|
|
}
|
|
|
|
FuriHalNfcError furi_hal_nfc_listener_enable_rx() {
|
|
FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc;
|
|
|
|
st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA);
|
|
|
|
return FuriHalNfcErrorNone;
|
|
}
|