unleashed-firmware/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c
gornekich c00776ca22
[FL-3666] NFC API improvements (#3214)
* drivers: expose st25r3916 driver API
* nfc poller: add start with custom callback
* mf classic: rework sync API with poller custom start
* mf ultralight: rework sync API with poller custom start
* iso14443_3a poller: remove unused col res state
* nfc: rework nfc poller custom start
* mf ultralight: rename sync API
* mf classic: rename sync API
* iso14443-3a: rename sync API
* nfc: remove async prefix in internal functions
* nfc: expose internal API
* nfc: fix sync api include and docs
* targets: fix f18 build
* nfc: rework NfcGenericEventEx type
* nfc poller: add documentation
* iso14443-3a poller: add documentation
* felica poller: add documentation
* iso14443_3b poller: add documentation
* so14443_4a poller: add documentation
* iso14443_4b poller: add documentation
* iso15693 poller: add documentation
* slix poller: add documentation
* mf desfire poller: add documentation
* mf ultralight poller: fix API and add documentation
* mf classic poller: add documentation

Co-authored-by: あく <alleteam@gmail.com>
2023-11-15 17:32:45 +09:00

293 lines
11 KiB
C

#include "iso14443_3a_poller_i.h"
#include <furi.h>
#include "nfc/helpers/iso14443_crc.h"
#define TAG "ISO14443_3A"
static Iso14443_3aError iso14443_3a_poller_process_error(NfcError error) {
Iso14443_3aError ret = Iso14443_3aErrorNone;
if(error == NfcErrorNone) {
ret = Iso14443_3aErrorNone;
} else if(error == NfcErrorTimeout) {
ret = Iso14443_3aErrorTimeout;
} else {
ret = Iso14443_3aErrorNotPresent;
}
return ret;
}
static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange(
Iso14443_3aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
uint16_t tx_bytes = bit_buffer_get_size_bytes(tx_buffer);
furi_assert(tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - 2);
bit_buffer_copy(instance->tx_buffer, tx_buffer);
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer);
Iso14443_3aError ret = Iso14443_3aErrorNone;
do {
NfcError error =
nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt);
if(error != NfcErrorNone) {
ret = iso14443_3a_poller_process_error(error);
break;
}
bit_buffer_copy(rx_buffer, instance->rx_buffer);
if(!iso14443_crc_check(Iso14443CrcTypeA, instance->rx_buffer)) {
ret = Iso14443_3aErrorWrongCrc;
break;
}
iso14443_crc_trim(rx_buffer);
} while(false);
return ret;
}
Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance) {
furi_assert(instance);
furi_assert(instance->nfc);
NfcError error = NfcErrorNone;
Iso14443_3aError ret = Iso14443_3aErrorNone;
do {
error = nfc_iso14443a_poller_trx_short_frame(
instance->nfc,
NfcIso14443aShortFrameSensReq,
instance->rx_buffer,
ISO14443_3A_FDT_LISTEN_FC);
if(error != NfcErrorNone) {
ret = iso14443_3a_poller_process_error(error);
break;
}
if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) {
ret = Iso14443_3aErrorCommunication;
break;
}
} while(false);
return ret;
}
Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(instance->tx_buffer);
uint8_t halt_cmd[2] = {0x50, 0x00};
bit_buffer_copy_bytes(instance->tx_buffer, halt_cmd, sizeof(halt_cmd));
iso14443_3a_poller_standard_frame_exchange(
instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC);
instance->state = Iso14443_3aPollerStateIdle;
return Iso14443_3aErrorNone;
}
Iso14443_3aError
iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data) {
furi_assert(instance);
furi_assert(instance->nfc);
furi_assert(instance->tx_buffer);
furi_assert(instance->rx_buffer);
// Reset Iso14443_3a poller state
memset(&instance->col_res, 0, sizeof(instance->col_res));
memset(instance->data, 0, sizeof(Iso14443_3aData));
bit_buffer_reset(instance->tx_buffer);
bit_buffer_reset(instance->rx_buffer);
// Halt if necessary
if(instance->state != Iso14443_3aPollerStateIdle) {
iso14443_3a_poller_halt(instance);
instance->state = Iso14443_3aPollerStateIdle;
}
NfcError error = NfcErrorNone;
Iso14443_3aError ret = Iso14443_3aErrorNone;
bool activated = false;
do {
error = nfc_iso14443a_poller_trx_short_frame(
instance->nfc,
NfcIso14443aShortFrameSensReq,
instance->rx_buffer,
ISO14443_3A_FDT_LISTEN_FC);
if(error != NfcErrorNone) {
ret = Iso14443_3aErrorNotPresent;
break;
}
if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) {
FURI_LOG_W(TAG, "Wrong sens response size");
ret = Iso14443_3aErrorCommunication;
break;
}
bit_buffer_write_bytes(
instance->rx_buffer,
&instance->col_res.sens_resp,
sizeof(instance->col_res.sens_resp));
memcpy(
instance->data->atqa,
&instance->col_res.sens_resp,
sizeof(instance->col_res.sens_resp));
instance->state = Iso14443_3aPollerStateColResInProgress;
instance->col_res.cascade_level = 0;
instance->col_res.state = Iso14443_3aPollerColResStateStateNewCascade;
while(instance->state == Iso14443_3aPollerStateColResInProgress) {
if(instance->col_res.state == Iso14443_3aPollerColResStateStateNewCascade) {
bit_buffer_set_size_bytes(instance->tx_buffer, 2);
bit_buffer_set_byte(
instance->tx_buffer,
0,
ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level));
bit_buffer_set_byte(instance->tx_buffer, 1, ISO14443_3A_POLLER_SEL_PAR(2, 0));
error = nfc_iso14443a_poller_trx_sdd_frame(
instance->nfc,
instance->tx_buffer,
instance->rx_buffer,
ISO14443_3A_FDT_LISTEN_FC);
if(error != NfcErrorNone) {
FURI_LOG_E(TAG, "Sdd request failed: %d", error);
instance->state = Iso14443_3aPollerStateColResFailed;
ret = Iso14443_3aErrorColResFailed;
break;
}
if(bit_buffer_get_size_bytes(instance->rx_buffer) != 5) {
FURI_LOG_E(TAG, "Sdd response wrong length");
instance->state = Iso14443_3aPollerStateColResFailed;
ret = Iso14443_3aErrorColResFailed;
break;
}
bit_buffer_write_bytes(
instance->rx_buffer, &instance->col_res.sdd_resp, sizeof(Iso14443_3aSddResp));
instance->col_res.state = Iso14443_3aPollerColResStateStateSelectCascade;
} else if(instance->col_res.state == Iso14443_3aPollerColResStateStateSelectCascade) {
instance->col_res.sel_req.sel_cmd =
ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level);
instance->col_res.sel_req.sel_par = ISO14443_3A_POLLER_SEL_PAR(7, 0);
memcpy(
instance->col_res.sel_req.nfcid,
instance->col_res.sdd_resp.nfcid,
sizeof(instance->col_res.sdd_resp.nfcid));
instance->col_res.sel_req.bcc = instance->col_res.sdd_resp.bss;
bit_buffer_copy_bytes(
instance->tx_buffer,
(uint8_t*)&instance->col_res.sel_req,
sizeof(instance->col_res.sel_req));
ret = iso14443_3a_poller_send_standard_frame(
instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC);
if(ret != Iso14443_3aErrorNone) {
FURI_LOG_E(TAG, "Sel request failed: %d", ret);
instance->state = Iso14443_3aPollerStateColResFailed;
ret = Iso14443_3aErrorColResFailed;
break;
}
if(bit_buffer_get_size_bytes(instance->rx_buffer) !=
sizeof(instance->col_res.sel_resp)) {
FURI_LOG_E(TAG, "Sel response wrong length");
instance->state = Iso14443_3aPollerStateColResFailed;
ret = Iso14443_3aErrorColResFailed;
break;
}
bit_buffer_write_bytes(
instance->rx_buffer,
&instance->col_res.sel_resp,
sizeof(instance->col_res.sel_resp));
FURI_LOG_T(TAG, "Sel resp: %02X", instance->col_res.sel_resp.sak);
if(instance->col_res.sel_req.nfcid[0] == ISO14443_3A_POLLER_SDD_CL) {
// Copy part of UID
memcpy(
&instance->data->uid[instance->data->uid_len],
&instance->col_res.sel_req.nfcid[1],
3);
instance->data->uid_len += 3;
instance->col_res.cascade_level++;
instance->col_res.state = Iso14443_3aPollerColResStateStateNewCascade;
} else {
FURI_LOG_T(TAG, "Col resolution complete");
instance->data->sak = instance->col_res.sel_resp.sak;
memcpy(
&instance->data->uid[instance->data->uid_len],
&instance->col_res.sel_req.nfcid[0],
4);
instance->data->uid_len += 4;
instance->col_res.state = Iso14443_3aPollerColResStateStateSuccess;
instance->state = Iso14443_3aPollerStateActivated;
}
}
}
activated = (instance->state == Iso14443_3aPollerStateActivated);
} while(false);
if(activated && iso14443_3a_data) {
*iso14443_3a_data = *instance->data;
}
return ret;
}
Iso14443_3aError iso14443_3a_poller_txrx_custom_parity(
Iso14443_3aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
Iso14443_3aError ret = Iso14443_3aErrorNone;
NfcError error =
nfc_iso14443a_poller_trx_custom_parity(instance->nfc, tx_buffer, rx_buffer, fwt);
if(error != NfcErrorNone) {
ret = iso14443_3a_poller_process_error(error);
}
return ret;
}
Iso14443_3aError iso14443_3a_poller_txrx(
Iso14443_3aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
Iso14443_3aError ret = Iso14443_3aErrorNone;
NfcError error = nfc_poller_trx(instance->nfc, tx_buffer, rx_buffer, fwt);
if(error != NfcErrorNone) {
ret = iso14443_3a_poller_process_error(error);
}
return ret;
}
Iso14443_3aError iso14443_3a_poller_send_standard_frame(
Iso14443_3aPoller* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
furi_assert(instance);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
Iso14443_3aError ret =
iso14443_3a_poller_standard_frame_exchange(instance, tx_buffer, rx_buffer, fwt);
return ret;
}