mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-04 18:31:54 -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:
@@ -0,0 +1,300 @@
|
||||
#include "iso14443_4a_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define ISO14443_4A_PROTOCOL_NAME "ISO14443-4A"
|
||||
#define ISO14443_4A_DEVICE_NAME "ISO14443-4A (Unknown)"
|
||||
|
||||
#define ISO14443_4A_T0_KEY "T0"
|
||||
#define ISO14443_4A_TA1_KEY "TA(1)"
|
||||
#define ISO14443_4A_TB1_KEY "TB(1)"
|
||||
#define ISO14443_4A_TC1_KEY "TC(1)"
|
||||
#define ISO14443_4A_T1_TK_KEY "T1...Tk"
|
||||
|
||||
#define ISO14443_4A_FDT_DEFAULT_FC ISO14443_3A_FDT_POLL_FC
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aInterfaceByteTA1,
|
||||
Iso14443_4aInterfaceByteTB1,
|
||||
Iso14443_4aInterfaceByteTC1,
|
||||
} Iso14443_4aInterfaceByte;
|
||||
|
||||
const NfcDeviceBase nfc_device_iso14443_4a = {
|
||||
.protocol_name = ISO14443_4A_PROTOCOL_NAME,
|
||||
.alloc = (NfcDeviceAlloc)iso14443_4a_alloc,
|
||||
.free = (NfcDeviceFree)iso14443_4a_free,
|
||||
.reset = (NfcDeviceReset)iso14443_4a_reset,
|
||||
.copy = (NfcDeviceCopy)iso14443_4a_copy,
|
||||
.verify = (NfcDeviceVerify)iso14443_4a_verify,
|
||||
.load = (NfcDeviceLoad)iso14443_4a_load,
|
||||
.save = (NfcDeviceSave)iso14443_4a_save,
|
||||
.is_equal = (NfcDeviceEqual)iso14443_4a_is_equal,
|
||||
.get_name = (NfcDeviceGetName)iso14443_4a_get_device_name,
|
||||
.get_uid = (NfcDeviceGetUid)iso14443_4a_get_uid,
|
||||
.set_uid = (NfcDeviceSetUid)iso14443_4a_set_uid,
|
||||
.get_base_data = (NfcDeviceGetBaseData)iso14443_4a_get_base_data,
|
||||
};
|
||||
|
||||
Iso14443_4aData* iso14443_4a_alloc() {
|
||||
Iso14443_4aData* data = malloc(sizeof(Iso14443_4aData));
|
||||
|
||||
data->iso14443_3a_data = iso14443_3a_alloc();
|
||||
data->ats_data.t1_tk = simple_array_alloc(&simple_array_config_uint8_t);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void iso14443_4a_free(Iso14443_4aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
simple_array_free(data->ats_data.t1_tk);
|
||||
iso14443_3a_free(data->iso14443_3a_data);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
void iso14443_4a_reset(Iso14443_4aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
iso14443_3a_reset(data->iso14443_3a_data);
|
||||
|
||||
data->ats_data.tl = 1;
|
||||
data->ats_data.t0 = 0;
|
||||
data->ats_data.ta_1 = 0;
|
||||
data->ats_data.tb_1 = 0;
|
||||
data->ats_data.tc_1 = 0;
|
||||
|
||||
simple_array_reset(data->ats_data.t1_tk);
|
||||
}
|
||||
|
||||
void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) {
|
||||
furi_assert(data);
|
||||
furi_assert(other);
|
||||
|
||||
iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data);
|
||||
|
||||
data->ats_data.tl = other->ats_data.tl;
|
||||
data->ats_data.t0 = other->ats_data.t0;
|
||||
data->ats_data.ta_1 = other->ats_data.ta_1;
|
||||
data->ats_data.tb_1 = other->ats_data.tb_1;
|
||||
data->ats_data.tc_1 = other->ats_data.tc_1;
|
||||
|
||||
simple_array_copy(data->ats_data.t1_tk, other->ats_data.t1_tk);
|
||||
}
|
||||
|
||||
bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) {
|
||||
UNUSED(data);
|
||||
UNUSED(device_type);
|
||||
|
||||
// Empty, unified file format only
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) {
|
||||
furi_assert(data);
|
||||
|
||||
bool parsed = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break;
|
||||
|
||||
Iso14443_4aAtsData* ats_data = &data->ats_data;
|
||||
|
||||
ats_data->tl = 1;
|
||||
|
||||
if(flipper_format_key_exist(ff, ISO14443_4A_T0_KEY)) {
|
||||
if(!flipper_format_read_hex(ff, ISO14443_4A_T0_KEY, &ats_data->t0, 1)) break;
|
||||
++ats_data->tl;
|
||||
}
|
||||
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TA1) {
|
||||
if(!flipper_format_key_exist(ff, ISO14443_4A_TA1_KEY)) break;
|
||||
if(!flipper_format_read_hex(ff, ISO14443_4A_TA1_KEY, &ats_data->ta_1, 1)) break;
|
||||
++ats_data->tl;
|
||||
}
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TB1) {
|
||||
if(!flipper_format_key_exist(ff, ISO14443_4A_TB1_KEY)) break;
|
||||
if(!flipper_format_read_hex(ff, ISO14443_4A_TB1_KEY, &ats_data->tb_1, 1)) break;
|
||||
++ats_data->tl;
|
||||
}
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TC1) {
|
||||
if(!flipper_format_key_exist(ff, ISO14443_4A_TC1_KEY)) break;
|
||||
if(!flipper_format_read_hex(ff, ISO14443_4A_TC1_KEY, &ats_data->tc_1, 1)) break;
|
||||
++ats_data->tl;
|
||||
}
|
||||
|
||||
if(flipper_format_key_exist(ff, ISO14443_4A_T1_TK_KEY)) {
|
||||
uint32_t t1_tk_size;
|
||||
if(!flipper_format_get_value_count(ff, ISO14443_4A_T1_TK_KEY, &t1_tk_size)) break;
|
||||
|
||||
if(t1_tk_size > 0) {
|
||||
simple_array_init(ats_data->t1_tk, t1_tk_size);
|
||||
if(!flipper_format_read_hex(
|
||||
ff,
|
||||
ISO14443_4A_T1_TK_KEY,
|
||||
simple_array_get_data(ats_data->t1_tk),
|
||||
t1_tk_size))
|
||||
break;
|
||||
ats_data->tl += t1_tk_size;
|
||||
}
|
||||
}
|
||||
parsed = true;
|
||||
} while(false);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) {
|
||||
furi_assert(data);
|
||||
|
||||
bool saved = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break;
|
||||
if(!flipper_format_write_comment_cstr(ff, ISO14443_4A_PROTOCOL_NAME " specific data"))
|
||||
break;
|
||||
|
||||
const Iso14443_4aAtsData* ats_data = &data->ats_data;
|
||||
|
||||
if(ats_data->tl > 1) {
|
||||
if(!flipper_format_write_hex(ff, ISO14443_4A_T0_KEY, &ats_data->t0, 1)) break;
|
||||
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TA1) {
|
||||
if(!flipper_format_write_hex(ff, ISO14443_4A_TA1_KEY, &ats_data->ta_1, 1)) break;
|
||||
}
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TB1) {
|
||||
if(!flipper_format_write_hex(ff, ISO14443_4A_TB1_KEY, &ats_data->tb_1, 1)) break;
|
||||
}
|
||||
if(ats_data->t0 & ISO14443_4A_ATS_T0_TC1) {
|
||||
if(!flipper_format_write_hex(ff, ISO14443_4A_TC1_KEY, &ats_data->tc_1, 1)) break;
|
||||
}
|
||||
|
||||
const uint32_t t1_tk_size = simple_array_get_count(ats_data->t1_tk);
|
||||
if(t1_tk_size > 0) {
|
||||
if(!flipper_format_write_hex(
|
||||
ff,
|
||||
ISO14443_4A_T1_TK_KEY,
|
||||
simple_array_cget_data(ats_data->t1_tk),
|
||||
t1_tk_size))
|
||||
break;
|
||||
}
|
||||
}
|
||||
saved = true;
|
||||
} while(false);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) {
|
||||
return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data);
|
||||
}
|
||||
|
||||
const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNameType name_type) {
|
||||
UNUSED(data);
|
||||
UNUSED(name_type);
|
||||
return ISO14443_4A_DEVICE_NAME;
|
||||
}
|
||||
|
||||
const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) {
|
||||
return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len);
|
||||
}
|
||||
|
||||
bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len) {
|
||||
furi_assert(data);
|
||||
|
||||
return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len);
|
||||
}
|
||||
|
||||
Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
return data->iso14443_3a_data;
|
||||
}
|
||||
|
||||
uint16_t iso14443_4a_get_frame_size_max(const Iso14443_4aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
const uint8_t fsci = data->ats_data.t0 & 0x0F;
|
||||
|
||||
if(fsci < 5) {
|
||||
return fsci * 8 + 16;
|
||||
} else if(fsci == 5) {
|
||||
return 64;
|
||||
} else if(fsci == 6) {
|
||||
return 96;
|
||||
} else if(fsci < 13) {
|
||||
return 128U << (fsci - 7);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t iso14443_4a_get_fwt_fc_max(const Iso14443_4aData* data) {
|
||||
furi_assert(data);
|
||||
|
||||
uint32_t fwt_fc_max = ISO14443_4A_FDT_DEFAULT_FC;
|
||||
|
||||
do {
|
||||
if(!(data->ats_data.tl > 1)) break;
|
||||
if(!(data->ats_data.t0 & ISO14443_4A_ATS_T0_TB1)) break;
|
||||
|
||||
const uint8_t fwi = data->ats_data.tb_1 >> 4;
|
||||
if(fwi == 0x0F) break;
|
||||
|
||||
fwt_fc_max = 4096UL << fwi;
|
||||
} while(false);
|
||||
|
||||
return fwt_fc_max;
|
||||
}
|
||||
|
||||
const uint8_t* iso14443_4a_get_historical_bytes(const Iso14443_4aData* data, uint32_t* count) {
|
||||
furi_assert(data);
|
||||
furi_assert(count);
|
||||
|
||||
*count = simple_array_get_count(data->ats_data.t1_tk);
|
||||
return simple_array_cget_data(data->ats_data.t1_tk);
|
||||
}
|
||||
|
||||
bool iso14443_4a_supports_bit_rate(const Iso14443_4aData* data, Iso14443_4aBitRate bit_rate) {
|
||||
furi_assert(data);
|
||||
|
||||
if(!(data->ats_data.t0 & ISO14443_4A_ATS_T0_TA1))
|
||||
return bit_rate == Iso14443_4aBitRateBoth106Kbit;
|
||||
|
||||
const uint8_t ta_1 = data->ats_data.ta_1;
|
||||
|
||||
switch(bit_rate) {
|
||||
case Iso14443_4aBitRateBoth106Kbit:
|
||||
return ta_1 == ISO14443_4A_ATS_TA1_BOTH_SAME_COMPULSORY;
|
||||
case Iso14443_4aBitRatePiccToPcd212Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PCD_TO_PICC_212KBIT;
|
||||
case Iso14443_4aBitRatePiccToPcd424Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PCD_TO_PICC_424KBIT;
|
||||
case Iso14443_4aBitRatePiccToPcd848Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PCD_TO_PICC_848KBIT;
|
||||
case Iso14443_4aBitRatePcdToPicc212Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PICC_TO_PCD_212KBIT;
|
||||
case Iso14443_4aBitRatePcdToPicc424Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PICC_TO_PCD_424KBIT;
|
||||
case Iso14443_4aBitRatePcdToPicc848Kbit:
|
||||
return ta_1 & ISO14443_4A_ATS_TA1_PICC_TO_PCD_848KBIT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool iso14443_4a_supports_frame_option(const Iso14443_4aData* data, Iso14443_4aFrameOption option) {
|
||||
furi_assert(data);
|
||||
|
||||
const Iso14443_4aAtsData* ats_data = &data->ats_data;
|
||||
if(!(ats_data->t0 & ISO14443_4A_ATS_T0_TC1)) return false;
|
||||
|
||||
switch(option) {
|
||||
case Iso14443_4aFrameOptionNad:
|
||||
return ats_data->tc_1 & ISO14443_4A_ATS_TC1_NAD;
|
||||
case Iso14443_4aFrameOptionCid:
|
||||
return ats_data->tc_1 & ISO14443_4A_ATS_TC1_CID;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aErrorNone,
|
||||
Iso14443_4aErrorNotPresent,
|
||||
Iso14443_4aErrorProtocol,
|
||||
Iso14443_4aErrorTimeout,
|
||||
} Iso14443_4aError;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aBitRateBoth106Kbit,
|
||||
Iso14443_4aBitRatePiccToPcd212Kbit,
|
||||
Iso14443_4aBitRatePiccToPcd424Kbit,
|
||||
Iso14443_4aBitRatePiccToPcd848Kbit,
|
||||
Iso14443_4aBitRatePcdToPicc212Kbit,
|
||||
Iso14443_4aBitRatePcdToPicc424Kbit,
|
||||
Iso14443_4aBitRatePcdToPicc848Kbit,
|
||||
} Iso14443_4aBitRate;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aFrameOptionNad,
|
||||
Iso14443_4aFrameOptionCid,
|
||||
} Iso14443_4aFrameOption;
|
||||
|
||||
typedef struct Iso14443_4aData Iso14443_4aData;
|
||||
|
||||
// Virtual methods
|
||||
|
||||
Iso14443_4aData* iso14443_4a_alloc();
|
||||
|
||||
void iso14443_4a_free(Iso14443_4aData* data);
|
||||
|
||||
void iso14443_4a_reset(Iso14443_4aData* data);
|
||||
|
||||
void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other);
|
||||
|
||||
bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type);
|
||||
|
||||
bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version);
|
||||
|
||||
bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff);
|
||||
|
||||
bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other);
|
||||
|
||||
const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNameType name_type);
|
||||
|
||||
const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len);
|
||||
|
||||
bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len);
|
||||
|
||||
Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data);
|
||||
|
||||
// Getters & Tests
|
||||
|
||||
uint16_t iso14443_4a_get_frame_size_max(const Iso14443_4aData* data);
|
||||
|
||||
uint32_t iso14443_4a_get_fwt_fc_max(const Iso14443_4aData* data);
|
||||
|
||||
const uint8_t* iso14443_4a_get_historical_bytes(const Iso14443_4aData* data, uint32_t* count);
|
||||
|
||||
bool iso14443_4a_supports_bit_rate(const Iso14443_4aData* data, Iso14443_4aBitRate bit_rate);
|
||||
|
||||
bool iso14443_4a_supports_frame_option(const Iso14443_4aData* data, Iso14443_4aFrameOption option);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_device_base_i.h>
|
||||
|
||||
extern const NfcDeviceBase nfc_device_iso14443_4a;
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "iso14443_4a_i.h"
|
||||
|
||||
bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) {
|
||||
bool can_parse = false;
|
||||
|
||||
do {
|
||||
const size_t buf_size = bit_buffer_get_size_bytes(buf);
|
||||
if(buf_size == 0) break;
|
||||
|
||||
size_t current_index = 0;
|
||||
|
||||
const uint8_t tl = bit_buffer_get_byte(buf, current_index++);
|
||||
if(tl != buf_size) break;
|
||||
|
||||
data->tl = tl;
|
||||
|
||||
if(tl > 1) {
|
||||
const uint8_t t0 = bit_buffer_get_byte(buf, current_index++);
|
||||
|
||||
const bool has_ta_1 = t0 & ISO14443_4A_ATS_T0_TA1;
|
||||
const bool has_tb_1 = t0 & ISO14443_4A_ATS_T0_TB1;
|
||||
const bool has_tc_1 = t0 & ISO14443_4A_ATS_T0_TC1;
|
||||
|
||||
const uint8_t buf_size_min =
|
||||
2 + (has_ta_1 ? 1 : 0) + (has_tb_1 ? 1 : 0) + (has_tc_1 ? 1 : 0);
|
||||
|
||||
if(buf_size < buf_size_min) break;
|
||||
|
||||
data->t0 = t0;
|
||||
|
||||
if(has_ta_1) {
|
||||
data->ta_1 = bit_buffer_get_byte(buf, current_index++);
|
||||
}
|
||||
if(has_tb_1) {
|
||||
data->tb_1 = bit_buffer_get_byte(buf, current_index++);
|
||||
}
|
||||
if(has_tc_1) {
|
||||
data->tc_1 = bit_buffer_get_byte(buf, current_index++);
|
||||
}
|
||||
|
||||
const uint8_t t1_tk_size = buf_size - buf_size_min;
|
||||
|
||||
if(t1_tk_size > 0) {
|
||||
simple_array_init(data->t1_tk, t1_tk_size);
|
||||
bit_buffer_write_bytes_mid(
|
||||
buf, simple_array_get_data(data->t1_tk), current_index, t1_tk_size);
|
||||
}
|
||||
}
|
||||
|
||||
can_parse = true;
|
||||
} while(false);
|
||||
|
||||
return can_parse;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error) {
|
||||
switch(error) {
|
||||
case Iso14443_3aErrorNone:
|
||||
return Iso14443_4aErrorNone;
|
||||
case Iso14443_3aErrorNotPresent:
|
||||
return Iso14443_4aErrorNotPresent;
|
||||
case Iso14443_3aErrorColResFailed:
|
||||
case Iso14443_3aErrorCommunication:
|
||||
case Iso14443_3aErrorWrongCrc:
|
||||
return Iso14443_4aErrorProtocol;
|
||||
case Iso14443_3aErrorTimeout:
|
||||
return Iso14443_4aErrorTimeout;
|
||||
default:
|
||||
return Iso14443_4aErrorProtocol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "iso14443_4a.h"
|
||||
|
||||
#include <lib/toolbox/simple_array.h>
|
||||
|
||||
#define ISO14443_4A_CMD_READ_ATS (0xE0)
|
||||
|
||||
// ATS bit definitions
|
||||
#define ISO14443_4A_ATS_T0_TA1 (1U << 4)
|
||||
#define ISO14443_4A_ATS_T0_TB1 (1U << 5)
|
||||
#define ISO14443_4A_ATS_T0_TC1 (1U << 6)
|
||||
|
||||
#define ISO14443_4A_ATS_TA1_BOTH_106KBIT (0U << 0)
|
||||
#define ISO14443_4A_ATS_TA1_PCD_TO_PICC_212KBIT (1U << 0)
|
||||
#define ISO14443_4A_ATS_TA1_PCD_TO_PICC_424KBIT (1U << 1)
|
||||
#define ISO14443_4A_ATS_TA1_PCD_TO_PICC_848KBIT (1U << 2)
|
||||
#define ISO14443_4A_ATS_TA1_PICC_TO_PCD_212KBIT (1U << 4)
|
||||
#define ISO14443_4A_ATS_TA1_PICC_TO_PCD_424KBIT (1U << 5)
|
||||
#define ISO14443_4A_ATS_TA1_PICC_TO_PCD_848KBIT (1U << 6)
|
||||
#define ISO14443_4A_ATS_TA1_BOTH_SAME_COMPULSORY (1U << 7)
|
||||
|
||||
#define ISO14443_4A_ATS_TC1_NAD (1U << 0)
|
||||
#define ISO14443_4A_ATS_TC1_CID (1U << 1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t tl;
|
||||
uint8_t t0;
|
||||
uint8_t ta_1;
|
||||
uint8_t tb_1;
|
||||
uint8_t tc_1;
|
||||
SimpleArray* t1_tk;
|
||||
} Iso14443_4aAtsData;
|
||||
|
||||
struct Iso14443_4aData {
|
||||
Iso14443_3aData* iso14443_3a_data;
|
||||
Iso14443_4aAtsData ats_data;
|
||||
};
|
||||
|
||||
bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf);
|
||||
|
||||
Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error);
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "iso14443_4a_listener_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <nfc/protocols/nfc_listener_base.h>
|
||||
|
||||
#define TAG "Iso14443_4aListener"
|
||||
|
||||
#define ISO14443_4A_LISTENER_BUF_SIZE (256U)
|
||||
|
||||
static Iso14443_4aListener*
|
||||
iso14443_4a_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, Iso14443_4aData* data) {
|
||||
furi_assert(iso14443_3a_listener);
|
||||
|
||||
Iso14443_4aListener* instance = malloc(sizeof(Iso14443_4aListener));
|
||||
instance->iso14443_3a_listener = iso14443_3a_listener;
|
||||
instance->data = data;
|
||||
|
||||
instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_LISTENER_BUF_SIZE);
|
||||
|
||||
instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data;
|
||||
instance->generic_event.protocol = NfcProtocolIso14443_4a;
|
||||
instance->generic_event.instance = instance;
|
||||
instance->generic_event.event_data = &instance->iso14443_4a_event;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void iso14443_4a_listener_free(Iso14443_4aListener* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
furi_assert(instance->tx_buffer);
|
||||
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void iso14443_4a_listener_set_callback(
|
||||
Iso14443_4aListener* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static const Iso14443_4aData* iso14443_4a_listener_get_data(Iso14443_4aListener* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->data);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(context);
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
||||
furi_assert(event.event_data);
|
||||
|
||||
Iso14443_4aListener* instance = context;
|
||||
Iso14443_3aListenerEvent* iso14443_3a_event = event.event_data;
|
||||
BitBuffer* rx_buffer = iso14443_3a_event->data->buffer;
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) {
|
||||
if(instance->state == Iso14443_4aListenerStateIdle) {
|
||||
if(bit_buffer_get_size_bytes(rx_buffer) == 2 &&
|
||||
bit_buffer_get_byte(rx_buffer, 0) == ISO14443_4A_CMD_READ_ATS) {
|
||||
if(iso14443_4a_listener_send_ats(instance, &instance->data->ats_data) !=
|
||||
Iso14443_4aErrorNone) {
|
||||
command = NfcCommandContinue;
|
||||
} else {
|
||||
instance->state = Iso14443_4aListenerStateActive;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instance->iso14443_4a_event.type = Iso14443_4aListenerEventTypeReceivedData;
|
||||
instance->iso14443_4a_event.data->buffer = rx_buffer;
|
||||
|
||||
if(instance->callback) {
|
||||
command = instance->callback(instance->generic_event, instance->context);
|
||||
}
|
||||
}
|
||||
} else if(
|
||||
iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted ||
|
||||
iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) {
|
||||
instance->state = Iso14443_4aListenerStateIdle;
|
||||
command = NfcCommandContinue;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
const NfcListenerBase nfc_listener_iso14443_4a = {
|
||||
.alloc = (NfcListenerAlloc)iso14443_4a_listener_alloc,
|
||||
.free = (NfcListenerFree)iso14443_4a_listener_free,
|
||||
.set_callback = (NfcListenerSetCallback)iso14443_4a_listener_set_callback,
|
||||
.get_data = (NfcListenerGetData)iso14443_4a_listener_get_data,
|
||||
.run = (NfcListenerRun)iso14443_4a_listener_run,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h>
|
||||
|
||||
#include "iso14443_4a.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Iso14443_4aListener Iso14443_4aListener;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aListenerEventTypeHalted,
|
||||
Iso14443_4aListenerEventTypeReceivedData,
|
||||
} Iso14443_4aListenerEventType;
|
||||
|
||||
typedef struct {
|
||||
BitBuffer* buffer;
|
||||
} Iso14443_4aListenerEventData;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_4aListenerEventType type;
|
||||
Iso14443_4aListenerEventData* data;
|
||||
} Iso14443_4aListenerEvent;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_listener_base.h>
|
||||
|
||||
extern const NfcListenerBase nfc_listener_iso14443_4a;
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "iso14443_4a_listener_i.h"
|
||||
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h>
|
||||
|
||||
Iso14443_4aError
|
||||
iso14443_4a_listener_send_ats(Iso14443_4aListener* instance, const Iso14443_4aAtsData* data) {
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_append_byte(instance->tx_buffer, data->tl);
|
||||
|
||||
if(data->tl > 1) {
|
||||
bit_buffer_append_byte(instance->tx_buffer, data->t0);
|
||||
if(data->t0 & ISO14443_4A_ATS_T0_TA1) {
|
||||
bit_buffer_append_byte(instance->tx_buffer, data->ta_1);
|
||||
}
|
||||
if(data->t0 & ISO14443_4A_ATS_T0_TB1) {
|
||||
bit_buffer_append_byte(instance->tx_buffer, data->tb_1);
|
||||
}
|
||||
if(data->t0 & ISO14443_4A_ATS_T0_TC1) {
|
||||
bit_buffer_append_byte(instance->tx_buffer, data->tc_1);
|
||||
}
|
||||
|
||||
const uint32_t t1_tk_size = simple_array_get_count(data->t1_tk);
|
||||
if(t1_tk_size != 0) {
|
||||
bit_buffer_append_bytes(
|
||||
instance->tx_buffer, simple_array_cget_data(data->t1_tk), t1_tk_size);
|
||||
}
|
||||
}
|
||||
|
||||
const Iso14443_3aError error = iso14443_3a_listener_send_standard_frame(
|
||||
instance->iso14443_3a_listener, instance->tx_buffer);
|
||||
return iso14443_4a_process_error(error);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_generic_event.h>
|
||||
|
||||
#include "iso14443_4a_listener.h"
|
||||
#include "iso14443_4a_i.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aListenerStateIdle,
|
||||
Iso14443_4aListenerStateActive,
|
||||
} Iso14443_4aListenerState;
|
||||
|
||||
struct Iso14443_4aListener {
|
||||
Iso14443_3aListener* iso14443_3a_listener;
|
||||
Iso14443_4aData* data;
|
||||
Iso14443_4aListenerState state;
|
||||
|
||||
BitBuffer* tx_buffer;
|
||||
|
||||
NfcGenericEvent generic_event;
|
||||
Iso14443_4aListenerEvent iso14443_4a_event;
|
||||
Iso14443_4aListenerEventData iso14443_4a_event_data;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
Iso14443_4aError
|
||||
iso14443_4a_listener_send_ats(Iso14443_4aListener* instance, const Iso14443_4aAtsData* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,154 @@
|
||||
#include "iso14443_4a_poller_i.h"
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "Iso14443_4aPoller"
|
||||
|
||||
#define ISO14443_4A_POLLER_BUF_SIZE (256U)
|
||||
|
||||
typedef NfcCommand (*Iso14443_4aPollerStateHandler)(Iso14443_4aPoller* instance);
|
||||
|
||||
const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
static Iso14443_4aPoller* iso14443_4a_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) {
|
||||
Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller));
|
||||
instance->iso14443_3a_poller = iso14443_3a_poller;
|
||||
instance->data = iso14443_4a_alloc();
|
||||
instance->iso14443_4_layer = iso14443_4_layer_alloc();
|
||||
instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_POLLER_BUF_SIZE);
|
||||
instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_POLLER_BUF_SIZE);
|
||||
|
||||
instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data;
|
||||
|
||||
instance->general_event.protocol = NfcProtocolIso14443_4a;
|
||||
instance->general_event.event_data = &instance->iso14443_4a_event;
|
||||
instance->general_event.instance = instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void iso14443_4a_poller_free(Iso14443_4aPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
iso14443_4a_free(instance->data);
|
||||
iso14443_4_layer_free(instance->iso14443_4_layer);
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
bit_buffer_free(instance->rx_buffer);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) {
|
||||
iso14443_3a_copy(
|
||||
instance->data->iso14443_3a_data,
|
||||
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
||||
|
||||
iso14443_4_layer_reset(instance->iso14443_4_layer);
|
||||
|
||||
instance->poller_state = Iso14443_4aPollerStateReadAts;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) {
|
||||
Iso14443_4aError error =
|
||||
iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data);
|
||||
if(error == Iso14443_4aErrorNone) {
|
||||
FURI_LOG_D(TAG, "Read ATS success");
|
||||
instance->poller_state = Iso14443_4aPollerStateReady;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Failed to read ATS");
|
||||
instance->poller_state = Iso14443_4aPollerStateError;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance) {
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->iso14443_4a_event_data.error = instance->error;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
instance->poller_state = Iso14443_4aPollerStateIdle;
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance) {
|
||||
instance->iso14443_4a_event.type = Iso14443_4aPollerEventTypeReady;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
return command;
|
||||
}
|
||||
|
||||
static const Iso14443_4aPollerStateHandler
|
||||
iso14443_4a_poller_state_handler[Iso14443_4aPollerStateNum] = {
|
||||
[Iso14443_4aPollerStateIdle] = iso14443_4a_poller_handler_idle,
|
||||
[Iso14443_4aPollerStateReadAts] = iso14443_4a_poller_handler_read_ats,
|
||||
[Iso14443_4aPollerStateError] = iso14443_4a_poller_handler_error,
|
||||
[Iso14443_4aPollerStateReady] = iso14443_4a_poller_handler_ready,
|
||||
};
|
||||
|
||||
static void iso14443_4a_poller_set_callback(
|
||||
Iso14443_4aPoller* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static NfcCommand iso14443_4a_poller_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
||||
|
||||
Iso14443_4aPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->callback);
|
||||
|
||||
Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data;
|
||||
furi_assert(iso14443_3a_event);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||
command = iso14443_4a_poller_state_handler[instance->poller_state](instance);
|
||||
} else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) {
|
||||
instance->iso14443_4a_event.type = Iso14443_4aPollerEventTypeError;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static bool iso14443_4a_poller_detect(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
||||
|
||||
const Iso14443_4aPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
|
||||
const Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data;
|
||||
furi_assert(iso14443_3a_event);
|
||||
iso14443_3a_copy(
|
||||
instance->data->iso14443_3a_data,
|
||||
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
||||
|
||||
bool protocol_detected = false;
|
||||
|
||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||
protocol_detected = iso14443_3a_supports_iso14443_4(instance->data->iso14443_3a_data);
|
||||
}
|
||||
|
||||
return protocol_detected;
|
||||
}
|
||||
|
||||
const NfcPollerBase nfc_poller_iso14443_4a = {
|
||||
.alloc = (NfcPollerAlloc)iso14443_4a_poller_alloc,
|
||||
.free = (NfcPollerFree)iso14443_4a_poller_free,
|
||||
.set_callback = (NfcPollerSetCallback)iso14443_4a_poller_set_callback,
|
||||
.run = (NfcPollerRun)iso14443_4a_poller_run,
|
||||
.detect = (NfcPollerDetect)iso14443_4a_poller_detect,
|
||||
.get_data = (NfcPollerGetData)iso14443_4a_poller_get_data,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
|
||||
|
||||
#include "iso14443_4a.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Iso14443_4aPoller Iso14443_4aPoller;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aPollerEventTypeError,
|
||||
Iso14443_4aPollerEventTypeReady,
|
||||
} Iso14443_4aPollerEventType;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_4aError error;
|
||||
} Iso14443_4aPollerEventData;
|
||||
|
||||
typedef struct {
|
||||
Iso14443_4aPollerEventType type;
|
||||
Iso14443_4aPollerEventData* data;
|
||||
} Iso14443_4aPollerEvent;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
extern const NfcPollerBase nfc_poller_iso14443_4a;
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "iso14443_4a_poller_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include "iso14443_4a_i.h"
|
||||
|
||||
#define TAG "Iso14443_4aPoller"
|
||||
|
||||
#define ISO14443_4A_FSDI_256 (0x8U)
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->poller_state = Iso14443_4aPollerStateIdle;
|
||||
|
||||
return Iso14443_4aErrorNone;
|
||||
}
|
||||
|
||||
Iso14443_4aError
|
||||
iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) {
|
||||
furi_assert(instance);
|
||||
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_CMD_READ_ATS);
|
||||
bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_FSDI_256 << 4);
|
||||
|
||||
Iso14443_4aError error = Iso14443_4aErrorNone;
|
||||
|
||||
do {
|
||||
const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
|
||||
instance->iso14443_3a_poller,
|
||||
instance->tx_buffer,
|
||||
instance->rx_buffer,
|
||||
ISO14443_4A_POLLER_ATS_FWT_FC);
|
||||
|
||||
if(iso14443_3a_error != Iso14443_3aErrorNone) {
|
||||
FURI_LOG_E(TAG, "ATS request failed");
|
||||
error = iso14443_4a_process_error(iso14443_3a_error);
|
||||
break;
|
||||
|
||||
} else if(!iso14443_4a_ats_parse(data, instance->rx_buffer)) {
|
||||
FURI_LOG_E(TAG, "Failed to parse ATS response");
|
||||
error = Iso14443_4aErrorProtocol;
|
||||
break;
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
furi_assert(instance);
|
||||
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer);
|
||||
|
||||
Iso14443_4aError error = Iso14443_4aErrorNone;
|
||||
|
||||
do {
|
||||
Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame(
|
||||
instance->iso14443_3a_poller,
|
||||
instance->tx_buffer,
|
||||
instance->rx_buffer,
|
||||
iso14443_4a_get_fwt_fc_max(instance->data));
|
||||
|
||||
if(iso14443_3a_error != Iso14443_3aErrorNone) {
|
||||
error = iso14443_4a_process_error(iso14443_3a_error);
|
||||
break;
|
||||
|
||||
} else if(!iso14443_4_layer_decode_block(
|
||||
instance->iso14443_4_layer, rx_buffer, instance->rx_buffer)) {
|
||||
error = Iso14443_4aErrorProtocol;
|
||||
break;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h>
|
||||
#include <nfc/helpers/iso14443_4_layer.h>
|
||||
|
||||
#include "iso14443_4a_poller.h"
|
||||
#include "iso14443_4a_i.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ISO14443_4A_POLLER_ATS_FWT_FC (40000)
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aPollerStateIdle,
|
||||
Iso14443_4aPollerStateReadAts,
|
||||
Iso14443_4aPollerStateError,
|
||||
Iso14443_4aPollerStateReady,
|
||||
|
||||
Iso14443_4aPollerStateNum,
|
||||
} Iso14443_4aPollerState;
|
||||
|
||||
typedef enum {
|
||||
Iso14443_4aPollerSessionStateIdle,
|
||||
Iso14443_4aPollerSessionStateActive,
|
||||
Iso14443_4aPollerSessionStateStopRequest,
|
||||
} Iso14443_4aPollerSessionState;
|
||||
|
||||
struct Iso14443_4aPoller {
|
||||
Iso14443_3aPoller* iso14443_3a_poller;
|
||||
Iso14443_4aPollerState poller_state;
|
||||
Iso14443_4aPollerSessionState session_state;
|
||||
Iso14443_4aError error;
|
||||
Iso14443_4aData* data;
|
||||
Iso14443_4Layer* iso14443_4_layer;
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
Iso14443_4aPollerEventData iso14443_4a_event_data;
|
||||
Iso14443_4aPollerEvent iso14443_4a_event;
|
||||
NfcGenericEvent general_event;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error);
|
||||
|
||||
const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance);
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance);
|
||||
|
||||
Iso14443_4aError
|
||||
iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data);
|
||||
|
||||
Iso14443_4aError iso14443_4a_poller_send_block(
|
||||
Iso14443_4aPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user