diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index cc28d7078b..8088e6c022 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -127,8 +127,18 @@ void PN532::loop() { if (!this->requested_read_) return; + auto ready = this->read_ready_(false); + if (ready == WOULDBLOCK) + return; + + bool success = false; std::vector read; - bool success = this->read_response(PN532_COMMAND_INLISTPASSIVETARGET, read); + + if (ready == READY) { + success = this->read_response(PN532_COMMAND_INLISTPASSIVETARGET, read); + } else { + this->send_ack_(); // abort still running InListPassiveTarget + } this->requested_read_ = false; @@ -286,12 +296,58 @@ bool PN532::read_ack_() { return matches; } +void PN532::send_ack_() { + ESP_LOGV(TAG, "Sending ACK for abort"); + this->write_data({0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00}); + delay(10); +} void PN532::send_nack_() { ESP_LOGV(TAG, "Sending NACK for retransmit"); this->write_data({0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}); delay(10); } +enum PN532ReadReady PN532::read_ready_(bool block) { + if (this->rd_ready_ == READY) { + if (block) { + this->rd_start_time_ = 0; + this->rd_ready_ = WOULDBLOCK; + } + return READY; + } + + if (!this->rd_start_time_) { + this->rd_start_time_ = millis(); + } + + while (true) { + if (this->is_read_ready()) { + this->rd_ready_ = READY; + break; + } + + if (millis() - this->rd_start_time_ > 100) { + ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); + this->rd_ready_ = TIMEOUT; + break; + } + + if (!block) { + this->rd_ready_ = WOULDBLOCK; + break; + } + + yield(); + } + + auto rdy = this->rd_ready_; + if (block || rdy == TIMEOUT) { + this->rd_start_time_ = 0; + this->rd_ready_ = WOULDBLOCK; + } + return rdy; +} + void PN532::turn_off_rf_() { ESP_LOGV(TAG, "Turning RF field OFF"); this->write_command_({ diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 8ae215dfd9..8194d86477 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -20,6 +20,12 @@ static const uint8_t PN532_COMMAND_INDATAEXCHANGE = 0x40; static const uint8_t PN532_COMMAND_INLISTPASSIVETARGET = 0x4A; static const uint8_t PN532_COMMAND_POWERDOWN = 0x16; +enum PN532ReadReady { + WOULDBLOCK = 0, + TIMEOUT, + READY, +}; + class PN532BinarySensor; class PN532 : public PollingComponent { @@ -54,8 +60,11 @@ class PN532 : public PollingComponent { void turn_off_rf_(); bool write_command_(const std::vector &data); bool read_ack_(); + void send_ack_(); void send_nack_(); + enum PN532ReadReady read_ready_(bool block); + virtual bool is_read_ready() = 0; virtual bool write_data(const std::vector &data) = 0; virtual bool read_data(std::vector &data, uint8_t len) = 0; virtual bool read_response(uint8_t command, std::vector &data) = 0; @@ -91,6 +100,8 @@ class PN532 : public PollingComponent { std::vector triggers_ontagremoved_; std::vector current_uid_; nfc::NdefMessage *next_task_message_to_write_; + uint32_t rd_start_time_{0}; + enum PN532ReadReady rd_ready_ { WOULDBLOCK }; enum NfcTask { READ = 0, CLEAN, diff --git a/esphome/components/pn532_i2c/pn532_i2c.cpp b/esphome/components/pn532_i2c/pn532_i2c.cpp index e7c99e94b0..b306222a21 100644 --- a/esphome/components/pn532_i2c/pn532_i2c.cpp +++ b/esphome/components/pn532_i2c/pn532_i2c.cpp @@ -12,6 +12,14 @@ namespace pn532_i2c { static const char *const TAG = "pn532_i2c"; +bool PN532I2C::is_read_ready() { + uint8_t ready; + if (!this->read_bytes_raw(&ready, 1)) { + return false; + } + return ready == 0x01; +} + bool PN532I2C::write_data(const std::vector &data) { return this->write(data.data(), data.size()) == i2c::ERROR_OK; } @@ -19,19 +27,8 @@ bool PN532I2C::write_data(const std::vector &data) { bool PN532I2C::read_data(std::vector &data, uint8_t len) { delay(1); - std::vector ready; - ready.resize(1); - uint32_t start_time = millis(); - while (true) { - if (this->read_bytes_raw(ready.data(), 1)) { - if (ready[0] == 0x01) - break; - } - - if (millis() - start_time > 100) { - ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); - return false; - } + if (this->read_ready_(true) != pn532::PN532ReadReady::READY) { + return false; } data.resize(len + 1); diff --git a/esphome/components/pn532_i2c/pn532_i2c.h b/esphome/components/pn532_i2c/pn532_i2c.h index 95cf8eeb36..00c0df206d 100644 --- a/esphome/components/pn532_i2c/pn532_i2c.h +++ b/esphome/components/pn532_i2c/pn532_i2c.h @@ -14,6 +14,7 @@ class PN532I2C : public pn532::PN532, public i2c::I2CDevice { void dump_config() override; protected: + bool is_read_ready() override; bool write_data(const std::vector &data) override; bool read_data(std::vector &data, uint8_t len) override; bool read_response(uint8_t command, std::vector &data) override; diff --git a/esphome/components/pn532_spi/pn532_spi.cpp b/esphome/components/pn532_spi/pn532_spi.cpp index be58f265b9..d55d8161d8 100644 --- a/esphome/components/pn532_spi/pn532_spi.cpp +++ b/esphome/components/pn532_spi/pn532_spi.cpp @@ -21,6 +21,14 @@ void PN532Spi::setup() { PN532::setup(); } +bool PN532Spi::is_read_ready() { + this->enable(); + this->write_byte(0x02); + bool ready = this->read_byte() == 0x01; + this->disable(); + return ready; +} + bool PN532Spi::write_data(const std::vector &data) { this->enable(); delay(2); @@ -34,24 +42,8 @@ bool PN532Spi::write_data(const std::vector &data) { } bool PN532Spi::read_data(std::vector &data, uint8_t len) { - ESP_LOGV(TAG, "Waiting for ready byte..."); - - uint32_t start_time = millis(); - while (true) { - this->enable(); - // First byte, communication mode: Read state - this->write_byte(0x02); - bool ready = this->read_byte() == 0x01; - this->disable(); - if (ready) - break; - ESP_LOGV(TAG, "Not ready yet..."); - - if (millis() - start_time > 100) { - ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); - return false; - } - yield(); + if (this->read_ready_(true) != pn532::PN532ReadReady::READY) { + return false; } // Read data (transmission from the PN532 to the host) @@ -72,22 +64,8 @@ bool PN532Spi::read_data(std::vector &data, uint8_t len) { bool PN532Spi::read_response(uint8_t command, std::vector &data) { ESP_LOGV(TAG, "Reading response"); - uint32_t start_time = millis(); - while (true) { - this->enable(); - // First byte, communication mode: Read state - this->write_byte(0x02); - bool ready = this->read_byte() == 0x01; - this->disable(); - if (ready) - break; - ESP_LOGV(TAG, "Not ready yet..."); - - if (millis() - start_time > 100) { - ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); - return false; - } - yield(); + if (this->read_ready_(true) != pn532::PN532ReadReady::READY) { + return false; } this->enable(); diff --git a/esphome/components/pn532_spi/pn532_spi.h b/esphome/components/pn532_spi/pn532_spi.h index 2d8312813d..b7adca22e9 100644 --- a/esphome/components/pn532_spi/pn532_spi.h +++ b/esphome/components/pn532_spi/pn532_spi.h @@ -18,6 +18,7 @@ class PN532Spi : public pn532::PN532, void dump_config() override; protected: + bool is_read_ready() override; bool write_data(const std::vector &data) override; bool read_data(std::vector &data, uint8_t len) override; bool read_response(uint8_t command, std::vector &data) override;