17 data) != nfc::STATUS_OK) {
18 return nfc::STATUS_FAILED;
22 ESP_LOGW(TAG,
"Not NDEF formatted");
23 return nfc::STATUS_FAILED;
26 uint8_t message_length;
27 uint8_t message_start_index;
29 ESP_LOGW(TAG,
"Couldn't find NDEF message");
30 return nfc::STATUS_FAILED;
32 ESP_LOGVV(TAG,
"NDEF message length: %u, start: %u", message_length, message_start_index);
34 if (message_length == 0) {
35 return nfc::STATUS_FAILED;
38 const uint8_t read_length = message_length + message_start_index > 12 ? message_length + message_start_index - 12 : 0;
42 ESP_LOGE(TAG,
"Error reading tag data");
43 return nfc::STATUS_FAILED;
47 const size_t skip = message_start_index + nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
48 if (skip >= data.size()) {
49 return nfc::STATUS_FAILED;
51 tag.
set_ndef_message(make_unique<nfc::NdefMessage>(std::span<const uint8_t>(data).subspan(skip)));
53 return nfc::STATUS_OK;
57 const uint8_t read_increment = nfc::MIFARE_ULTRALIGHT_READ_SIZE * nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
59 nfc::NciMessage tx(nfc::NCI_PKT_MT_DATA, {nfc::MIFARE_CMD_READ, start_page});
61 for (
size_t i = 0; i * read_increment < num_bytes; i++) {
62 const uint8_t page = i * nfc::MIFARE_ULTRALIGHT_READ_SIZE + start_page;
63 tx.set_payload({nfc::MIFARE_CMD_READ, page});
68 ESP_LOGE(TAG,
"Error reading tag data");
69 return nfc::STATUS_FAILED;
71 if (++attempts > NFCC_MAX_COMM_FAILS && rx.
get_payload_size() < read_increment) {
72 ESP_LOGE(TAG,
"Short read from page %u", page);
73 return nfc::STATUS_FAILED;
77 const uint16_t wanted = num_bytes - i * read_increment;
78 const size_t count = std::min<size_t>(read_increment, wanted);
84 char buf[nfc::FORMAT_BYTES_BUFFER_SIZE];
87 return nfc::STATUS_OK;
91 const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
93 return (page_3_to_6.size() > p4_offset + 3) &&
94 ((page_3_to_6[p4_offset + 0] != 0xFF) || (page_3_to_6[p4_offset + 1] != 0xFF) ||
95 (page_3_to_6[p4_offset + 2] != 0xFF) || (page_3_to_6[p4_offset + 3] != 0xFF));
101 ESP_LOGV(TAG,
"Tag capacity is %u bytes", data[2] * 8U);
108 uint8_t &message_start_index) {
109 const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
111 if (!(page_3_to_6.size() > p4_offset + 6)) {
112 return nfc::STATUS_FAILED;
115 if (page_3_to_6[p4_offset + 0] == 0x03) {
116 message_length = page_3_to_6[p4_offset + 1];
117 message_start_index = 2;
118 return nfc::STATUS_OK;
119 }
else if (page_3_to_6[p4_offset + 5] == 0x03) {
120 message_length = page_3_to_6[p4_offset + 6];
121 message_start_index = 7;
122 return nfc::STATUS_OK;
124 return nfc::STATUS_FAILED;
130 const auto encoded =
message->encode();
134 ESP_LOGE(TAG,
"Message length exceeds tag capacity %" PRIu32
" > %" PRIu32, buffer_length,
capacity);
135 return nfc::STATUS_FAILED;
142 uint8_t current_page = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE;
144 while (index < buffer_length) {
147 return nfc::STATUS_FAILED;
149 index += nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
152 return nfc::STATUS_OK;
157 uint8_t pages = (
capacity / nfc::MIFARE_ULTRALIGHT_PAGE_SIZE) + nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE;
159 static constexpr std::array<uint8_t, nfc::MIFARE_ULTRALIGHT_PAGE_SIZE> BLANK_DATA = {0x00, 0x00, 0x00, 0x00};
161 for (
int i = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE; i < pages; i++) {
163 return nfc::STATUS_FAILED;
166 return nfc::STATUS_OK;
171 nfc::NciMessage tx(nfc::NCI_PKT_MT_DATA, {nfc::MIFARE_CMD_WRITE_ULTRALIGHT, page_num});
172 tx.
append(std::span<const uint8_t>(write_data,
len));
174 if (this->
transceive_(tx, rx, NFCC_TAG_WRITE_TIMEOUT) != nfc::STATUS_OK) {
175 ESP_LOGE(TAG,
"Error writing page %u", page_num);
176 return nfc::STATUS_FAILED;
178 return nfc::STATUS_OK;
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
Minimal static vector - saves memory by avoiding std::vector overhead.
One NCI packet, held in a fixed buffer so building and reading messages never allocates.
uint8_t get_payload_size(bool recompute=false)
std::span< const uint8_t > get_payload() const
The payload bytes that follow the header.
void append(std::span< const uint8_t > data)
Appends bytes to the payload; bytes that do not fit are dropped.
void set_ndef_message(std::unique_ptr< NdefMessage > ndef_message)
uint8_t find_mifare_ultralight_ndef_(std::span< const uint8_t > page_3_to_6, uint8_t &message_length, uint8_t &message_start_index)
uint8_t write_mifare_ultralight_tag_(nfc::NfcTagUid &uid, const std::shared_ptr< nfc::NdefMessage > &message)
uint8_t transceive_(nfc::NciMessage &tx, nfc::NciMessage &rx, uint16_t timeout=NFCC_DEFAULT_TIMEOUT, bool expect_notification=true)
uint8_t clean_mifare_ultralight_()
bool is_mifare_ultralight_formatted_(std::span< const uint8_t > page_3_to_6)
uint8_t read_mifare_ultralight_bytes_(uint8_t start_page, uint16_t num_bytes, UltralightReadBuffer &data)
uint16_t read_mifare_ultralight_capacity_()
uint8_t read_mifare_ultralight_tag_(nfc::NfcTag &tag)
uint8_t write_mifare_ultralight_page_(uint8_t page_num, const uint8_t *write_data, size_t len)
const LogString * message
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.
uint32_t get_mifare_ultralight_buffer_size(uint32_t message_length)
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
ESPHOME_LOG_TAG(TAG, "pn71xx")
uint16_t uint16_t & capacity