ESPHome  2023.5.5
pn532_mifare_ultralight.cpp
Go to the documentation of this file.
1 #include <memory>
2 
3 #include "pn532.h"
4 #include "esphome/core/log.h"
5 
6 namespace esphome {
7 namespace pn532 {
8 
9 static const char *const TAG = "pn532.mifare_ultralight";
10 
11 std::unique_ptr<nfc::NfcTag> PN532::read_mifare_ultralight_tag_(std::vector<uint8_t> &uid) {
12  if (!this->is_mifare_ultralight_formatted_()) {
13  ESP_LOGD(TAG, "Not NDEF formatted");
14  return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
15  }
16 
17  uint8_t message_length;
18  uint8_t message_start_index;
19  if (!this->find_mifare_ultralight_ndef_(message_length, message_start_index)) {
20  return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
21  }
22  ESP_LOGVV(TAG, "message length: %d, start: %d", message_length, message_start_index);
23 
24  if (message_length == 0) {
25  return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
26  }
27  std::vector<uint8_t> data;
28  for (uint8_t page = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE; page < nfc::MIFARE_ULTRALIGHT_MAX_PAGE; page++) {
29  std::vector<uint8_t> page_data;
30  if (!this->read_mifare_ultralight_page_(page, page_data)) {
31  ESP_LOGE(TAG, "Error reading page %d", page);
32  return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
33  }
34  data.insert(data.end(), page_data.begin(), page_data.end());
35 
36  if (data.size() >= (message_length + message_start_index))
37  break;
38  }
39 
40  data.erase(data.begin(), data.begin() + message_start_index);
41  data.erase(data.begin() + message_length, data.end());
42 
43  return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2, data);
44 }
45 
46 bool PN532::read_mifare_ultralight_page_(uint8_t page_num, std::vector<uint8_t> &data) {
47  if (!this->write_command_({
48  PN532_COMMAND_INDATAEXCHANGE,
49  0x01, // One card
50  nfc::MIFARE_CMD_READ,
51  page_num,
52  })) {
53  return false;
54  }
55 
56  if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) {
57  return false;
58  }
59  data.erase(data.begin());
60  // We only want 1 page of data but the PN532 returns 4 at once.
61  data.erase(data.begin() + 4, data.end());
62 
63  ESP_LOGVV(TAG, "Pages %d-%d: %s", page_num, page_num + 4, nfc::format_bytes(data).c_str());
64 
65  return true;
66 }
67 
69  std::vector<uint8_t> data;
70  if (this->read_mifare_ultralight_page_(4, data)) {
71  return !(data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
72  }
73  return true;
74 }
75 
77  std::vector<uint8_t> data;
78  if (this->read_mifare_ultralight_page_(3, data)) {
79  return data[2] * 8U;
80  }
81  return 0;
82 }
83 
84 bool PN532::find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index) {
85  std::vector<uint8_t> data;
86  for (int page = 4; page < 6; page++) {
87  std::vector<uint8_t> page_data;
88  if (!this->read_mifare_ultralight_page_(page, page_data)) {
89  return false;
90  }
91  data.insert(data.end(), page_data.begin(), page_data.end());
92  }
93  if (data[0] == 0x03) {
94  message_length = data[1];
95  message_start_index = 2;
96  return true;
97  } else if (data[5] == 0x03) {
98  message_length = data[6];
99  message_start_index = 7;
100  return true;
101  }
102  return false;
103 }
104 
105 bool PN532::write_mifare_ultralight_tag_(std::vector<uint8_t> &uid, nfc::NdefMessage *message) {
106  uint32_t capacity = this->read_mifare_ultralight_capacity_();
107 
108  auto encoded = message->encode();
109 
110  uint32_t message_length = encoded.size();
111  uint32_t buffer_length = nfc::get_mifare_ultralight_buffer_size(message_length);
112 
113  if (buffer_length > capacity) {
114  ESP_LOGE(TAG, "Message length exceeds tag capacity %d > %d", buffer_length, capacity);
115  return false;
116  }
117 
118  encoded.insert(encoded.begin(), 0x03);
119  if (message_length < 255) {
120  encoded.insert(encoded.begin() + 1, message_length);
121  } else {
122  encoded.insert(encoded.begin() + 1, 0xFF);
123  encoded.insert(encoded.begin() + 2, (message_length >> 8) & 0xFF);
124  encoded.insert(encoded.begin() + 2, message_length & 0xFF);
125  }
126  encoded.push_back(0xFE);
127 
128  encoded.resize(buffer_length, 0);
129 
130  uint32_t index = 0;
131  uint8_t current_page = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE;
132 
133  while (index < buffer_length) {
134  std::vector<uint8_t> data(encoded.begin() + index, encoded.begin() + index + nfc::MIFARE_ULTRALIGHT_PAGE_SIZE);
135  if (!this->write_mifare_ultralight_page_(current_page, data)) {
136  return false;
137  }
138  index += nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
139  current_page++;
140  }
141  return true;
142 }
143 
145  uint32_t capacity = this->read_mifare_ultralight_capacity_();
146  uint8_t pages = (capacity / nfc::MIFARE_ULTRALIGHT_PAGE_SIZE) + nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE;
147 
148  std::vector<uint8_t> blank_data = {0x00, 0x00, 0x00, 0x00};
149 
150  for (int i = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE; i < pages; i++) {
151  if (!this->write_mifare_ultralight_page_(i, blank_data)) {
152  return false;
153  }
154  }
155  return true;
156 }
157 
158 bool PN532::write_mifare_ultralight_page_(uint8_t page_num, std::vector<uint8_t> &write_data) {
159  std::vector<uint8_t> data({
160  PN532_COMMAND_INDATAEXCHANGE,
161  0x01, // One card
162  nfc::MIFARE_CMD_WRITE_ULTRALIGHT,
163  page_num,
164  });
165  data.insert(data.end(), write_data.begin(), write_data.end());
166  if (!this->write_command_(data)) {
167  ESP_LOGE(TAG, "Error writing page %d", page_num);
168  return false;
169  }
170 
171  std::vector<uint8_t> response;
172  if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) {
173  ESP_LOGE(TAG, "Error writing page %d", page_num);
174  return false;
175  }
176 
177  return true;
178 }
179 
180 } // namespace pn532
181 } // namespace esphome
virtual bool write_data(const std::vector< uint8_t > &data)=0
virtual bool read_response(uint8_t command, std::vector< uint8_t > &data)=0
bool read_mifare_ultralight_page_(uint8_t page_num, std::vector< uint8_t > &data)
bool find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index)
std::unique_ptr< nfc::NfcTag > read_mifare_ultralight_tag_(std::vector< uint8_t > &uid)
std::vector< uint8_t > encode()
Definition: a4988.cpp:4
bool write_mifare_ultralight_page_(uint8_t page_num, std::vector< uint8_t > &write_data)
bool write_mifare_ultralight_tag_(std::vector< uint8_t > &uid, nfc::NdefMessage *message)
uint32_t get_mifare_ultralight_buffer_size(uint32_t message_length)
Definition: nfc.cpp:71
bool write_command_(const std::vector< uint8_t > &data)
Definition: pn532.cpp:236
std::string format_bytes(std::vector< uint8_t > &bytes)
Definition: nfc.cpp:22