ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
pn532_i2c.cpp
Go to the documentation of this file.
1#include "pn532_i2c.h"
2#include "esphome/core/log.h"
3#include "esphome/core/hal.h"
4
5#include <algorithm>
6
7// Based on:
8// - https://cdn-shop.adafruit.com/datasheets/PN532C106_Application+Note_v1.2.pdf
9// - https://www.nxp.com/docs/en/nxp/application-notes/AN133910.pdf
10// - https://www.nxp.com/docs/en/nxp/application-notes/153710.pdf
11
13
14ESPHOME_LOG_TAG(TAG, "pn532_i2c");
15
17 uint8_t status;
18 if (!this->read_bytes_raw(&status, 1)) {
19 return false;
20 }
21 // only bit 0 (RDY) of the status byte is defined (UM0701-02, 6.2.4)
22 return status & 0x01;
23}
24
25bool PN532I2C::write_data(const std::span<const uint8_t> data) {
26 return this->write(data.data(), data.size()) == i2c::ERROR_OK;
27}
28
30 if (len + 1 > pn532::PN532_FRAME_MAX_SIZE) {
31 return false;
32 }
33 delay(1);
34
35 if (this->read_ready_(true) != pn532::PN532ReadReady::READY) {
36 return false;
37 }
38
39 // the PN532 prefixes every frame with a status byte
40 data.resize(len + 1);
41 return this->read_bytes_raw(data.data(), len + 1);
42}
43
44bool PN532I2C::read_response(uint8_t command, pn532::PN532Frame &data) {
45 ESP_LOGV(TAG, "Reading response");
46 uint8_t len = this->read_response_length_();
47 if (len == 0) {
48 return false;
49 }
50
51 ESP_LOGV(TAG, "Reading response of length %d", len);
52 if (!this->read_data(data, 6 + len + 2)) {
53 ESP_LOGD(TAG, "No response data");
54 return false;
55 }
56
57 if (data[1] != 0x00 || data[2] != 0x00 || data[3] != 0xFF) {
58 // invalid packet
59 ESP_LOGV(TAG, "read data invalid preamble!");
60 return false;
61 }
62
63 bool valid_header = (static_cast<uint8_t>(data[4] + data[5]) == 0 && // LCS, len + lcs = 0
64 data[6] == 0xD5 && // TFI - frame from PN532 to system controller
65 data[7] == command + 1); // Correct command response
66
67 if (!valid_header) {
68 ESP_LOGV(TAG, "read data invalid header!");
69 return false;
70 }
71
72 // frame: status, preamble, start code (2), LEN, LCS, TFI, command response code, data, DCS, postamble
73 constexpr size_t tfi_offset = 6;
74 const uint8_t checksum = -sum_bytes(data.data() + tfi_offset, len + 1U);
75
76 if (data[tfi_offset + len + 1] != checksum) {
77 ESP_LOGV(TAG, "read data invalid checksum! %02X != %02X", data[tfi_offset + len + 1], checksum);
78 return false;
79 }
80
81 if (data[tfi_offset + len + 2] != 0x00) {
82 ESP_LOGV(TAG, "read data invalid postamble!");
83 return false;
84 }
85
86 // keep only the data bytes that follow the command response code
87 std::copy(data.begin() + tfi_offset + 2, data.begin() + tfi_offset + len + 1, data.begin());
88 data.resize(len - 1);
89
90 return true;
91}
92
95 if (!this->read_data(data, 6)) {
96 return 0;
97 }
98
99 if (data[1] != 0x00 || data[2] != 0x00 || data[3] != 0xFF) {
100 // invalid packet
101 ESP_LOGV(TAG, "read data invalid preamble!");
102 return 0;
103 }
104
105 bool valid_header = (static_cast<uint8_t>(data[4] + data[5]) == 0 && // LCS, len + lcs = 0
106 data[6] == 0xD5); // TFI - frame from PN532 to system controller
107
108 if (!valid_header) {
109 ESP_LOGV(TAG, "read data invalid header!");
110 return 0;
111 }
112
113 this->send_nack_();
114
115 // full length of message, including TFI
116 uint8_t full_len = data[4];
117 // length of data, excluding TFI
118 uint8_t len = full_len - 1;
119 if (full_len == 0)
120 len = 0;
121 return len;
122}
123
125 PN532::dump_config();
126 LOG_I2C_DEVICE(this);
127}
128
129} // namespace esphome::pn532_i2c
uint8_t checksum
Definition bl0906.h:3
uint8_t status
Definition bl0942.h:8
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:286
void resize(size_t n)
Definition helpers.h:335
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:195
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition i2c.h:262
enum PN532ReadReady read_ready_(bool block)
Definition pn532.cpp:326
bool read_data(pn532::PN532Frame &data, size_t len) override
Definition pn532_i2c.cpp:29
bool write_data(std::span< const uint8_t > data) override
Definition pn532_i2c.cpp:25
bool read_response(uint8_t command, pn532::PN532Frame &data) override
Definition pn532_i2c.cpp:44
bool is_read_ready() override
Definition pn532_i2c.cpp:16
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:15
ESPHOME_LOG_TAG(TAG, "pn532_i2c")
constexpr uint8_t sum_bytes(const uint8_t *data, size_t len, uint8_t sum=0)
Add up the bytes of data with size len, truncated to 8 bits: the checksum many serial and IR protocol...
Definition helpers.h:894
const void size_t len
Definition hal.h:68
void HOT delay(uint32_t ms)
Definition hal.cpp:85