API Reference
This section provides detailed documentation of the classes, methods, and configuration options available in the NFC Access Control System.
Note
For practical examples of using these APIs, see Examples which covers the basic read and write operations (Course Tasks 1 & 2).
Core Classes
AccessControlSystem
The main class that manages the access control logic, menu system, and hardware interface.
Header: include/AccessControlSystem.h
Public Methods:
-
class AccessControlSystem
-
AccessControlSystem()
Constructor. Initializes the access control system with default settings.
-
void begin()
Initializes all hardware components (LCD, NFC reader, buttons, relay). Must be called in
setup()before using the system.
-
void update()
Main update loop. Should be called repeatedly in
loop(). Handles state machine updates, button input, and card reading.
-
bool isCardAuthorized(uint8_t *uid, uint8_t uidLength)
Checks if a card UID is in the authorized list.
- Parameters:
uid – Pointer to UID bytes array
uidLength – Length of UID (4 or 7 bytes)
- Returns:
trueif authorized,falseotherwise
-
bool registerCard(uint8_t *uid, uint8_t uidLength)
Adds a card to the authorized list in EEPROM.
- Parameters:
uid – Pointer to UID bytes array
uidLength – Length of UID (4 or 7 bytes)
- Returns:
trueif successful,falseif card exists or storage full
-
bool deleteCard(uint8_t *uid, uint8_t uidLength)
Removes a card from the authorized list.
- Parameters:
uid – Pointer to UID bytes array
uidLength – Length of UID (4 or 7 bytes)
- Returns:
trueif successful,falseif card not found
-
int getStoredCardCount()
Returns the number of cards currently stored.
- Returns:
Number of authorized cards (0-40)
-
void grantAccess()
Activates the relay for the configured duration. Called when an authorized card is detected.
-
void denyAccess()
Displays access denied message. Called when an unauthorized card is detected.
-
AccessControlSystem()
NFCReader
Wrapper class for the PN532 NFC module, providing simplified card reading and cloning functionality.
Header: include/NFCReader.h
Public Methods:
-
class NFCReader
-
NFCReader(NFCCommMode commMode = NFCCommMode::SPI, NFCReadMode readMode = NFCReadMode::IRQ)
Constructor with communication and reading mode selection.
- Parameters:
commMode – Communication mode (I2C or SPI)
readMode – Reading mode (POLLING or IRQ)
-
bool begin()
Initializes the PN532 module.
- Returns:
trueif initialization successful,falseotherwise
-
NFCCardInfo readCard()
Reads a card and retrieves its complete information. Automatically uses cloned UID if present, otherwise physical UID.
- Returns:
NFCCardInfostructure containing all card data
-
bool isCardPresent()
Checks if a card is currently in the reader field.
- Returns:
trueif card detected
-
void resetCardState()
Resets the card detection state to allow re-reading the same card. Call this after processing a card to enable detection again.
-
NFCWriteResult writeString(const String &text, uint8_t startAddress = 0, bool verify = true)
Writes a string to the card, auto-detecting card type.
- Parameters:
text – String to write
startAddress – Starting address (block or page depending on card type)
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCWriteResult writeData(const uint8_t *data, uint8_t dataLength, uint8_t startAddress = 0, bool verify = true)
Writes binary data to the card, auto-detecting card type.
- Parameters:
data – Pointer to data buffer
dataLength – Number of bytes to write
startAddress – Starting address
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCWriteResult writeNTAG(uint8_t page, const uint8_t *data, uint8_t dataLength, bool verify = true)
Writes data to an NTAG or Ultralight card (page-based).
- Parameters:
page – Page number (use 4 or higher for user data)
data – Pointer to data buffer (4 bytes per page)
dataLength – Number of bytes to write
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCWriteResult writeNTAGString(uint8_t startPage, const String &text, bool verify = true)
Writes a string across multiple NTAG/Ultralight pages.
- Parameters:
startPage – Starting page number
text – String to write
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCWriteResult writeMifareClassic(uint8_t block, const uint8_t *data, uint8_t dataLength, const uint8_t *key = DEFAULT_KEY, bool useKeyB = false, bool verify = true)
Writes data to a Mifare Classic card (block-based, requires authentication).
- Parameters:
block – Block number (use 4 or higher for user data)
data – Pointer to data buffer (16 bytes per block)
dataLength – Number of bytes to write
key – Authentication key (6 bytes, default FF FF FF FF FF FF)
useKeyB – Use Key B instead of Key A
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCWriteResult writeMifareClassicString(uint8_t startBlock, const String &text, const uint8_t *key = DEFAULT_KEY, bool useKeyB = false, bool verify = true)
Writes a string across multiple Mifare Classic blocks.
- Parameters:
startBlock – Starting block number
text – String to write
key – Authentication key
useKeyB – Use Key B instead of Key A
verify – Whether to verify the write operation
- Returns:
NFCWriteResultstructure with success status
-
NFCReader(NFCCommMode commMode = NFCCommMode::SPI, NFCReadMode readMode = NFCReadMode::IRQ)
Enumerations
NFCCommMode
PN532 communication modes.
enum class NFCCommMode {
I2C, // I2C communication (simpler wiring, slower)
SPI // SPI communication (more wires, faster - recommended)
};
NFCReadMode
Card reading modes.
enum class NFCReadMode {
POLLING, // Continuous polling (~100ms interval)
IRQ // Interrupt-driven (faster, recommended)
};
NFCCardType
Supported NFC card types.
enum class NFCCardType {
UNKNOWN, // Unknown or unsupported card type
MIFARE_CLASSIC_1K, // Mifare Classic 1K (4-byte UID, 1KB)
MIFARE_CLASSIC_4K, // Mifare Classic 4K (4-byte UID, 4KB)
MIFARE_ULTRALIGHT, // Mifare Ultralight (7-byte UID, 64 bytes)
NTAG // NTAG213/215/216 (7-byte UID, varies)
};
Data Structures
NFCCardInfo
Complete information about a detected NFC card.
struct NFCCardInfo {
bool detected; // True if card was detected
uint8_t uid[7]; // Physical UID from manufacturer block
uint8_t uidLength; // UID length (4 or 7 bytes)
NFCCardType cardType; // Type of card detected
uint32_t cardID; // Numeric ID for 4-byte UIDs
// Card cloning features (advanced)
bool hasClonedUID; // True if card has cloned UID in custom sector
uint8_t clonedUID[7]; // Cloned UID data
uint8_t clonedUIDLength; // Length of cloned UID
// Helper methods
const uint8_t* getEffectiveUID() const; // Returns cloned or physical UID
uint8_t getEffectiveUIDLength() const; // Returns effective UID length
};
Usage Example:
NFCCardInfo card = nfcReader.readCard();
if (card.detected) {
// Use effective UID (cloned if available, otherwise physical)
const uint8_t* uid = card.getEffectiveUID();
uint8_t len = card.getEffectiveUIDLength();
// Or access specific UIDs
if (card.hasClonedUID) {
// This card has been cloned
Serial.print("Cloned UID: ");
for (int i = 0; i < card.clonedUIDLength; i++) {
Serial.print(card.clonedUID[i], HEX);
}
}
}
NFCWriteResult
Result of a write operation to an NFC card.
struct NFCWriteResult {
bool success; // True if write was successful
bool verified; // True if write was verified
String errorMessage; // Description of error (if success is false)
};
Usage Example:
NFCWriteResult result = nfcReader.writeString("Hello NFC!", 4, true);
if (result.success) {
Serial.println("Write successful!");
if (result.verified) {
Serial.println("Data verified!");
}
} else {
Serial.print("Write failed: ");
Serial.println(result.errorMessage);
}
SystemState
States of the access control system state machine.
enum class SystemState {
IDLE, // Ready to scan card
ACCESS_GRANTED, // Card authorized, relay activated
ACCESS_DENIED, // Card not authorized
MENU, // In menu system
REGISTERING, // Registering new card
DELETING, // Deleting card
LISTING_CARDS, // Displaying stored cards
CLONING_SOURCE, // Waiting for source card to clone
CLONING_TARGET // Waiting for target card to write
};
State Machine Diagram
System State Machine
Configuration Constants
Hardware Pin Definitions
Located in include/Config.h:
// PN532 NFC Module pins (SPI mode)
#define PN532_SCK (13)
#define PN532_MISO (12)
#define PN532_MOSI (11)
#define PN532_SS (10)
#define PN532_IRQ (2)
#define PN532_RST (3)
// LCD Display pins (4-bit parallel)
#define LCD_RS (4)
#define LCD_EN (5)
#define LCD_D4 (6)
#define LCD_D5 (7)
#define LCD_D6 (8)
#define LCD_D7 (9)
// Button pins
#define BTN_UP (A0)
#define BTN_DOWN (A1)
#define BTN_SELECT (A2)
#define BTN_BACK (A3)
// Relay pin
#define RELAY_PIN (A4)
System Parameters
// Maximum number of authorized cards
#define MAX_CARDS 40
// Relay activation duration (milliseconds)
#define ACCESS_GRANT_DURATION 3000
// Button debounce delay (milliseconds)
#define DEBOUNCE_DELAY 50
// LCD dimensions
#define LCD_COLS 16
#define LCD_ROWS 2
// UID length constants
#define UID_LENGTH_4BYTE 4
#define UID_LENGTH_7BYTE 7
#define MAX_UID_LENGTH 7
EEPROM Memory Map
// EEPROM addresses
#define EEPROM_MAGIC_ADDR 0 // Magic number (2 bytes)
#define EEPROM_COUNT_ADDR 2 // Card count (1 byte)
#define EEPROM_CARDS_ADDR 3 // Start of card data
// Card entry structure (8 bytes per card)
// Byte 0: UID length (4 or 7)
// Bytes 1-7: UID data (padded with 0xFF)
Custom Sector Configuration
For card cloning functionality:
// Custom sector for cloned UID storage
#define CUSTOM_SECTOR 1
#define CUSTOM_BLOCK_UID 4 // Block for UID storage
#define CUSTOM_BLOCK_META 5 // Block for metadata
#define CUSTOM_BLOCK_SPARE 6 // Spare block
// Default Mifare Classic keys
uint8_t defaultKeyA[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t defaultKeyB[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Example Usage
Basic Setup
#include <AccessControlSystem.h>
AccessControlSystem accessControl;
void setup() {
Serial.begin(115200);
accessControl.begin();
}
void loop() {
accessControl.update();
}
Custom Card Handling
#include <NFCReader.h>
NFCReader reader(NFCCommMode::SPI, NFCReadMode::IRQ);
uint8_t uid[7];
uint8_t uidLength;
void setup() {
Serial.begin(115200);
if (!reader.begin()) {
Serial.println("NFC reader initialization failed!");
while(1);
}
}
void loop() {
if (reader.readCard(uid, &uidLength)) {
Serial.print("Card UID: ");
for (uint8_t i = 0; i < uidLength; i++) {
Serial.print(uid[i], HEX);
Serial.print(" ");
}
Serial.println();
}
delay(100);
}
Manual Card Registration
void registerNewCard() {
uint8_t uid[7];
uint8_t uidLength;
Serial.println("Present card to register...");
if (reader.readCard(uid, &uidLength)) {
if (accessControl.registerCard(uid, uidLength)) {
Serial.println("Card registered successfully!");
} else {
Serial.println("Failed to register card");
}
}
}
Return Values
Most methods return boolean values:
true: Operation successfulfalse: Operation failed or card not found
Check serial output for detailed error messages during development.
Memory Considerations
EEPROM Usage
Magic number: 2 bytes
Card count: 1 byte
Card data: 8 bytes per card × 40 cards = 320 bytes
Total: 323 bytes of 1024 bytes available
RAM Usage
Approximate RAM usage:
LiquidCrystal library: ~100 bytes
Adafruit_PN532 library: ~200 bytes
System variables: ~150 bytes
Stack and buffers: ~200 bytes
Total: ~650 bytes of 2048 bytes available
Thread Safety
The system is single-threaded and designed for Arduino’s cooperative multitasking model. All operations are non-blocking when using IRQ mode.
Debugging
Enable serial debugging in Config.h:
#define DEBUG_MODE 1
This provides verbose logging of all operations.