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