Skip to content

ADR-006: PN532 Dev Hardware Setup

Status: Accepted Date: 2026-02-26

Context

The production hardware uses a CONLAN M1200 NFC terminal (~100+ EUR) with Wiegand output, a 5V→3.3V level shifter, and a 12V power supply. Developers need a cheaper, simpler setup to work on the firmware without this full hardware stack.

We need to support a second NFC reader option for development while keeping the production Wiegand reader unchanged.

Options Considered

A) RC522 (MFRC522) Module

  • Pro: Very cheap (~2-4 EUR)
  • Pro: Widely available, mature library (miguelbalboa/MFRC522)
  • Con: SPI only — uses more GPIO pins
  • Con: ISO14443A only, limited DESFire support
  • Con: Cannot read all card types we might want to test

B) PN532 Module

  • Pro: Supports ISO14443A/B, FeliCa, NFC — broadest protocol coverage
  • Pro: I2C mode requires only 2 data pins (SDA, SCL)
  • Pro: Can read MIFARE DESFire cards (for testing with production cards)
  • Pro: Good library support (elechouse/PN532)
  • Con: Slightly more expensive (~6-8 EUR)

Decision

PN532 in I2C mode (Option B).

The PN532 costs only a few EUR more than the RC522 but supports more card types, including DESFire. This means developers can test with both cheap NTAG215 tags and actual production DESFire cards. I2C mode minimizes wiring (2 data pins + power).

Implementation

Abstract CardReader Interface

Both readers implement the same CardReader interface:

class CardReader {
public:
    virtual bool begin() = 0;
    virtual bool poll(CardEvent& event) = 0;
};

The firmware selects the reader at compile time via build flags: - esp32dev environment: -DUSE_WIEGANDWiegandReader - esp32dev-pn532 environment: -DUSE_PN532PN532Reader

No Protocol Changes

NTAG215 tags have 7-byte UIDs. The allow-list protocol already supports UIDs of 4, 7, or 10 bytes (AllowEntry.uid[10] with uid_length field), so no changes to the binary protocol or backend are needed.

DESFire Compatibility

The PN532 reads DESFire EV2/EV3 card UIDs out of the box via ISO14443A anti-collision — no additional code needed. Developers can test with both cheap NTAG215 tags and production DESFire cards.

Full DESFire challenge-response authentication (AES-128) is also possible in software via the PN532's APDU passthrough mode (inDataExchange). This is not implemented yet but could be added to match the production CONLAN M1200's anti-cloning behavior, without any hardware changes.

Consequences

  • Developers can build and test firmware for ~18 EUR (ESP32 + PN532 + NTAG215 tags)
  • Production DESFire cards are also readable (UID-only, no auth)
  • The CardReader abstraction keeps the rest of the firmware reader-agnostic
  • Native tests cover Wiegand decoding logic without hardware
  • The production build (esp32dev) is unaffected
  • Future: DESFire auth can be added in software if needed