cryptnox-sdk-arduino 1.0.0
Arduino library for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
PN532Adapter.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
18
19#include "PN532Adapter.h"
20
21// cppcheck-suppress misra-c2012-12.3 -- C++: member initializer-list commas are not the comma operator
22PN532Adapter::PN532Adapter(CW_Logger& logger, uint8_t ssPin, SPIClass *theSPI)
24 _nfc(new Adafruit_PN532(ssPin, theSPI)) {}
25
26// cppcheck-suppress misra-c2012-12.3 -- C++: member initializer-list commas are not the comma operator
27PN532Adapter::PN532Adapter(CW_Logger& logger, uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t ss)
29 _nfc(new Adafruit_PN532(clk, miso, mosi, ss)) {}
30
31// cppcheck-suppress misra-c2012-12.3 -- C++: member initializer-list commas are not the comma operator
32PN532Adapter::PN532Adapter(CW_Logger& logger, uint8_t irqPin, uint8_t resetPin, TwoWire *wire)
34 _nfc(new Adafruit_PN532(irqPin, resetPin, wire)) {}
35
36// cppcheck-suppress misra-c2012-12.3 -- C++: member initializer-list commas are not the comma operator
37PN532Adapter::PN532Adapter(CW_Logger& logger, uint8_t resetPin, HardwareSerial *uartSerial)
39 _nfc(new Adafruit_PN532(resetPin, uartSerial)) {}
40
42 if (_nfc) {
43 delete _nfc;
44 _nfc = NULL;
45 }
46}
47
49 _nfc->begin();
50 return _nfc->getFirmwareVersion() != 0;
51}
52
53bool PN532Adapter::sendAPDU(const uint8_t* apdu, uint8_t apduLen,
54 uint8_t* response, uint8_t& responseLen) {
55 /* HIGH-05: the uint8_t apduLen already constrains the APDU to the
56 * PN532's ISO-DEP 255-byte limit at the type level; no runtime check
57 * needed. */
58
59 /* Adafruit_PN532::inDataExchange takes a uint8_t* for the response
60 * length (in = capacity, out = actual), matching our uint8_t& on
61 * the CW_NfcTransport contract — pass it through directly. */
62 bool success = _nfc->inDataExchange(const_cast<uint8_t*>(apdu), apduLen,
63 response, &responseLen);
64 if (!success) {
65 _logger->println(F("APDU exchange failed!"));
66 return false;
67 }
68
69#if CW_DEBUG_LOGGING
70 _logger->print(F("APDU response ("));
71 _logger->print(responseLen);
72 _logger->println(F(" bytes):"));
73
74 for (uint8_t i = 0; i < responseLen; i++) {
75 _logger->print(F("0x"));
76 if (response[i] < 16) { _logger->print(F("0")); }
77 _logger->print(response[i], HEX);
78 _logger->print(F(" "));
79 if (((i + 1) % 16 == 0) && ((i + 1) != responseLen)) { _logger->println(); }
80 }
81 _logger->println();
82#endif /* CW_DEBUG_LOGGING */
83
84 return true;
85}
86
87bool PN532Adapter::sendAPDULarge(const uint8_t* apdu, uint8_t apduLen,
88 uint8_t* response, uint16_t& responseLen) {
89 /* Adafruit_PN532::inDataExchange16 is provided by the
90 * Adafruit_PN532_extended_frame.patch. It handles both PN532 normal
91 * frames (1-byte LEN, <=255-byte payload) and PN532 extended frames
92 * (0xFF 0xFF + 16-bit LEN, up to ~436-byte payload). The Cryptnox
93 * card's GET_MANUFACTURER_CERTIFICATE per-page answer exceeds the
94 * normal-frame ceiling on cards whose cert is ~411 bytes, so
95 * delegating to the default uint8_t sendAPDU would lose the data. */
96 bool success = _nfc->inDataExchange16(const_cast<uint8_t*>(apdu), apduLen,
97 response, &responseLen);
98 if (!success) {
99 _logger->println(F("APDU exchange (large) failed!"));
100 return false;
101 }
102
103#if CW_DEBUG_LOGGING
104 _logger->print(F("APDU response ("));
105 _logger->print(responseLen);
106 _logger->println(F(" bytes, large):"));
107
108 for (uint16_t i = 0; i < responseLen; i++) {
109 _logger->print(F("0x"));
110 if (response[i] < 16) { _logger->print(F("0")); }
111 _logger->print(response[i], HEX);
112 _logger->print(F(" "));
113 if (((i + 1) % 16 == 0) && ((i + 1) != responseLen)) { _logger->println(); }
114 }
115 _logger->println();
116#endif /* CW_DEBUG_LOGGING */
117
118 return true;
119}
120
122 return _nfc->inListPassiveTarget();
123}
124
126 _nfc->SAMConfig();
127}
128
130 uint32_t versionData = _nfc->getFirmwareVersion();
131
132 if (versionData == 0) {
133 _logger->println(F("PN532 not found!"));
134 return false;
135 }
136
137 uint8_t ic = (versionData >> 24U) & 0xFFU;
138 uint8_t verMajor = (versionData >> 16U) & 0xFFU;
139 uint8_t verMinor = (versionData >> 8U) & 0xFFU;
140 uint8_t flags = versionData & 0xFFU;
141 bool first = true;
142
143 _logger->println(F("PN532 information"));
144 _logger->print(F(" ├─ Raw firmware: 0x"));
145 _logger->println(versionData, HEX);
146
147 _logger->print(F(" ├─ IC Chip: "));
148 _logger->println((ic == 0x32U) ? F("PN532") : F("Unknown"));
149
150 _logger->print(F(" ├─ Firmware: "));
151 _logger->print(verMajor);
152 _logger->print(F("."));
153 _logger->println(verMinor);
154
155 _logger->print(F(" └─ Features: "));
156 if ((flags & 0x01U) != 0U) { _logger->print(F("MIFARE")); first = false; }
157 if ((flags & 0x02U) != 0U) {
158 if (!first) { _logger->print(F(" + ")); }
159 _logger->print(F("ISO-DEP")); first = false;
160 }
161 if ((flags & 0x04U) != 0U) {
162 if (!first) { _logger->print(F(" + ")); }
163 _logger->print(F("FeliCa")); first = false;
164 }
165 if (first) { _logger->print(F("Unknown")); }
166
167 _logger->print(F(" (0x"));
168 _logger->print(flags, HEX);
169 _logger->println(F(")"));
170
171 _nfc->SAMConfig();
172 return true;
173}
Concrete CW_NfcTransport over Adafruit_PN532 (SPI / I2C / UART).
Abstract interface for serial/debug output.
Definition CW_Logger.h:48
PN532Interface _interface
Wiring variant the active constructor selected.
void resetReader() override
Reset the PN532 into a clean idle state.
bool printFirmwareVersion() override
Pretty-print the PN532 firmware version + supported features.
bool sendAPDU(const uint8_t *apdu, uint8_t apduLen, uint8_t *response, uint8_t &responseLen) override
Exchange one ISO-DEP APDU with the currently selected card.
Adafruit_PN532 * _nfc
Owned Adafruit_PN532 driver instance.
PN532Adapter(CW_Logger &logger, uint8_t ssPin, SPIClass *theSPI=&SPI)
Construct an adapter wired over hardware SPI.
bool inListPassiveTarget() override
Poll for a card in the field.
bool begin() override
Initialise the PN532 and probe its firmware version.
~PN532Adapter() override
Release the heap-allocated Adafruit_PN532 instance.
CW_Logger * _logger
Logger reference (non-owning).
bool sendAPDULarge(const uint8_t *apdu, uint8_t apduLen, uint8_t *response, uint16_t &responseLen) override
APDU exchange that can return more than 255 bytes.
PN532Interface
Physical wiring used to reach the PN532 reader.
@ SPI_HARDWARE
Hardware SPI via an SPIClass instance.
@ SPI_SOFTWARE
Bit-banged SPI on four arbitrary GPIOs.
@ UART
UART via a HardwareSerial instance.
@ I2C
I2C via a TwoWire instance.
#define F(string_literal)
#define HEX