optimized NFC code a bit

This commit is contained in:
André Fiedler 2025-02-15 18:43:06 +01:00
parent 4af6ac8975
commit b757e557ed
2 changed files with 104 additions and 71 deletions

View File

@ -7,106 +7,108 @@ NFC::NFC(int pin_sda, int pin_scl)
{
Serial.println("NFC: Start");
// Create a new PN532 instance with the defined IRQ and RESET pins.
rfid = new Adafruit_PN532(PN532_IRQ, PN532_RESET);
rfid->begin(); // Initialize the PN532 chip
rfid->begin();
// Retrieve the firmware version from the PN532.
uint32_t versiondata = rfid->getFirmwareVersion();
if (!versiondata)
{
Serial.print("Didn't find PN53x board");
while (1)
// If no version data is returned, the PN532 was not detected.
Serial.println("Didn't find PN53x board");
while (true)
{
yield(); // halt
yield(); // Halt execution indefinitely if the board is missing.
}
}
// Got ok data, print it out!
Serial.print("NFC: Found chip PN5");
Serial.println((versiondata >> 24) & 0xFF, HEX);
Serial.print("NFC: Firmware ver. ");
Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.');
Serial.println((versiondata >> 8) & 0xFF, DEC);
// Print chip and firmware details using formatted output.
Serial.printf("NFC: Found chip PN5%02X\n", (versiondata >> 24) & 0xFF);
Serial.printf("NFC: Firmware ver. %d.%d\n", (versiondata >> 16) & 0xFF, (versiondata >> 8) & 0xFF);
}
String NFC::getUID()
// Convert the card's UID (stored in a byte array) into a hexadecimal String.
String NFC::getUID() const
{
String uidStr;
for (int i = 0; i < uidLength; i++)
uidStr.reserve(uidLength * 2); // Reserve memory to optimize String allocation.
for (uint8_t i = 0; i < uidLength; i++)
{
// Ensure each byte is represented by two hex digits.
if (uid[i] < 0x10)
{
uidStr += "0";
}
uidStr += String(uid[i], HEX);
uidStr += String(uid[i], HEX); // Convert byte to hex string.
}
return uidStr;
}
bool NFC::hasCardSelected()
// Returns true if a card has been successfully selected/connected.
bool NFC::hasCardSelected() const
{
return cardSelected;
}
// This function is a placeholder for a possible PN532 self-test.
// Uncomment and implement if your PN532 supports self-testing.
bool NFC::testNFC()
{
// return rfid->PCD_PerformSelfTest();
return true;
}
// Check for the presence of an NFC card within a 1000ms timeout.
bool NFC::checkforCard()
{
// Attempt to read a card (timeout in milliseconds, adjust as needed)
// Attempt to read the card's UID (ISO14443A standard) within 1000 ms.
if (!rfid->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000))
{
Serial.println("No card found within the timeout period");
// No card found within the timeout period
return false;
}
// At this point, a card has been detected and its UID is in 'uid' with length 'uidLength'
// If you expect a DESFire card, you might assume its UID is 7 bytes.
// (Alternatively, if you extend the library to capture the SAK, you could check that here.)
// Validate the card's UID length: 7 for DESFire, 4 for MIFARE Classic/ISO14443A.
if (uidLength != 7 && uidLength != 4)
{
Serial.println("No card detected");
return false;
}
// Report the type of card detected.
if (uidLength == 7)
{
Serial.println("DESFire card detected");
Serial.print("UID: ");
printbytes(uid, uidLength);
return true;
}
// If we're getting 4 bytes, we might be scanning a MIFARE Classic or another ISO14443A card.
if (uidLength == 4)
else
{
Serial.println("MIFARE Classic or another ISO14443A card detected");
}
// Print the card's UID in hexadecimal format.
Serial.print("UID: ");
printbytes(uid, uidLength);
return true;
}
// The card detected does not match the expected DESFireor MIFARE Classic UID length
Serial.println("No card detected");
return false;
}
// Connect to the detected card using RATS (Request for ATS) and PPS (Protocol and Parameter Selection).
bool NFC::connecttoCard()
{
// --- RATS (Request for ATS) ---
// RATS command format: [0xE0, param]
// The parameter byte encodes the Frame Size and other options.
// Here we use 0x80 as an example parameter (adjust as needed for your card).
uint8_t ratsCmd[] = {0xE0, 0x80};
uint8_t atsResponse[16]; // Buffer to hold the ATS response
uint8_t atsResponseLength = sizeof(atsResponse);
// Send the RATS command via inDataExchange.
// inDataExchange() returns a negative value on error.
int result = rfid->inDataExchange(ratsCmd, sizeof(ratsCmd), atsResponse, &atsResponseLength);
if (result < 0)
// --- RATS (Request for ATS) ---
// RATS command structure: [0xE0, parameter]
// The parameter byte encodes the Frame Size and other options.
// 0xE0 identifies the command; 0x80 is an example parameter for frame size.
uint8_t ratsCmd[] = {0xE0, 0x80};
uint8_t atsResponse[16] = {0}; // Buffer to store ATS response.
uint8_t atsResponseLength = sizeof(atsResponse);
// Send the RATS command and check for errors.
if (rfid->inDataExchange(ratsCmd, sizeof(ratsCmd), atsResponse, &atsResponseLength) < 0)
{
Serial.println(F("Failed ATS"));
// PN532 does not offer a dedicated halt command,
@ -118,33 +120,34 @@ bool NFC::connecttoCard()
// The ATS provides card-specific information, such as supported protocols and frame sizes.
// --- PPS (Protocol and Parameter Selection) ---
// PPS command format (example): [0xD0, PPS0, PPS1]
// In this example, PPS0 is set to 0x11 and PPS1 to 0x00.
// Adjust the values according to your protocol requirements.
// PPS command example: [0xD0, PPS0, PPS1]
// 0xD0 indicates the PPS command; 0x11 and 0x00 are example parameters.
uint8_t ppsCmd[] = {0xD0, 0x11, 0x00};
uint8_t ppsResponse[16];
uint8_t ppsResponse[16] = {0}; // Buffer to store PPS response.
uint8_t ppsResponseLength = sizeof(ppsResponse);
result = rfid->inDataExchange(ppsCmd, sizeof(ppsCmd), ppsResponse, &ppsResponseLength);
if (result < 0)
// Send the PPS command and check for errors.
if (rfid->inDataExchange(ppsCmd, sizeof(ppsCmd), ppsResponse, &ppsResponseLength) < 0)
{
Serial.println(F("Failed PPS"));
return false;
}
// If both exchanges were successful, mark the card as selected.
// If both RATS and PPS commands succeed, mark the card as selected.
cardSelected = true;
// Save any card-specific data if needed here.
// Note: Unlike MFRC522, Adafruit_PN532 does not store the UID in a public member.
// We save the UID when we detect the card.
pcb = 0x0A;
pcb = 0x0A; // Example PCB (Protocol Control Byte) value.
return true;
}
// Disconnect from the card by issuing an ISO14443A HALT command.
bool NFC::disconnectCard()
{
// ISO14443A HALT command: 0x50, 0x00, followed by the two-byte CRC.
// HALT command for ISO14443A cards in auto-CRC mode: [0x50, 0x00]
// You can either compute the CRC or, if your setup automatically appends it,
// simply send the command without CRC bytes.
// Here, we assume you have to include the CRC.
@ -154,9 +157,10 @@ bool NFC::disconnectCard()
// Option 1: If your PN532 is configured to append the CRC automatically,
// you can send just the two-byte command.
uint8_t haltCmd[] = {0x50, 0x00};
uint8_t response[8];
uint8_t response[8] = {0}; // Buffer to hold any response.
uint8_t responseLength = sizeof(response);
// Send the HALT command. A negative return value indicates failure.
int status = rfid->inDataExchange(haltCmd, sizeof(haltCmd), response, &responseLength);
if (status < 0)
{
@ -178,6 +182,7 @@ bool NFC::disconnectCard()
return true;
}
// A placeholder function to test card functionalities; extend as needed.
bool NFC::testCard()
{
return true;

View File

@ -1,32 +1,60 @@
#ifndef NFC_H
#define NFC_H
#include <PubSubClient.h>
#include <Pins.h>
#include <Wire.h>
#include <Adafruit_PN532.h>
// NOTE: The warning about "PN532_I2C_ADDRESS redefined" comes from multiple definitions
// (e.g. one from your build configuration or command-line and one in the library).
// You can safely ignore this warning, or if needed, undefine the macro before including
// the Adafruit PN532 library, for example:
//
// #ifdef PN532_I2C_ADDRESS
// #undef PN532_I2C_ADDRESS
// #endif
#define APDU_BUFFER_SIZE 256
#include <PubSubClient.h> // For MQTT functionality
#include <Pins.h> // Board-specific pin definitions
#include <Wire.h> // For I2C communication
#include <Adafruit_PN532.h> // NFC library
#include <Arduino.h> // For String and other Arduino types
#define APDU_BUFFER_SIZE 256 // Buffer size for APDU communication
// The NFC class encapsulates the functionality to interact with a PN532-based NFC reader.
class NFC
{
private:
uint8_t uid[7]; // Buffer to hold the card's UID (PN532 supports up to 7 bytes for ISO14443A)
uint8_t uidLength; // Length of the UID (will be set by readPassiveTargetID)
byte pcb = 0x0A;
byte cid = 0x00;
bool cardSelected = false;
uint8_t uid[7]; // Buffer to hold the card's UID (supports up to 7 bytes for ISO14443A)
uint8_t uidLength; // Actual length of the UID (set by readPassiveTargetID)
uint8_t pcb = 0x0A; // Protocol Control Byte (example value)
uint8_t cid = 0x00; // Card Identifier (example value)
bool cardSelected = false; // Flag indicating if a card is currently selected/connected
public:
// Pointer to the PN532 instance for interfacing with the NFC chip.
Adafruit_PN532 *rfid;
NFC(int pin_sda, int pin_scl);
// Constructor: Initializes the NFC reader using the provided SDA and SCL pins.
explicit NFC(int pin_sda, int pin_scl);
// Test the NFC hardware (e.g., via a self-test, if supported).
bool testNFC();
// Attempt to detect an NFC card within a specified timeout period.
bool checkforCard();
// Connect to a detected card by performing RATS and PPS exchanges.
bool connecttoCard();
// Disconnect from the currently connected card using the HALT command.
bool disconnectCard();
// Placeholder for card-specific tests; extend as needed.
bool testCard();
bool hasCardSelected();
String getUID();
// Returns true if a card has been successfully selected/connected.
bool hasCardSelected() const;
// Returns the UID of the detected card as a hexadecimal String.
String getUID() const;
};
#endif
#endif // NFC_H