ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
pn532.h
Go to the documentation of this file.
1#pragma once
2
9
10#include <array>
11#include <cinttypes>
12#include <initializer_list>
13#include <span>
14
15namespace esphome::pn532 {
16
17static const uint8_t PN532_COMMAND_VERSION_DATA = 0x02;
18static const uint8_t PN532_COMMAND_SAMCONFIGURATION = 0x14;
19static const uint8_t PN532_COMMAND_RFCONFIGURATION = 0x32;
20static const uint8_t PN532_COMMAND_INDATAEXCHANGE = 0x40;
21static const uint8_t PN532_COMMAND_INLISTPASSIVETARGET = 0x4A;
22static const uint8_t PN532_COMMAND_POWERDOWN = 0x16;
23
24enum PN532ReadReady : uint8_t {
28};
29
30// SEL_RES (SAK) bits, as reported by InListPassiveTarget for ISO/IEC 14443 type A targets (NXP AN10833)
31static constexpr uint8_t SEL_RES_MIFARE_CLASSIC = 0x08;
32static constexpr uint8_t SEL_RES_ISO_DEP = 0x20;
33static constexpr uint8_t SEL_RES_TNP3XXX = 0x01; // MIFARE Classic 1K compatible
34
36inline uint8_t tag_type_from_sel_res(uint8_t sel_res) {
37 if ((sel_res & SEL_RES_MIFARE_CLASSIC) || sel_res == SEL_RES_TNP3XXX)
38 return nfc::TAG_TYPE_MIFARE_CLASSIC;
39 if (sel_res & SEL_RES_ISO_DEP)
40 return nfc::TAG_TYPE_4;
41 if (sel_res == 0x00)
42 return nfc::TAG_TYPE_2;
43 return nfc::TAG_TYPE_UNKNOWN;
44}
45
47static constexpr size_t PN532_FRAME_MAX_DATA_SIZE = 254;
50static constexpr size_t PN532_FRAME_MAX_SIZE = 1 + 6 + PN532_FRAME_MAX_DATA_SIZE + 2;
54static constexpr uint32_t MIFARE_ULTRALIGHT_MAX_NDEF_SIZE = 888;
56static constexpr uint32_t MIFARE_CLASSIC_MAX_NDEF_SIZE = 3440;
58static constexpr size_t MIFARE_READ_SIZE = 16;
59using MifareReadData = std::array<uint8_t, MIFARE_READ_SIZE>;
61using UltralightHeader = std::array<uint8_t, MIFARE_READ_SIZE>;
62
64
65class PN532 : public PollingComponent {
66 public:
67 void setup() override;
68
69 void dump_config() override;
70
71 void update() override;
72
73 void loop() override;
74 void on_powerdown() override { powerdown(); }
75
76#ifdef PN532_BINARY_SENSOR_COUNT
77 void register_tag(PN532BinarySensor *tag) { this->binary_sensors_.push_back(tag); }
78#endif
79#ifdef PN532_ON_TAG_TRIGGER_COUNT
80 void register_ontag_trigger(nfc::NfcOnTagTrigger *trig) { this->triggers_ontag_.push_back(trig); }
81#endif
82#ifdef PN532_ON_TAG_REMOVED_TRIGGER_COUNT
84#endif
85
86 template<typename F> void add_on_finished_write_callback(F &&callback) {
87 this->on_finished_write_callback_.add(std::forward<F>(callback));
88 }
89
90 bool is_writing() { return this->next_task_ != READ; };
91
92 void read_mode();
93 void clean_mode();
94 void format_mode();
96 bool powerdown();
97
98 protected:
99 void turn_off_rf_();
100 bool write_command_(std::span<const uint8_t> data);
101 bool write_command_(std::initializer_list<uint8_t> data) {
102 return this->write_command_(std::span<const uint8_t>(data.begin(), data.size()));
103 }
104 bool read_ack_();
105 void send_ack_();
106 void send_nack_();
107
108 enum PN532ReadReady read_ready_(bool block);
109 virtual bool is_read_ready() = 0;
110 virtual bool write_data(std::span<const uint8_t> data) = 0;
112 virtual bool read_data(PN532Frame &data, size_t len) = 0;
114 virtual bool read_response(uint8_t command, PN532Frame &data) = 0;
115
116 std::unique_ptr<nfc::NfcTag> read_tag_(nfc::NfcTagUid &uid, uint8_t tag_type);
117
118 bool format_tag_(nfc::NfcTagUid &uid, uint8_t tag_type);
119 bool clean_tag_(nfc::NfcTagUid &uid, uint8_t tag_type);
120 bool write_tag_(nfc::NfcTagUid &uid, uint8_t tag_type, nfc::NdefMessage *message);
123 bool in_data_exchange_(std::span<const uint8_t> command, PN532Frame &response);
124 bool in_data_exchange_(std::initializer_list<uint8_t> command, PN532Frame &response) {
125 return this->in_data_exchange_(std::span<const uint8_t>(command.begin(), command.size()), response);
126 }
128 bool mifare_read_(uint8_t address, MifareReadData &data);
129
130 std::unique_ptr<nfc::NfcTag> read_mifare_classic_tag_(nfc::NfcTagUid &uid);
131 bool read_mifare_classic_block_(uint8_t block_num, MifareReadData &data);
132 bool write_mifare_classic_block_(uint8_t block_num, std::span<const uint8_t> data);
133 bool auth_mifare_classic_block_(nfc::NfcTagUid &uid, uint8_t block_num, uint8_t key_num, const uint8_t *key);
137
138 std::unique_ptr<nfc::NfcTag> read_mifare_ultralight_tag_(nfc::NfcTagUid &uid);
140 bool read_mifare_ultralight_bytes_(uint8_t start_page, std::span<uint8_t> data);
141 bool is_mifare_ultralight_formatted_(std::span<const uint8_t> page_3_to_6);
143 bool find_mifare_ultralight_ndef_(std::span<const uint8_t> page_3_to_6, uint32_t &message_length,
144 uint8_t &message_start_index);
145 bool write_mifare_ultralight_page_(uint8_t page_num, std::span<const uint8_t> write_data);
148
149 enum NfcTask : uint8_t {
150 READ = 0,
154 };
155
156 // members are ordered by alignment, widest first, to minimize padding
158#ifdef PN532_BINARY_SENSOR_COUNT
160#endif
161#ifdef PN532_ON_TAG_TRIGGER_COUNT
163#endif
164#ifdef PN532_ON_TAG_REMOVED_TRIGGER_COUNT
166#endif
167 std::unique_ptr<nfc::NdefMessage> next_task_message_to_write_;
169 uint32_t rd_start_time_{0}; // valid only while rd_started_ is set
172 bool rd_started_{false};
174 bool requested_read_{false};
175};
176
178 public:
179 void set_uid(const nfc::NfcTagUid &uid) { uid_ = uid; }
180
181 bool process(const nfc::NfcTagUid &data);
182
183 void on_scan_end() {
184 if (!this->found_) {
185 this->publish_state(false);
186 }
187 this->found_ = false;
188 }
189
190 protected:
192 bool found_{false};
193};
194
195} // namespace esphome::pn532
uint8_t address
Definition bl0906.h:4
This class simplifies creating components that periodically check a state.
Definition component.h:519
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:286
Base class for all binary_sensor-type classes.
void publish_state(bool new_state)
Publish a new state to the front-end.
Fires with the formatted UID and the tag itself; the tag is passed by reference so no copy is made pe...
Definition automation.h:11
bool process(const nfc::NfcTagUid &data)
Definition pn532.cpp:488
void set_uid(const nfc::NfcTagUid &uid)
Definition pn532.h:179
bool find_mifare_ultralight_ndef_(std::span< const uint8_t > page_3_to_6, uint32_t &message_length, uint8_t &message_start_index)
bool in_data_exchange_(std::initializer_list< uint8_t > command, PN532Frame &response)
Definition pn532.h:124
StaticVector< nfc::NfcOnTagTrigger *, PN532_ON_TAG_REMOVED_TRIGGER_COUNT > triggers_ontagremoved_
Definition pn532.h:165
nfc::NfcTagUid current_uid_
Definition pn532.h:168
void add_on_finished_write_callback(F &&callback)
Definition pn532.h:86
virtual bool read_data(PN532Frame &data, size_t len)=0
Reads len frame bytes into data behind a leading status byte, so every bus presents the I2C layout.
enum PN532ReadReady read_ready_(bool block)
Definition pn532.cpp:326
bool auth_mifare_classic_block_(nfc::NfcTagUid &uid, uint8_t block_num, uint8_t key_num, const uint8_t *key)
virtual bool is_read_ready()=0
bool mifare_read_(uint8_t address, MifareReadData &data)
Sends MIFARE READ for address and returns the 16 bytes the tag answers with.
Definition pn532.cpp:459
LazyCallbackManager< void()> on_finished_write_callback_
Definition pn532.h:157
bool format_mifare_classic_mifare_(nfc::NfcTagUid &uid)
std::unique_ptr< nfc::NfcTag > read_mifare_ultralight_tag_(nfc::NfcTagUid &uid)
bool write_command_(std::initializer_list< uint8_t > data)
Definition pn532.h:101
StaticVector< PN532BinarySensor *, PN532_BINARY_SENSOR_COUNT > binary_sensors_
Definition pn532.h:159
bool write_command_(std::span< const uint8_t > data)
Definition pn532.cpp:257
PN532ReadReady rd_ready_
Definition pn532.h:170
bool format_mifare_classic_ndef_(nfc::NfcTagUid &uid)
bool read_mifare_classic_block_(uint8_t block_num, MifareReadData &data)
virtual bool read_response(uint8_t command, PN532Frame &data)=0
Reads the response to command; on success data holds only the bytes that follow the response code.
void dump_config() override
Definition pn532.cpp:476
bool write_mifare_ultralight_page_(uint8_t page_num, std::span< const uint8_t > write_data)
void setup() override
Definition pn532.cpp:19
bool write_mifare_classic_tag_(nfc::NfcTagUid &uid, nfc::NdefMessage *message)
std::unique_ptr< nfc::NfcTag > read_mifare_classic_tag_(nfc::NfcTagUid &uid)
void register_ontagremoved_trigger(nfc::NfcOnTagTrigger *trig)
Definition pn532.h:83
void register_tag(PN532BinarySensor *tag)
Definition pn532.h:77
void on_powerdown() override
Definition pn532.h:74
std::unique_ptr< nfc::NdefMessage > next_task_message_to_write_
Definition pn532.h:167
void write_mode(nfc::NdefMessage *message)
Definition pn532.cpp:404
void update() override
Definition pn532.cpp:100
bool write_mifare_ultralight_tag_(nfc::NfcTagUid &uid, nfc::NdefMessage *message)
bool read_mifare_ultralight_bytes_(uint8_t start_page, std::span< uint8_t > data)
Fills data with the bytes from start_page onward.
std::unique_ptr< nfc::NfcTag > read_tag_(nfc::NfcTagUid &uid, uint8_t tag_type)
Definition pn532.cpp:380
bool write_mifare_classic_block_(uint8_t block_num, std::span< const uint8_t > data)
virtual bool write_data(std::span< const uint8_t > data)=0
void register_ontag_trigger(nfc::NfcOnTagTrigger *trig)
Definition pn532.h:80
bool in_data_exchange_(std::span< const uint8_t > command, PN532Frame &response)
Sends an InDataExchange command and reads the response; returns false unless the status byte reports ...
Definition pn532.cpp:440
StaticVector< nfc::NfcOnTagTrigger *, PN532_ON_TAG_TRIGGER_COUNT > triggers_ontag_
Definition pn532.h:162
bool clean_tag_(nfc::NfcTagUid &uid, uint8_t tag_type)
Definition pn532.cpp:410
uint32_t rd_start_time_
Definition pn532.h:169
bool write_tag_(nfc::NfcTagUid &uid, uint8_t tag_type, nfc::NdefMessage *message)
Definition pn532.cpp:430
void loop() override
Definition pn532.cpp:121
bool is_mifare_ultralight_formatted_(std::span< const uint8_t > page_3_to_6)
bool format_tag_(nfc::NfcTagUid &uid, uint8_t tag_type)
Definition pn532.cpp:420
const LogString * message
Definition component.cpp:35
const char * key
uint8_t tag_type_from_sel_res(uint8_t sel_res)
Tag type (nfc::TAG_TYPE_*) from a type A target's SEL_RES byte.
Definition pn532.h:36
std::array< uint8_t, MIFARE_READ_SIZE > MifareReadData
Definition pn532.h:59
std::array< uint8_t, MIFARE_READ_SIZE > UltralightHeader
Pages 3 to 6, read in one go: the capability container and the start of the NDEF TLV.
Definition pn532.h:61
const void size_t len
Definition hal.h:68
static void uint32_t