diff options
Diffstat (limited to 'firmware/targets/f6/furi_hal/furi_hal_nfc.c')
-rw-r--r-- | firmware/targets/f6/furi_hal/furi_hal_nfc.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/firmware/targets/f6/furi_hal/furi_hal_nfc.c b/firmware/targets/f6/furi_hal/furi_hal_nfc.c new file mode 100644 index 00000000..be79aca1 --- /dev/null +++ b/firmware/targets/f6/furi_hal/furi_hal_nfc.c @@ -0,0 +1,233 @@ +#include "furi_hal_nfc.h" +#include <st25r3916.h> + +#define TAG "FuriHalNfc" + +static const uint32_t clocks_in_ms = 64 * 1000; + +void furi_hal_nfc_init() { + ReturnCode ret = rfalNfcInitialize(); + if(ret == ERR_NONE) { + furi_hal_nfc_start_sleep(); + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); + } +} + +bool furi_hal_nfc_is_busy() { + return rfalNfcGetState() != RFAL_NFC_STATE_IDLE; +} + +void furi_hal_nfc_field_on() { + furi_hal_nfc_exit_sleep(); + st25r3916TxRxOn(); +} + +void furi_hal_nfc_field_off() { + st25r3916TxRxOff(); + furi_hal_nfc_start_sleep(); +} + +void furi_hal_nfc_start_sleep() { + rfalLowPowerModeStart(); +} + +void furi_hal_nfc_exit_sleep() { + rfalLowPowerModeStop(); +} + +bool furi_hal_nfc_detect( + rfalNfcDevice** dev_list, + uint8_t* dev_cnt, + uint32_t timeout, + bool deactivate) { + furi_assert(dev_list); + furi_assert(dev_cnt); + + rfalLowPowerModeStop(); + rfalNfcState state = rfalNfcGetState(); + if(state == RFAL_NFC_STATE_NOTINIT) { + rfalNfcInitialize(); + } + rfalNfcDiscoverParam params; + params.compMode = RFAL_COMPLIANCE_MODE_EMV; + params.techs2Find = RFAL_NFC_POLL_TECH_A | RFAL_NFC_POLL_TECH_B | RFAL_NFC_POLL_TECH_F | + RFAL_NFC_POLL_TECH_V | RFAL_NFC_POLL_TECH_AP2P | RFAL_NFC_POLL_TECH_ST25TB; + params.totalDuration = 1000; + params.devLimit = 3; + params.wakeupEnabled = false; + params.wakeupConfigDefault = true; + params.nfcfBR = RFAL_BR_212; + params.ap2pBR = RFAL_BR_424; + params.maxBR = RFAL_BR_KEEP; + params.GBLen = RFAL_NFCDEP_GB_MAX_LEN; + params.notifyCb = NULL; + + uint32_t start = DWT->CYCCNT; + rfalNfcDiscover(¶ms); + while(state != RFAL_NFC_STATE_ACTIVATED) { + rfalNfcWorker(); + state = rfalNfcGetState(); + FURI_LOG_T(TAG, "Current state %d", state); + if(state == RFAL_NFC_STATE_POLL_ACTIVATION) { + start = DWT->CYCCNT; + continue; + } + if(state == RFAL_NFC_STATE_POLL_SELECT) { + rfalNfcSelect(0); + } + if(DWT->CYCCNT - start > timeout * clocks_in_ms) { + rfalNfcDeactivate(true); + FURI_LOG_T(TAG, "Timeout"); + return false; + } + osThreadYield(); + } + rfalNfcGetDevicesFound(dev_list, dev_cnt); + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return true; +} + +bool furi_hal_nfc_listen( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak, + bool activate_after_sak, + uint32_t timeout) { + rfalNfcState state = rfalNfcGetState(); + if(state == RFAL_NFC_STATE_NOTINIT) { + rfalNfcInitialize(); + } else if(state >= RFAL_NFC_STATE_ACTIVATED) { + rfalNfcDeactivate(false); + } + rfalLowPowerModeStop(); + rfalNfcDiscoverParam params = { + .compMode = RFAL_COMPLIANCE_MODE_NFC, + .techs2Find = RFAL_NFC_LISTEN_TECH_A, + .totalDuration = 1000, + .devLimit = 1, + .wakeupEnabled = false, + .wakeupConfigDefault = true, + .nfcfBR = RFAL_BR_212, + .ap2pBR = RFAL_BR_424, + .maxBR = RFAL_BR_KEEP, + .GBLen = RFAL_NFCDEP_GB_MAX_LEN, + .notifyCb = NULL, + .activate_after_sak = activate_after_sak, + }; + params.lmConfigPA.nfcidLen = uid_len; + memcpy(params.lmConfigPA.nfcid, uid, uid_len); + params.lmConfigPA.SENS_RES[0] = atqa[0]; + params.lmConfigPA.SENS_RES[1] = atqa[1]; + params.lmConfigPA.SEL_RES = sak; + rfalNfcDiscover(¶ms); + + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_ACTIVATED) { + rfalNfcWorker(); + state = rfalNfcGetState(); + if(DWT->CYCCNT - start > timeout * clocks_in_ms) { + rfalNfcDeactivate(true); + return false; + } + osThreadYield(); + } + return true; +} + +bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { + ReturnCode ret = + rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); + return ret == ERR_NONE; +} + +ReturnCode furi_hal_nfc_data_exchange( + uint8_t* tx_buff, + uint16_t tx_len, + uint8_t** rx_buff, + uint16_t** rx_len, + bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); + if(ret != ERR_NONE) { + return ret; + } + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { + rfalNfcWorker(); + state = rfalNfcGetState(); + ret = rfalNfcDataExchangeGetStatus(); + if(ret > ERR_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +ReturnCode furi_hal_nfc_raw_bitstream_exchange( + uint8_t* tx_buff, + uint16_t tx_bit_len, + uint8_t** rx_buff, + uint16_t** rx_bit_len, + bool deactivate) { + furi_assert(rx_buff); + furi_assert(rx_bit_len); + + ReturnCode ret; + rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; + ret = + rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); + if(ret != ERR_NONE) { + return ret; + } + uint32_t start = DWT->CYCCNT; + while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { + rfalNfcWorker(); + state = rfalNfcGetState(); + ret = rfalNfcDataExchangeGetStatus(); + if(ret > ERR_SLEEP_REQ) { + return ret; + } + if(ret == ERR_BUSY) { + if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { + return ERR_TIMEOUT; + } + continue; + } else { + start = DWT->CYCCNT; + } + taskYIELD(); + } + if(deactivate) { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); + } + return ERR_NONE; +} + +void furi_hal_nfc_deactivate() { + rfalNfcDeactivate(false); + rfalLowPowerModeStart(); +} |