#include "pn532_i2c.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" // Based on: // - https://cdn-shop.adafruit.com/datasheets/PN532C106_Application+Note_v1.2.pdf // - https://www.nxp.com/docs/en/nxp/application-notes/AN133910.pdf // - https://www.nxp.com/docs/en/nxp/application-notes/153710.pdf namespace esphome { 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; } bool PN532I2C::read_data(std::vector &data, uint8_t len) { delay(1); if (this->read_ready_(true) != pn532::PN532ReadReady::READY) { return false; } data.resize(len + 1); this->read_bytes_raw(data.data(), len + 1); return true; } bool PN532I2C::read_response(uint8_t command, std::vector &data) { ESP_LOGV(TAG, "Reading response"); uint8_t len = this->read_response_length_(); if (len == 0) { return false; } ESP_LOGV(TAG, "Reading response of length %d", len); if (!this->read_data(data, 6 + len + 2)) { ESP_LOGD(TAG, "No response data"); return false; } if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { // invalid packet ESP_LOGV(TAG, "read data invalid preamble!"); return false; } bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 data[6] == 0xD5 && // TFI - frame from PN532 to system controller data[7] == command + 1); // Correct command response if (!valid_header) { ESP_LOGV(TAG, "read data invalid header!"); return false; } data.erase(data.begin(), data.begin() + 6); // Remove headers uint8_t checksum = 0; for (int i = 0; i < len + 1; i++) { uint8_t dat = data[i]; checksum += dat; } checksum = ~checksum + 1; if (data[len + 1] != checksum) { ESP_LOGV(TAG, "read data invalid checksum! %02X != %02X", data[len], checksum); return false; } if (data[len + 2] != 0x00) { ESP_LOGV(TAG, "read data invalid postamble!"); return false; } data.erase(data.begin(), data.begin() + 2); // Remove TFI and command code data.erase(data.end() - 2, data.end()); // Remove checksum and postamble return true; } uint8_t PN532I2C::read_response_length_() { std::vector data; if (!this->read_data(data, 6)) { return 0; } if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { // invalid packet ESP_LOGV(TAG, "read data invalid preamble!"); return 0; } bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 data[6] == 0xD5); // TFI - frame from PN532 to system controller if (!valid_header) { ESP_LOGV(TAG, "read data invalid header!"); return 0; } this->send_nack_(); // full length of message, including TFI uint8_t full_len = data[4]; // length of data, excluding TFI uint8_t len = full_len - 1; if (full_len == 0) len = 0; return len; } void PN532I2C::dump_config() { PN532::dump_config(); LOG_I2C_DEVICE(this); } } // namespace pn532_i2c } // namespace esphome