mirror of
https://github.com/esphome/esphome.git
synced 2025-03-14 06:38:17 +00:00
Merge 422e699aa69284416b650fca3e5295144c39c7ac into 755b0bbfc7d404d9ce1a4a02ee8c99c4c838e63f
This commit is contained in:
commit
7664bbc056
@ -31,11 +31,36 @@ std::string format_bytes(std::vector<uint8_t> &bytes) {
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
uint8_t guess_tag_type(uint8_t uid_length) {
|
||||
bool is_ntag(const std::vector<uint8_t> &first_page) {
|
||||
// NTAG typically has a capability container (CC) starting at byte 3
|
||||
// The CC for NTAG is usually 0xE1 0x10 followed by a type-specific byte
|
||||
if (first_page.size() >= 16 && first_page[3] == 0xE1 && first_page[4] == 0x10) {
|
||||
switch (first_page[5]) {
|
||||
case 0x11:
|
||||
return TAG_TYPE_NTAG_213;
|
||||
case 0x12:
|
||||
return TAG_TYPE_NTAG_215;
|
||||
case 0x13:
|
||||
return TAG_TYPE_NTAG_216;
|
||||
default:
|
||||
return TAG_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
return TAG_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t guess_tag_type(uint8_t uid_length, const std::vector<uint8_t> &first_page) {
|
||||
if (uid_length == 4) {
|
||||
return TAG_TYPE_MIFARE_CLASSIC;
|
||||
} else if (uid_length == 7) {
|
||||
uint8_t ntag_type = is_ntag(first_page);
|
||||
if (ntag_type != TAG_TYPE_UNKNOWN) {
|
||||
return ntag_type;
|
||||
} else {
|
||||
return TAG_TYPE_2;
|
||||
return TAG_TYPE_2; // Could be MIFARE Ultralight or other Type 2 tag
|
||||
}
|
||||
} else {
|
||||
return TAG_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,16 @@ static const uint8_t TAG_TYPE_1 = 1;
|
||||
static const uint8_t TAG_TYPE_2 = 2;
|
||||
static const uint8_t TAG_TYPE_3 = 3;
|
||||
static const uint8_t TAG_TYPE_4 = 4;
|
||||
static const uint8_t TAG_TYPE_NTAG_213 = 5;
|
||||
static const uint8_t TAG_TYPE_NTAG_215 = 6;
|
||||
static const uint8_t TAG_TYPE_NTAG_216 = 7;
|
||||
static const uint8_t TAG_TYPE_UNKNOWN = 99;
|
||||
|
||||
static const uint8_t NTAG_PAGE_SIZE = 4;
|
||||
static const uint8_t NTAG_213_MAX_PAGE = 45; // NTAG213 has 180 bytes of memory (45 pages * 4 bytes per page)
|
||||
static const uint8_t NTAG_215_MAX_PAGE = 135; // NTAG215 has 540 bytes of memory (135 pages * 4 bytes per page)
|
||||
static const uint8_t NTAG_216_MAX_PAGE = 231; // NTAG216 has 924 bytes of memory (231 pages * 4 bytes per page)
|
||||
|
||||
// Mifare Commands
|
||||
static const uint8_t MIFARE_CMD_AUTH_A = 0x60;
|
||||
static const uint8_t MIFARE_CMD_AUTH_B = 0x61;
|
||||
@ -56,7 +64,8 @@ static const uint8_t MAD_KEY[6] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
|
||||
std::string format_uid(std::vector<uint8_t> &uid);
|
||||
std::string format_bytes(std::vector<uint8_t> &bytes);
|
||||
|
||||
uint8_t guess_tag_type(uint8_t uid_length);
|
||||
// uint8_t guess_tag_type(uint8_t uid_length);//TODO: deprecate guess_tag_type
|
||||
uint8_t guess_tag_type(uint8_t uid_length, const std::vector<uint8_t> &first_page);
|
||||
uint8_t get_mifare_classic_ndef_start_index(std::vector<uint8_t> &data);
|
||||
bool decode_mifare_classic_tlv(std::vector<uint8_t> &data, uint32_t &message_length, uint8_t &message_start_index);
|
||||
uint32_t get_mifare_classic_buffer_size(uint32_t message_length);
|
||||
@ -66,6 +75,10 @@ bool mifare_classic_is_trailer_block(uint8_t block_num);
|
||||
|
||||
uint32_t get_mifare_ultralight_buffer_size(uint32_t message_length);
|
||||
|
||||
bool is_ntag(const std::vector<uint8_t> &first_page);
|
||||
uint32_t get_ntag_buffer_size(uint32_t message_length);
|
||||
bool decode_ntag_tlv(const std::vector<uint8_t> &data, uint32_t &message_length, uint8_t &message_start_index);
|
||||
|
||||
class NfcTagListener {
|
||||
public:
|
||||
virtual void tag_off(NfcTag &tag) {}
|
||||
|
@ -357,23 +357,124 @@ void PN532::turn_off_rf_() {
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> PN532::read_tag_(std::vector<uint8_t> &uid) {
|
||||
uint8_t type = nfc::guess_tag_type(uid.size());
|
||||
bool PN532::ntag2xx_read_page(uint8_t page_number, std::vector<uint8_t> &data) {
|
||||
std::vector<uint8_t> command = {
|
||||
PN532_COMMAND_INDATAEXCHANGE,
|
||||
0x01, // Card number
|
||||
0x30, // MIFARE Read command
|
||||
page_number // Page to read
|
||||
};
|
||||
|
||||
if (type == nfc::TAG_TYPE_MIFARE_CLASSIC) {
|
||||
ESP_LOGD(TAG, "Mifare classic");
|
||||
return this->read_mifare_classic_tag_(uid);
|
||||
} else if (type == nfc::TAG_TYPE_2) {
|
||||
ESP_LOGD(TAG, "Mifare ultralight");
|
||||
return this->read_mifare_ultralight_tag_(uid);
|
||||
} else if (type == nfc::TAG_TYPE_UNKNOWN) {
|
||||
ESP_LOGV(TAG, "Cannot determine tag type");
|
||||
return make_unique<nfc::NfcTag>(uid);
|
||||
if (!this->write_command_(command)) {
|
||||
ESP_LOGE(TAG, "Error writing read command");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data)) {
|
||||
ESP_LOGE(TAG, "Error reading page data");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove status byte
|
||||
data.erase(data.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> PN532::read_tag_(std::vector<uint8_t> &uid) {
|
||||
std::vector<uint8_t> first_page(16); // 4 pages, 4 bytes each
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
std::vector<uint8_t> page_data(4);
|
||||
if (this->ntag2xx_read_page(i, page_data)) {
|
||||
first_page.insert(first_page.begin() + i * 4, page_data.begin(), page_data.end());
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to read page %d", i);
|
||||
return make_unique<nfc::NfcTag>(uid);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t type = nfc::guess_tag_type(uid.size(), first_page);
|
||||
|
||||
switch (type) {
|
||||
case nfc::TAG_TYPE_MIFARE_CLASSIC:
|
||||
ESP_LOGD(TAG, "Mifare classic");
|
||||
return this->read_mifare_classic_tag_(uid);
|
||||
case nfc::TAG_TYPE_2:
|
||||
ESP_LOGD(TAG, "Mifare ultralight");
|
||||
return this->read_mifare_ultralight_tag_(uid);
|
||||
case nfc::TAG_TYPE_NTAG_213:
|
||||
ESP_LOGD(TAG, "NTAG213");
|
||||
return this->read_ntag_tag_(uid, nfc::TAG_TYPE_NTAG_213);
|
||||
case nfc::TAG_TYPE_NTAG_215:
|
||||
ESP_LOGD(TAG, "NTAG215");
|
||||
return this->read_ntag_tag_(uid, nfc::TAG_TYPE_NTAG_215);
|
||||
case nfc::TAG_TYPE_NTAG_216:
|
||||
ESP_LOGD(TAG, "NTAG216");
|
||||
return this->read_ntag_tag_(uid, nfc::TAG_TYPE_NTAG_216);
|
||||
case nfc::TAG_TYPE_UNKNOWN:
|
||||
default:
|
||||
ESP_LOGV(TAG, "Cannot determine tag type");
|
||||
return make_unique<nfc::NfcTag>(uid);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> PN532::read_ntag_tag_(std::vector<uint8_t> &uid, uint8_t tag_type) {
|
||||
std::vector<uint8_t> data(4);
|
||||
uint8_t max_page;
|
||||
|
||||
switch (tag_type) {
|
||||
case nfc::TAG_TYPE_NTAG_213:
|
||||
max_page = 39;
|
||||
break;
|
||||
case nfc::TAG_TYPE_NTAG_215:
|
||||
max_page = 129;
|
||||
break;
|
||||
case nfc::TAG_TYPE_NTAG_216:
|
||||
max_page = 225;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown NTAG type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> tag_data;
|
||||
for (uint8_t page = 4; page <= max_page; page++) {
|
||||
if (!this->ntag2xx_read_page(page, data)) {
|
||||
ESP_LOGE(TAG, "Failed to read page %d", page);
|
||||
return nullptr;
|
||||
}
|
||||
tag_data.insert(tag_data.end(), data.begin(), data.end());
|
||||
}
|
||||
|
||||
return make_unique<nfc::NfcTag>(uid, tag_data, tag_type);
|
||||
}
|
||||
|
||||
bool PN532::ntag2xx_read_page(uint8_t page, std::vector<uint8_t> &data) {
|
||||
std::vector<uint8_t> command = {
|
||||
PN532_COMMAND_INDATAEXCHANGE,
|
||||
0x01, // Card number
|
||||
0x30, // MIFARE Read command
|
||||
page // Page to read
|
||||
};
|
||||
|
||||
if (!this->write_command_(command)) {
|
||||
ESP_LOGE(TAG, "Error writing read command");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> response;
|
||||
if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) {
|
||||
ESP_LOGE(TAG, "Error reading page data");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove status byte
|
||||
response.erase(response.begin());
|
||||
data = response;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PN532::read_mode() {
|
||||
this->next_task_ = READ;
|
||||
ESP_LOGD(TAG, "Waiting to read next tag");
|
||||
@ -393,7 +494,13 @@ void PN532::write_mode(nfc::NdefMessage *message) {
|
||||
}
|
||||
|
||||
bool PN532::clean_tag_(std::vector<uint8_t> &uid) {
|
||||
uint8_t type = nfc::guess_tag_type(uid.size());
|
||||
std::vector<uint8_t> first_page(16);
|
||||
if (!this->ntag2xx_read_page(4, first_page)) {
|
||||
ESP_LOGE(TAG, "Failed to read first page");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t type = nfc::guess_tag_type(uid.size(), first_page);
|
||||
if (type == nfc::TAG_TYPE_MIFARE_CLASSIC) {
|
||||
return this->format_mifare_classic_mifare_(uid);
|
||||
} else if (type == nfc::TAG_TYPE_2) {
|
||||
|
@ -70,6 +70,7 @@ class PN532 : public PollingComponent {
|
||||
virtual bool read_response(uint8_t command, std::vector<uint8_t> &data) = 0;
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> read_tag_(std::vector<uint8_t> &uid);
|
||||
std::unique_ptr<nfc::NfcTag> PN532::read_ntag_tag_(std::vector<uint8_t> &uid, uint8_t tag_type);
|
||||
|
||||
bool format_tag_(std::vector<uint8_t> &uid);
|
||||
bool clean_tag_(std::vector<uint8_t> &uid);
|
||||
@ -93,6 +94,8 @@ class PN532 : public PollingComponent {
|
||||
bool write_mifare_ultralight_tag_(std::vector<uint8_t> &uid, nfc::NdefMessage *message);
|
||||
bool clean_mifare_ultralight_();
|
||||
|
||||
bool ntag2xx_read_page(uint8_t page_number, std::vector<uint8_t> &data);
|
||||
|
||||
bool updates_enabled_{true};
|
||||
bool requested_read_{false};
|
||||
std::vector<PN532BinarySensor *> binary_sensors_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user