ESPHome  2024.12.2
pn7160.cpp
Go to the documentation of this file.
1 #include <utility>
2 
3 #include "automation.h"
4 #include "pn7160.h"
5 
6 #include "esphome/core/hal.h"
7 #include "esphome/core/helpers.h"
8 #include "esphome/core/log.h"
9 
10 namespace esphome {
11 namespace pn7160 {
12 
13 static const char *const TAG = "pn7160";
14 
15 void PN7160::setup() {
16  this->irq_pin_->setup();
17  this->ven_pin_->setup();
18  if (this->dwl_req_pin_ != nullptr) {
19  this->dwl_req_pin_->setup();
20  }
21  if (this->wkup_req_pin_ != nullptr) {
22  this->wkup_req_pin_->setup();
23  }
24 
25  this->nci_fsm_transition_(); // kick off reset & init processes
26 }
27 
29  ESP_LOGCONFIG(TAG, "PN7160:");
30  if (this->dwl_req_pin_ != nullptr) {
31  LOG_PIN(" DWL_REQ pin: ", this->dwl_req_pin_);
32  }
33  LOG_PIN(" IRQ pin: ", this->irq_pin_);
34  LOG_PIN(" VEN pin: ", this->ven_pin_);
35  if (this->wkup_req_pin_ != nullptr) {
36  LOG_PIN(" WKUP_REQ pin: ", this->wkup_req_pin_);
37  }
38 }
39 
40 void PN7160::loop() {
41  this->nci_fsm_transition_();
42  this->purge_old_tags_();
43 }
44 
45 void PN7160::set_tag_emulation_message(std::shared_ptr<nfc::NdefMessage> message) {
46  this->card_emulation_message_ = std::move(message);
47  ESP_LOGD(TAG, "Tag emulation message set");
48 }
49 
51  const optional<bool> include_android_app_record) {
52  if (!message.has_value()) {
53  return;
54  }
55 
56  auto ndef_message = make_unique<nfc::NdefMessage>();
57 
58  ndef_message->add_uri_record(message.value());
59 
60  if (!include_android_app_record.has_value() || include_android_app_record.value()) {
61  auto ext_record = make_unique<nfc::NdefRecord>();
62  ext_record->set_tnf(nfc::TNF_EXTERNAL_TYPE);
63  ext_record->set_type(nfc::HA_TAG_ID_EXT_RECORD_TYPE);
64  ext_record->set_payload(nfc::HA_TAG_ID_EXT_RECORD_PAYLOAD);
65  ndef_message->add_record(std::move(ext_record));
66  }
67 
68  this->card_emulation_message_ = std::move(ndef_message);
69  ESP_LOGD(TAG, "Tag emulation message set");
70 }
71 
72 void PN7160::set_tag_emulation_message(const char *message, const bool include_android_app_record) {
73  this->set_tag_emulation_message(std::string(message), include_android_app_record);
74 }
75 
77  if (this->listening_enabled_) {
78  this->listening_enabled_ = false;
79  this->config_refresh_pending_ = true;
80  }
81  ESP_LOGD(TAG, "Tag emulation disabled");
82 }
83 
85  if (this->card_emulation_message_ == nullptr) {
86  ESP_LOGE(TAG, "No NDEF message is set; tag emulation cannot be enabled");
87  return;
88  }
89  if (!this->listening_enabled_) {
90  this->listening_enabled_ = true;
91  this->config_refresh_pending_ = true;
92  }
93  ESP_LOGD(TAG, "Tag emulation enabled");
94 }
95 
97  if (this->polling_enabled_) {
98  this->polling_enabled_ = false;
99  this->config_refresh_pending_ = true;
100  }
101  ESP_LOGD(TAG, "Tag polling disabled");
102 }
103 
105  if (!this->polling_enabled_) {
106  this->polling_enabled_ = true;
107  this->config_refresh_pending_ = true;
108  }
109  ESP_LOGD(TAG, "Tag polling enabled");
110 }
111 
113  this->next_task_ = EP_READ;
114  ESP_LOGD(TAG, "Waiting to read next tag");
115 }
116 
118  this->next_task_ = EP_CLEAN;
119  ESP_LOGD(TAG, "Waiting to clean next tag");
120 }
121 
123  this->next_task_ = EP_FORMAT;
124  ESP_LOGD(TAG, "Waiting to format next tag");
125 }
126 
128  if (this->next_task_message_to_write_ == nullptr) {
129  ESP_LOGW(TAG, "Message to write must be set before setting write mode");
130  return;
131  }
132 
133  this->next_task_ = EP_WRITE;
134  ESP_LOGD(TAG, "Waiting to write next tag");
135 }
136 
137 void PN7160::set_tag_write_message(std::shared_ptr<nfc::NdefMessage> message) {
138  this->next_task_message_to_write_ = std::move(message);
139  ESP_LOGD(TAG, "Message to write has been set");
140 }
141 
142 void PN7160::set_tag_write_message(optional<std::string> message, optional<bool> include_android_app_record) {
143  if (!message.has_value()) {
144  return;
145  }
146 
147  auto ndef_message = make_unique<nfc::NdefMessage>();
148 
149  ndef_message->add_uri_record(message.value());
150 
151  if (!include_android_app_record.has_value() || include_android_app_record.value()) {
152  auto ext_record = make_unique<nfc::NdefRecord>();
153  ext_record->set_tnf(nfc::TNF_EXTERNAL_TYPE);
154  ext_record->set_type(nfc::HA_TAG_ID_EXT_RECORD_TYPE);
155  ext_record->set_payload(nfc::HA_TAG_ID_EXT_RECORD_PAYLOAD);
156  ndef_message->add_record(std::move(ext_record));
157  }
158 
159  this->next_task_message_to_write_ = std::move(ndef_message);
160  ESP_LOGD(TAG, "Message to write has been set");
161 }
162 
163 uint8_t PN7160::set_test_mode(const TestMode test_mode, const std::vector<uint8_t> &data,
164  std::vector<uint8_t> &result) {
165  auto test_oid = TEST_PRBS_OID;
166 
167  switch (test_mode) {
168  case TestMode::TEST_PRBS:
169  // test_oid = TEST_PRBS_OID;
170  break;
171 
173  test_oid = TEST_ANTENNA_OID;
174  break;
175 
177  test_oid = TEST_GET_REGISTER_OID;
178  break;
179 
180  case TestMode::TEST_NONE:
181  default:
182  ESP_LOGD(TAG, "Exiting test mode");
184  return nfc::STATUS_OK;
185  }
186 
187  if (this->reset_core_(true, true) != nfc::STATUS_OK) {
188  ESP_LOGE(TAG, "Failed to reset NCI core");
190  result.clear();
191  return nfc::STATUS_FAILED;
192  } else {
194  }
195  if (this->init_core_() != nfc::STATUS_OK) {
196  ESP_LOGE(TAG, "Failed to initialise NCI core");
198  result.clear();
199  return nfc::STATUS_FAILED;
200  } else {
202  }
203 
204  nfc::NciMessage rx;
205  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_PROPRIETARY_GID, test_oid, data);
206 
207  ESP_LOGW(TAG, "Starting test mode, OID 0x%02X", test_oid);
208  auto status = this->transceive_(tx, rx, NFCC_INIT_TIMEOUT);
209 
210  if (status != nfc::STATUS_OK) {
211  ESP_LOGE(TAG, "Failed to start test mode, OID 0x%02X", test_oid);
213  result.clear();
214  } else {
215  result = rx.get_message();
216  result.erase(result.begin(), result.begin() + 4); // remove NCI header
217  if (!result.empty()) {
218  ESP_LOGW(TAG, "Test results: %s", nfc::format_bytes(result).c_str());
219  }
220  }
221  return status;
222 }
223 
224 uint8_t PN7160::reset_core_(const bool reset_config, const bool power) {
225  if (this->dwl_req_pin_ != nullptr) {
226  this->dwl_req_pin_->digital_write(false);
227  delay(NFCC_DEFAULT_TIMEOUT);
228  }
229 
230  if (power) {
231  this->ven_pin_->digital_write(true);
232  delay(NFCC_DEFAULT_TIMEOUT);
233  this->ven_pin_->digital_write(false);
234  delay(NFCC_DEFAULT_TIMEOUT);
235  this->ven_pin_->digital_write(true);
236  delay(NFCC_INIT_TIMEOUT);
237  }
238 
239  nfc::NciMessage rx;
240  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_CORE_GID, nfc::NCI_CORE_RESET_OID,
241  {(uint8_t) reset_config});
242 
243  if (this->transceive_(tx, rx, NFCC_INIT_TIMEOUT) != nfc::STATUS_OK) {
244  ESP_LOGE(TAG, "Error sending reset command");
245  return nfc::STATUS_FAILED;
246  }
247 
248  if (!rx.simple_status_response_is(nfc::STATUS_OK)) {
249  ESP_LOGE(TAG, "Invalid reset response: %s", nfc::format_bytes(rx.get_message()).c_str());
250  return rx.get_simple_status_response();
251  }
252  // read reset notification
253  if (this->read_nfcc(rx, NFCC_INIT_TIMEOUT) != nfc::STATUS_OK) {
254  ESP_LOGE(TAG, "Reset notification was not received");
255  return nfc::STATUS_FAILED;
256  }
257  // verify reset notification
258  if ((!rx.message_type_is(nfc::NCI_PKT_MT_CTRL_NOTIFICATION)) || (!rx.message_length_is(9)) ||
259  (rx.get_message()[nfc::NCI_PKT_PAYLOAD_OFFSET] != 0x02) ||
260  (rx.get_message()[nfc::NCI_PKT_PAYLOAD_OFFSET + 1] != (uint8_t) reset_config)) {
261  ESP_LOGE(TAG, "Reset notification was malformed: %s", nfc::format_bytes(rx.get_message()).c_str());
262  return nfc::STATUS_FAILED;
263  }
264 
265  ESP_LOGD(TAG, "Configuration %s", rx.get_message()[4] ? "reset" : "retained");
266  ESP_LOGD(TAG, "NCI version: %s", rx.get_message()[5] == 0x20 ? "2.0" : "1.0");
267  ESP_LOGD(TAG, "Manufacturer ID: 0x%02X", rx.get_message()[6]);
268  rx.get_message().erase(rx.get_message().begin(), rx.get_message().begin() + 8);
269  ESP_LOGD(TAG, "Manufacturer info: %s", nfc::format_bytes(rx.get_message()).c_str());
270 
271  return nfc::STATUS_OK;
272 }
273 
275  nfc::NciMessage rx;
276  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_CORE_GID, nfc::NCI_CORE_INIT_OID);
277 
278  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
279  ESP_LOGE(TAG, "Error sending initialise command");
280  return nfc::STATUS_FAILED;
281  }
282 
283  if (!rx.simple_status_response_is(nfc::STATUS_OK)) {
284  ESP_LOGE(TAG, "Invalid initialise response: %s", nfc::format_bytes(rx.get_message()).c_str());
285  return nfc::STATUS_FAILED;
286  }
287 
288  uint8_t hw_version = rx.get_message()[17 + rx.get_message()[8]];
289  uint8_t rom_code_version = rx.get_message()[18 + rx.get_message()[8]];
290  uint8_t flash_major_version = rx.get_message()[19 + rx.get_message()[8]];
291  uint8_t flash_minor_version = rx.get_message()[20 + rx.get_message()[8]];
292  std::vector<uint8_t> features(rx.get_message().begin() + 4, rx.get_message().begin() + 8);
293 
294  ESP_LOGD(TAG, "Hardware version: %u", hw_version);
295  ESP_LOGD(TAG, "ROM code version: %u", rom_code_version);
296  ESP_LOGD(TAG, "FLASH major version: %u", flash_major_version);
297  ESP_LOGD(TAG, "FLASH minor version: %u", flash_minor_version);
298  ESP_LOGD(TAG, "Features: %s", nfc::format_bytes(features).c_str());
299 
300  return rx.get_simple_status_response();
301 }
302 
304  nfc::NciMessage rx;
305  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_PROPRIETARY_GID, nfc::NCI_CORE_SET_CONFIG_OID);
306 
307  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
308  ESP_LOGE(TAG, "Error enabling proprietary extensions");
309  return nfc::STATUS_FAILED;
310  }
311 
312  tx.set_message(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_CORE_GID, nfc::NCI_CORE_SET_CONFIG_OID,
313  std::vector<uint8_t>(std::begin(PMU_CFG), std::end(PMU_CFG)));
314 
315  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
316  ESP_LOGE(TAG, "Error sending PMU config");
317  return nfc::STATUS_FAILED;
318  }
319 
320  return this->send_core_config_();
321 }
322 
324  const auto *core_config_begin = std::begin(CORE_CONFIG_SOLO);
325  const auto *core_config_end = std::end(CORE_CONFIG_SOLO);
326  this->core_config_is_solo_ = true;
327 
328  if (this->listening_enabled_ && this->polling_enabled_) {
329  core_config_begin = std::begin(CORE_CONFIG_RW_CE);
330  core_config_end = std::end(CORE_CONFIG_RW_CE);
331  this->core_config_is_solo_ = false;
332  }
333 
334  nfc::NciMessage rx;
335  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::NCI_CORE_GID, nfc::NCI_CORE_SET_CONFIG_OID,
336  std::vector<uint8_t>(core_config_begin, core_config_end));
337 
338  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
339  ESP_LOGW(TAG, "Error sending core config");
340  return nfc::STATUS_FAILED;
341  }
342 
343  return nfc::STATUS_OK;
344 }
345 
347  bool core_config_should_be_solo = !(this->listening_enabled_ && this->polling_enabled_);
348 
349  if (this->nci_state_ == NCIState::RFST_DISCOVERY) {
350  if (this->stop_discovery_() != nfc::STATUS_OK) {
352  return nfc::STATUS_FAILED;
353  }
355  }
356 
357  if (this->core_config_is_solo_ != core_config_should_be_solo) {
358  if (this->send_core_config_() != nfc::STATUS_OK) {
359  ESP_LOGV(TAG, "Failed to refresh core config");
360  return nfc::STATUS_FAILED;
361  }
362  }
363  this->config_refresh_pending_ = false;
364  return nfc::STATUS_OK;
365 }
366 
368  std::vector<uint8_t> discover_map = {sizeof(RF_DISCOVER_MAP_CONFIG) / 3};
369  discover_map.insert(discover_map.end(), std::begin(RF_DISCOVER_MAP_CONFIG), std::end(RF_DISCOVER_MAP_CONFIG));
370 
371  nfc::NciMessage rx;
372  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::RF_GID, nfc::RF_DISCOVER_MAP_OID, discover_map);
373 
374  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
375  ESP_LOGE(TAG, "Error sending discover map poll config");
376  return nfc::STATUS_FAILED;
377  }
378  return nfc::STATUS_OK;
379 }
380 
382  nfc::NciMessage rx;
383  nfc::NciMessage tx(
384  nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::RF_GID, nfc::RF_SET_LISTEN_MODE_ROUTING_OID,
385  std::vector<uint8_t>(std::begin(RF_LISTEN_MODE_ROUTING_CONFIG), std::end(RF_LISTEN_MODE_ROUTING_CONFIG)));
386 
387  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
388  ESP_LOGE(TAG, "Error setting listen mode routing config");
389  return nfc::STATUS_FAILED;
390  }
391  return nfc::STATUS_OK;
392 }
393 
395  const uint8_t *rf_discovery_config = RF_DISCOVERY_CONFIG;
396  uint8_t length = sizeof(RF_DISCOVERY_CONFIG);
397 
398  if (!this->listening_enabled_) {
399  length = sizeof(RF_DISCOVERY_POLL_CONFIG);
400  rf_discovery_config = RF_DISCOVERY_POLL_CONFIG;
401  } else if (!this->polling_enabled_) {
402  length = sizeof(RF_DISCOVERY_LISTEN_CONFIG);
403  rf_discovery_config = RF_DISCOVERY_LISTEN_CONFIG;
404  }
405 
406  std::vector<uint8_t> discover_config = std::vector<uint8_t>((length * 2) + 1);
407 
408  discover_config[0] = length;
409  for (uint8_t i = 0; i < length; i++) {
410  discover_config[(i * 2) + 1] = rf_discovery_config[i];
411  discover_config[(i * 2) + 2] = 0x01; // RF Technology and Mode will be executed in every discovery period
412  }
413 
414  nfc::NciMessage rx;
415  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::RF_GID, nfc::RF_DISCOVER_OID, discover_config);
416 
417  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
418  switch (rx.get_simple_status_response()) {
419  // in any of these cases, we are either already in or will remain in discovery, which satisfies the function call
420  case nfc::STATUS_OK:
421  case nfc::DISCOVERY_ALREADY_STARTED:
422  case nfc::DISCOVERY_TARGET_ACTIVATION_FAILED:
423  case nfc::DISCOVERY_TEAR_DOWN:
424  return nfc::STATUS_OK;
425 
426  default:
427  ESP_LOGE(TAG, "Error starting discovery");
428  return nfc::STATUS_FAILED;
429  }
430  }
431 
432  return nfc::STATUS_OK;
433 }
434 
435 uint8_t PN7160::stop_discovery_() { return this->deactivate_(nfc::DEACTIVATION_TYPE_IDLE, NFCC_TAG_WRITE_TIMEOUT); }
436 
437 uint8_t PN7160::deactivate_(const uint8_t type, const uint16_t timeout) {
438  nfc::NciMessage rx;
439  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::RF_GID, nfc::RF_DEACTIVATE_OID, {type});
440 
441  auto status = this->transceive_(tx, rx, timeout);
442  // if (status != nfc::STATUS_OK) {
443  // ESP_LOGE(TAG, "Error sending deactivate type %u", type);
444  // return nfc::STATUS_FAILED;
445  // }
446  return status;
447 }
448 
450  if (this->discovered_endpoint_.empty()) {
451  ESP_LOGW(TAG, "No cached tags to select");
452  this->stop_discovery_();
454  return;
455  }
456  std::vector<uint8_t> endpoint_data = {this->discovered_endpoint_[0].id, this->discovered_endpoint_[0].protocol,
457  0x01}; // that last byte is the interface ID
458  for (size_t i = 0; i < this->discovered_endpoint_.size(); i++) {
459  if (!this->discovered_endpoint_[i].trig_called) {
460  endpoint_data = {this->discovered_endpoint_[i].id, this->discovered_endpoint_[i].protocol,
461  0x01}; // that last byte is the interface ID
462  this->selecting_endpoint_ = i;
463  break;
464  }
465  }
466 
467  nfc::NciMessage rx;
468  nfc::NciMessage tx(nfc::NCI_PKT_MT_CTRL_COMMAND, nfc::RF_GID, nfc::RF_DISCOVER_SELECT_OID, endpoint_data);
469 
470  if (this->transceive_(tx, rx) != nfc::STATUS_OK) {
471  ESP_LOGE(TAG, "Error selecting endpoint");
472  } else {
474  }
475 }
476 
478  uint8_t type = nfc::guess_tag_type(tag.get_uid().size());
479 
480  switch (type) {
481  case nfc::TAG_TYPE_MIFARE_CLASSIC:
482  ESP_LOGV(TAG, "Reading Mifare classic");
483  return this->read_mifare_classic_tag_(tag);
484 
485  case nfc::TAG_TYPE_2:
486  ESP_LOGV(TAG, "Reading Mifare ultralight");
487  return this->read_mifare_ultralight_tag_(tag);
488 
489  case nfc::TAG_TYPE_UNKNOWN:
490  default:
491  ESP_LOGV(TAG, "Cannot determine tag type");
492  break;
493  }
494  return nfc::STATUS_FAILED;
495 }
496 
497 uint8_t PN7160::clean_endpoint_(std::vector<uint8_t> &uid) {
498  uint8_t type = nfc::guess_tag_type(uid.size());
499  switch (type) {
500  case nfc::TAG_TYPE_MIFARE_CLASSIC:
501  return this->format_mifare_classic_mifare_();
502 
503  case nfc::TAG_TYPE_2:
504  return this->clean_mifare_ultralight_();
505 
506  default:
507  ESP_LOGE(TAG, "Unsupported tag for cleaning");
508  break;
509  }
510  return nfc::STATUS_FAILED;
511 }
512 
513 uint8_t PN7160::format_endpoint_(std::vector<uint8_t> &uid) {
514  uint8_t type = nfc::guess_tag_type(uid.size());
515  switch (type) {
516  case nfc::TAG_TYPE_MIFARE_CLASSIC:
517  return this->format_mifare_classic_ndef_();
518 
519  case nfc::TAG_TYPE_2:
520  return this->clean_mifare_ultralight_();
521 
522  default:
523  ESP_LOGE(TAG, "Unsupported tag for formatting");
524  break;
525  }
526  return nfc::STATUS_FAILED;
527 }
528 
529 uint8_t PN7160::write_endpoint_(std::vector<uint8_t> &uid, std::shared_ptr<nfc::NdefMessage> &message) {
530  uint8_t type = nfc::guess_tag_type(uid.size());
531  switch (type) {
532  case nfc::TAG_TYPE_MIFARE_CLASSIC:
533  return this->write_mifare_classic_tag_(message);
534 
535  case nfc::TAG_TYPE_2:
536  return this->write_mifare_ultralight_tag_(uid, message);
537 
538  default:
539  ESP_LOGE(TAG, "Unsupported tag for writing");
540  break;
541  }
542  return nfc::STATUS_FAILED;
543 }
544 
545 std::unique_ptr<nfc::NfcTag> PN7160::build_tag_(const uint8_t mode_tech, const std::vector<uint8_t> &data) {
546  switch (mode_tech) {
547  case (nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA): {
548  uint8_t uid_length = data[2];
549  if (!uid_length) {
550  ESP_LOGE(TAG, "UID length cannot be zero");
551  return nullptr;
552  }
553  std::vector<uint8_t> uid(data.begin() + 3, data.begin() + 3 + uid_length);
554  const auto *tag_type_str =
555  nfc::guess_tag_type(uid_length) == nfc::TAG_TYPE_MIFARE_CLASSIC ? nfc::MIFARE_CLASSIC : nfc::NFC_FORUM_TYPE_2;
556  return make_unique<nfc::NfcTag>(uid, tag_type_str);
557  }
558  }
559  return nullptr;
560 }
561 
562 optional<size_t> PN7160::find_tag_uid_(const std::vector<uint8_t> &uid) {
563  if (!this->discovered_endpoint_.empty()) {
564  for (size_t i = 0; i < this->discovered_endpoint_.size(); i++) {
565  auto existing_tag_uid = this->discovered_endpoint_[i].tag->get_uid();
566  bool uid_match = (uid.size() == existing_tag_uid.size());
567 
568  if (uid_match) {
569  for (size_t i = 0; i < uid.size(); i++) {
570  uid_match &= (uid[i] == existing_tag_uid[i]);
571  }
572  if (uid_match) {
573  return i;
574  }
575  }
576  }
577  }
578  return nullopt;
579 }
580 
582  for (size_t i = 0; i < this->discovered_endpoint_.size(); i++) {
583  if (millis() - this->discovered_endpoint_[i].last_seen > this->tag_ttl_) {
584  this->erase_tag_(i);
585  }
586  }
587 }
588 
589 void PN7160::erase_tag_(const uint8_t tag_index) {
590  if (tag_index < this->discovered_endpoint_.size()) {
591  for (auto *trigger : this->triggers_ontagremoved_) {
592  trigger->process(this->discovered_endpoint_[tag_index].tag);
593  }
594  for (auto *listener : this->tag_listeners_) {
595  listener->tag_off(*this->discovered_endpoint_[tag_index].tag);
596  }
597  ESP_LOGI(TAG, "Tag %s removed", nfc::format_uid(this->discovered_endpoint_[tag_index].tag->get_uid()).c_str());
598  this->discovered_endpoint_.erase(this->discovered_endpoint_.begin() + tag_index);
599  }
600 }
601 
603  switch (this->nci_state_) {
605  if (this->reset_core_(true, true) != nfc::STATUS_OK) {
606  ESP_LOGE(TAG, "Failed to reset NCI core");
608  return;
609  } else {
611  }
612  // fall through
613 
614  case NCIState::NFCC_INIT:
615  if (this->init_core_() != nfc::STATUS_OK) {
616  ESP_LOGE(TAG, "Failed to initialise NCI core");
618  return;
619  } else {
621  }
622  // fall through
623 
625  if (this->send_init_config_() != nfc::STATUS_OK) {
626  ESP_LOGE(TAG, "Failed to send initial config");
628  return;
629  } else {
630  this->config_refresh_pending_ = false;
632  }
633  // fall through
634 
636  if (this->set_discover_map_() != nfc::STATUS_OK) {
637  ESP_LOGE(TAG, "Failed to set discover map");
639  return;
640  } else {
642  }
643  // fall through
644 
646  if (this->set_listen_mode_routing_() != nfc::STATUS_OK) {
647  ESP_LOGE(TAG, "Failed to set listen mode routing");
649  return;
650  } else {
652  }
653  // fall through
654 
655  case NCIState::RFST_IDLE:
657  this->stop_discovery_();
658  }
659 
660  if (this->config_refresh_pending_) {
661  this->refresh_core_config_();
662  }
663 
664  if (!this->listening_enabled_ && !this->polling_enabled_) {
665  return;
666  }
667 
668  if (this->start_discovery_() != nfc::STATUS_OK) {
669  ESP_LOGV(TAG, "Failed to start discovery");
671  } else {
673  }
674  return;
675 
678  // fall through
679 
680  // All cases below are waiting for NOTIFICATION messages
682  if (this->config_refresh_pending_) {
683  this->refresh_core_config_();
684  }
685  // fall through
686 
692  if (this->irq_pin_->digital_read()) {
693  this->process_message_();
694  }
695  break;
696 
697  case NCIState::FAILED:
698  case NCIState::NONE:
699  default:
700  return;
701  }
702 }
703 
705  ESP_LOGVV(TAG, "nci_fsm_set_state_(%u)", (uint8_t) new_state);
706  this->nci_state_ = new_state;
708  this->error_count_ = 0;
709  this->last_nci_state_change_ = millis();
710 }
711 
713  ESP_LOGVV(TAG, "nci_fsm_set_error_state_(%u); error_count_ = %u", (uint8_t) new_state, this->error_count_);
714  this->nci_state_error_ = new_state;
715  if (this->error_count_++ > NFCC_MAX_ERROR_COUNT) {
718  ESP_LOGE(TAG, "Too many initialization failures -- check device connections");
719  this->mark_failed();
721  } else {
722  ESP_LOGW(TAG, "Too many errors transitioning to state %u; resetting NFCC", (uint8_t) this->nci_state_error_);
724  }
725  }
726  return this->error_count_ > NFCC_MAX_ERROR_COUNT;
727 }
728 
730  nfc::NciMessage rx;
731  if (this->read_nfcc(rx, NFCC_DEFAULT_TIMEOUT) != nfc::STATUS_OK) {
732  return; // No data
733  }
734 
735  switch (rx.get_message_type()) {
736  case nfc::NCI_PKT_MT_CTRL_NOTIFICATION:
737  if (rx.get_gid() == nfc::RF_GID) {
738  switch (rx.get_oid()) {
739  case nfc::RF_INTF_ACTIVATED_OID:
740  ESP_LOGVV(TAG, "RF_INTF_ACTIVATED_OID");
742  return;
743 
744  case nfc::RF_DISCOVER_OID:
745  ESP_LOGVV(TAG, "RF_DISCOVER_OID");
746  this->process_rf_discover_oid_(rx);
747  return;
748 
749  case nfc::RF_DEACTIVATE_OID:
750  ESP_LOGVV(TAG, "RF_DEACTIVATE_OID: type: 0x%02X, reason: 0x%02X", rx.get_message()[3], rx.get_message()[4]);
751  this->process_rf_deactivate_oid_(rx);
752  return;
753 
754  default:
755  ESP_LOGV(TAG, "Unimplemented RF OID received: 0x%02X", rx.get_oid());
756  }
757  } else if (rx.get_gid() == nfc::NCI_CORE_GID) {
758  switch (rx.get_oid()) {
759  case nfc::NCI_CORE_GENERIC_ERROR_OID:
760  ESP_LOGV(TAG, "NCI_CORE_GENERIC_ERROR_OID:");
761  switch (rx.get_simple_status_response()) {
762  case nfc::DISCOVERY_ALREADY_STARTED:
763  ESP_LOGV(TAG, " DISCOVERY_ALREADY_STARTED");
764  break;
765 
766  case nfc::DISCOVERY_TARGET_ACTIVATION_FAILED:
767  // Tag removed too soon
768  ESP_LOGV(TAG, " DISCOVERY_TARGET_ACTIVATION_FAILED");
769  if (this->nci_state_ == NCIState::EP_SELECTING) {
771  if (!this->discovered_endpoint_.empty()) {
772  this->erase_tag_(this->selecting_endpoint_);
773  }
774  } else {
775  this->stop_discovery_();
777  }
778  break;
779 
780  case nfc::DISCOVERY_TEAR_DOWN:
781  ESP_LOGV(TAG, " DISCOVERY_TEAR_DOWN");
782  break;
783 
784  default:
785  ESP_LOGW(TAG, "Unknown error: 0x%02X", rx.get_simple_status_response());
786  break;
787  }
788  break;
789 
790  default:
791  ESP_LOGV(TAG, "Unimplemented NCI Core OID received: 0x%02X", rx.get_oid());
792  }
793  } else {
794  ESP_LOGV(TAG, "Unimplemented notification: %s", nfc::format_bytes(rx.get_message()).c_str());
795  }
796  break;
797 
798  case nfc::NCI_PKT_MT_CTRL_RESPONSE:
799  ESP_LOGV(TAG, "Unimplemented GID: 0x%02X OID: 0x%02X Full response: %s", rx.get_gid(), rx.get_oid(),
800  nfc::format_bytes(rx.get_message()).c_str());
801  break;
802 
803  case nfc::NCI_PKT_MT_CTRL_COMMAND:
804  ESP_LOGV(TAG, "Unimplemented command: %s", nfc::format_bytes(rx.get_message()).c_str());
805  break;
806 
807  case nfc::NCI_PKT_MT_DATA:
808  this->process_data_message_(rx);
809  break;
810 
811  default:
812  ESP_LOGV(TAG, "Unimplemented message type: %s", nfc::format_bytes(rx.get_message()).c_str());
813  break;
814  }
815 }
816 
817 void PN7160::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoint was activated
818  uint8_t discovery_id = rx.get_message_byte(nfc::RF_INTF_ACTIVATED_NTF_DISCOVERY_ID);
819  uint8_t interface = rx.get_message_byte(nfc::RF_INTF_ACTIVATED_NTF_INTERFACE);
820  uint8_t protocol = rx.get_message_byte(nfc::RF_INTF_ACTIVATED_NTF_PROTOCOL);
821  uint8_t mode_tech = rx.get_message_byte(nfc::RF_INTF_ACTIVATED_NTF_MODE_TECH);
822  uint8_t max_size = rx.get_message_byte(nfc::RF_INTF_ACTIVATED_NTF_MAX_SIZE);
823 
824  ESP_LOGVV(TAG, "Endpoint activated -- interface: 0x%02X, protocol: 0x%02X, mode&tech: 0x%02X, max payload: %u",
825  interface, protocol, mode_tech, max_size);
826 
827  if (mode_tech & nfc::MODE_LISTEN_MASK) {
828  ESP_LOGVV(TAG, "Tag activated in listen mode");
830  return;
831  }
832 
834  auto incoming_tag =
835  this->build_tag_(mode_tech, std::vector<uint8_t>(rx.get_message().begin() + 10, rx.get_message().end()));
836 
837  if (incoming_tag == nullptr) {
838  ESP_LOGE(TAG, "Could not build tag");
839  } else {
840  auto tag_loc = this->find_tag_uid_(incoming_tag->get_uid());
841  if (tag_loc.has_value()) {
842  this->discovered_endpoint_[tag_loc.value()].id = discovery_id;
843  this->discovered_endpoint_[tag_loc.value()].protocol = protocol;
844  this->discovered_endpoint_[tag_loc.value()].last_seen = millis();
845  ESP_LOGVV(TAG, "Tag cache updated");
846  } else {
847  this->discovered_endpoint_.emplace_back(
848  DiscoveredEndpoint{discovery_id, protocol, millis(), std::move(incoming_tag), false});
849  tag_loc = this->discovered_endpoint_.size() - 1;
850  ESP_LOGVV(TAG, "Tag added to cache");
851  }
852 
853  auto &working_endpoint = this->discovered_endpoint_[tag_loc.value()];
854 
855  switch (this->next_task_) {
856  case EP_CLEAN:
857  ESP_LOGD(TAG, " Tag cleaning...");
858  if (this->clean_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) {
859  ESP_LOGE(TAG, " Tag cleaning incomplete");
860  }
861  ESP_LOGD(TAG, " Tag cleaned!");
862  break;
863 
864  case EP_FORMAT:
865  ESP_LOGD(TAG, " Tag formatting...");
866  if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) {
867  ESP_LOGE(TAG, "Error formatting tag as NDEF");
868  }
869  ESP_LOGD(TAG, " Tag formatted!");
870  break;
871 
872  case EP_WRITE:
873  if (this->next_task_message_to_write_ != nullptr) {
874  ESP_LOGD(TAG, " Tag writing...");
875  ESP_LOGD(TAG, " Tag formatting...");
876  if (this->format_endpoint_(working_endpoint.tag->get_uid()) != nfc::STATUS_OK) {
877  ESP_LOGE(TAG, " Tag could not be formatted for writing");
878  } else {
879  ESP_LOGD(TAG, " Writing NDEF data");
880  if (this->write_endpoint_(working_endpoint.tag->get_uid(), this->next_task_message_to_write_) !=
881  nfc::STATUS_OK) {
882  ESP_LOGE(TAG, " Failed to write message to tag");
883  }
884  ESP_LOGD(TAG, " Finished writing NDEF data");
885  this->next_task_message_to_write_ = nullptr;
886  this->on_finished_write_callback_.call();
887  }
888  }
889  break;
890 
891  case EP_READ:
892  default:
893  if (!working_endpoint.trig_called) {
894  ESP_LOGI(TAG, "Read tag type %s with UID %s", working_endpoint.tag->get_tag_type().c_str(),
895  nfc::format_uid(working_endpoint.tag->get_uid()).c_str());
896  if (this->read_endpoint_data_(*working_endpoint.tag) != nfc::STATUS_OK) {
897  ESP_LOGW(TAG, " Unable to read NDEF record(s)");
898  } else if (working_endpoint.tag->has_ndef_message()) {
899  const auto message = working_endpoint.tag->get_ndef_message();
900  const auto records = message->get_records();
901  ESP_LOGD(TAG, " NDEF record(s):");
902  for (const auto &record : records) {
903  ESP_LOGD(TAG, " %s - %s", record->get_type().c_str(), record->get_payload().c_str());
904  }
905  } else {
906  ESP_LOGW(TAG, " No NDEF records found");
907  }
908  for (auto *trigger : this->triggers_ontag_) {
909  trigger->process(working_endpoint.tag);
910  }
911  for (auto *listener : this->tag_listeners_) {
912  listener->tag_on(*working_endpoint.tag);
913  }
914  working_endpoint.trig_called = true;
915  break;
916  }
917  }
918  if (working_endpoint.tag->get_tag_type() == nfc::MIFARE_CLASSIC) {
919  this->halt_mifare_classic_tag_();
920  }
921  }
922  if (this->next_task_ != EP_READ) {
923  this->read_mode();
924  }
925 
926  this->stop_discovery_();
928 }
929 
931  auto incoming_tag = this->build_tag_(rx.get_message_byte(nfc::RF_DISCOVER_NTF_MODE_TECH),
932  std::vector<uint8_t>(rx.get_message().begin() + 7, rx.get_message().end()));
933 
934  if (incoming_tag == nullptr) {
935  ESP_LOGE(TAG, "Could not build tag!");
936  } else {
937  auto tag_loc = this->find_tag_uid_(incoming_tag->get_uid());
938  if (tag_loc.has_value()) {
939  this->discovered_endpoint_[tag_loc.value()].id = rx.get_message_byte(nfc::RF_DISCOVER_NTF_DISCOVERY_ID);
940  this->discovered_endpoint_[tag_loc.value()].protocol = rx.get_message_byte(nfc::RF_DISCOVER_NTF_PROTOCOL);
941  this->discovered_endpoint_[tag_loc.value()].last_seen = millis();
942  ESP_LOGVV(TAG, "Tag found & updated");
943  } else {
944  this->discovered_endpoint_.emplace_back(DiscoveredEndpoint{rx.get_message_byte(nfc::RF_DISCOVER_NTF_DISCOVERY_ID),
945  rx.get_message_byte(nfc::RF_DISCOVER_NTF_PROTOCOL),
946  millis(), std::move(incoming_tag), false});
947  ESP_LOGVV(TAG, "Tag saved");
948  }
949  }
950 
951  if (rx.get_message().back() != nfc::RF_DISCOVER_NTF_NT_MORE) {
953  ESP_LOGVV(TAG, "Discovered %u endpoints", this->discovered_endpoint_.size());
954  }
955 }
956 
959 
960  switch (rx.get_simple_status_response()) {
961  case nfc::DEACTIVATION_TYPE_DISCOVERY:
963  break;
964 
965  case nfc::DEACTIVATION_TYPE_IDLE:
967  break;
968 
969  case nfc::DEACTIVATION_TYPE_SLEEP:
970  case nfc::DEACTIVATION_TYPE_SLEEP_AF:
973  } else if (this->nci_state_ == NCIState::RFST_POLL_ACTIVE) {
975  } else {
977  }
978  break;
979 
980  default:
981  break;
982  }
983 }
984 
986  ESP_LOGVV(TAG, "Received data message: %s", nfc::format_bytes(rx.get_message()).c_str());
987 
988  std::vector<uint8_t> ndef_response;
989  this->card_emu_t4t_get_response_(rx.get_message(), ndef_response);
990 
991  uint16_t ndef_response_size = ndef_response.size();
992  if (!ndef_response_size) {
993  return; // no message returned, we cannot respond
994  }
995 
996  std::vector<uint8_t> tx_msg = {nfc::NCI_PKT_MT_DATA, uint8_t((ndef_response_size & 0xFF00) >> 8),
997  uint8_t(ndef_response_size & 0x00FF)};
998  tx_msg.insert(tx_msg.end(), ndef_response.begin(), ndef_response.end());
999  nfc::NciMessage tx(tx_msg);
1000  ESP_LOGVV(TAG, "Sending data message: %s", nfc::format_bytes(tx.get_message()).c_str());
1001  if (this->transceive_(tx, rx, NFCC_DEFAULT_TIMEOUT, false) != nfc::STATUS_OK) {
1002  ESP_LOGE(TAG, "Sending reply for card emulation failed");
1003  }
1004 }
1005 
1006 void PN7160::card_emu_t4t_get_response_(std::vector<uint8_t> &response, std::vector<uint8_t> &ndef_response) {
1007  if (this->card_emulation_message_ == nullptr) {
1008  ESP_LOGE(TAG, "No NDEF message is set; tag emulation not possible");
1009  ndef_response.clear();
1010  return;
1011  }
1012 
1013  if (equal(response.begin() + nfc::NCI_PKT_HEADER_SIZE, response.end(), std::begin(CARD_EMU_T4T_APP_SELECT))) {
1014  // CARD_EMU_T4T_APP_SELECT
1015  ESP_LOGVV(TAG, "CARD_EMU_NDEF_APP_SELECTED");
1017  ndef_response.insert(ndef_response.begin(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1018  } else if (equal(response.begin() + nfc::NCI_PKT_HEADER_SIZE, response.end(), std::begin(CARD_EMU_T4T_CC_SELECT))) {
1019  // CARD_EMU_T4T_CC_SELECT
1021  ESP_LOGVV(TAG, "CARD_EMU_CC_SELECTED");
1023  ndef_response.insert(ndef_response.begin(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1024  }
1025  } else if (equal(response.begin() + nfc::NCI_PKT_HEADER_SIZE, response.end(), std::begin(CARD_EMU_T4T_NDEF_SELECT))) {
1026  // CARD_EMU_T4T_NDEF_SELECT
1027  ESP_LOGVV(TAG, "CARD_EMU_NDEF_SELECTED");
1029  ndef_response.insert(ndef_response.begin(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1030  } else if (equal(response.begin() + nfc::NCI_PKT_HEADER_SIZE,
1031  response.begin() + nfc::NCI_PKT_HEADER_SIZE + sizeof(CARD_EMU_T4T_READ),
1032  std::begin(CARD_EMU_T4T_READ))) {
1033  // CARD_EMU_T4T_READ
1035  // CARD_EMU_T4T_READ with CARD_EMU_CC_SELECTED
1036  ESP_LOGVV(TAG, "CARD_EMU_T4T_READ with CARD_EMU_CC_SELECTED");
1037  uint16_t offset = (response[nfc::NCI_PKT_HEADER_SIZE + 2] << 8) + response[nfc::NCI_PKT_HEADER_SIZE + 3];
1038  uint8_t length = response[nfc::NCI_PKT_HEADER_SIZE + 4];
1039 
1040  if (length <= (sizeof(CARD_EMU_T4T_CC) + offset + 2)) {
1041  ndef_response.insert(ndef_response.begin(), std::begin(CARD_EMU_T4T_CC) + offset,
1042  std::begin(CARD_EMU_T4T_CC) + offset + length);
1043  ndef_response.insert(ndef_response.end(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1044  }
1046  // CARD_EMU_T4T_READ with CARD_EMU_NDEF_SELECTED
1047  ESP_LOGVV(TAG, "CARD_EMU_T4T_READ with CARD_EMU_NDEF_SELECTED");
1048  auto ndef_message = this->card_emulation_message_->encode();
1049  uint16_t ndef_msg_size = ndef_message.size();
1050  uint16_t offset = (response[nfc::NCI_PKT_HEADER_SIZE + 2] << 8) + response[nfc::NCI_PKT_HEADER_SIZE + 3];
1051  uint8_t length = response[nfc::NCI_PKT_HEADER_SIZE + 4];
1052 
1053  ESP_LOGVV(TAG, "Encoded NDEF message: %s", nfc::format_bytes(ndef_message).c_str());
1054 
1055  if (length <= (ndef_msg_size + offset + 2)) {
1056  if (offset == 0) {
1057  ndef_response.resize(2);
1058  ndef_response[0] = (ndef_msg_size & 0xFF00) >> 8;
1059  ndef_response[1] = (ndef_msg_size & 0x00FF);
1060  if (length > 2) {
1061  ndef_response.insert(ndef_response.end(), ndef_message.begin(), ndef_message.begin() + length - 2);
1062  }
1063  } else if (offset == 1) {
1064  ndef_response.resize(1);
1065  ndef_response[0] = (ndef_msg_size & 0x00FF);
1066  if (length > 1) {
1067  ndef_response.insert(ndef_response.end(), ndef_message.begin(), ndef_message.begin() + length - 1);
1068  }
1069  } else {
1070  ndef_response.insert(ndef_response.end(), ndef_message.begin(), ndef_message.begin() + length);
1071  }
1072 
1073  ndef_response.insert(ndef_response.end(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1074 
1075  if ((offset + length) >= (ndef_msg_size + 2)) {
1076  ESP_LOGD(TAG, "NDEF message sent");
1077  this->on_emulated_tag_scan_callback_.call();
1078  }
1079  }
1080  }
1081  } else if (equal(response.begin() + nfc::NCI_PKT_HEADER_SIZE,
1082  response.begin() + nfc::NCI_PKT_HEADER_SIZE + sizeof(CARD_EMU_T4T_WRITE),
1083  std::begin(CARD_EMU_T4T_WRITE))) {
1084  // CARD_EMU_T4T_WRITE
1086  ESP_LOGVV(TAG, "CARD_EMU_T4T_WRITE");
1087  uint8_t length = response[nfc::NCI_PKT_HEADER_SIZE + 4];
1088  std::vector<uint8_t> ndef_msg_written;
1089 
1090  ndef_msg_written.insert(ndef_msg_written.end(), response.begin() + nfc::NCI_PKT_HEADER_SIZE + 5,
1091  response.begin() + nfc::NCI_PKT_HEADER_SIZE + 5 + length);
1092  ESP_LOGD(TAG, "Received %u-byte NDEF message: %s", length, nfc::format_bytes(ndef_msg_written).c_str());
1093  ndef_response.insert(ndef_response.end(), std::begin(CARD_EMU_T4T_OK), std::end(CARD_EMU_T4T_OK));
1094  }
1095  }
1096 }
1097 
1098 uint8_t PN7160::transceive_(nfc::NciMessage &tx, nfc::NciMessage &rx, const uint16_t timeout,
1099  const bool expect_notification) {
1100  uint8_t retries = NFCC_MAX_COMM_FAILS;
1101 
1102  while (retries) {
1103  // first, send the message we need to send
1104  if (this->write_nfcc(tx) != nfc::STATUS_OK) {
1105  ESP_LOGE(TAG, "Error sending message");
1106  return nfc::STATUS_FAILED;
1107  }
1108  ESP_LOGVV(TAG, "Wrote: %s", nfc::format_bytes(tx.get_message()).c_str());
1109  // next, the NFCC should send back a response
1110  if (this->read_nfcc(rx, timeout) != nfc::STATUS_OK) {
1111  ESP_LOGW(TAG, "Error receiving message");
1112  if (!retries--) {
1113  ESP_LOGE(TAG, " ...giving up");
1114  return nfc::STATUS_FAILED;
1115  }
1116  } else {
1117  break;
1118  }
1119  }
1120  ESP_LOGVV(TAG, "Read: %s", nfc::format_bytes(rx.get_message()).c_str());
1121  // validate the response based on the message type that was sent (command vs. data)
1122  if (!tx.message_type_is(nfc::NCI_PKT_MT_DATA)) {
1123  // for commands, the GID and OID should match and the status should be OK
1124  if ((rx.get_gid() != tx.get_gid()) || (rx.get_oid()) != tx.get_oid()) {
1125  ESP_LOGE(TAG, "Incorrect response to command: %s", nfc::format_bytes(rx.get_message()).c_str());
1126  return nfc::STATUS_FAILED;
1127  }
1128 
1129  if (!rx.simple_status_response_is(nfc::STATUS_OK)) {
1130  ESP_LOGE(TAG, "Error in response to command: %s", nfc::format_bytes(rx.get_message()).c_str());
1131  }
1132  return rx.get_simple_status_response();
1133  } else {
1134  // when requesting data from the endpoint, the first response is from the NFCC; we must validate this, first
1135  if ((!rx.message_type_is(nfc::NCI_PKT_MT_CTRL_NOTIFICATION)) || (!rx.gid_is(nfc::NCI_CORE_GID)) ||
1136  (!rx.oid_is(nfc::NCI_CORE_CONN_CREDITS_OID)) || (!rx.message_length_is(3))) {
1137  ESP_LOGE(TAG, "Incorrect response to data message: %s", nfc::format_bytes(rx.get_message()).c_str());
1138  return nfc::STATUS_FAILED;
1139  }
1140 
1141  if (expect_notification) {
1142  // if the NFCC said "OK", there will be additional data to read; this comes back in a notification message
1143  if (this->read_nfcc(rx, timeout) != nfc::STATUS_OK) {
1144  ESP_LOGE(TAG, "Error receiving data from endpoint");
1145  return nfc::STATUS_FAILED;
1146  }
1147  ESP_LOGVV(TAG, "Read: %s", nfc::format_bytes(rx.get_message()).c_str());
1148  }
1149 
1150  return nfc::STATUS_OK;
1151  }
1152 }
1153 
1154 uint8_t PN7160::wait_for_irq_(uint16_t timeout, bool pin_state) {
1155  auto start_time = millis();
1156 
1157  while (millis() - start_time < timeout) {
1158  if (this->irq_pin_->digital_read() == pin_state) {
1159  return nfc::STATUS_OK;
1160  }
1161  }
1162  ESP_LOGW(TAG, "Timed out waiting for IRQ state");
1163  return nfc::STATUS_FAILED;
1164 }
1165 
1166 } // namespace pn7160
1167 } // namespace esphome
CardEmulationState ce_state_
Definition: pn7160.h:303
virtual void digital_write(bool value)=0
value_type const & value() const
Definition: optional.h:89
virtual uint8_t read_nfcc(nfc::NciMessage &rx, uint16_t timeout)=0
uint8_t stop_discovery_()
Definition: pn7160.cpp:435
uint8_t wait_for_irq_(uint16_t timeout=NFCC_DEFAULT_TIMEOUT, bool pin_state=true)
Definition: pn7160.cpp:1154
std::vector< NfcTagListener * > tag_listeners_
Definition: nfc.h:80
uint8_t read_mifare_ultralight_tag_(nfc::NfcTag &tag)
uint8_t get_gid() const
Definition: nci_message.cpp:39
uint8_t get_message_type() const
Definition: nci_message.cpp:35
void set_tag_emulation_message(std::shared_ptr< nfc::NdefMessage > message)
Definition: pn7160.cpp:45
void set_tag_emulation_off()
Definition: pn7160.cpp:76
std::string format_uid(std::vector< uint8_t > &uid)
Definition: nfc.cpp:10
std::shared_ptr< nfc::NdefMessage > next_task_message_to_write_
Definition: pn7160.h:308
void card_emu_t4t_get_response_(std::vector< uint8_t > &response, std::vector< uint8_t > &ndef_response)
Definition: pn7160.cpp:1006
void set_tag_emulation_on()
Definition: pn7160.cpp:84
CallbackManager< void()> on_finished_write_callback_
Definition: pn7160.h:299
bool message_type_is(uint8_t message_type) const
Definition: nci_message.cpp:71
GPIOPin * wkup_req_pin_
Definition: pn7160.h:296
bool has_value() const
Definition: optional.h:87
std::vector< DiscoveredEndpoint > discovered_endpoint_
Definition: pn7160.h:301
virtual void setup()=0
std::vector< nfc::NfcOnTagTrigger * > triggers_ontagremoved_
Definition: pn7160.h:311
std::vector< nfc::NfcOnTagTrigger * > triggers_ontag_
Definition: pn7160.h:310
uint8_t start_discovery_()
Definition: pn7160.cpp:394
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void setup() override
Definition: pn7160.cpp:15
uint8_t write_mifare_classic_tag_(const std::shared_ptr< nfc::NdefMessage > &message)
std::shared_ptr< nfc::NdefMessage > card_emulation_message_
Definition: pn7160.h:307
uint8_t get_message_byte(uint8_t offset) const
Definition: nci_message.cpp:60
uint8_t set_test_mode(TestMode test_mode, const std::vector< uint8_t > &data, std::vector< uint8_t > &result)
Definition: pn7160.cpp:163
void process_rf_discover_oid_(nfc::NciMessage &rx)
Definition: pn7160.cpp:930
uint8_t read_mifare_classic_tag_(nfc::NfcTag &tag)
NCIState nci_state_error_
Definition: pn7160.h:305
const nullopt_t nullopt((nullopt_t::init()))
GPIOPin * irq_pin_
Definition: pn7160.h:294
uint32_t last_nci_state_change_
Definition: pn7160.h:289
virtual uint8_t write_nfcc(nfc::NciMessage &tx)=0
std::vector< uint8_t > & get_message()
Definition: nci_message.cpp:67
uint8_t format_endpoint_(std::vector< uint8_t > &uid)
Definition: pn7160.cpp:513
void nci_fsm_set_state_(NCIState new_state)
set new controller state
Definition: pn7160.cpp:704
uint8_t selecting_endpoint_
Definition: pn7160.h:290
uint8_t guess_tag_type(uint8_t uid_length)
Definition: nfc.cpp:34
void process_rf_intf_activated_oid_(nfc::NciMessage &rx)
Definition: pn7160.cpp:817
uint8_t set_discover_map_()
Definition: pn7160.cpp:367
void loop() override
Definition: pn7160.cpp:40
uint8_t type
void process_message_()
parse & process incoming messages from the NFCC
Definition: pn7160.cpp:729
GPIOPin * dwl_req_pin_
Definition: pn7160.h:293
void process_data_message_(nfc::NciMessage &rx)
Definition: pn7160.cpp:985
std::vector< uint8_t > & get_uid()
Definition: nfc_tag.h:44
uint8_t send_core_config_()
Definition: pn7160.cpp:323
bool gid_is(uint8_t gid) const
Definition: nci_message.cpp:88
virtual bool digital_read()=0
void erase_tag_(uint8_t tag_index)
Definition: pn7160.cpp:589
uint8_t status
Definition: bl0942.h:74
bool simple_status_response_is(uint8_t response) const
void process_rf_deactivate_oid_(nfc::NciMessage &rx)
Definition: pn7160.cpp:957
uint8_t get_oid() const
Definition: nci_message.cpp:41
uint8_t deactivate_(uint8_t type, uint16_t timeout=NFCC_DEFAULT_TIMEOUT)
Definition: pn7160.cpp:437
void dump_config() override
Definition: pn7160.cpp:28
uint8_t write_mifare_ultralight_tag_(std::vector< uint8_t > &uid, const std::shared_ptr< nfc::NdefMessage > &message)
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
void set_message(uint8_t message_type, const std::vector< uint8_t > &payload)
bool oid_is(uint8_t oid) const
Definition: nci_message.cpp:95
void set_tag_write_message(std::shared_ptr< nfc::NdefMessage > message)
Definition: pn7160.cpp:137
uint8_t read_endpoint_data_(nfc::NfcTag &tag)
Definition: pn7160.cpp:477
void nci_fsm_transition_()
advance controller state as required
Definition: pn7160.cpp:602
uint16_t length
Definition: tt21100.cpp:12
uint8_t transceive_(nfc::NciMessage &tx, nfc::NciMessage &rx, uint16_t timeout=NFCC_DEFAULT_TIMEOUT, bool expect_notification=true)
Definition: pn7160.cpp:1098
uint8_t write_endpoint_(std::vector< uint8_t > &uid, std::shared_ptr< nfc::NdefMessage > &message)
Definition: pn7160.cpp:529
bool message_length_is(uint8_t message_length, bool recompute=false)
Definition: nci_message.cpp:78
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
uint8_t refresh_core_config_()
Definition: pn7160.cpp:346
optional< size_t > find_tag_uid_(const std::vector< uint8_t > &uid)
Definition: pn7160.cpp:562
std::unique_ptr< nfc::NfcTag > build_tag_(uint8_t mode_tech, const std::vector< uint8_t > &data)
Definition: pn7160.cpp:545
uint8_t end[39]
Definition: sun_gtil2.cpp:31
uint8_t send_init_config_()
Definition: pn7160.cpp:303
uint8_t get_simple_status_response() const
Definition: nci_message.cpp:53
uint8_t clean_endpoint_(std::vector< uint8_t > &uid)
Definition: pn7160.cpp:497
bool nci_fsm_set_error_state_(NCIState new_state)
setting controller to this state caused an error; returns true if too many errors/failures ...
Definition: pn7160.cpp:712
uint8_t reset_core_(bool reset_config, bool power)
Definition: pn7160.cpp:224
enum esphome::pn7160::PN7160::NfcTask EP_READ
GPIOPin * ven_pin_
Definition: pn7160.h:295
bool config_refresh_pending_
Definition: pn7160.h:282
std::string format_bytes(std::vector< uint8_t > &bytes)
Definition: nfc.cpp:22
CallbackManager< void()> on_emulated_tag_scan_callback_
Definition: pn7160.h:298
uint8_t set_listen_mode_routing_()
Definition: pn7160.cpp:381
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26