diff --git a/Software/src/NFC.cpp b/Software/src/NFC.cpp index f7ed257..6628763 100644 --- a/Software/src/NFC.cpp +++ b/Software/src/NFC.cpp @@ -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"); - 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; + // Print the card's UID in hexadecimal format. + Serial.print("UID: "); + printbytes(uid, uidLength); + return true; } +// 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; diff --git a/Software/src/NFC.h b/Software/src/NFC.h index 899083d..5482807 100644 --- a/Software/src/NFC.h +++ b/Software/src/NFC.h @@ -1,32 +1,60 @@ #ifndef NFC_H #define NFC_H -#include -#include -#include -#include +// 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 // For MQTT functionality +#include // Board-specific pin definitions +#include // For I2C communication +#include // NFC library +#include // 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