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"); 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 = 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(); uint32_t versiondata = rfid->getFirmwareVersion();
if (!versiondata) if (!versiondata)
{ {
Serial.print("Didn't find PN53x board"); // If no version data is returned, the PN532 was not detected.
while (1) 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! // Print chip and firmware details using formatted output.
Serial.print("NFC: Found chip PN5"); Serial.printf("NFC: Found chip PN5%02X\n", (versiondata >> 24) & 0xFF);
Serial.println((versiondata >> 24) & 0xFF, HEX); Serial.printf("NFC: Firmware ver. %d.%d\n", (versiondata >> 16) & 0xFF, (versiondata >> 8) & 0xFF);
Serial.print("NFC: Firmware ver. ");
Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.');
Serial.println((versiondata >> 8) & 0xFF, DEC);
} }
String NFC::getUID() // Convert the card's UID (stored in a byte array) into a hexadecimal String.
String NFC::getUID() const
{ {
String uidStr; 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) if (uid[i] < 0x10)
{ {
uidStr += "0"; uidStr += "0";
} }
uidStr += String(uid[i], HEX); uidStr += String(uid[i], HEX); // Convert byte to hex string.
} }
return uidStr; return uidStr;
} }
bool NFC::hasCardSelected() // Returns true if a card has been successfully selected/connected.
bool NFC::hasCardSelected() const
{ {
return cardSelected; 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() bool NFC::testNFC()
{ {
// return rfid->PCD_PerformSelfTest(); // return rfid->PCD_PerformSelfTest();
return true;
} }
// Check for the presence of an NFC card within a 1000ms timeout.
bool NFC::checkforCard() 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)) if (!rfid->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000))
{ {
Serial.println("No card found within the timeout period"); Serial.println("No card found within the timeout period");
// No card found within the timeout period
return false; return false;
} }
// At this point, a card has been detected and its UID is in 'uid' with length 'uidLength' // Validate the card's UID length: 7 for DESFire, 4 for MIFARE Classic/ISO14443A.
// If you expect a DESFire card, you might assume its UID is 7 bytes. if (uidLength != 7 && uidLength != 4)
// (Alternatively, if you extend the library to capture the SAK, you could check that here.) {
Serial.println("No card detected");
return false;
}
// Report the type of card detected.
if (uidLength == 7) if (uidLength == 7)
{ {
Serial.println("DESFire card detected"); Serial.println("DESFire card detected");
Serial.print("UID: ");
printbytes(uid, uidLength);
return true;
} }
else
// If we're getting 4 bytes, we might be scanning a MIFARE Classic or another ISO14443A card.
if (uidLength == 4)
{ {
Serial.println("MIFARE Classic or another ISO14443A card detected"); Serial.println("MIFARE Classic or another ISO14443A card detected");
Serial.print("UID: ");
printbytes(uid, uidLength);
return true;
} }
// The card detected does not match the expected DESFireor MIFARE Classic UID length // Print the card's UID in hexadecimal format.
Serial.println("No card detected"); Serial.print("UID: ");
printbytes(uid, uidLength);
return false; return true;
} }
// Connect to the detected card using RATS (Request for ATS) and PPS (Protocol and Parameter Selection).
bool NFC::connecttoCard() 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. // Send the RATS command via inDataExchange.
// inDataExchange() returns a negative value on error. // 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")); Serial.println(F("Failed ATS"));
// PN532 does not offer a dedicated halt command, // 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. // The ATS provides card-specific information, such as supported protocols and frame sizes.
// --- PPS (Protocol and Parameter Selection) --- // --- PPS (Protocol and Parameter Selection) ---
// PPS command format (example): [0xD0, PPS0, PPS1] // PPS command example: [0xD0, PPS0, PPS1]
// In this example, PPS0 is set to 0x11 and PPS1 to 0x00. // 0xD0 indicates the PPS command; 0x11 and 0x00 are example parameters.
// Adjust the values according to your protocol requirements.
uint8_t ppsCmd[] = {0xD0, 0x11, 0x00}; 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); uint8_t ppsResponseLength = sizeof(ppsResponse);
result = rfid->inDataExchange(ppsCmd, sizeof(ppsCmd), ppsResponse, &ppsResponseLength); // Send the PPS command and check for errors.
if (result < 0) if (rfid->inDataExchange(ppsCmd, sizeof(ppsCmd), ppsResponse, &ppsResponseLength) < 0)
{ {
Serial.println(F("Failed PPS")); Serial.println(F("Failed PPS"));
return false; 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; cardSelected = true;
// Save any card-specific data if needed here. // Save any card-specific data if needed here.
// Note: Unlike MFRC522, Adafruit_PN532 does not store the UID in a public member. // Note: Unlike MFRC522, Adafruit_PN532 does not store the UID in a public member.
// We save the UID when we detect the card. // We save the UID when we detect the card.
pcb = 0x0A; pcb = 0x0A; // Example PCB (Protocol Control Byte) value.
return true; return true;
} }
// Disconnect from the card by issuing an ISO14443A HALT command.
bool NFC::disconnectCard() 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, // You can either compute the CRC or, if your setup automatically appends it,
// simply send the command without CRC bytes. // simply send the command without CRC bytes.
// Here, we assume you have to include the CRC. // 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, // Option 1: If your PN532 is configured to append the CRC automatically,
// you can send just the two-byte command. // you can send just the two-byte command.
uint8_t haltCmd[] = {0x50, 0x00}; uint8_t haltCmd[] = {0x50, 0x00};
uint8_t response[8]; uint8_t response[8] = {0}; // Buffer to hold any response.
uint8_t responseLength = sizeof(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); int status = rfid->inDataExchange(haltCmd, sizeof(haltCmd), response, &responseLength);
if (status < 0) if (status < 0)
{ {
@ -178,6 +182,7 @@ bool NFC::disconnectCard()
return true; return true;
} }
// A placeholder function to test card functionalities; extend as needed.
bool NFC::testCard() bool NFC::testCard()
{ {
return true; return true;

View File

@ -1,32 +1,60 @@
#ifndef NFC_H #ifndef NFC_H
#define NFC_H #define NFC_H
#include <PubSubClient.h> // NOTE: The warning about "PN532_I2C_ADDRESS redefined" comes from multiple definitions
#include <Pins.h> // (e.g. one from your build configuration or command-line and one in the library).
#include <Wire.h> // You can safely ignore this warning, or if needed, undefine the macro before including
#include <Adafruit_PN532.h> // 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 class NFC
{ {
private: private:
uint8_t uid[7]; // Buffer to hold the card's UID (PN532 supports up to 7 bytes for ISO14443A) uint8_t uid[7]; // Buffer to hold the card's UID (supports up to 7 bytes for ISO14443A)
uint8_t uidLength; // Length of the UID (will be set by readPassiveTargetID) uint8_t uidLength; // Actual length of the UID (set by readPassiveTargetID)
byte pcb = 0x0A; uint8_t pcb = 0x0A; // Protocol Control Byte (example value)
byte cid = 0x00; uint8_t cid = 0x00; // Card Identifier (example value)
bool cardSelected = false; bool cardSelected = false; // Flag indicating if a card is currently selected/connected
public: public:
// Pointer to the PN532 instance for interfacing with the NFC chip.
Adafruit_PN532 *rfid; 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(); bool testNFC();
// Attempt to detect an NFC card within a specified timeout period.
bool checkforCard(); bool checkforCard();
// Connect to a detected card by performing RATS and PPS exchanges.
bool connecttoCard(); bool connecttoCard();
// Disconnect from the currently connected card using the HALT command.
bool disconnectCard(); bool disconnectCard();
// Placeholder for card-specific tests; extend as needed.
bool testCard(); 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