Class Diagrams

This section provides visual diagrams of the NFC Access Control System architecture using both Graphviz and PlantUML.

System Architecture Overview

digraph system_overview { rankdir=TB; node [shape=box, style=filled, fillcolor=lightblue]; main [label="main.cpp"]; acs [label="AccessControlSystem"]; nfc [label="NFCReader"]; pn532 [label="Adafruit_PN532"]; lcd [label="LiquidCrystal"]; eeprom [label="EEPROM"]; main -> acs [label="creates"]; main -> nfc [label="creates"]; acs -> nfc [label="uses"]; acs -> lcd [label="controls"]; acs -> eeprom [label="stores data"]; nfc -> pn532 [label="uses"]; }

System Component Diagram

AccessControlSystem Class

@startuml
scale max 1024 width
skinparam classAttributeIconSize 0

enum SystemState {
    IDLE
    ACCESS_GRANTED
    ACCESS_DENIED
    MENU
    REGISTERING
    DELETING
    LISTING_CARDS
    CLONING_SOURCE
    CLONING_TARGET
}

enum MenuItem {
    REGISTER_CARD
    DELETE_CARD
    LIST_CARDS
    CLONE_CARD
    SETTINGS
    CLEAR_ALL
    EXIT_MENU
    MENU_COUNT
}

class StoredCard {
    + uint8_t uid[MAX_UID_LENGTH]
    + uint8_t uidLength
    + bool active
}

class AccessControlSystem {
    - NFCReader& reader
    - LiquidCrystal lcd
    - SystemState currentState
    - MenuItem currentMenuItem
    - unsigned long lastStateChange
    - uint8_t cloneSourceUID[7]
    - uint8_t cloneSourceLength
    - int totalCardsStored
    - int currentListIndex

    + AccessControlSystem(NFCReader& nfcReader)
    + void begin()
    + void update()
    + void handleButtons()

    - void handleIdleState()
    - void handleMenuState()
    - void handleRegisteringState()
    - void handleDeletingState()
    - void handleListingCardsState()
    - void handleCloningSourceState()
    - void handleCloningTargetState()

    - bool isCardAuthorized(uint8_t* uid, uint8_t uidLength)
    - bool registerCard(uint8_t* uid, uint8_t uidLength)
    - bool deleteCard(uint8_t* uid, uint8_t uidLength)
    - int findCard(uint8_t* uid, uint8_t uidLength)
    - void grantAccess()
    - void denyAccess()
    - void displayMenu()
    - void executeMenuItem()

    - void initializeEEPROM()
    - void loadCardsFromEEPROM()
    - void saveCardToEEPROM(int index)
    - void clearAllCards()
    - int countStoredCards()
}

AccessControlSystem --> SystemState
AccessControlSystem --> MenuItem
AccessControlSystem --> StoredCard
AccessControlSystem ..> NFCReader : uses

@enduml

AccessControlSystem Class Diagram

NFCReader Class

@startuml
scale max 1024 width
skinparam classAttributeIconSize 0

enum NFCCommMode {
    I2C
    SPI
}

enum NFCReadMode {
    POLLING
    IRQ
}

enum NFCCardType {
    UNKNOWN
    MIFARE_CLASSIC_1K
    MIFARE_CLASSIC_4K
    MIFARE_ULTRALIGHT
    NTAG
}

class NFCCardInfo {
    + bool detected
    + uint8_t uid[7]
    + uint8_t uidLength
    + NFCCardType cardType
    + uint32_t cardID
    + bool hasClonedUID
    + uint8_t clonedUID[7]
    + uint8_t clonedUIDLength
    + uint32_t timestamp
}

class NFCReader {
    - Adafruit_PN532* pn532
    - NFCCommMode commMode
    - NFCReadMode readMode
    - int irqPin
    - int resetPin
    - bool initialized
    - NFCCardInfo lastCard
    - uint8_t keyA[6]
    - uint8_t keyB[6]

    + NFCReader(NFCCommMode mode, NFCReadMode readMode)
    + NFCReader(int irq, int reset)
    + ~NFCReader()

    + bool begin()
    + NFCCardInfo readCard()
    + NFCCardInfo getLastCardInfo()
    + bool isCardPresent()

    + bool authenticateBlock(uint8_t blockNumber, uint8_t* key)
    + bool readBlock(uint8_t blockNumber, uint8_t* data)
    + bool writeBlock(uint8_t blockNumber, uint8_t* data)
    + bool formatSector(uint8_t sectorNumber)

