mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
NFC: Support NTAG4xx detection and basic info
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "mf_desfire/mf_desfire.h"
|
||||
#include "slix/slix.h"
|
||||
#include "st25tb/st25tb.h"
|
||||
#include "ntag4xx/ntag4xx.h"
|
||||
|
||||
/**
|
||||
* @brief Array of pointers to concrete protocol support implementations.
|
||||
@@ -43,5 +44,6 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = {
|
||||
[NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire,
|
||||
[NfcProtocolSlix] = &nfc_protocol_support_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_protocol_support_st25tb,
|
||||
[NfcProtocolNtag4xx] = &nfc_protocol_support_ntag4xx,
|
||||
/* Add new protocol support implementations here */
|
||||
};
|
||||
|
||||
133
applications/main/nfc/helpers/protocol_support/ntag4xx/ntag4xx.c
Normal file
133
applications/main/nfc/helpers/protocol_support/ntag4xx/ntag4xx.c
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "ntag4xx.h"
|
||||
#include "ntag4xx_render.h"
|
||||
|
||||
#include <nfc/protocols/ntag4xx/ntag4xx_poller.h>
|
||||
|
||||
#include "nfc/nfc_app_i.h"
|
||||
|
||||
#include "../nfc_protocol_support_common.h"
|
||||
#include "../nfc_protocol_support_gui_common.h"
|
||||
#include "../iso14443_4a/iso14443_4a_i.h"
|
||||
|
||||
static void nfc_scene_info_on_enter_ntag4xx(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const Ntag4xxData* data = nfc_device_get_data(device, NfcProtocolNtag4xx);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
nfc_append_filename_string_when_present(instance, temp_str);
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_ntag4xx_info(data, NfcProtocolFormatTypeFull, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static void nfc_scene_more_info_on_enter_ntag4xx(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const Ntag4xxData* data = nfc_device_get_data(device, NfcProtocolNtag4xx);
|
||||
|
||||
furi_string_reset(instance->text_box_store);
|
||||
nfc_render_ntag4xx_data(data, instance->text_box_store);
|
||||
|
||||
text_box_set_font(instance->text_box, TextBoxFontHex);
|
||||
text_box_set_text(instance->text_box, furi_string_get_cstr(instance->text_box_store));
|
||||
|
||||
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox);
|
||||
}
|
||||
|
||||
static NfcCommand nfc_scene_read_poller_callback_ntag4xx(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolNtag4xx);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
NfcApp* instance = context;
|
||||
const Ntag4xxPollerEvent* ntag4xx_event = event.event_data;
|
||||
|
||||
if(ntag4xx_event->type == Ntag4xxPollerEventTypeReadSuccess) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolNtag4xx, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
command = NfcCommandStop;
|
||||
} else if(ntag4xx_event->type == Ntag4xxPollerEventTypeReadFailed) {
|
||||
command = NfcCommandReset;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static void nfc_scene_read_on_enter_ntag4xx(NfcApp* instance) {
|
||||
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_ntag4xx, instance);
|
||||
}
|
||||
|
||||
static void nfc_scene_read_success_on_enter_ntag4xx(NfcApp* instance) {
|
||||
const NfcDevice* device = instance->nfc_device;
|
||||
const Ntag4xxData* data = nfc_device_get_data(device, NfcProtocolNtag4xx);
|
||||
|
||||
FuriString* temp_str = furi_string_alloc();
|
||||
furi_string_cat_printf(
|
||||
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
|
||||
nfc_render_ntag4xx_info(data, NfcProtocolFormatTypeShort, temp_str);
|
||||
|
||||
widget_add_text_scroll_element(
|
||||
instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
|
||||
|
||||
furi_string_free(temp_str);
|
||||
}
|
||||
|
||||
static void nfc_scene_emulate_on_enter_ntag4xx(NfcApp* instance) {
|
||||
const Iso14443_4aData* iso14443_4a_data =
|
||||
nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a);
|
||||
|
||||
instance->listener =
|
||||
nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data);
|
||||
nfc_listener_start(
|
||||
instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance);
|
||||
}
|
||||
|
||||
const NfcProtocolSupportBase nfc_protocol_support_ntag4xx = {
|
||||
.features = NfcProtocolFeatureEmulateUid | NfcProtocolFeatureMoreInfo,
|
||||
|
||||
.scene_info =
|
||||
{
|
||||
.on_enter = nfc_scene_info_on_enter_ntag4xx,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_more_info =
|
||||
{
|
||||
.on_enter = nfc_scene_more_info_on_enter_ntag4xx,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read =
|
||||
{
|
||||
.on_enter = nfc_scene_read_on_enter_ntag4xx,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_read_success =
|
||||
{
|
||||
.on_enter = nfc_scene_read_success_on_enter_ntag4xx,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_saved_menu =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_save_name =
|
||||
{
|
||||
.on_enter = nfc_protocol_support_common_on_enter_empty,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
.scene_emulate =
|
||||
{
|
||||
.on_enter = nfc_scene_emulate_on_enter_ntag4xx,
|
||||
.on_event = nfc_protocol_support_common_on_event_empty,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../nfc_protocol_support_base.h"
|
||||
|
||||
extern const NfcProtocolSupportBase nfc_protocol_support_ntag4xx;
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "ntag4xx_render.h"
|
||||
|
||||
#include "../iso14443_4a/iso14443_4a_render.h"
|
||||
|
||||
void nfc_render_ntag4xx_info(
|
||||
const Ntag4xxData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str) {
|
||||
nfc_render_iso14443_4a_brief(ntag4xx_get_base_data(data), str);
|
||||
|
||||
const Ntag4xxType type = ntag4xx_get_type_from_version(&data->version);
|
||||
if(type >= Ntag4xxTypeUnknown) {
|
||||
furi_string_cat(str, "Memory Size: unknown");
|
||||
} else {
|
||||
size_t size_cc = 32;
|
||||
size_t size_ndef = 0;
|
||||
size_t size_proprietary = 0;
|
||||
bool has_tagtamper = false;
|
||||
switch(type) {
|
||||
case Ntag4xxType413DNA:
|
||||
size_ndef = 128;
|
||||
size_proprietary = 0;
|
||||
break;
|
||||
case Ntag4xxType424DNATT:
|
||||
has_tagtamper = true;
|
||||
/* fall-through */
|
||||
case Ntag4xxType424DNA:
|
||||
size_ndef = 256;
|
||||
size_proprietary = 128;
|
||||
break;
|
||||
case Ntag4xxType426QDNATT:
|
||||
has_tagtamper = true;
|
||||
/* fall-through */
|
||||
case Ntag4xxType426QDNA:
|
||||
size_ndef = 768;
|
||||
size_proprietary = 128;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_string_cat_printf(
|
||||
str, "\nMemory Size: %zu bytes\n", size_cc + size_ndef + size_proprietary);
|
||||
furi_string_cat_printf(str, "Usable NDEF Size: %zu bytes\n", size_ndef - sizeof(uint16_t));
|
||||
furi_string_cat_printf(str, "Capability Cont.: %zu bytes\n", size_cc);
|
||||
if(size_proprietary) {
|
||||
furi_string_cat_printf(str, "Proprietary File: %zu bytes\n", size_proprietary);
|
||||
}
|
||||
furi_string_cat_printf(str, "TagTamper: %ssupported", has_tagtamper ? "" : "not ");
|
||||
}
|
||||
|
||||
if(format_type != NfcProtocolFormatTypeFull) return;
|
||||
|
||||
furi_string_cat(str, "\n\e#ISO14443-4 data");
|
||||
nfc_render_iso14443_4a_extra(ntag4xx_get_base_data(data), str);
|
||||
}
|
||||
|
||||
void nfc_render_ntag4xx_data(const Ntag4xxData* data, FuriString* str) {
|
||||
nfc_render_ntag4xx_version(&data->version, str);
|
||||
}
|
||||
|
||||
void nfc_render_ntag4xx_version(const Ntag4xxVersion* data, FuriString* str) {
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
data->uid[0],
|
||||
data->uid[1],
|
||||
data->uid[2],
|
||||
data->uid[3],
|
||||
data->uid[4],
|
||||
data->uid[5],
|
||||
data->uid[6]);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"hw %02x type %02x sub %02x\n"
|
||||
" maj %02x min %02x\n"
|
||||
" size %02x proto %02x\n",
|
||||
data->hw_vendor,
|
||||
data->hw_type,
|
||||
data->hw_subtype,
|
||||
data->hw_major,
|
||||
data->hw_minor,
|
||||
data->hw_storage,
|
||||
data->hw_proto);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"sw %02x type %02x sub %02x\n"
|
||||
" maj %02x min %02x\n"
|
||||
" size %02x proto %02x\n",
|
||||
data->sw_vendor,
|
||||
data->sw_type,
|
||||
data->sw_subtype,
|
||||
data->sw_major,
|
||||
data->sw_minor,
|
||||
data->sw_storage,
|
||||
data->sw_proto);
|
||||
furi_string_cat_printf(
|
||||
str,
|
||||
"batch %02x:%02x:%02x:%02x:%01x\n"
|
||||
"week %d year %d\n"
|
||||
"fab key %02x id %02x\n",
|
||||
data->batch[0],
|
||||
data->batch[1],
|
||||
data->batch[2],
|
||||
data->batch[3],
|
||||
data->batch_extra,
|
||||
data->prod_week,
|
||||
data->prod_year,
|
||||
(data->fab_key_4b << 1) | (data->fab_key_1b),
|
||||
data->optional.fab_key_id);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/ntag4xx/ntag4xx.h>
|
||||
|
||||
#include "../nfc_protocol_support_render_common.h"
|
||||
|
||||
void nfc_render_ntag4xx_info(
|
||||
const Ntag4xxData* data,
|
||||
NfcProtocolFormatType format_type,
|
||||
FuriString* str);
|
||||
|
||||
void nfc_render_ntag4xx_data(const Ntag4xxData* data, FuriString* str);
|
||||
|
||||
void nfc_render_ntag4xx_version(const Ntag4xxVersion* data, FuriString* str);
|
||||
@@ -27,6 +27,7 @@ env.Append(
|
||||
File("protocols/mf_desfire/mf_desfire.h"),
|
||||
File("protocols/slix/slix.h"),
|
||||
File("protocols/st25tb/st25tb.h"),
|
||||
File("protocols/ntag4xx/ntag4xx.h"),
|
||||
# Pollers
|
||||
File("protocols/iso14443_3a/iso14443_3a_poller.h"),
|
||||
File("protocols/iso14443_3b/iso14443_3b_poller.h"),
|
||||
@@ -40,6 +41,7 @@ env.Append(
|
||||
File("protocols/mf_desfire/mf_desfire_poller.h"),
|
||||
File("protocols/slix/slix_poller.h"),
|
||||
File("protocols/st25tb/st25tb_poller.h"),
|
||||
File("protocols/ntag4xx/ntag4xx_poller.h"),
|
||||
# Listeners
|
||||
File("protocols/iso14443_3a/iso14443_3a_listener.h"),
|
||||
File("protocols/iso14443_4a/iso14443_4a_listener.h"),
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire.h>
|
||||
#include <nfc/protocols/slix/slix_device_defs.h>
|
||||
#include <nfc/protocols/st25tb/st25tb.h>
|
||||
#include <nfc/protocols/ntag4xx/ntag4xx.h>
|
||||
|
||||
/**
|
||||
* @brief List of registered NFC device implementations.
|
||||
@@ -44,5 +45,6 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = {
|
||||
[NfcProtocolMfDesfire] = &nfc_device_mf_desfire,
|
||||
[NfcProtocolSlix] = &nfc_device_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_device_st25tb,
|
||||
[NfcProtocolNtag4xx] = &nfc_device_ntag4xx,
|
||||
/* Add new protocols here */
|
||||
};
|
||||
|
||||
@@ -21,4 +21,5 @@ const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = {
|
||||
[NfcProtocolMfDesfire] = NULL,
|
||||
[NfcProtocolSlix] = &nfc_listener_slix,
|
||||
[NfcProtocolSt25tb] = NULL,
|
||||
[NfcProtocolNtag4xx] = NULL,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <nfc/protocols/mf_desfire/mf_desfire_poller_defs.h>
|
||||
#include <nfc/protocols/slix/slix_poller_defs.h>
|
||||
#include <nfc/protocols/st25tb/st25tb_poller_defs.h>
|
||||
#include <nfc/protocols/ntag4xx/ntag4xx_poller_defs.h>
|
||||
|
||||
const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = {
|
||||
[NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a,
|
||||
@@ -26,5 +27,6 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = {
|
||||
[NfcProtocolMfDesfire] = &mf_desfire_poller,
|
||||
[NfcProtocolSlix] = &nfc_poller_slix,
|
||||
[NfcProtocolSt25tb] = &nfc_poller_st25tb,
|
||||
[NfcProtocolNtag4xx] = &ntag4xx_poller,
|
||||
/* Add new pollers here */
|
||||
};
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* | | |
|
||||
* ISO14443-4A Mf Ultralight Mf Classic
|
||||
* |
|
||||
* +-----+----+
|
||||
* | |
|
||||
* Mf Desfire Mf Plus
|
||||
* +-----+----+----------+
|
||||
* | | |
|
||||
* Mf Desfire Mf Plus NTAG4xx
|
||||
* ```
|
||||
*
|
||||
* When implementing a new protocol, its place in the tree must be determined first.
|
||||
@@ -64,6 +64,7 @@ static const NfcProtocol nfc_protocol_iso14443_3b_children_protocol[] = {
|
||||
static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = {
|
||||
NfcProtocolMfPlus,
|
||||
NfcProtocolMfDesfire,
|
||||
NfcProtocolNtag4xx,
|
||||
};
|
||||
|
||||
/** List of ISO115693-3 child protocols. */
|
||||
@@ -155,6 +156,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = {
|
||||
.children_num = 0,
|
||||
.children_protocol = NULL,
|
||||
},
|
||||
[NfcProtocolNtag4xx] =
|
||||
{
|
||||
.parent_protocol = NfcProtocolIso14443_4a,
|
||||
.children_num = 0,
|
||||
.children_protocol = NULL,
|
||||
},
|
||||
/* Add new protocols here */
|
||||
};
|
||||
|
||||
|
||||
@@ -188,6 +188,7 @@ typedef enum {
|
||||
NfcProtocolMfDesfire,
|
||||
NfcProtocolSlix,
|
||||
NfcProtocolSt25tb,
|
||||
NfcProtocolNtag4xx,
|
||||
/* Add new protocols here */
|
||||
|
||||
NfcProtocolNum, /**< Special value representing the number of available protocols. */
|
||||
|
||||
192
lib/nfc/protocols/ntag4xx/ntag4xx.c
Normal file
192
lib/nfc/protocols/ntag4xx/ntag4xx.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "ntag4xx_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define NTAG4XX_PROTOCOL_NAME "NTAG4xx"
|
||||
|
||||
#define NTAG4XX_HW_MAJOR_TYPE_413_DNA (0x10)
|
||||
#define NTAG4XX_HW_MAJOR_TYPE_424_DNA (0x30)
|
||||
|
||||
#define NTAG4XX_HW_SUBTYPE_TAGTAMPER_FLAG (0x08)
|
||||
|
||||
static const char* ntag4xx_type_strings[] = {
|
||||
[Ntag4xxType413DNA] = "NTAG413 DNA",
|
||||
[Ntag4xxType424DNA] = "NTAG424 DNA",
|
||||
[Ntag4xxType424DNATT] = "NTAG424 DNA TagTamper",
|
||||
[Ntag4xxType426QDNA] = "NTAG426Q DNA",
|
||||
[Ntag4xxType426QDNATT] = "NTAG426Q DNA TagTamper",
|
||||
[Ntag4xxTypeUnknown] = "UNK",
|
||||
};
|
||||
|
||||
const NfcDeviceBase nfc_device_ntag4xx = {
|
||||
.protocol_name = NTAG4XX_PROTOCOL_NAME,
|
||||
.alloc = (NfcDeviceAlloc)ntag4xx_alloc,
|
||||
.free = (NfcDeviceFree)ntag4xx_free,
|
||||
.reset = (NfcDeviceReset)ntag4xx_reset,
|
||||
.copy = (NfcDeviceCopy)ntag4xx_copy,
|
||||
.verify = (NfcDeviceVerify)ntag4xx_verify,
|
||||
.load = (NfcDeviceLoad)ntag4xx_load,
|
||||
.save = (NfcDeviceSave)ntag4xx_save,
|
||||
.is_equal = (NfcDeviceEqual)ntag4xx_is_equal,
|
||||
.get_name = (NfcDeviceGetName)ntag4xx_get_device_name,
|
||||
.get_uid = (NfcDeviceGetUid)ntag4xx_get_uid,
|
||||
.set_uid = (NfcDeviceSetUid)ntag4xx_set_uid,
|
||||
.get_base_data = (NfcDeviceGetBaseData)ntag4xx_get_base_data,
|
||||
};
|
||||
|
||||
Ntag4xxData* ntag4xx_alloc(void) {
|
||||
Ntag4xxData* data = malloc(sizeof(Ntag4xxData));
|
||||
data->iso14443_4a_data = iso14443_4a_alloc();
|
||||
data->device_name = furi_string_alloc();
|
||||
return data;
|
||||
}
|
||||
|
||||
void ntag4xx_free(Ntag4xxData* data) {
|
||||
furi_check(data);
|
||||
|
||||
ntag4xx_reset(data);
|
||||
iso14443_4a_free(data->iso14443_4a_data);
|
||||
furi_string_free(data->device_name);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void ntag4xx_reset(Ntag4xxData* data) {
|
||||
furi_check(data);
|
||||
|
||||
iso14443_4a_reset(data->iso14443_4a_data);
|
||||
|
||||
memset(&data->version, 0, sizeof(Ntag4xxVersion));
|
||||
}
|
||||
|
||||
void ntag4xx_copy(Ntag4xxData* data, const Ntag4xxData* other) {
|
||||
furi_check(data);
|
||||
furi_check(other);
|
||||
|
||||
ntag4xx_reset(data);
|
||||
|
||||
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
|
||||
|
||||
data->version = other->version;
|
||||
}
|
||||
|
||||
bool ntag4xx_verify(Ntag4xxData* data, const FuriString* device_type) {
|
||||
UNUSED(data);
|
||||
UNUSED(device_type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ntag4xx_load(Ntag4xxData* data, FlipperFormat* ff, uint32_t version) {
|
||||
furi_check(data);
|
||||
furi_check(ff);
|
||||
|
||||
FuriString* prefix = furi_string_alloc();
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
|
||||
|
||||
if(!ntag4xx_version_load(&data->version, ff)) break;
|
||||
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_free(prefix);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ntag4xx_save(const Ntag4xxData* data, FlipperFormat* ff) {
|
||||
furi_check(data);
|
||||
furi_check(ff);
|
||||
|
||||
FuriString* prefix = furi_string_alloc();
|
||||
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!iso14443_4a_save(data->iso14443_4a_data, ff)) break;
|
||||
|
||||
if(!flipper_format_write_comment_cstr(ff, NTAG4XX_PROTOCOL_NAME " specific data")) break;
|
||||
if(!ntag4xx_version_save(&data->version, ff)) break;
|
||||
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_free(prefix);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ntag4xx_is_equal(const Ntag4xxData* data, const Ntag4xxData* other) {
|
||||
furi_check(data);
|
||||
furi_check(other);
|
||||
|
||||
return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) &&
|
||||
memcmp(&data->version, &other->version, sizeof(Ntag4xxVersion)) == 0;
|
||||
}
|
||||
|
||||
Ntag4xxType ntag4xx_get_type_from_version(const Ntag4xxVersion* const version) {
|
||||
Ntag4xxType type = Ntag4xxTypeUnknown;
|
||||
|
||||
switch(version->hw_major) {
|
||||
case NTAG4XX_HW_MAJOR_TYPE_413_DNA:
|
||||
type = Ntag4xxType413DNA;
|
||||
break;
|
||||
case NTAG4XX_HW_MAJOR_TYPE_424_DNA:
|
||||
if(version->hw_subtype & NTAG4XX_HW_SUBTYPE_TAGTAMPER_FLAG) {
|
||||
type = Ntag4xxType424DNATT;
|
||||
} else {
|
||||
type = Ntag4xxType424DNA;
|
||||
}
|
||||
break;
|
||||
// TODO: there is no info online or in other implementations (NXP TagInfo, NFC Tools, Proxmark3)
|
||||
// about what the HWMajorVersion is supposed to be for NTAG426Q DNA, and they don't seem to be for sale
|
||||
// case NTAG4XX_HW_MAJOR_TYPE_426Q_DNA:
|
||||
// if(version->hw_subtype & NTAG4XX_HW_SUBTYPE_TAGTAMPER_FLAG) {
|
||||
// type = Ntag4xxType426QDNATT;
|
||||
// } else {
|
||||
// type = Ntag4xxType426QDNA;
|
||||
// }
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
const char* ntag4xx_get_device_name(const Ntag4xxData* data, NfcDeviceNameType name_type) {
|
||||
furi_check(data);
|
||||
|
||||
const Ntag4xxType type = ntag4xx_get_type_from_version(&data->version);
|
||||
|
||||
if(type == Ntag4xxTypeUnknown) {
|
||||
furi_string_printf(data->device_name, "Unknown %s", NTAG4XX_PROTOCOL_NAME);
|
||||
} else {
|
||||
furi_string_printf(data->device_name, "%s", ntag4xx_type_strings[type]);
|
||||
if(name_type == NfcDeviceNameTypeShort) {
|
||||
furi_string_replace(data->device_name, "TagTamper", "TT");
|
||||
}
|
||||
}
|
||||
|
||||
return furi_string_get_cstr(data->device_name);
|
||||
}
|
||||
|
||||
const uint8_t* ntag4xx_get_uid(const Ntag4xxData* data, size_t* uid_len) {
|
||||
furi_check(data);
|
||||
furi_check(uid_len);
|
||||
|
||||
return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len);
|
||||
}
|
||||
|
||||
bool ntag4xx_set_uid(Ntag4xxData* data, const uint8_t* uid, size_t uid_len) {
|
||||
furi_check(data);
|
||||
|
||||
return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len);
|
||||
}
|
||||
|
||||
Iso14443_4aData* ntag4xx_get_base_data(const Ntag4xxData* data) {
|
||||
furi_check(data);
|
||||
|
||||
return data->iso14443_4a_data;
|
||||
}
|
||||
114
lib/nfc/protocols/ntag4xx/ntag4xx.h
Normal file
114
lib/nfc/protocols/ntag4xx/ntag4xx.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NTAG4XX_UID_SIZE (7)
|
||||
#define NTAG4XX_BATCH_SIZE (4)
|
||||
#define NTAG4XX_BATCH_EXTRA_BITS 4
|
||||
#define NTAG4XX_FAB_KEY_SIZE_BITS_4 4
|
||||
#define NTAG4XX_FAB_KEY_SIZE_BITS_1 1
|
||||
#define NTAG4XX_PROD_WEEK_SIZE_BITS 7
|
||||
|
||||
#define NTAG4XX_CMD_GET_VERSION (0x60)
|
||||
|
||||
typedef enum {
|
||||
Ntag4xxErrorNone,
|
||||
Ntag4xxErrorNotPresent,
|
||||
Ntag4xxErrorProtocol,
|
||||
Ntag4xxErrorTimeout,
|
||||
} Ntag4xxError;
|
||||
|
||||
typedef enum {
|
||||
Ntag4xxType413DNA,
|
||||
Ntag4xxType424DNA,
|
||||
Ntag4xxType424DNATT,
|
||||
Ntag4xxType426QDNA,
|
||||
Ntag4xxType426QDNATT,
|
||||
|
||||
Ntag4xxTypeUnknown,
|
||||
Ntag4xxTypeNum,
|
||||
} Ntag4xxType;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t hw_vendor;
|
||||
uint8_t hw_type;
|
||||
uint8_t hw_subtype;
|
||||
uint8_t hw_major;
|
||||
uint8_t hw_minor;
|
||||
uint8_t hw_storage;
|
||||
uint8_t hw_proto;
|
||||
|
||||
uint8_t sw_vendor;
|
||||
uint8_t sw_type;
|
||||
uint8_t sw_subtype;
|
||||
uint8_t sw_major;
|
||||
uint8_t sw_minor;
|
||||
uint8_t sw_storage;
|
||||
uint8_t sw_proto;
|
||||
|
||||
uint8_t uid[NTAG4XX_UID_SIZE];
|
||||
// [36b batch][5b fab key][7b prod week]
|
||||
// 5b fab key is split 4b in last byte of batch and 1b in prod week
|
||||
// Due to endianness, they appear swapped in the struct definition
|
||||
uint8_t batch[NTAG4XX_BATCH_SIZE];
|
||||
struct {
|
||||
uint8_t fab_key_4b : NTAG4XX_FAB_KEY_SIZE_BITS_4;
|
||||
uint8_t batch_extra : NTAG4XX_BATCH_EXTRA_BITS;
|
||||
};
|
||||
struct {
|
||||
uint8_t prod_week : NTAG4XX_PROD_WEEK_SIZE_BITS;
|
||||
uint8_t fab_key_1b : NTAG4XX_FAB_KEY_SIZE_BITS_1;
|
||||
};
|
||||
uint8_t prod_year;
|
||||
struct {
|
||||
uint8_t fab_key_id;
|
||||
} optional;
|
||||
} Ntag4xxVersion;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
Iso14443_4aData* iso14443_4a_data;
|
||||
Ntag4xxVersion version;
|
||||
FuriString* device_name;
|
||||
} Ntag4xxData;
|
||||
|
||||
extern const NfcDeviceBase nfc_device_ntag4xx;
|
||||
|
||||
// Virtual methods
|
||||
|
||||
Ntag4xxData* ntag4xx_alloc(void);
|
||||
|
||||
void ntag4xx_free(Ntag4xxData* data);
|
||||
|
||||
void ntag4xx_reset(Ntag4xxData* data);
|
||||
|
||||
void ntag4xx_copy(Ntag4xxData* data, const Ntag4xxData* other);
|
||||
|
||||
bool ntag4xx_verify(Ntag4xxData* data, const FuriString* device_type);
|
||||
|
||||
bool ntag4xx_load(Ntag4xxData* data, FlipperFormat* ff, uint32_t version);
|
||||
|
||||
bool ntag4xx_save(const Ntag4xxData* data, FlipperFormat* ff);
|
||||
|
||||
bool ntag4xx_is_equal(const Ntag4xxData* data, const Ntag4xxData* other);
|
||||
|
||||
const char* ntag4xx_get_device_name(const Ntag4xxData* data, NfcDeviceNameType name_type);
|
||||
|
||||
const uint8_t* ntag4xx_get_uid(const Ntag4xxData* data, size_t* uid_len);
|
||||
|
||||
bool ntag4xx_set_uid(Ntag4xxData* data, const uint8_t* uid, size_t uid_len);
|
||||
|
||||
Iso14443_4aData* ntag4xx_get_base_data(const Ntag4xxData* data);
|
||||
|
||||
// Helpers
|
||||
|
||||
Ntag4xxType ntag4xx_get_type_from_version(const Ntag4xxVersion* const version);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
54
lib/nfc/protocols/ntag4xx/ntag4xx_i.c
Normal file
54
lib/nfc/protocols/ntag4xx/ntag4xx_i.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "ntag4xx_i.h"
|
||||
|
||||
#define TAG "Ntag4xx"
|
||||
|
||||
#define NTAG4XX_FFF_VERSION_KEY \
|
||||
NTAG4XX_FFF_PICC_PREFIX " " \
|
||||
"Version"
|
||||
|
||||
Ntag4xxError ntag4xx_process_error(Iso14443_4aError error) {
|
||||
switch(error) {
|
||||
case Iso14443_4aErrorNone:
|
||||
return Ntag4xxErrorNone;
|
||||
case Iso14443_4aErrorNotPresent:
|
||||
return Ntag4xxErrorNotPresent;
|
||||
case Iso14443_4aErrorTimeout:
|
||||
return Ntag4xxErrorTimeout;
|
||||
default:
|
||||
return Ntag4xxErrorProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
Ntag4xxError ntag4xx_process_status_code(uint8_t status_code) {
|
||||
switch(status_code) {
|
||||
case NXP_NATIVE_COMMAND_STATUS_OPERATION_OK:
|
||||
return Ntag4xxErrorNone;
|
||||
default:
|
||||
return Ntag4xxErrorProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
bool ntag4xx_version_parse(Ntag4xxVersion* data, const BitBuffer* buf) {
|
||||
const size_t buf_size = bit_buffer_get_size_bytes(buf);
|
||||
const bool can_parse = buf_size == sizeof(Ntag4xxVersion) ||
|
||||
buf_size == sizeof(Ntag4xxVersion) - sizeof(data->optional);
|
||||
|
||||
if(can_parse) {
|
||||
bit_buffer_write_bytes(buf, data, sizeof(Ntag4xxVersion));
|
||||
if(buf_size < sizeof(Ntag4xxVersion)) {
|
||||
memset(&data->optional, 0, sizeof(data->optional));
|
||||
}
|
||||
}
|
||||
|
||||
return can_parse && (data->hw_type & 0x0F) == 0x04;
|
||||
}
|
||||
|
||||
bool ntag4xx_version_load(Ntag4xxVersion* data, FlipperFormat* ff) {
|
||||
return flipper_format_read_hex(
|
||||
ff, NTAG4XX_FFF_VERSION_KEY, (uint8_t*)data, sizeof(Ntag4xxVersion));
|
||||
}
|
||||
|
||||
bool ntag4xx_version_save(const Ntag4xxVersion* data, FlipperFormat* ff) {
|
||||
return flipper_format_write_hex(
|
||||
ff, NTAG4XX_FFF_VERSION_KEY, (const uint8_t*)data, sizeof(Ntag4xxVersion));
|
||||
}
|
||||
25
lib/nfc/protocols/ntag4xx/ntag4xx_i.h
Normal file
25
lib/nfc/protocols/ntag4xx/ntag4xx_i.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "ntag4xx.h"
|
||||
|
||||
#include <nfc/helpers/nxp_native_command.h>
|
||||
|
||||
#define NTAG4XX_FFF_PICC_PREFIX "PICC"
|
||||
|
||||
// Internal helpers
|
||||
|
||||
Ntag4xxError ntag4xx_process_error(Iso14443_4aError error);
|
||||
|
||||
Ntag4xxError ntag4xx_process_status_code(uint8_t status_code);
|
||||
|
||||
// Parse internal Ntag4xx structures
|
||||
|
||||
bool ntag4xx_version_parse(Ntag4xxVersion* data, const BitBuffer* buf);
|
||||
|
||||
// Load internal Ntag4xx structures
|
||||
|
||||
bool ntag4xx_version_load(Ntag4xxVersion* data, FlipperFormat* ff);
|
||||
|
||||
// Save internal Ntag4xx structures
|
||||
|
||||
bool ntag4xx_version_save(const Ntag4xxVersion* data, FlipperFormat* ff);
|
||||
165
lib/nfc/protocols/ntag4xx/ntag4xx_poller.c
Normal file
165
lib/nfc/protocols/ntag4xx/ntag4xx_poller.c
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "ntag4xx_poller_i.h"
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "Ntag4xxPoller"
|
||||
|
||||
#define NTAG4XX_BUF_SIZE (64U)
|
||||
#define NTAG4XX_RESULT_BUF_SIZE (512U)
|
||||
|
||||
typedef NfcCommand (*Ntag4xxPollerReadHandler)(Ntag4xxPoller* instance);
|
||||
|
||||
static const Ntag4xxData* ntag4xx_poller_get_data(Ntag4xxPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->data;
|
||||
}
|
||||
|
||||
static Ntag4xxPoller* ntag4xx_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) {
|
||||
Ntag4xxPoller* instance = malloc(sizeof(Ntag4xxPoller));
|
||||
instance->iso14443_4a_poller = iso14443_4a_poller;
|
||||
instance->data = ntag4xx_alloc();
|
||||
instance->tx_buffer = bit_buffer_alloc(NTAG4XX_BUF_SIZE);
|
||||
instance->rx_buffer = bit_buffer_alloc(NTAG4XX_BUF_SIZE);
|
||||
instance->input_buffer = bit_buffer_alloc(NTAG4XX_BUF_SIZE);
|
||||
instance->result_buffer = bit_buffer_alloc(NTAG4XX_RESULT_BUF_SIZE);
|
||||
|
||||
instance->ntag4xx_event.data = &instance->ntag4xx_event_data;
|
||||
|
||||
instance->general_event.protocol = NfcProtocolNtag4xx;
|
||||
instance->general_event.event_data = &instance->ntag4xx_event;
|
||||
instance->general_event.instance = instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void ntag4xx_poller_free(Ntag4xxPoller* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
ntag4xx_free(instance->data);
|
||||
bit_buffer_free(instance->tx_buffer);
|
||||
bit_buffer_free(instance->rx_buffer);
|
||||
bit_buffer_free(instance->input_buffer);
|
||||
bit_buffer_free(instance->result_buffer);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static NfcCommand ntag4xx_poller_handler_idle(Ntag4xxPoller* instance) {
|
||||
bit_buffer_reset(instance->input_buffer);
|
||||
bit_buffer_reset(instance->result_buffer);
|
||||
bit_buffer_reset(instance->tx_buffer);
|
||||
bit_buffer_reset(instance->rx_buffer);
|
||||
|
||||
iso14443_4a_copy(
|
||||
instance->data->iso14443_4a_data,
|
||||
iso14443_4a_poller_get_data(instance->iso14443_4a_poller));
|
||||
|
||||
instance->state = Ntag4xxPollerStateReadVersion;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand ntag4xx_poller_handler_read_version(Ntag4xxPoller* instance) {
|
||||
instance->error = ntag4xx_poller_read_version(instance, &instance->data->version);
|
||||
if(instance->error == Ntag4xxErrorNone) {
|
||||
FURI_LOG_D(TAG, "Read version success");
|
||||
instance->state = Ntag4xxPollerStateReadSuccess;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to read version");
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
instance->state = Ntag4xxPollerStateReadFailed;
|
||||
}
|
||||
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand ntag4xx_poller_handler_read_failed(Ntag4xxPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Read Failed");
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
instance->ntag4xx_event.type = Ntag4xxPollerEventTypeReadFailed;
|
||||
instance->ntag4xx_event.data->error = instance->error;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
instance->state = Ntag4xxPollerStateIdle;
|
||||
return command;
|
||||
}
|
||||
|
||||
static NfcCommand ntag4xx_poller_handler_read_success(Ntag4xxPoller* instance) {
|
||||
FURI_LOG_D(TAG, "Read success");
|
||||
iso14443_4a_poller_halt(instance->iso14443_4a_poller);
|
||||
instance->ntag4xx_event.type = Ntag4xxPollerEventTypeReadSuccess;
|
||||
NfcCommand command = instance->callback(instance->general_event, instance->context);
|
||||
return command;
|
||||
}
|
||||
|
||||
static const Ntag4xxPollerReadHandler ntag4xx_poller_read_handler[Ntag4xxPollerStateNum] = {
|
||||
[Ntag4xxPollerStateIdle] = ntag4xx_poller_handler_idle,
|
||||
[Ntag4xxPollerStateReadVersion] = ntag4xx_poller_handler_read_version,
|
||||
[Ntag4xxPollerStateReadFailed] = ntag4xx_poller_handler_read_failed,
|
||||
[Ntag4xxPollerStateReadSuccess] = ntag4xx_poller_handler_read_success,
|
||||
};
|
||||
|
||||
static void ntag4xx_poller_set_callback(
|
||||
Ntag4xxPoller* instance,
|
||||
NfcGenericCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static NfcCommand ntag4xx_poller_run(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_4a);
|
||||
|
||||
Ntag4xxPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->callback);
|
||||
|
||||
const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
|
||||
furi_assert(iso14443_4a_event);
|
||||
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
|
||||
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
||||
command = ntag4xx_poller_read_handler[instance->state](instance);
|
||||
} else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) {
|
||||
instance->ntag4xx_event.type = Ntag4xxPollerEventTypeReadFailed;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static bool ntag4xx_poller_detect(NfcGenericEvent event, void* context) {
|
||||
furi_assert(event.protocol == NfcProtocolIso14443_4a);
|
||||
|
||||
Ntag4xxPoller* instance = context;
|
||||
furi_assert(instance);
|
||||
|
||||
const Iso14443_4aPollerEvent* iso14443_4a_event = event.event_data;
|
||||
furi_assert(iso14443_4a_event);
|
||||
|
||||
bool protocol_detected = false;
|
||||
|
||||
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
||||
do {
|
||||
Ntag4xxError error = ntag4xx_poller_read_version(instance, &instance->data->version);
|
||||
if(error != Ntag4xxErrorNone) break;
|
||||
|
||||
protocol_detected = true;
|
||||
} while(false);
|
||||
}
|
||||
|
||||
return protocol_detected;
|
||||
}
|
||||
|
||||
const NfcPollerBase ntag4xx_poller = {
|
||||
.alloc = (NfcPollerAlloc)ntag4xx_poller_alloc,
|
||||
.free = (NfcPollerFree)ntag4xx_poller_free,
|
||||
.set_callback = (NfcPollerSetCallback)ntag4xx_poller_set_callback,
|
||||
.run = (NfcPollerRun)ntag4xx_poller_run,
|
||||
.detect = (NfcPollerDetect)ntag4xx_poller_detect,
|
||||
.get_data = (NfcPollerGetData)ntag4xx_poller_get_data,
|
||||
};
|
||||
43
lib/nfc/protocols/ntag4xx/ntag4xx_poller.h
Normal file
43
lib/nfc/protocols/ntag4xx/ntag4xx_poller.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "ntag4xx.h"
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Ntag4xxPoller opaque type definition.
|
||||
*/
|
||||
typedef struct Ntag4xxPoller Ntag4xxPoller;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible Ntag4xx poller event types.
|
||||
*/
|
||||
typedef enum {
|
||||
Ntag4xxPollerEventTypeReadSuccess, /**< Card was read successfully. */
|
||||
Ntag4xxPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
||||
} Ntag4xxPollerEventType;
|
||||
|
||||
/**
|
||||
* @brief Ntag4xx poller event data.
|
||||
*/
|
||||
typedef union {
|
||||
Ntag4xxError error; /**< Error code indicating card reading fail reason. */
|
||||
} Ntag4xxPollerEventData;
|
||||
|
||||
/**
|
||||
* @brief Ntag4xx poller event structure.
|
||||
*
|
||||
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||
*/
|
||||
typedef struct {
|
||||
Ntag4xxPollerEventType type; /**< Type of emmitted event. */
|
||||
Ntag4xxPollerEventData* data; /**< Pointer to event specific data. */
|
||||
} Ntag4xxPollerEvent;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
5
lib/nfc/protocols/ntag4xx/ntag4xx_poller_defs.h
Normal file
5
lib/nfc/protocols/ntag4xx/ntag4xx_poller_defs.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <nfc/protocols/nfc_poller_base.h>
|
||||
|
||||
extern const NfcPollerBase ntag4xx_poller;
|
||||
52
lib/nfc/protocols/ntag4xx/ntag4xx_poller_i.c
Normal file
52
lib/nfc/protocols/ntag4xx/ntag4xx_poller_i.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "ntag4xx_poller_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#include "ntag4xx_i.h"
|
||||
|
||||
#define TAG "Ntag4xxPoller"
|
||||
|
||||
Ntag4xxError ntag4xx_poller_send_chunks(
|
||||
Ntag4xxPoller* instance,
|
||||
const BitBuffer* tx_buffer,
|
||||
BitBuffer* rx_buffer) {
|
||||
furi_check(instance);
|
||||
|
||||
NxpNativeCommandStatus status_code = NXP_NATIVE_COMMAND_STATUS_OPERATION_OK;
|
||||
Iso14443_4aError iso14443_4a_error = nxp_native_command_iso14443_4a_poller(
|
||||
instance->iso14443_4a_poller,
|
||||
&status_code,
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
NxpNativeCommandModeIsoWrapped,
|
||||
instance->tx_buffer,
|
||||
instance->rx_buffer);
|
||||
|
||||
if(iso14443_4a_error != Iso14443_4aErrorNone) {
|
||||
return ntag4xx_process_error(iso14443_4a_error);
|
||||
}
|
||||
|
||||
return ntag4xx_process_status_code(status_code);
|
||||
}
|
||||
|
||||
Ntag4xxError ntag4xx_poller_read_version(Ntag4xxPoller* instance, Ntag4xxVersion* data) {
|
||||
furi_check(instance);
|
||||
|
||||
bit_buffer_reset(instance->input_buffer);
|
||||
bit_buffer_append_byte(instance->input_buffer, NTAG4XX_CMD_GET_VERSION);
|
||||
|
||||
Ntag4xxError error;
|
||||
|
||||
do {
|
||||
error =
|
||||
ntag4xx_poller_send_chunks(instance, instance->input_buffer, instance->result_buffer);
|
||||
|
||||
if(error != Ntag4xxErrorNone) break;
|
||||
|
||||
if(!ntag4xx_version_parse(data, instance->result_buffer)) {
|
||||
error = Ntag4xxErrorProtocol;
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return error;
|
||||
}
|
||||
40
lib/nfc/protocols/ntag4xx/ntag4xx_poller_i.h
Normal file
40
lib/nfc/protocols/ntag4xx/ntag4xx_poller_i.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "ntag4xx_poller.h"
|
||||
|
||||
#include <lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
Ntag4xxPollerStateIdle,
|
||||
Ntag4xxPollerStateReadVersion,
|
||||
Ntag4xxPollerStateReadFailed,
|
||||
Ntag4xxPollerStateReadSuccess,
|
||||
|
||||
Ntag4xxPollerStateNum,
|
||||
} Ntag4xxPollerState;
|
||||
|
||||
struct Ntag4xxPoller {
|
||||
Iso14443_4aPoller* iso14443_4a_poller;
|
||||
Ntag4xxPollerState state;
|
||||
Ntag4xxError error;
|
||||
Ntag4xxData* data;
|
||||
BitBuffer* tx_buffer;
|
||||
BitBuffer* rx_buffer;
|
||||
BitBuffer* input_buffer;
|
||||
BitBuffer* result_buffer;
|
||||
Ntag4xxPollerEventData ntag4xx_event_data;
|
||||
Ntag4xxPollerEvent ntag4xx_event;
|
||||
NfcGenericEvent general_event;
|
||||
NfcGenericCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
Ntag4xxError ntag4xx_poller_read_version(Ntag4xxPoller* instance, Ntag4xxVersion* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,82.2,,
|
||||
Version,+,82.3,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,82.2,,
|
||||
Version,+,82.3,,
|
||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||
@@ -167,6 +167,8 @@ Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,,
|
||||
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,,
|
||||
Header,+,lib/nfc/protocols/ntag4xx/ntag4xx.h,,
|
||||
Header,+,lib/nfc/protocols/ntag4xx/ntag4xx_poller.h,,
|
||||
Header,+,lib/nfc/protocols/slix/slix.h,,
|
||||
Header,+,lib/nfc/protocols/slix/slix_listener.h,,
|
||||
Header,+,lib/nfc/protocols/slix/slix_poller.h,,
|
||||
@@ -2895,6 +2897,19 @@ Function,+,notification_internal_message_block,void,"NotificationApp*, const Not
|
||||
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
||||
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||
Function,-,nrand48,long,unsigned short[3]
|
||||
Function,+,ntag4xx_alloc,Ntag4xxData*,
|
||||
Function,+,ntag4xx_copy,void,"Ntag4xxData*, const Ntag4xxData*"
|
||||
Function,+,ntag4xx_free,void,Ntag4xxData*
|
||||
Function,+,ntag4xx_get_base_data,Iso14443_4aData*,const Ntag4xxData*
|
||||
Function,+,ntag4xx_get_device_name,const char*,"const Ntag4xxData*, NfcDeviceNameType"
|
||||
Function,+,ntag4xx_get_type_from_version,Ntag4xxType,const Ntag4xxVersion*
|
||||
Function,+,ntag4xx_get_uid,const uint8_t*,"const Ntag4xxData*, size_t*"
|
||||
Function,+,ntag4xx_is_equal,_Bool,"const Ntag4xxData*, const Ntag4xxData*"
|
||||
Function,+,ntag4xx_load,_Bool,"Ntag4xxData*, FlipperFormat*, uint32_t"
|
||||
Function,+,ntag4xx_reset,void,Ntag4xxData*
|
||||
Function,+,ntag4xx_save,_Bool,"const Ntag4xxData*, FlipperFormat*"
|
||||
Function,+,ntag4xx_set_uid,_Bool,"Ntag4xxData*, const uint8_t*, size_t"
|
||||
Function,+,ntag4xx_verify,_Bool,"Ntag4xxData*, const FuriString*"
|
||||
Function,+,number_input_alloc,NumberInput*,
|
||||
Function,+,number_input_free,void,NumberInput*
|
||||
Function,+,number_input_get_view,View*,NumberInput*
|
||||
@@ -4022,6 +4037,7 @@ Variable,-,nfc_device_mf_classic,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_desfire,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_plus,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_ntag4xx,const NfcDeviceBase,
|
||||
Variable,-,nfc_device_st25tb,const NfcDeviceBase,
|
||||
Variable,+,sequence_audiovisual_alert,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_10,const NotificationSequence,
|
||||
|
||||
|
Reference in New Issue
Block a user