mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-12 11:18:35 -07:00
NFC: Implement Type 4 Tag saving
This commit is contained in:
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "../iso14443_4a/iso14443_4a_render.h"
|
#include "../iso14443_4a/iso14443_4a_render.h"
|
||||||
|
|
||||||
#define TYPE_4_TAG_RENDER_MAX_RECORD_SIZE (256U)
|
|
||||||
|
|
||||||
void nfc_render_type_4_tag_info(
|
void nfc_render_type_4_tag_info(
|
||||||
const Type4TagData* data,
|
const Type4TagData* data,
|
||||||
NfcProtocolFormatType format_type,
|
NfcProtocolFormatType format_type,
|
||||||
@@ -11,26 +9,27 @@ void nfc_render_type_4_tag_info(
|
|||||||
nfc_render_iso14443_4a_brief(type_4_tag_get_base_data(data), str);
|
nfc_render_iso14443_4a_brief(type_4_tag_get_base_data(data), str);
|
||||||
|
|
||||||
furi_string_cat(str, "\n:::::::::::::::[Stored NDEF]:::::::::::::::\n");
|
furi_string_cat(str, "\n:::::::::::::::[Stored NDEF]:::::::::::::::\n");
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(str, "Current NDEF Size: %lu", simple_array_get_count(data->ndef_data));
|
||||||
str, "Current NDEF Size: %lu\n", simple_array_get_count(data->ndef_data));
|
|
||||||
|
|
||||||
furi_string_cat(str, "::::::::::::::::::[Tag Specs]::::::::::::::::::\n");
|
if(data->is_tag_specific) {
|
||||||
furi_string_cat_printf(
|
furi_string_cat(str, "\n::::::::::::::::::[Tag Specs]::::::::::::::::::\n");
|
||||||
str, "T4T Mapping Version: %u.%u\n", data->t4t_version.major, data->t4t_version.minor);
|
furi_string_cat_printf(
|
||||||
furi_string_cat_printf(str, "NDEF File ID: 0x%04X\n", data->ndef_file_id);
|
str, "T4T Mapping Version: %u.%u\n", data->t4t_version.major, data->t4t_version.minor);
|
||||||
furi_string_cat_printf(str, "Max NDEF Size: %u\n", data->ndef_max_len);
|
furi_string_cat_printf(str, "NDEF File ID: 0x%04X\n", data->ndef_file_id);
|
||||||
furi_string_cat_printf(
|
furi_string_cat_printf(str, "Max NDEF Size: %u\n", data->ndef_max_len);
|
||||||
str, "APDU Sizes: R:%u W:%u\n", data->chunk_max_read, data->chunk_max_write);
|
furi_string_cat_printf(
|
||||||
furi_string_cat_printf(
|
str, "APDU Sizes: R:%u W:%u\n", data->chunk_max_read, data->chunk_max_write);
|
||||||
str,
|
furi_string_cat_printf(
|
||||||
"Read Lock: 0x%02X%s\n",
|
str,
|
||||||
data->ndef_read_lock,
|
"Read Lock: 0x%02X%s\n",
|
||||||
data->ndef_read_lock == 0 ? " (unlocked)" : "");
|
data->ndef_read_lock,
|
||||||
furi_string_cat_printf(
|
data->ndef_read_lock == 0 ? " (unlocked)" : "");
|
||||||
str,
|
furi_string_cat_printf(
|
||||||
"Write Lock: 0x%02X%s",
|
str,
|
||||||
data->ndef_write_lock,
|
"Write Lock: 0x%02X%s",
|
||||||
data->ndef_write_lock == 0 ? " (unlocked)" : "");
|
data->ndef_write_lock,
|
||||||
|
data->ndef_write_lock == 0 ? " (unlocked)" : "");
|
||||||
|
}
|
||||||
|
|
||||||
if(format_type != NfcProtocolFormatTypeFull) return;
|
if(format_type != NfcProtocolFormatTypeFull) return;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "../nfc_protocol_support_render_common.h"
|
#include "../nfc_protocol_support_render_common.h"
|
||||||
|
|
||||||
#define TYPE_4_TAG_RENDER_BYTES_PER_LINE (4)
|
#define TYPE_4_TAG_RENDER_BYTES_PER_LINE (4U)
|
||||||
|
|
||||||
void nfc_render_type_4_tag_info(
|
void nfc_render_type_4_tag_info(
|
||||||
const Type4TagData* data,
|
const Type4TagData* data,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ void type_4_tag_reset(Type4TagData* data) {
|
|||||||
|
|
||||||
iso14443_4a_reset(data->iso14443_4a_data);
|
iso14443_4a_reset(data->iso14443_4a_data);
|
||||||
|
|
||||||
|
data->is_tag_specific = false;
|
||||||
data->t4t_version.value = 0;
|
data->t4t_version.value = 0;
|
||||||
data->chunk_max_read = 0;
|
data->chunk_max_read = 0;
|
||||||
data->chunk_max_write = 0;
|
data->chunk_max_write = 0;
|
||||||
@@ -60,6 +61,7 @@ void type_4_tag_copy(Type4TagData* data, const Type4TagData* other) {
|
|||||||
|
|
||||||
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
|
iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data);
|
||||||
|
|
||||||
|
data->is_tag_specific = other->is_tag_specific;
|
||||||
data->t4t_version.value = other->t4t_version.value;
|
data->t4t_version.value = other->t4t_version.value;
|
||||||
data->chunk_max_read = other->chunk_max_read;
|
data->chunk_max_read = other->chunk_max_read;
|
||||||
data->chunk_max_write = other->chunk_max_write;
|
data->chunk_max_write = other->chunk_max_write;
|
||||||
@@ -89,6 +91,8 @@ bool type_4_tag_load(Type4TagData* data, FlipperFormat* ff, uint32_t version) {
|
|||||||
do {
|
do {
|
||||||
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
|
if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break;
|
||||||
|
|
||||||
|
if(!type_4_tag_ndef_data_load(data, ff)) break;
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -109,6 +113,7 @@ bool type_4_tag_save(const Type4TagData* data, FlipperFormat* ff) {
|
|||||||
|
|
||||||
if(!flipper_format_write_comment_cstr(ff, TYPE_4_TAG_PROTOCOL_NAME " specific data"))
|
if(!flipper_format_write_comment_cstr(ff, TYPE_4_TAG_PROTOCOL_NAME " specific data"))
|
||||||
break;
|
break;
|
||||||
|
if(!type_4_tag_ndef_data_save(data, ff)) break;
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
@@ -122,6 +127,7 @@ bool type_4_tag_is_equal(const Type4TagData* data, const Type4TagData* other) {
|
|||||||
furi_check(other);
|
furi_check(other);
|
||||||
|
|
||||||
return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) &&
|
return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data) &&
|
||||||
|
data->is_tag_specific == other->is_tag_specific &&
|
||||||
data->t4t_version.value == other->t4t_version.value &&
|
data->t4t_version.value == other->t4t_version.value &&
|
||||||
data->chunk_max_read == other->chunk_max_read &&
|
data->chunk_max_read == other->chunk_max_read &&
|
||||||
data->chunk_max_write == other->chunk_max_write &&
|
data->chunk_max_write == other->chunk_max_write &&
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso14443_4aData* iso14443_4a_data;
|
Iso14443_4aData* iso14443_4a_data;
|
||||||
// Tag specific
|
// Tag specific data
|
||||||
|
bool is_tag_specific;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint8_t minor : 4;
|
uint8_t minor : 4;
|
||||||
|
|||||||
@@ -1,3 +1,63 @@
|
|||||||
#include "type_4_tag_i.h"
|
#include "type_4_tag_i.h"
|
||||||
|
|
||||||
#define TAG "Type4Tag"
|
#define TAG "Type4Tag"
|
||||||
|
|
||||||
|
#define TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY "NDEF Data Size"
|
||||||
|
#define TYPE_4_TAG_FFF_NDEF_DATA_KEY "NDEF Data"
|
||||||
|
|
||||||
|
#define TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE (16U)
|
||||||
|
|
||||||
|
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff) {
|
||||||
|
uint32_t ndef_data_size;
|
||||||
|
if(!flipper_format_read_uint32(ff, TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY, &ndef_data_size, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(ndef_data_size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_array_init(data->ndef_data, ndef_data_size);
|
||||||
|
|
||||||
|
uint32_t ndef_data_pos = 0;
|
||||||
|
uint8_t* ndef_data = simple_array_get_data(data->ndef_data);
|
||||||
|
while(ndef_data_size > 0) {
|
||||||
|
uint8_t ndef_line_size = MIN(ndef_data_size, TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE);
|
||||||
|
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
ff, TYPE_4_TAG_FFF_NDEF_DATA_KEY, &ndef_data[ndef_data_pos], ndef_line_size)) {
|
||||||
|
simple_array_reset(data->ndef_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndef_data_pos += ndef_line_size;
|
||||||
|
ndef_data_size -= ndef_line_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_4_tag_ndef_data_save(const Type4TagData* data, FlipperFormat* ff) {
|
||||||
|
uint32_t ndef_data_size = simple_array_get_count(data->ndef_data);
|
||||||
|
if(!flipper_format_write_uint32(ff, TYPE_4_TAG_FFF_NDEF_DATA_SIZE_KEY, &ndef_data_size, 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(ndef_data_size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ndef_data_pos = 0;
|
||||||
|
uint8_t* ndef_data = simple_array_get_data(data->ndef_data);
|
||||||
|
while(ndef_data_size > 0) {
|
||||||
|
uint8_t ndef_line_size = MIN(ndef_data_size, TYPE_4_TAG_FFF_NDEF_DATA_PER_LINE);
|
||||||
|
|
||||||
|
if(!flipper_format_write_hex(
|
||||||
|
ff, TYPE_4_TAG_FFF_NDEF_DATA_KEY, &ndef_data[ndef_data_pos], ndef_line_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ndef_data_pos += ndef_line_size;
|
||||||
|
ndef_data_size -= ndef_line_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,26 +2,30 @@
|
|||||||
|
|
||||||
#include "type_4_tag.h"
|
#include "type_4_tag.h"
|
||||||
|
|
||||||
|
// ISO SELECT FILE command and parameters
|
||||||
#define TYPE_4_TAG_ISO_SELECT_CMD 0x00, 0xA4
|
#define TYPE_4_TAG_ISO_SELECT_CMD 0x00, 0xA4
|
||||||
#define TYPE_4_TAG_ISO_SELECT_P1_BY_NAME (0x04)
|
#define TYPE_4_TAG_ISO_SELECT_P1_BY_NAME (0x04)
|
||||||
#define TYPE_4_TAG_ISO_SELECT_P1_BY_ID (0x00)
|
#define TYPE_4_TAG_ISO_SELECT_P1_BY_ID (0x00)
|
||||||
#define TYPE_4_TAG_ISO_SELECT_P2_EMPTY (0x0C)
|
#define TYPE_4_TAG_ISO_SELECT_P2_EMPTY (0x0C)
|
||||||
#define TYPE_4_TAG_ISO_SELECT_LE_EMPTY (0x00)
|
#define TYPE_4_TAG_ISO_SELECT_LE_EMPTY (0x00)
|
||||||
|
|
||||||
|
// ISO READ BINARY command and parameters
|
||||||
#define TYPE_4_TAG_ISO_READ_CMD 0x00, 0xB0
|
#define TYPE_4_TAG_ISO_READ_CMD 0x00, 0xB0
|
||||||
#define TYPE_4_TAG_ISO_READ_P1_EMPTY (0x00)
|
#define TYPE_4_TAG_ISO_READ_P1_EMPTY (0x00)
|
||||||
#define TYPE_4_TAG_ISO_READ_P2_BEGINNING (0x00)
|
#define TYPE_4_TAG_ISO_READ_P2_BEGINNING (0x00)
|
||||||
#define TYPE_4_TAG_ISO_READ_LE_FULL (0x00)
|
#define TYPE_4_TAG_ISO_READ_LE_FULL (0x00)
|
||||||
|
|
||||||
#define TYPE_4_TAG_ISO_STATUS_LEN (2)
|
// Common APDU parameters and values
|
||||||
|
#define TYPE_4_TAG_ISO_STATUS_LEN (2U)
|
||||||
#define TYPE_4_TAG_ISO_STATUS_SUCCESS 0x90, 0x00
|
#define TYPE_4_TAG_ISO_STATUS_SUCCESS 0x90, 0x00
|
||||||
#define TYPE_4_TAG_ISO_RW_CHUNK_LEN (255)
|
#define TYPE_4_TAG_ISO_RW_CHUNK_LEN (255U)
|
||||||
#define TYPE_4_TAG_ISO_APP_NAME_LEN (7)
|
#define TYPE_4_TAG_ISO_APP_NAME_LEN (7U)
|
||||||
#define TYPE_4_TAG_ISO_APP_NAME 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01
|
#define TYPE_4_TAG_ISO_APP_NAME 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01
|
||||||
#define TYPE_4_TAG_T4T_CC_FILE_ID_LEN (2)
|
#define TYPE_4_TAG_T4T_CC_FILE_ID_LEN (2U)
|
||||||
#define TYPE_4_TAG_T4T_CC_FILE_ID 0xE1, 0x03
|
#define TYPE_4_TAG_T4T_CC_FILE_ID 0xE1, 0x03
|
||||||
|
#define TYPE_4_TAG_T4T_CC_VNO (0x20)
|
||||||
|
|
||||||
#define TYPE_4_TAG_T4T_CC_VNO 0x20
|
// Capability Container parsing structures
|
||||||
|
|
||||||
typedef enum FURI_PACKED {
|
typedef enum FURI_PACKED {
|
||||||
Type4TagCcTlvTypeNdefFileCtrl = 0x04,
|
Type4TagCcTlvTypeNdefFileCtrl = 0x04,
|
||||||
@@ -52,3 +56,11 @@ typedef struct FURI_PACKED {
|
|||||||
uint16_t mlc;
|
uint16_t mlc;
|
||||||
Type4TagCcTlv tlv[];
|
Type4TagCcTlv tlv[];
|
||||||
} Type4TagCc;
|
} Type4TagCc;
|
||||||
|
|
||||||
|
// Load internal Type4Tag structures
|
||||||
|
|
||||||
|
bool type_4_tag_ndef_data_load(Type4TagData* data, FlipperFormat* ff);
|
||||||
|
|
||||||
|
// Save internal Type4Tag structures
|
||||||
|
|
||||||
|
bool type_4_tag_ndef_data_save(const Type4TagData* data, FlipperFormat* ff);
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ Type4TagError type_4_tag_poller_read_cc(Type4TagPoller* instance) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->data->is_tag_specific = true;
|
||||||
instance->data->t4t_version.value = cc->t4t_vno;
|
instance->data->t4t_version.value = cc->t4t_vno;
|
||||||
instance->data->chunk_max_read = bit_lib_bytes_to_num_be((void*)&cc->mle, sizeof(cc->mle));
|
instance->data->chunk_max_read = bit_lib_bytes_to_num_be((void*)&cc->mle, sizeof(cc->mle));
|
||||||
instance->data->chunk_max_write =
|
instance->data->chunk_max_write =
|
||||||
|
|||||||
Reference in New Issue
Block a user