mirror of
https://github.com/esphome/esphome.git
synced 2024-12-26 15:34:53 +01:00
Fix PN532 for IDF 5 and ultralight enhancements (#5352)
This commit is contained in:
parent
87395d259e
commit
ab872b075a
3 changed files with 71 additions and 58 deletions
|
@ -54,7 +54,7 @@ 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) {
|
||||
uint8_t i = get_mifare_classic_ndef_start_index(data);
|
||||
if (i < 0 || data[i] != 0x03) {
|
||||
if (data[i] != 0x03) {
|
||||
ESP_LOGE(TAG, "Error, Can't decode message length.");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "esphome/components/nfc/nfc.h"
|
||||
#include "esphome/components/nfc/automation.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
|
@ -74,10 +75,11 @@ class PN532 : public PollingComponent {
|
|||
bool write_mifare_classic_tag_(std::vector<uint8_t> &uid, nfc::NdefMessage *message);
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> read_mifare_ultralight_tag_(std::vector<uint8_t> &uid);
|
||||
bool read_mifare_ultralight_page_(uint8_t page_num, std::vector<uint8_t> &data);
|
||||
bool is_mifare_ultralight_formatted_();
|
||||
bool read_mifare_ultralight_bytes_(uint8_t start_page, uint16_t num_bytes, std::vector<uint8_t> &data);
|
||||
bool is_mifare_ultralight_formatted_(const std::vector<uint8_t> &page_3_to_6);
|
||||
uint16_t read_mifare_ultralight_capacity_();
|
||||
bool find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index);
|
||||
bool find_mifare_ultralight_ndef_(const std::vector<uint8_t> &page_3_to_6, uint8_t &message_length,
|
||||
uint8_t &message_start_index);
|
||||
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);
|
||||
bool clean_mifare_ultralight_();
|
||||
|
|
|
@ -9,93 +9,104 @@ namespace pn532 {
|
|||
static const char *const TAG = "pn532.mifare_ultralight";
|
||||
|
||||
std::unique_ptr<nfc::NfcTag> PN532::read_mifare_ultralight_tag_(std::vector<uint8_t> &uid) {
|
||||
if (!this->is_mifare_ultralight_formatted_()) {
|
||||
ESP_LOGD(TAG, "Not NDEF formatted");
|
||||
std::vector<uint8_t> data;
|
||||
// pages 3 to 6 contain various info we are interested in -- do one read to grab it all
|
||||
if (!this->read_mifare_ultralight_bytes_(3, nfc::MIFARE_ULTRALIGHT_PAGE_SIZE * nfc::MIFARE_ULTRALIGHT_READ_SIZE,
|
||||
data)) {
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
|
||||
}
|
||||
|
||||
if (!this->is_mifare_ultralight_formatted_(data)) {
|
||||
ESP_LOGW(TAG, "Not NDEF formatted");
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
|
||||
}
|
||||
|
||||
uint8_t message_length;
|
||||
uint8_t message_start_index;
|
||||
if (!this->find_mifare_ultralight_ndef_(message_length, message_start_index)) {
|
||||
if (!this->find_mifare_ultralight_ndef_(data, message_length, message_start_index)) {
|
||||
ESP_LOGW(TAG, "Couldn't find NDEF message");
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
|
||||
}
|
||||
ESP_LOGVV(TAG, "message length: %d, start: %d", message_length, message_start_index);
|
||||
ESP_LOGVV(TAG, "NDEF message length: %u, start: %u", message_length, message_start_index);
|
||||
|
||||
if (message_length == 0) {
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
|
||||
}
|
||||
std::vector<uint8_t> data;
|
||||
for (uint8_t page = nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE; page < nfc::MIFARE_ULTRALIGHT_MAX_PAGE; page++) {
|
||||
std::vector<uint8_t> page_data;
|
||||
if (!this->read_mifare_ultralight_page_(page, page_data)) {
|
||||
ESP_LOGE(TAG, "Error reading page %d", page);
|
||||
// we already read pages 3-6 earlier -- pick up where we left off so we're not re-reading pages
|
||||
const uint8_t read_length = message_length + message_start_index > 12 ? message_length + message_start_index - 12 : 0;
|
||||
if (read_length) {
|
||||
if (!read_mifare_ultralight_bytes_(nfc::MIFARE_ULTRALIGHT_DATA_START_PAGE + 3, read_length, data)) {
|
||||
ESP_LOGE(TAG, "Error reading tag data");
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2);
|
||||
}
|
||||
data.insert(data.end(), page_data.begin(), page_data.end());
|
||||
|
||||
if (data.size() >= (message_length + message_start_index))
|
||||
break;
|
||||
}
|
||||
|
||||
data.erase(data.begin(), data.begin() + message_start_index);
|
||||
data.erase(data.begin() + message_length, data.end());
|
||||
// we need to trim off page 3 as well as any bytes ahead of message_start_index
|
||||
data.erase(data.begin(), data.begin() + message_start_index + nfc::MIFARE_ULTRALIGHT_PAGE_SIZE);
|
||||
|
||||
return make_unique<nfc::NfcTag>(uid, nfc::NFC_FORUM_TYPE_2, data);
|
||||
}
|
||||
|
||||
bool PN532::read_mifare_ultralight_page_(uint8_t page_num, std::vector<uint8_t> &data) {
|
||||
if (!this->write_command_({
|
||||
PN532_COMMAND_INDATAEXCHANGE,
|
||||
0x01, // One card
|
||||
nfc::MIFARE_CMD_READ,
|
||||
page_num,
|
||||
})) {
|
||||
return false;
|
||||
bool PN532::read_mifare_ultralight_bytes_(uint8_t start_page, uint16_t num_bytes, std::vector<uint8_t> &data) {
|
||||
const uint8_t read_increment = nfc::MIFARE_ULTRALIGHT_READ_SIZE * nfc::MIFARE_ULTRALIGHT_PAGE_SIZE;
|
||||
std::vector<uint8_t> response;
|
||||
|
||||
for (uint8_t i = 0; i * read_increment < num_bytes; i++) {
|
||||
if (!this->write_command_({
|
||||
PN532_COMMAND_INDATAEXCHANGE,
|
||||
0x01, // One card
|
||||
nfc::MIFARE_CMD_READ,
|
||||
uint8_t(i * nfc::MIFARE_ULTRALIGHT_READ_SIZE + start_page),
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response) || response[0] != 0x00) {
|
||||
return false;
|
||||
}
|
||||
uint16_t bytes_offset = (i + 1) * read_increment;
|
||||
auto pages_in_end_itr = bytes_offset <= num_bytes ? response.end() : response.end() - (bytes_offset - num_bytes);
|
||||
|
||||
if ((pages_in_end_itr > response.begin()) && (pages_in_end_itr <= response.end())) {
|
||||
data.insert(data.end(), response.begin() + 1, pages_in_end_itr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) {
|
||||
return false;
|
||||
}
|
||||
data.erase(data.begin());
|
||||
// We only want 1 page of data but the PN532 returns 4 at once.
|
||||
data.erase(data.begin() + 4, data.end());
|
||||
|
||||
ESP_LOGVV(TAG, "Pages %d-%d: %s", page_num, page_num + 4, nfc::format_bytes(data).c_str());
|
||||
ESP_LOGVV(TAG, "Data read: %s", nfc::format_bytes(data).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PN532::is_mifare_ultralight_formatted_() {
|
||||
std::vector<uint8_t> data;
|
||||
if (this->read_mifare_ultralight_page_(4, data)) {
|
||||
return !(data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
|
||||
}
|
||||
return true;
|
||||
bool PN532::is_mifare_ultralight_formatted_(const std::vector<uint8_t> &page_3_to_6) {
|
||||
const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector
|
||||
|
||||
return (page_3_to_6.size() > p4_offset + 3) &&
|
||||
!((page_3_to_6[p4_offset + 0] == 0xFF) && (page_3_to_6[p4_offset + 1] == 0xFF) &&
|
||||
(page_3_to_6[p4_offset + 2] == 0xFF) && (page_3_to_6[p4_offset + 3] == 0xFF));
|
||||
}
|
||||
|
||||
uint16_t PN532::read_mifare_ultralight_capacity_() {
|
||||
std::vector<uint8_t> data;
|
||||
if (this->read_mifare_ultralight_page_(3, data)) {
|
||||
if (this->read_mifare_ultralight_bytes_(3, nfc::MIFARE_ULTRALIGHT_PAGE_SIZE, data)) {
|
||||
ESP_LOGV(TAG, "Tag capacity is %u bytes", data[2] * 8U);
|
||||
return data[2] * 8U;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PN532::find_mifare_ultralight_ndef_(uint8_t &message_length, uint8_t &message_start_index) {
|
||||
std::vector<uint8_t> data;
|
||||
for (int page = 4; page < 6; page++) {
|
||||
std::vector<uint8_t> page_data;
|
||||
if (!this->read_mifare_ultralight_page_(page, page_data)) {
|
||||
return false;
|
||||
}
|
||||
data.insert(data.end(), page_data.begin(), page_data.end());
|
||||
bool PN532::find_mifare_ultralight_ndef_(const std::vector<uint8_t> &page_3_to_6, uint8_t &message_length,
|
||||
uint8_t &message_start_index) {
|
||||
const uint8_t p4_offset = nfc::MIFARE_ULTRALIGHT_PAGE_SIZE; // page 4 will begin 4 bytes into the vector
|
||||
|
||||
if (!(page_3_to_6.size() > p4_offset + 5)) {
|
||||
return false;
|
||||
}
|
||||
if (data[0] == 0x03) {
|
||||
message_length = data[1];
|
||||
|
||||
if (page_3_to_6[p4_offset + 0] == 0x03) {
|
||||
message_length = page_3_to_6[p4_offset + 1];
|
||||
message_start_index = 2;
|
||||
return true;
|
||||
} else if (data[5] == 0x03) {
|
||||
message_length = data[6];
|
||||
} else if (page_3_to_6[p4_offset + 5] == 0x03) {
|
||||
message_length = page_3_to_6[p4_offset + 6];
|
||||
message_start_index = 7;
|
||||
return true;
|
||||
}
|
||||
|
@ -111,7 +122,7 @@ bool PN532::write_mifare_ultralight_tag_(std::vector<uint8_t> &uid, nfc::NdefMes
|
|||
uint32_t buffer_length = nfc::get_mifare_ultralight_buffer_size(message_length);
|
||||
|
||||
if (buffer_length > capacity) {
|
||||
ESP_LOGE(TAG, "Message length exceeds tag capacity %d > %d", buffer_length, capacity);
|
||||
ESP_LOGE(TAG, "Message length exceeds tag capacity %" PRIu32 " > %" PRIu32, buffer_length, capacity);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,13 +175,13 @@ bool PN532::write_mifare_ultralight_page_(uint8_t page_num, std::vector<uint8_t>
|
|||
});
|
||||
data.insert(data.end(), write_data.begin(), write_data.end());
|
||||
if (!this->write_command_(data)) {
|
||||
ESP_LOGE(TAG, "Error writing page %d", page_num);
|
||||
ESP_LOGE(TAG, "Error writing page %u", page_num);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> response;
|
||||
if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) {
|
||||
ESP_LOGE(TAG, "Error writing page %d", page_num);
|
||||
ESP_LOGE(TAG, "Error writing page %u", page_num);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue