ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
nfc.cpp
Go to the documentation of this file.
1#include "nfc.h"
2#include <cstdio>
4#include "esphome/core/log.h"
5
6namespace esphome::nfc {
7
8ESPHOME_LOG_TAG(TAG, "nfc");
9
10char *format_uid_to(char *buffer, std::span<const uint8_t> uid) {
11 return format_hex_pretty_to(buffer, FORMAT_UID_BUFFER_SIZE, uid.data(), uid.size(), '-');
12}
13
14char *format_bytes_to(char *buffer, std::span<const uint8_t> bytes) {
15 return format_hex_pretty_to(buffer, FORMAT_BYTES_BUFFER_SIZE, bytes.data(), bytes.size(), ' ');
16}
17
18uint8_t guess_tag_type(uint8_t uid_length) {
19 if (uid_length == 4) {
20 return TAG_TYPE_MIFARE_CLASSIC;
21 } else {
22 return TAG_TYPE_2;
23 }
24}
25
26int8_t get_mifare_classic_ndef_start_index(const std::span<const uint8_t> data) {
27 for (uint8_t i = 0; i < MIFARE_CLASSIC_BLOCK_SIZE; i++) {
28 if (data[i] == 0x00) {
29 // Do nothing, skip
30 } else if (data[i] == 0x03) {
31 return i;
32 } else {
33 return -2;
34 }
35 }
36 return -1;
37}
38
39bool decode_mifare_classic_tlv(const std::span<const uint8_t> data, uint32_t &message_length,
40 uint8_t &message_start_index) {
41 if (data.size() < MIFARE_CLASSIC_BLOCK_SIZE) {
42 ESP_LOGE(TAG, "Error, data too short for NDEF detection.");
43 return false;
44 }
46 if (i < 0 || data[i] != 0x03) {
47 ESP_LOGE(TAG, "Error, Can't decode message length.");
48 return false;
49 }
50 uint8_t idx = static_cast<uint8_t>(i);
51 if (idx + 4 <= data.size() && data[idx + 1] == 0xFF) {
52 message_length = ((0xFF & data[idx + 2]) << 8) | (0xFF & data[idx + 3]);
53 message_start_index = idx + MIFARE_CLASSIC_LONG_TLV_SIZE;
54 } else if (idx + 2 <= data.size()) {
55 message_length = data[idx + 1];
56 message_start_index = idx + MIFARE_CLASSIC_SHORT_TLV_SIZE;
57 } else {
58 ESP_LOGE(TAG, "Error, TLV data too short.");
59 return false;
60 }
61 return true;
62}
63
65 // TLV header (2 bytes, or 4 for messages of 255 bytes or more) plus the terminator TLV
66 uint32_t buffer_size = message_length + (message_length < 255 ? 2 : 4) + 1;
67 if (buffer_size % MIFARE_ULTRALIGHT_READ_SIZE != 0)
68 buffer_size = ((buffer_size / MIFARE_ULTRALIGHT_READ_SIZE) + 1) * MIFARE_ULTRALIGHT_READ_SIZE;
69 return buffer_size;
70}
71
72void fill_ndef_tlv(const std::span<const uint8_t> message, const uint32_t buffer_length, FixedVector<uint8_t> &buffer) {
73 buffer.init(buffer_length);
74 buffer.push_back(0x03);
75 if (message.size() < 255) {
76 buffer.push_back(message.size());
77 } else {
78 buffer.push_back(0xFF);
79 buffer.push_back((message.size() >> 8) & 0xFF);
80 buffer.push_back(message.size() & 0xFF);
81 }
82 for (const uint8_t byte : message) {
83 buffer.push_back(byte);
84 }
85 buffer.push_back(0xFE);
86 while (buffer.size() < buffer_length) {
87 buffer.push_back(0x00);
88 }
89}
90
92 uint32_t buffer_size = message_length;
93 if (message_length < 255) {
94 buffer_size += MIFARE_CLASSIC_SHORT_TLV_SIZE + 1;
95 } else {
96 buffer_size += MIFARE_CLASSIC_LONG_TLV_SIZE + 1;
97 }
98 if (buffer_size % MIFARE_CLASSIC_BLOCK_SIZE != 0) {
99 buffer_size = ((buffer_size / MIFARE_CLASSIC_BLOCK_SIZE) + 1) * MIFARE_CLASSIC_BLOCK_SIZE;
100 }
101 return buffer_size;
102}
103
104bool mifare_classic_is_first_block(uint8_t block_num) {
105 if (block_num < MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW * MIFARE_CLASSIC_16BLOCK_SECT_START) {
106 return (block_num % MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW == 0);
107 } else {
108 return (block_num % MIFARE_CLASSIC_BLOCKS_PER_SECT_HIGH == 0);
109 }
110}
111
112bool mifare_classic_is_trailer_block(uint8_t block_num) {
113 if (block_num < MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW * MIFARE_CLASSIC_16BLOCK_SECT_START) {
114 return ((block_num + 1) % MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW == 0);
115 } else {
116 return ((block_num + 1) % MIFARE_CLASSIC_BLOCKS_PER_SECT_HIGH == 0);
117 }
118}
119
120} // namespace esphome::nfc
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
Definition helpers.h:624
const LogString * message
Definition component.cpp:35
uint32_t buffer
Definition gif.cpp:50
char * format_bytes_to(char *buffer, std::span< const uint8_t > bytes)
Format bytes to buffer with ' ' separator (e.g., "04 11 22 33"). Returns buffer for inline use.
Definition nfc.cpp:14
int8_t get_mifare_classic_ndef_start_index(const std::span< const uint8_t > data)
Definition nfc.cpp:26
uint32_t get_mifare_ultralight_buffer_size(uint32_t message_length)
Definition nfc.cpp:64
ESPHOME_LOG_TAG(TAG, "nfc.binary_sensor")
char * format_uid_to(char *buffer, std::span< const uint8_t > uid)
Format UID to buffer with '-' separator (e.g., "04-11-22-33"). Returns buffer for inline use.
Definition nfc.cpp:10
uint8_t guess_tag_type(uint8_t uid_length)
Definition nfc.cpp:18
bool mifare_classic_is_trailer_block(uint8_t block_num)
Definition nfc.cpp:112
bool decode_mifare_classic_tlv(const std::span< const uint8_t > data, uint32_t &message_length, uint8_t &message_start_index)
Definition nfc.cpp:39
uint32_t get_mifare_classic_buffer_size(uint32_t message_length)
Definition nfc.cpp:91
void fill_ndef_tlv(const std::span< const uint8_t > message, const uint32_t buffer_length, FixedVector< uint8_t > &buffer)
Fills buffer with the NDEF TLV (type, length, message, terminator) padded with zeros to buffer_length
Definition nfc.cpp:72
bool mifare_classic_is_first_block(uint8_t block_num)
Definition nfc.cpp:104
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
Definition helpers.cpp:498
static void uint32_t