mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-17 04:34:44 -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:
186
lib/nfc/protocols/iso14443_3a/iso14443_3a.c
Normal file
186
lib/nfc/protocols/iso14443_3a/iso14443_3a.c
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "iso14443_3a.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <nfc/nfc_common.h>
|
||||
|
||||
#define ISO14443A_ATS_BIT (1U << 5)
|
||||
|
||||
#define ISO14443_3A_PROTOCOL_NAME_LEGACY "UID"
|
||||
#define ISO14443_3A_PROTOCOL_NAME "ISO14443-3A"
|
||||
#define ISO14443_3A_DEVICE_NAME "ISO14443-3A (Unknown)"
|
||||
|
||||
#define ISO14443_3A_ATQA_KEY "ATQA"
|
||||
#define ISO14443_3A_SAK_KEY "SAK"
|
||||
|
||||
const NfcDeviceBase nfc_device_iso14443_3a = {
|
||||
.protocol_name = ISO14443_3A_PROTOCOL_NAME,
|
||||
.alloc = (NfcDeviceAlloc)iso14443_3a_alloc,
|
||||
.free = (NfcDeviceFree)iso14443_3a_free,
|
||||
.reset = (NfcDeviceReset)iso14443_3a_reset,
|
||||
.copy = (NfcDeviceCopy)iso14443_3a_copy,
|
||||
.verify = (NfcDeviceVerify)iso14443_3a_verify,
|
||||
.load = (NfcDeviceLoad)iso14443_3a_load,
|
||||
.save = (NfcDeviceSave)iso14443_3a_save,
|
||||
.is_equal = (NfcDeviceEqual)iso14443_3a_is_equal,
|
||||
.get_name = (NfcDeviceGetName)iso14443_3a_get_device_name,
|
||||
.get_uid = (NfcDeviceGetUid)iso14443_3a_get_uid,
|
||||
.set_uid = (NfcDeviceSetUid)iso14443_3a_set_uid,
|
||||
.get_base_data = (NfcDeviceGetBaseData)iso14443_3a_get_base_data,
|
||||
};
|
||||
|
||||
Iso14443_3aData* iso14443_3a_alloc() {
|
||||
Iso14443_3aData* data = malloc(sizeof(Iso14443_3aData));
|
||||
return data;
|
||||
}
|
||||
|
||||
void iso14443_3a_free(Iso14443_3aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
void iso14443_3a_reset(Iso14443_3aData* data) {
|
||||
furi_assert(data);
|
||||
memset(data, 0, sizeof(Iso14443_3aData));
|
||||
}
|
||||
|
||||
void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other) {
|
||||
furi_assert(data);
|
||||
furi_assert(other);
|
||||
|
||||
*data = *other;
|
||||
}
|
||||
|
||||
bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) {
|
||||
UNUSED(data);
|
||||
return furi_string_equal(device_type, ISO14443_3A_PROTOCOL_NAME_LEGACY);
|
||||
}
|
||||
|
||||
bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) {
|
||||
furi_assert(data);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
do {
|
||||
// Common to all format versions
|
||||
if(!flipper_format_read_hex(ff, ISO14443_3A_ATQA_KEY, data->atqa, 2)) break;
|
||||
if(!flipper_format_read_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break;
|
||||
|
||||
if(version > NFC_LSB_ATQA_FORMAT_VERSION) {
|
||||
// Swap ATQA bytes for newer versions
|
||||
FURI_SWAP(data->atqa[0], data->atqa[1]);
|
||||
}
|
||||
|
||||
parsed = true;
|
||||
} while(false);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff) {
|
||||
furi_assert(data);
|
||||
|
||||
bool saved = false;
|
||||
|
||||
do {
|
||||
// Save ATQA in MSB order for correct companion apps display
|
||||
const uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
|
||||
if(!flipper_format_write_comment_cstr(ff, ISO14443_3A_PROTOCOL_NAME " specific data"))
|
||||
break;
|
||||
|
||||
// Write ATQA and SAK
|
||||
if(!flipper_format_write_hex(ff, ISO14443_3A_ATQA_KEY, atqa, 2)) break;
|
||||
if(!flipper_format_write_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break;
|
||||
saved = true;
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other) {
|
||||
furi_assert(data);
|
||||
furi_assert(other);
|
||||
|
||||
return memcmp(data, other, sizeof(Iso14443_3aData)) == 0;
|
||||
}
|
||||
|
||||
const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNameType name_type) {
|
||||
UNUSED(data);
|
||||
UNUSED(name_type);
|
||||
return ISO14443_3A_DEVICE_NAME;
|
||||
}
|
||||
|
||||
const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) {
|
||||
furi_assert(data);
|
||||
|
||||
if(uid_len) {
|
||||
*uid_len = data->uid_len;
|
||||
}
|
||||
|
||||
return data->uid;
|
||||
}
|
||||
|
||||
bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len) {
|
||||
furi_assert(data);
|
||||
|
||||
const bool uid_valid = uid_len == ISO14443_3A_UID_4_BYTES ||
|
||||
uid_len == ISO14443_3A_UID_7_BYTES ||
|
||||
uid_len == ISO14443_3A_UID_10_BYTES;
|
||||
|
||||
if(uid_valid) {
|
||||
memcpy(data->uid, uid, uid_len);
|
||||
data->uid_len = uid_len;
|
||||
}
|
||||
|
||||
return uid_valid;
|
||||
}
|
||||
|
||||
Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) {
|
||||
UNUSED(data);
|
||||
furi_crash("No base data");
|
||||
}
|
||||
|
||||
uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
uint32_t cuid = 0;
|
||||
const uint8_t* cuid_start = data->uid;
|
||||
if(data->uid_len == ISO14443_3A_UID_7_BYTES) {
|
||||
cuid_start = &data->uid[3];
|
||||
}
|
||||
cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]);
|
||||
|
||||
return cuid;
|
||||
}
|
||||
|
||||
bool iso14443_3a_supports_iso14443_4(const Iso14443_3aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
return data->sak & ISO14443A_ATS_BIT;
|
||||
}
|
||||
|
||||
uint8_t iso14443_3a_get_sak(const Iso14443_3aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
return data->sak;
|
||||
}
|
||||
|
||||
void iso14443_3a_get_atqa(const Iso14443_3aData* data, uint8_t atqa[2]) {
|
||||
furi_assert(data);
|
||||
furi_assert(atqa);
|
||||
|
||||
memcpy(atqa, data->atqa, sizeof(data->atqa));
|
||||
}
|
||||
|
||||
void iso14443_3a_set_sak(Iso14443_3aData* data, uint8_t sak) {
|
||||
furi_assert(data);
|
||||
|
||||
data->sak = sak;
|
||||
}
|
||||
|
||||
void iso14443_3a_set_atqa(Iso14443_3aData* data, const uint8_t atqa[2]) {
|
||||
furi_assert(data);
|
||||
furi_assert(atqa);
|
||||
|
||||
memcpy(data->atqa, atqa, sizeof(data->atqa));
|
||||
}
|
||||
107
lib/nfc/protocols/iso14443_3a/iso14443_3a.h
Normal file
107
lib/nfc/protocols/iso14443_3a/iso14443_3a.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <toolbox/bit_buffer.h>
|
||||
#include <nfc/protocols/nfc_device_base_i.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ISO14443_3A_UID_4_BYTES (4U)
|
||||
#define ISO14443_3A_UID_7_BYTES (7U)
|
||||
#define ISO14443_3A_UID_10_BYTES (10U)
|
||||
#define ISO14443_3A_MAX_UID_SIZE ISO14443_3A_UID_10_BYTES
|
||||
|
||||
#define ISO14443_3A_GUARD_TIME_US (5000)
|
||||
#define ISO14443_3A_FDT_POLL_FC (1620)
|
||||
#define ISO14443_3A_FDT_LISTEN_FC (1172)
|
||||
#define ISO14443_3A_POLLER_MASK_RX_FS ((ISO14443_3A_FDT_LISTEN_FC) / 2)
|
||||
#define ISO14443_3A_POLL_POLL_MIN_US (1100)
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aErrorNone,
|
||||
Iso14443_3aErrorNotPresent,
|
||||
Iso14443_3aErrorColResFailed,
|
||||
Iso14443_3aErrorBufferOverflow,
|
||||
Iso14443_3aErrorCommunication,
|
||||
Iso14443_3aErrorFieldOff,
|
||||
Iso14443_3aErrorWrongCrc,
|
||||
Iso14443_3aErrorTimeout,
|
||||
} Iso14443_3aError;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sens_resp[2];
|
||||
} Iso14443_3aSensResp;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sel_cmd;
|
||||
uint8_t sel_par;
|
||||
uint8_t data[4]; // max data bit is 32
|
||||
} Iso14443_3aSddReq;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nfcid[4];
|
||||
uint8_t bss;
|
||||
} Iso14443_3aSddResp;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sel_cmd;
|
||||
uint8_t sel_par;
|
||||
uint8_t nfcid[4];
|
||||
uint8_t bcc;
|
||||
} Iso14443_3aSelReq;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sak;
|
||||
} Iso14443_3aSelResp;
|
||||
|
||||
typedef struct {
|
||||
uint8_t uid[ISO14443_3A_MAX_UID_SIZE];
|
||||
uint8_t uid_len;
|
||||
uint8_t atqa[2];
|
||||
uint8_t sak;
|
||||
} Iso14443_3aData;
|
||||
|
||||
Iso14443_3aData* iso14443_3a_alloc();
|
||||
|
||||
void iso14443_3a_free(Iso14443_3aData* data);
|
||||
|
||||
void iso14443_3a_reset(Iso14443_3aData* data);
|
||||
|
||||
void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other);
|
||||
|
||||
bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type);
|
||||
|
||||
bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version);
|
||||
|
||||
bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff);
|
||||
|
||||
bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other);
|
||||
|
||||
const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNameType name_type);
|
||||
|
||||
const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len);
|
||||
|
||||
bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len);
|
||||
|
||||
Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data);
|
||||
|
||||
uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data);
|
||||
|
||||
// Getters and tests
|
||||
|
||||
bool iso14443_3a_supports_iso14443_4(const Iso14443_3aData* data);
|
||||
|
||||
uint8_t iso14443_3a_get_sak(const Iso14443_3aData* data);
|
||||
|
||||
void iso14443_3a_get_atqa(const Iso14443_3aData* data, uint8_t atqa[2]);
|
||||
|
||||
// Setters
|
||||
|
||||
void iso14443_3a_set_sak(Iso14443_3aData* data, uint8_t sak);
|
||||
|
||||
void iso14443_3a_set_atqa(Iso14443_3aData* data, const uint8_t atqa[2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
5
lib/nfc/protocols/iso14443_3a/iso14443_3a_device_defs.h
Normal file
5
lib/nfc/protocols/iso14443_3a/iso14443_3a_device_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_device_base_i.h>
|
||||
|
||||
extern const NfcDeviceBase nfc_device_iso14443_3a;
|
||||
127
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c
Normal file
127
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "iso14443_3a_listener_i.h"
|
||||
|
||||
#include "nfc/protocols/nfc_listener_base.h"
|
||||
#include "nfc/helpers/iso14443_crc.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/nfc/nfc.h>
|
||||
|
||||
#define TAG "Iso14443_3aListener"
|
||||
|
||||
#define ISO14443_3A_LISTENER_MAX_BUFFER_SIZE (256)
|
||||
|
||||
static bool iso14443_3a_listener_halt_received(BitBuffer* buf) {
|
||||
bool halt_cmd_received = false;
|
||||
|
||||
do {
|
||||
if(bit_buffer_get_size_bytes(buf) != 4) break;
|
||||
if(!iso14443_crc_check(Iso14443CrcTypeA, buf)) break;
|
||||
if(bit_buffer_get_byte(buf, 0) != 0x50) break;
|
||||
if(bit_buffer_get_byte(buf, 1) != 0x00) break;
|
||||
halt_cmd_received = true;
|
||||
} while(false);
|
||||
|
||||
return halt_cmd_received;
|
||||
}
|
||||
|
||||
Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, Iso14443_3aData* data) {
|
||||
furi_assert(nfc);
|
||||
|
||||
Iso14443_3aListener* instance = malloc(sizeof(Iso14443_3aListener));
|
||||
instance->nfc = nfc;
|
||||
instance->data = data;
|
||||
instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_LISTENER_MAX_BUFFER_SIZE);
|
||||
|
||||
instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data;
|
||||
instance->generic_event.protocol = NfcProtocolIso14443_3a;
|
||||
instance->generic_event.instance = instance;
|
||||
instance->generic_event.event_data = &instance->iso14443_3a_event;
|
||||
|
||||
nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC);
|
||||
nfc_config(instance->nfc, NfcModeListener, NfcTechIso14443a);
|
||||
nfc_iso14443a_listener_set_col_res_data(
|
||||
instance->nfc,
|
||||
instance->data->uid,
|
||||
instance->data->uid_len,
|
||||
instance->data->atqa,
|
||||
instance->data->sak);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void iso14443_3a_listener_free(Iso14443_3aListener* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
furi_assert(instance->tx_buffer);
|
||||
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void iso14443_3a_listener_set_callback(
|
||||
Iso14443_3aListener* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
const Iso14443_3aData* iso14443_3a_listener_get_data(Iso14443_3aListener* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.protocol == NfcProtocolInvalid);
|
||||
furi_assert(event.event_data);
|
||||
|
||||
Iso14443_3aListener* instance = context;
|
||||
NfcEvent* nfc_event = event.event_data;
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(nfc_event->type == NfcEventTypeListenerActivated) {
|
||||
instance->state = Iso14443_3aListenerStateActive;
|
||||
} else if(nfc_event->type == NfcEventTypeFieldOff) {
|
||||
instance->state = Iso14443_3aListenerStateIdle;
|
||||
if(instance->callback) {
|
||||
instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff;
|
||||
instance->callback(instance->generic_event, instance->context);
|
||||
}
|
||||
command = NfcCommandSleep;
|
||||
} else if(nfc_event->type == NfcEventTypeRxEnd) {
|
||||
if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) {
|
||||
if(instance->callback) {
|
||||
instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted;
|
||||
instance->callback(instance->generic_event, instance->context);
|
||||
}
|
||||
command = NfcCommandSleep;
|
||||
} else {
|
||||
if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) {
|
||||
instance->iso14443_3a_event.type =
|
||||
Iso14443_3aListenerEventTypeReceivedStandardFrame;
|
||||
iso14443_crc_trim(nfc_event->data.buffer);
|
||||
} else {
|
||||
instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedData;
|
||||
}
|
||||
instance->iso14443_3a_event_data.buffer = nfc_event->data.buffer;
|
||||
if(instance->callback) {
|
||||
command = instance->callback(instance->generic_event, instance->context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
const NfcListenerBase nfc_listener_iso14443_3a = {
|
||||
.alloc = (NfcListenerAlloc)iso14443_3a_listener_alloc,
|
||||
.free = (NfcListenerFree)iso14443_3a_listener_free,
|
||||
.set_callback = (NfcListenerSetCallback)iso14443_3a_listener_set_callback,
|
||||
.get_data = (NfcListenerGetData)iso14443_3a_listener_get_data,
|
||||
.run = (NfcListenerRun)iso14443_3a_listener_run,
|
||||
};
|
||||
31
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h
Normal file
31
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_3a.h"
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Iso14443_3aListener Iso14443_3aListener;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aListenerEventTypeFieldOff,
|
||||
Iso14443_3aListenerEventTypeHalted,
|
||||
|
||||
Iso14443_3aListenerEventTypeReceivedStandardFrame,
|
||||
Iso14443_3aListenerEventTypeReceivedData,
|
||||
} Iso14443_3aListenerEventType;
|
||||
|
||||
typedef struct {
|
||||
BitBuffer* buffer;
|
||||
} Iso14443_3aListenerEventData;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_3aListenerEventType type;
|
||||
Iso14443_3aListenerEventData* data;
|
||||
} Iso14443_3aListenerEvent;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_listener_base.h>
|
||||
|
||||
extern const NfcListenerBase nfc_listener_iso14443_3a;
|
||||
73
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c
Normal file
73
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "iso14443_3a_listener_i.h"
|
||||
|
||||
#include "nfc/helpers/iso14443_crc.h"
|
||||
|
||||
#define TAG "Iso14443_3aListener"
|
||||
|
||||
static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) {
|
||||
Iso14443_3aError ret = Iso14443_3aErrorNone;
|
||||
|
||||
if(error == NfcErrorNone) {
|
||||
ret = Iso14443_3aErrorNone;
|
||||
} else if(error == NfcErrorTimeout) {
|
||||
ret = Iso14443_3aErrorTimeout;
|
||||
} else {
|
||||
ret = Iso14443_3aErrorFieldOff;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso14443_3aError
|
||||
iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
|
||||
Iso14443_3aError ret = Iso14443_3aErrorNone;
|
||||
NfcError error = nfc_listener_tx(instance->nfc, tx_buffer);
|
||||
if(error != NfcErrorNone) {
|
||||
FURI_LOG_W(TAG, "Tx error: %d", error);
|
||||
ret = iso14443_3a_listener_process_nfc_error(error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iso14443_3aError iso14443_3a_listener_tx_with_custom_parity(
|
||||
Iso14443_3aListener* instance,
|
||||
const BitBuffer* tx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
|
||||
Iso14443_3aError ret = Iso14443_3aErrorNone;
|
||||
NfcError error = nfc_iso14443a_listener_tx_custom_parity(instance->nfc, tx_buffer);
|
||||
if(error != NfcErrorNone) {
|
||||
FURI_LOG_W(TAG, "Tx error: %d", error);
|
||||
ret = iso14443_3a_listener_process_nfc_error(error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
Iso14443_3aError iso14443_3a_listener_send_standard_frame(
|
||||
Iso14443_3aListener* instance,
|
||||
const BitBuffer* tx_buffer) {
|
||||
furi_assert(instance);
|
||||
furi_assert(tx_buffer);
|
||||
furi_assert(instance->tx_buffer);
|
||||
|
||||
Iso14443_3aError ret = Iso14443_3aErrorNone;
|
||||
do {
|
||||
bit_buffer_copy(instance->tx_buffer, tx_buffer);
|
||||
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer);
|
||||
|
||||
NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer);
|
||||
if(error != NfcErrorNone) {
|
||||
FURI_LOG_W(TAG, "Tx error: %d", error);
|
||||
ret = iso14443_3a_listener_process_nfc_error(error);
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
42
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h
Normal file
42
lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_3a_listener.h"
|
||||
#include <nfc/protocols/nfc_generic_event.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aListenerStateIdle,
|
||||
Iso14443_3aListenerStateActive,
|
||||
} Iso14443_3aListenerState;
|
||||
|
||||
struct Iso14443_3aListener {
|
||||
Nfc* nfc;
|
||||
Iso14443_3aData* data;
|
||||
Iso14443_3aListenerState state;
|
||||
|
||||
BitBuffer* tx_buffer;
|
||||
|
||||
NfcGenericEvent generic_event;
|
||||
Iso14443_3aListenerEvent iso14443_3a_event;
|
||||
Iso14443_3aListenerEventData iso14443_3a_event_data;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
Iso14443_3aError
|
||||
iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer);
|
||||
|
||||
Iso14443_3aError iso14443_3a_listener_tx_with_custom_parity(
|
||||
Iso14443_3aListener* instance,
|
||||
const BitBuffer* tx_buffer);
|
||||
|
||||
Iso14443_3aError iso14443_3a_listener_send_standard_frame(
|
||||
Iso14443_3aListener* instance,
|
||||
const BitBuffer* tx_buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
128
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c
Normal file
128
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "iso14443_3a_poller_i.h"
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "ISO14443_3A"
|
||||
|
||||
const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
static Iso14443_3aPoller* iso14443_3a_poller_alloc(Nfc* nfc) {
|
||||
furi_assert(nfc);
|
||||
|
||||
Iso14443_3aPoller* instance = malloc(sizeof(Iso14443_3aPoller));
|
||||
instance->nfc = nfc;
|
||||
instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE);
|
||||
instance->rx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE);
|
||||
|
||||
nfc_config(instance->nfc, NfcModePoller, NfcTechIso14443a);
|
||||
nfc_set_guard_time_us(instance->nfc, ISO14443_3A_GUARD_TIME_US);
|
||||
nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3A_FDT_POLL_FC);
|
||||
nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3A_POLL_POLL_MIN_US);
|
||||
instance->data = iso14443_3a_alloc();
|
||||
|
||||
instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data;
|
||||
instance->general_event.protocol = NfcProtocolIso14443_3a;
|
||||
instance->general_event.event_data = &instance->iso14443_3a_event;
|
||||
instance->general_event.instance = instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void iso14443_3a_poller_free_new(Iso14443_3aPoller* iso14443_3a_poller) {
|
||||
furi_assert(iso14443_3a_poller);
|
||||
|
||||
Iso14443_3aPoller* instance = iso14443_3a_poller;
|
||||
furi_assert(instance->tx_buffer);
|
||||
furi_assert(instance->rx_buffer);
|
||||
furi_assert(instance->data);
|
||||
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
bit_buffer_free(instance->rx_buffer);
|
||||
iso14443_3a_free(instance->data);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void iso14443_3a_poller_set_callback(
|
||||
Iso14443_3aPoller* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.protocol == NfcProtocolInvalid);
|
||||
furi_assert(event.event_data);
|
||||
|
||||
Iso14443_3aPoller* instance = context;
|
||||
NfcEvent* nfc_event = event.event_data;
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||
if(instance->state != Iso14443_3aPollerStateActivated) {
|
||||
Iso14443_3aData data = {};
|
||||
Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, &data);
|
||||
if(error == Iso14443_3aErrorNone) {
|
||||
instance->state = Iso14443_3aPollerStateActivated;
|
||||
instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady;
|
||||
instance->iso14443_3a_event_data.error = error;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
} else {
|
||||
instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeError;
|
||||
instance->iso14443_3a_event_data.error = error;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
// Add delay to switch context
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
} else {
|
||||
instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady;
|
||||
instance->iso14443_3a_event_data.error = Iso14443_3aErrorNone;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
}
|
||||
}
|
||||
|
||||
if(command == NfcCommandReset) {
|
||||
instance->state = Iso14443_3aPollerStateIdle;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static bool iso14443_3a_poller_detect(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.event_data);
|
||||
furi_assert(event.instance);
|
||||
furi_assert(event.protocol == NfcProtocolInvalid);
|
||||
|
||||
bool protocol_detected = false;
|
||||
Iso14443_3aPoller* instance = context;
|
||||
NfcEvent* nfc_event = event.event_data;
|
||||
furi_assert(instance->state == Iso14443_3aPollerStateIdle);
|
||||
|
||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||
Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, NULL);
|
||||
protocol_detected = (error == Iso14443_3aErrorNone);
|
||||
}
|
||||
|
||||
return protocol_detected;
|
||||
}
|
||||
|
||||
const NfcPollerBase nfc_poller_iso14443_3a = {
|
||||
.alloc = (NfcPollerAlloc)iso14443_3a_poller_alloc,
|
||||
.free = (NfcPollerFree)iso14443_3a_poller_free_new,
|
||||
.set_callback = (NfcPollerSetCallback)iso14443_3a_poller_set_callback,
|
||||
.run = (NfcPollerRun)iso14443_3a_poller_run,
|
||||
.detect = (NfcPollerDetect)iso14443_3a_poller_detect,
|
||||
.get_data = (NfcPollerGetData)iso14443_3a_poller_get_data,
|
||||
};
|
||||
42
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h
Normal file
42
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_3a.h"
|
||||
#include <lib/nfc/nfc.h>
|
||||
|
||||
#include <nfc/nfc_poller.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Iso14443_3aPoller Iso14443_3aPoller;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aPollerEventTypeError,
|
||||
Iso14443_3aPollerEventTypeReady,
|
||||
} Iso14443_3aPollerEventType;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_3aError error;
|
||||
} Iso14443_3aPollerEventData;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_3aPollerEventType type;
|
||||
Iso14443_3aPollerEventData* data;
|
||||
} Iso14443_3aPollerEvent;
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_txrx(
|
||||
Iso14443_3aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt);
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_send_standard_frame(
|
||||
Iso14443_3aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
5
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h
Normal file
5
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
extern const NfcPollerBase nfc_poller_iso14443_3a;
|
||||
293
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c
Normal file
293
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c
Normal file
@@ -0,0 +1,293 @@
|
||||
#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_async_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;
|
||||
}
|
||||
81
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h
Normal file
81
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_3a_poller.h"
|
||||
|
||||
#include <toolbox/bit_buffer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ISO14443_3A_POLLER_MAX_BUFFER_SIZE (512U)
|
||||
|
||||
#define ISO14443_3A_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl))
|
||||
#define ISO14443_3A_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU))
|
||||
#define ISO14443_3A_POLLER_SDD_CL (0x88U)
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aPollerColResStateStateIdle,
|
||||
Iso14443_3aPollerColResStateStateNewCascade,
|
||||
Iso14443_3aPollerColResStateStateSelectCascade,
|
||||
Iso14443_3aPollerColResStateStateSuccess,
|
||||
Iso14443_3aPollerColResStateStateFail,
|
||||
} Iso14443_3aPollerColResState;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_3aPollerColResState state;
|
||||
Iso14443_3aSensResp sens_resp;
|
||||
Iso14443_3aSddReq sdd_req;
|
||||
Iso14443_3aSddResp sdd_resp;
|
||||
Iso14443_3aSelReq sel_req;
|
||||
Iso14443_3aSelResp sel_resp;
|
||||
uint8_t cascade_level;
|
||||
} Iso14443_3aPollerColRes;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aPollerStateIdle,
|
||||
Iso14443_3aPollerStateColResInProgress,
|
||||
Iso14443_3aPollerStateColResFailed,
|
||||
Iso14443_3aPollerStateActivated,
|
||||
} Iso14443_3aPollerState;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_3aPollerConfigStateIdle,
|
||||
Iso14443_3aPollerConfigStateDone,
|
||||
} Iso14443_3aPollerConfigState;
|
||||
|
||||
struct Iso14443_3aPoller {
|
||||
Nfc* nfc;
|
||||
Iso14443_3aPollerState state;
|
||||
Iso14443_3aPollerConfigState config_state;
|
||||
Iso14443_3aPollerColRes col_res;
|
||||
Iso14443_3aData* data;
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
|
||||
NfcGenericEvent general_event;
|
||||
Iso14443_3aPollerEvent iso14443_3a_event;
|
||||
Iso14443_3aPollerEventData iso14443_3a_event_data;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance);
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance);
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_async_activate(
|
||||
Iso14443_3aPoller* instance,
|
||||
Iso14443_3aData* iso14443_3a_data);
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance);
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_txrx_custom_parity(
|
||||
Iso14443_3aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer,
|
||||
uint32_t fwt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
58
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c
Normal file
58
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "iso14443_3a_poller_sync_api.h"
|
||||
|
||||
#include "iso14443_3a_poller_i.h"
|
||||
#include <nfc/nfc_poller.h>
|
||||
|
||||
#include <furi/furi.h>
|
||||
|
||||
#define ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0)
|
||||
|
||||
typedef struct {
|
||||
Iso14443_3aPoller* instance;
|
||||
FuriThreadId thread_id;
|
||||
Iso14443_3aError error;
|
||||
Iso14443_3aData data;
|
||||
} Iso14443_3aPollerContext;
|
||||
|
||||
NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.event_data);
|
||||
furi_assert(event.instance);
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
||||
|
||||
Iso14443_3aPollerContext* poller_context = context;
|
||||
Iso14443_3aPoller* iso14443_3a_poller = event.instance;
|
||||
Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data;
|
||||
|
||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||
iso14443_3a_copy(&poller_context->data, iso14443_3a_poller->data);
|
||||
}
|
||||
poller_context->error = iso14443_3a_event->data->error;
|
||||
|
||||
furi_thread_flags_set(poller_context->thread_id, ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE);
|
||||
|
||||
return NfcCommandStop;
|
||||
}
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) {
|
||||
furi_assert(nfc);
|
||||
furi_assert(iso14443_3a_data);
|
||||
|
||||
Iso14443_3aPollerContext poller_context = {};
|
||||
poller_context.thread_id = furi_thread_get_current_id();
|
||||
|
||||
NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
|
||||
nfc_poller_start(poller, iso14443_3a_poller_read_callback, &poller_context);
|
||||
furi_thread_flags_wait(
|
||||
ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_thread_flags_clear(ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE);
|
||||
|
||||
nfc_poller_stop(poller);
|
||||
nfc_poller_free(poller);
|
||||
|
||||
if(poller_context.error == Iso14443_3aErrorNone) {
|
||||
*iso14443_3a_data = poller_context.data;
|
||||
}
|
||||
|
||||
return poller_context.error;
|
||||
}
|
||||
14
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h
Normal file
14
lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_3a.h"
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user