    + bool initializeCardForCloning(uint8_t* uid, uint8_t uidLength)
    + bool writeClonedUID(uint8_t* uid, uint8_t uidLength)
    + bool readClonedUID(uint8_t* uid, uint8_t* uidLength)
    + bool hasClonedData()
    + bool clearClonedData()

    + bool waitForCardRemoval(unsigned long timeout)
    + void printCardInfo(NFCCardInfo& card)
    + String getCardTypeString(NFCCardType type)

    - NFCCardType identifyCardType(uint8_t* atqa, uint8_t sak)
    - void setupKeys()
}

NFCReader --> NFCCommMode
NFCReader --> NFCReadMode
NFCReader --> NFCCardType
NFCReader --> NFCCardInfo
NFCReader ..> "Adafruit_PN532" : uses

@enduml

NFCReader Class Diagram

Complete System Relationships

digraph class_diagram { rankdir=BT; node [shape=record, style=filled]; // Classes AccessControlSystem [ fillcolor=lightblue, label="{AccessControlSystem|+ begin()\l+ update()\l+ handleButtons()\l| - handleIdleState()\l- handleMenuState()\l- registerCard()\l - deleteCard()\l- grantAccess()\l- denyAccess()\l}" ]; NFCReader [ fillcolor=lightgreen, label="{NFCReader|+ begin()\l+ readCard()\l+ isCardPresent()\l| + authenticateBlock()\l+ readBlock()\l+ writeBlock()\l + initializeCardForCloning()\l+ writeClonedUID()\l}" ]; NFCCardInfo [ fillcolor=lightyellow, label="{NFCCardInfo|+ uid[7]\l+ uidLength\l+ cardType\l+ hasClonedUID\l+ clonedUID[7]\l}" ]; StoredCard [ fillcolor=lightyellow, label="{StoredCard|+ uid[]\l+ uidLength\l+ active\l}" ]; SystemState [ fillcolor=lightcoral, shape=ellipse, label="SystemState\n(enum)" ]; MenuItem [ fillcolor=lightcoral, shape=ellipse, label="MenuItem\n(enum)" ]; NFCCardType [ fillcolor=lightcoral, shape=ellipse, label="NFCCardType\n(enum)" ]; // Relationships AccessControlSystem -> NFCReader [label="uses", style=dashed]; AccessControlSystem -> SystemState [label="has"]; AccessControlSystem -> MenuItem [label="has"]; AccessControlSystem -> StoredCard [label="manages", style=dashed]; NFCReader -> NFCCardInfo [label="returns"]; NFCReader -> NFCCardType [label="uses"]; NFCCardInfo -> NFCCardType [label="contains"]; }

Complete Class Relationships

State Machine

@startuml
scale max 800 width
skinparam state {
  BackgroundColor LightBlue
  BorderColor Black
}

[*] --> IDLE

IDLE : Waiting for card or button press
ACCESS_GRANTED : Display success message
ACCESS_DENIED : Display error message
MENU : Navigate menu options
REGISTERING : Register new card
DELETING : Delete existing card
LISTING_CARDS : Display stored cards
CLONING_SOURCE : Read source card to clone
CLONING_TARGET : Write to target card

IDLE --> ACCESS_GRANTED : Authorized card detected
IDLE --> ACCESS_DENIED : Unauthorized card detected
IDLE --> MENU : Menu button pressed

ACCESS_GRANTED --> IDLE : Timeout (3s)
ACCESS_DENIED --> IDLE : Timeout (3s)

MENU --> REGISTERING : Select REGISTER_CARD
MENU --> DELETING : Select DELETE_CARD
MENU --> LISTING_CARDS : Select LIST_CARDS
MENU --> CLONING_SOURCE : Select CLONE_CARD
MENU --> IDLE : Select EXIT_MENU

REGISTERING --> IDLE : Card registered or cancelled
DELETING --> IDLE : Card deleted or cancelled
LISTING_CARDS --> IDLE : Done viewing or cancelled

CLONING_SOURCE --> CLONING_TARGET : Source card read
CLONING_SOURCE --> IDLE : Cancelled
CLONING_TARGET --> IDLE : Clone complete or cancelled

@enduml

System State Machine

Card Registration Flow

@startuml
scale max 1024 width
skinparam sequenceMessageAlign center

actor User
participant "AccessControlSystem" as ACS
participant "NFCReader" as Reader
participant "PN532" as Hardware
participant "EEPROM" as Storage

User -> ACS: Press menu button
activate ACS
ACS -> ACS: Enter MENU state

User -> ACS: Navigate to REGISTER_CARD
ACS -> ACS: Enter REGISTERING state
ACS -> ACS: Display "Place card"

User -> Reader: Present NFC card
activate Reader
Reader -> Hardware: Read card UID
activate Hardware
Hardware --> Reader: Return UID
deactivate Hardware
Reader --> ACS: Return NFCCardInfo
deactivate Reader

ACS -> ACS: Check if card exists
alt Card not already registered
    ACS -> Storage: Save card to EEPROM
    activate Storage
    Storage --> ACS: Confirm save
    deactivate Storage
    ACS -> ACS: Display "Card registered"
else Card already exists
    ACS -> ACS: Display "Card exists"
end

ACS -> ACS: Return to IDLE state
deactivate ACS

@enduml

Card Registration Sequence

Card Cloning Flow

@startuml
scale max 1024 width
skinparam sequenceMessageAlign center

actor User
participant "AccessControlSystem" as ACS
participant "NFCReader" as Reader
participant "PN532" as Hardware

User -> ACS: Select CLONE_CARD
activate ACS
ACS -> ACS: Enter CLONING_SOURCE state
ACS -> ACS: Display "Scan source card"

User -> Reader: Present source card
activate Reader
Reader -> Hardware: Read physical UID
activate Hardware
Hardware --> Reader: Return UID
deactivate Hardware
Reader --> ACS: Return source UID
deactivate Reader

ACS -> ACS: Store source UID
ACS -> ACS: Enter CLONING_TARGET state
ACS -> ACS: Display "Scan target card"

User -> Reader: Present target card
activate Reader
Reader -> Hardware: Read target card
activate Hardware
Hardware --> Reader: Target ready
deactivate Hardware

Reader -> Reader: Authenticate sector
Reader -> Hardware: Write cloned UID to custom sector
activate Hardware
Hardware --> Reader: Write successful
deactivate Hardware

Reader --> ACS: Clone complete
deactivate Reader

ACS -> ACS: Display "Clone successful"
ACS -> ACS: Return to IDLE state
deactivate ACS

@enduml

Card Cloning Sequence

MIFARE Memory Layout

digraph memory_layout { rankdir=LR; node [shape=record, style=filled]; subgraph cluster_sector0 { label="Sector 0\n(Manufacturer)"; fillcolor=lightgray; style=filled; block0 [fillcolor=pink, label="Block 0\nManufacturer UID\n(Read-only)"]; block1 [fillcolor=white, label="Block 1\nData"]; block2 [fillcolor=white, label="Block 2\nData"]; block3 [fillcolor=yellow, label="Block 3\nSector Trailer"]; } subgraph cluster_sector1 { label="Sector 1\n(Custom Clone Data)"; fillcolor=lightblue; style=filled; block4 [fillcolor=lightgreen, label="Block 4\nCloned UID (7 bytes)\n+ Magic Bytes"]; block5 [fillcolor=lightgreen, label="Block 5\nTimestamp\n+ Metadata"]; block6 [fillcolor=white, label="Block 6\nReserved"]; block7 [fillcolor=yellow, label="Block 7\nSector Trailer\n(Keys)"]; } subgraph cluster_sector2 { label="Sector 2-15\n(Available)"; fillcolor=lightgray; style=filled; other [label="Other Sectors...", shape=box]; } block0 -> block1 -> block2 -> block3; block3 -> block4; block4 -> block5 -> block6 -> block7; block7 -> other; }

MIFARE Classic Memory Layout for Card Cloning

Installation and Usage

To use these diagram features in your documentation:

Prerequisites:

  1. For Graphviz: Install Graphviz on your system

  2. For PlantUML: Install Java and download PlantUML jar

    Alternatively, you can use the PlantUML server by modifying conf.py:

    plantuml = 'http://www.plantuml.com/plantuml'
    
  3. Install Python dependencies:

    pip install -r requirements.txt
    

Building the documentation:

cd docs
make html

Graphviz Syntax Example:

.. graphviz::
   :caption: My Diagram

   digraph MyGraph {
       A -> B;
       B -> C;
   }

PlantUML Syntax Example:

.. uml::
   :caption: My UML Diagram

   @startuml
   class MyClass {
       + publicMethod()
       - privateMethod()
   }
   @enduml

See Also