ESPHome 2026.3.0
Loading...
Searching...
No Matches
ndef_message.cpp
Go to the documentation of this file.
1#include "ndef_message.h"
2#include <cinttypes>
3
4namespace esphome {
5namespace nfc {
6
7static const char *const TAG = "nfc.ndef_message";
8
9NdefMessage::NdefMessage(std::vector<uint8_t> &data) {
10 ESP_LOGV(TAG, "Building NdefMessage with %zu bytes", data.size());
11 size_t index = 0;
12 while (index < data.size()) {
13 // Minimum record: TNF byte + type length byte + payload length (1 or 4 bytes)
14 if (index + 2 >= data.size()) {
15 ESP_LOGE(TAG, "Truncated record header; aborting");
16 break;
17 }
18
19 uint8_t tnf_byte = data[index++];
20 bool me = tnf_byte & 0x40; // Message End bit (is set if this is the last record of the message)
21 bool sr = tnf_byte & 0x10; // Short record bit (is set if payload size is less or equal to 255 bytes)
22 bool il = tnf_byte & 0x08; // ID length bit (is set if ID Length field exists)
23 uint8_t tnf = tnf_byte & 0x07; // Type Name Format
24
25 ESP_LOGVV(TAG, "me=%s, sr=%s, il=%s, tnf=%d", YESNO(me), YESNO(sr), YESNO(il), tnf);
26
27 uint8_t type_length = data[index++];
28 uint32_t payload_length = 0;
29 if (sr) {
30 payload_length = data[index++];
31 } else {
32 if (index + 4 > data.size()) {
33 ESP_LOGE(TAG, "Truncated payload length; aborting");
34 break;
35 }
36 payload_length = (static_cast<uint32_t>(data[index]) << 24) | (static_cast<uint32_t>(data[index + 1]) << 16) |
37 (static_cast<uint32_t>(data[index + 2]) << 8) | static_cast<uint32_t>(data[index + 3]);
38 index += 4;
39 }
40
41 uint8_t id_length = 0;
42 if (il) {
43 if (index >= data.size()) {
44 ESP_LOGE(TAG, "Truncated ID length; aborting");
45 break;
46 }
47 id_length = data[index++];
48 }
49
50 ESP_LOGVV(TAG, "Lengths: type=%d, payload=%" PRIu32 ", id=%d", type_length, payload_length, id_length);
51
52 std::string type_str(data.begin() + index, data.begin() + index + type_length);
53
54 index += type_length;
55
56 std::string id_str = "";
57 if (il) {
58 id_str = std::string(data.begin() + index, data.begin() + index + id_length);
59 index += id_length;
60 }
61
62 if ((data.begin() + index > data.end()) || (data.begin() + index + payload_length > data.end())) {
63 ESP_LOGE(TAG, "Corrupt record encountered; NdefMessage constructor aborting");
64 break;
65 }
66
67 std::vector<uint8_t> payload_data(data.begin() + index, data.begin() + index + payload_length);
68
69 std::unique_ptr<NdefRecord> record;
70
71 // Based on tnf and type, create a more specific NdefRecord object
72 // constructed from the payload data
73 if (tnf == TNF_WELL_KNOWN && type_str == "U") {
74 record = make_unique<NdefRecordUri>(payload_data);
75 } else if (tnf == TNF_WELL_KNOWN && type_str == "T") {
76 record = make_unique<NdefRecordText>(payload_data);
77 } else {
78 // Could not recognize the record, so store as generic one.
79 record = make_unique<NdefRecord>(payload_data);
80 record->set_tnf(tnf);
81 record->set_type(type_str);
82 }
83
84 record->set_id(id_str);
85
86 index += payload_length;
87
88 ESP_LOGV(TAG, "Adding record type %s = %s", record->get_type().c_str(), record->get_payload().c_str());
89 this->add_record(std::move(record));
90
91 if (me)
92 break;
93 }
94}
95
96bool NdefMessage::add_record(std::unique_ptr<NdefRecord> record) {
97 if (this->records_.size() >= MAX_NDEF_RECORDS) {
98 ESP_LOGE(TAG, "Too many records. Max: %d", MAX_NDEF_RECORDS);
99 return false;
100 }
101 this->records_.emplace_back(std::move(record));
102 return true;
103}
104
105bool NdefMessage::add_text_record(const std::string &text) { return this->add_text_record(text, "en"); };
106
107bool NdefMessage::add_text_record(const std::string &text, const std::string &encoding) {
108 return this->add_record(make_unique<NdefRecordText>(encoding, text));
109}
110
111bool NdefMessage::add_uri_record(const std::string &uri) { return this->add_record(make_unique<NdefRecordUri>(uri)); }
112
113std::vector<uint8_t> NdefMessage::encode() {
114 std::vector<uint8_t> data;
115
116 for (size_t i = 0; i < this->records_.size(); i++) {
117 auto encoded_record = this->records_[i]->encode(i == 0, (i + 1) == this->records_.size());
118 data.insert(data.end(), encoded_record.begin(), encoded_record.end());
119 }
120 return data;
121}
122
123} // namespace nfc
124} // namespace esphome
bool add_uri_record(const std::string &uri)
std::vector< std::shared_ptr< NdefRecord > > records_
bool add_text_record(const std::string &text)
bool add_record(std::unique_ptr< NdefRecord > record)
std::vector< uint8_t > encode()
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
static void uint32_t