# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

ESP32-C3 SuperMini firmware for the "Minecraft Orb" — an interactive treasure hunt device with RFID card reading, OLED display, LED effects, buzzer audio, and touch input. Built with Arduino framework via PlatformIO. Quest clues are stored directly on MIFARE Classic 1K cards and read/displayed by the device.

## Build & Upload Commands

```bash
pio run                     # Build firmware
pio run --target upload     # Upload to board via USB-C
pio device monitor          # Serial monitor (115200 baud)
pio run --target upload && pio device monitor  # Upload + monitor
```

## Hardware Configuration

- **MCU**: ESP32-C3 SuperMini (RISC-V), USB CDC serial on boot
- **Display**: SSD1306 128x64 OLED via I2C (GPIO2=SDA, GPIO3=SCL)
- **RFID**: RC522 via SPI (GPIO7=SCK, GPIO8=MOSI, GPIO9=MISO, GPIO6=CS, GPIO10=RST)
- **LED**: White LED on GPIO4 (PWM breathing effect)
- **Buzzer**: Piezo on GPIO0
- **Touch**: TTP223 sensor on GPIO5 (must be GPIO0-5 for deep sleep wake)

Pin definitions are in `include/pins.h`. Full wiring diagram in `pinout.svg`.

## Architecture

### Source Files

- **`src/main.cpp`** (~1500 lines) — Main firmware: hardware init, event loop, display rendering, serial command handler, RFID event processing, Morse code, touch input puzzle, authentication state machine, LED breathing
- **`src/cards.cpp`** — Card database: NVS storage, MIFARE card read/write operations (sectors 1-4, blocks 4-18)
- **`include/cards.h`** — Card struct and database interface
- **`include/config.h`** — WiFi credentials, NVS namespace config, power management timeouts
- **`include/pins.h`** — GPIO pin assignments

### Core Event Loop

`setup()` initializes all hardware then enters auth mode. `loop()` calls `checkSerial()`, `checkRFID()`, `checkTouch()`, `breatheLED()`, and `checkPowerSave()` each cycle. State is tracked via globals: `authMode`, `programmingMode`, `waitingForCard`, `authCount`.

### Operating Modes

1. **Auth Mode** (startup default): Requires 5 players to scan AUTH cards in sequence (IDs 1-5 in order)
2. **Programming Mode**: Entered via `PROG` serial command. Write/read quest data to MIFARE cards
3. **Normal Mode**: Scan cards to display clues; handles special command cards (MORSE, INPUT, AUTH)

### MIFARE Card Data Layout

Quest data is written directly to MIFARE Classic 1K cards (not ESP32 flash):
- Sector 1 (blocks 4-5): Card name (32 bytes)
- Sectors 2-4 (blocks 8-18): Clue text (144 bytes)
- Authentication uses key A = `0xFFFFFFFFFFFF`

### Serial Commands (Programming Mode)

`PROG` — enter programming mode | `EXIT` — leave | `SCAN` — read card | `ADD name|clue` — write quest to card | `HELP` — show commands

### Special Card Types

Cards with specific clue prefixes trigger special behaviors:
- `MORSE:` — Plays clue as Morse code via LED + buzzer
- `INPUT:` — Touch-based number input puzzle (answer 1-10)
- `AUTH:` — Multi-player authentication card (format: `name|id|text`)

## Key Libraries

- Adafruit SSD1306 v2.5.7 + GFX v1.11.5 (display)
- MFRC522 v1.4.10 (RFID)
- Preferences (ESP32 NVS for persistent storage)

## Power Management (Battery Operation)

Powered via ESP32-C3 SuperMini expansion board with 3.7V LiPo battery (USB charging).

- **Display auto-off**: 3 min inactivity (`DISPLAY_TIMEOUT_MS` in `config.h`)
- **Deep sleep**: 10 min inactivity (`SLEEP_TIMEOUT_MS` in `config.h`), ~µA draw
- **Wake**: Touch sensor press → full reboot through `setup()`
- Any interaction (card scan, touch, serial) resets inactivity timer
- ESP32-C3 deep sleep wake only supports GPIO0-5 — touch sensor must stay on one of these pins

## Notes

- No unit tests — embedded firmware tested via serial + hardware
- `main.cpp` is large; consider splitting display, audio, and RFID logic into separate modules for major changes
- WiFi code exists but is currently disabled
- See `PLANNING.md` for full architectural documentation and future plans
