Files
MTGcompanion/README.md
2026-09-11 19:10:31 +02:00

256 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MTG RFID Companion
A feature-packed, handheld **Magic: The Gathering** companion built on the **ESP32-WROOM-32**. Slip an RFID/NFC tag into your card sleeves and tap them to the device for instant card lookups, official art display, life tracking, dice rolling, and complete deck management.
All firmware is written in **pure ESP-IDF v5.x (C) / FreeRTOS** — no Arduino overhead, dual-core task segregation, and strictly optimized for devices without external PSRAM (< 520 KB SRAM).
---
## 🌟 Feature Tour & Modes
The companion boots directly into an interactive, rotary-controlled interface designed specifically for tabletop MTG gameplay:
```
┌──────────────────────────────┐
│ ★ MTG COMPANION ★ │
├──────────────────────────────┤
│ > [1] Card Scanner < │
│ [2] Life & Counters │
│ [3] Dice & Coin │
│ [4] Commander Tax │
│ [5] Token & Counters │
│ [6] Deck Storage │
│ [7] Device Info │
└──────────────────────────────┘
```
### 1. Interactive Boot Menu (`APP_STATE_MENU`)
On power-up, the device greets you with the Main Menu.
* **Rotate the knob** to highlight any of the 7 modes with an active amber cursor.
* **Click the knob** to enter the highlighted mode.
* **Universal Back (Hold knob $\ge$ 0.75s):** Press and hold the rotary switch from **any** screen to sound a double-chirp, flash purple on the WS2812B LED, and instantly return to the Main Menu.
* **Universal Card Interrupt:** Tapping a card tag from **any** screen or menu immediately transitions into that card's view.
---
### 2. Universal RFID Scanner & Art Crop Display (`APP_STATE_CARD_VIEW`)
* **Instant Tag Identification:** Supports MFRC522, ISO/IEC 14443A, NTAG213/215 stickers, and standard MIFARE 1K cards (4-byte and 7-byte UIDs).
* **True RGB565 Scryfall Art:** Cards display official card illustrations pre-scaled to a crisp 200×110 format, decoded via hardware-assisted Baseline JPEG in ~10 ms with true color accuracy.
* **Card Metadata:** Shows card name, mana cost, type line, oracle text, power/toughness, loyalty, and market pricing.
* **8-Bit Legendary Stinger & Neopixel Feedback:**
* **Legendary / Mythic Stinger:** Scanning any Legendary creature or Mythic Rare plays an upward 8-bit stinger and pulses the LED in gold!
* **Mana Color LEDs:** WS2812B Neopixel illuminates in the card's native mana identity (White, Blue, Black, Red, Green, Gold, Colorless).
* **Unmapped Card Support:** Tapping an unmapped tag switches to the Registration view, displaying the UID and pairing instructions.
* **Smart Cache Validation:** When a card tag is re-paired or changed in the web UI, the firmware automatically detects the change, purges old cached assets, and downloads the fresh card details and art.
---
### 3. Life & Multi-Counter (`APP_STATE_LIFE_COUNTER`)
A dedicated, high-contrast tournament-grade counter supporting the three most important Magic metrics:
* **Life Total (Starts at 40 Commander / 20 Standard):**
* Turn clockwise to gain life (green LED flash); turn counter-clockwise to lose life (red LED flash).
* **Click to Cycle Counter Types:**
1. **Life Total:** Standard life tracking.
2. **Poison Counters (0–10):** In MTG, taking 10 poison counters loses the game.
3. **Commander Combat Damage (0–21):** Dealing 21 combat damage with a single commander eliminates a player.
* **8-Bit Dramatic Loss Tone:** Reaching 0 life or 10 poison triggers an 8-bit descending defeat stinger and a red alert banner.
---
### 4. Spindown D20 / D6 / Fair Coin Flip (`APP_STATE_DICE_ROLLER`)
* **Rotate knob** to select between **D20 (Spindown)**, **D6**, or **Coin Flip**, then **click to roll**.
* Plays an interactive rolling shuffle animation with rapid tick sounds.
* **Natural 20 (Critical Hit):** Plays the 8-bit **Victory Fanfare** and flashes brilliant green.
* **Natural 1 (Critical Fail):** Sounds a buzzer tone and flashes red.
* **D6 Mode:** Quick six-sided die roll for ability triggers and random player selection.
* **Coin Flip Mode:** Random 50/50 flip landing on **HEADS (Green)** or **TAILS (Amber)**.
---
### 5. Built-in Token & Counter Spawner (`APP_STATE_TOKEN_SPAWNER`)
An interactive tabletop tool for spawning and managing tokens on the battlefield:
* **Pre-configured Tokens:**
* **Treasure** (Artifact Token) — `{T}, Sacrifice: Add one mana of any color.`
* **Food** (Artifact Token) — `{2}, {T}, Sacrifice: You gain 3 life.`
* **Clue** (Artifact Token) — `{2}, Sacrifice: Draw a card.`
* **1/1 Soldier** (White Creature Token) — With full P/T box.
* **2/2 Zombie** (Black Creature Token) — With full P/T box.
* **1/1 Goblin** (Red Creature Token) — With full P/T box.
* **3/3 Beast** (Green Creature Token) — With full P/T box.
* **+1/+1 Counter** (Permanent Modifier) — Universal stat counter.
* **Controls:**
* **Pick Mode:** Rotate the knob to cycle through tokens (`< 1 OF 8 >`).
* **Edit Mode:** Click the knob to select; rotate to increment/decrement count (`0` to `99`). Click again to save. Token quantities persist throughout the play session.
---
### 6. Commander Tax & Turn Tracker (`APP_STATE_COMMANDER_TRACKER`)
In Commander (EDH), casting your commander costs an additional {2} generic mana for each time it has previously been cast from the command zone.
* **Commander Casts:** Rotate the knob to adjust casts; the screen automatically calculates and displays the total tax (e.g., `Cast 3 = +4 Mana`).
* **Turn Counter:** Click the button to switch to the table turn tracker.
---
### 7. Deck & Storage Manager (`APP_STATE_STORAGE_MANAGER`)
View flash disk usage and manage cards stored in LittleFS:
* **Storage Metrics:** Displays total storage space (~1.9 MB), used bytes, and counts of cached JSON cards and art crop images.
* **Wipe All Cards (New Deck Mode):** Switching to a new deck? Rotate to highlight "Wipe All Cards", click, and confirm. This purges `/spiffs/cards/*` and resets `mappings.json`, freeing space for a completely new 100-card deck with full artwork.
---
### 8. Web Registration, SoftAP Pairing & Scanned Cards Overview (`web_server`)
Pair tags and manage your entire scanned deck directly from your smartphone browser—no host software required:
1. Connect your phone or laptop to the Wi-Fi network: **`MTG-Companion`** (open network, default IP `192.168.4.1`).
2. Open `http://192.168.4.1` in your browser.
3. **Pair New Tag:**
* Tap an RFID tag to the reader — the UID populates automatically.
* Type the card name (Scryfall autocomplete suggestions appear in real time).
* Click **Pair Card**. The binding is saved to `/spiffs/mappings.json` and the firmware fetches the card details and cover art over Wi-Fi.
4. **Scanned / Paired Cards Overview:**
* View an alphabetized list of all registered cards in your deck with live card counter (`Paired Cards (X)`).
* Displays the card title, tag UID, and cover art thumbnails streamed directly from LittleFS flash storage (`/api/art?uid=...`).
* **Unbind Card:** Click "Unbind" next to any card to immediately delete its mapping and clean up its cached JSON and JPEG files from flash memory.
* **Refresh:** Click "Refresh" to re-sync the list after scans or edits.
---
### 9. Device Info Screen (`APP_STATE_DEVICE_INFO`)
Real-time diagnostic screen showing:
* Wi-Fi STA connection status, SSID, and assigned IP address.
* SoftAP network details (`MTG-Companion`, `192.168.4.1`).
* Free internal heap SRAM (typically ~180 KB free during active rendering).
* System uptime and LittleFS partition status.
---
## 🎮 Quick Controls Cheat Sheet
| Action | Control |
| :--- | :--- |
| **Navigate / Adjust** | Rotate EC11 rotary knob clockwise / counter-clockwise |
| **Select / Roll / Toggle** | Short press encoder button |
| **Universal Back (To Menu)** | **Long press encoder button ($\ge$ 0.75s)** (double chirp + purple flash) |
| **Instant Card View** | Tap any RFID card sleeve to reader from **any** screen |
---
## 🛠️ Hardware Requirements
- **ESP32-WROOM-32** development board (4MB flash, dual-core LX6, no external PSRAM needed).
- **ST7789** SPI TFT LCD, 240x320 resolution (2.0" or 2.4" breakout).
- **MFRC522** RFID reader module (13.56 MHz, SPI).
- **EC11** rotary encoder with integrated push switch.
- **WS2812B / Neopixel** (single addressable RGB LED).
- **Passive piezo buzzer** (driven via LEDC PWM).
- **Antenna-friendly NTAG213/NTAG215** micro FPC stickers (for card sleeves) or standard MIFARE cards.
- **2200 µF Electrolytic Capacitor** (placed directly across MFRC522 VCC and GND) — **CRITICAL**: absorbs RF transmit spikes and prevents 3.3V rail voltage dips that trigger ESP32 brownouts or MFRC522 register resets.
---
## 🔌 Peripheral Wiring & Pinout
The display and RFID reader use **two separate SPI host controllers** to prevent SPI bus contention and clock mismatch:
- **ST7789 Display:** `SPI2_HOST` (VSPI) at 20 MHz.
- **MFRC522 Reader:** `SPI3_HOST` (HSPI) at 1 MHz.
| Peripheral | Function | ESP32 GPIO | Notes |
| :--- | :--- | :---: | :--- |
| **ST7789 Display** (SPI2) | SCL (Clock) | **18** | SPI2_HOST (VSPI) clock |
| | SDA (MOSI) | **23** | SPI2_HOST MOSI |
| | CS | **21** | Dedicated Chip Select (non-strapping pin) |
| | DC | **19** | Data / Command select (non-strapping pin) |
| | RST | **4** | Display Reset |
| | VCC / GND | 3.3V / GND | Display logic & backlight power |
| **MFRC522 RFID** (SPI3) | SCK | **16** | SPI3_HOST (HSPI) clock |
| | MOSI | **17** | SPI3_HOST MOSI |
| | MISO | **13** | SPI3_HOST MISO |
| | SDA (CS) | **26** | Dedicated Chip Select |
| | RST | **22** | Hard reset line |
| | 3.3V / GND | 3.3V / GND | **Attach 2200 µF capacitor across these pins!** |
| **EC11 Rotary Encoder** | CLK (A) | **32** | Quadrature A (interrupt-driven, internal pull-up) |
| | DT (B) | **33** | Quadrature B (internal pull-up) |
| | SW (Button) | **25** | Push button (active LOW, internal pull-up) |
| **Indicators** | WS2812B DIN | **27** | RMT peripheral Tx (supply 5V to VDD, common GND) |
| **Audio** | Buzzer SIG | **14** | LEDC PWM channel |
### Wiring Diagram
```
ESP32-WROOM-32
┌────────────────────────────┐
│ 3V3 16 ── SCK ────────┐ │
│ GND 17 ── MOSI ────┐ │ │
│ 13 ── MISO ────┼──┘ │
│ 26 ── SDA(CS) ─┘ │
│ 22 ── RST ─┐ │
│ 21 ── CS ──┼───────┤ ST7789 (7-pin, SPI2_HOST)
│ 19 ── DC ──┤ │ SCL=18, SDA=23, CS=21, DC=19, RST=4
│ 4 ── RST ─┘ │ VCC=3.3V, GND=GND
│ 18 ── SCL ─────────┘
│ 23 ── SDA ─────────
│ 32 ── CLK ────────┤ EC11 Rotary Encoder (CLK=32, DT=33, SW=25)
│ 27 ── Din ────────┤ WS2812B LED (GPIO 27, 5V rail)
│ 14 ── SIG ────────┤ Piezo Buzzer (GPIO 14)
└────────────────────────────┘
│ │
[2200 µF Cap]
│ │
┌─────┴───┴──────────────────┐
│ 3V3 GND │
│ MFRC522 RFID Module (SPI3) │
└────────────────────────────┘
```
> **Note on Flashing:** GPIO21 (CS) and GPIO19 (DC) are deliberate non-strapping pins. The ST7789 display can remain fully connected during `idf.py flash`.
---
## 💻 Software Setup & Build
### 1. Requirements
- **ESP-IDF v5.x** (v5.0 through v5.5 supported):
```powershell
. C:\Espressif\frameworks\esp-idf-v5.5\export.ps1
idf.py --version
```
### 2. Configure Wi-Fi
Configure home Wi-Fi credentials for automatic Scryfall fetching:
```powershell
idf.py menuconfig
# Navigate to: MTG RFID Companion -> Wi-Fi SSID & Password
```
*(Or edit `sdkconfig.defaults.esp32` directly).*
### 3. Build & Flash
```powershell
idf.py set-target esp32
idf.py build
idf.py -p COM4 flash monitor
```
---
## 📂 LittleFS Storage Structure
```
/spiffs/
├── mappings.json UID -> Card Name JSON map
└── cards/
├── <UID>.json Scryfall attributes (Mana, Type, Oracle, P/T)
└── <UID>.jpg Cached 200x110 Baseline JPEG art crop
```
The `storage/` repository directory is compiled directly into the LittleFS partition image at build time (`littlefs_create_partition_image`).
---
## ❓ Troubleshooting
| Symptom | Cause & Solution |
| :--- | :--- |
| **ESP32 reboots when scanning card** | 3.3V rail voltage sag caused by the MFRC522 RF transmitter. **Add a 2200 µF capacitor** directly across the MFRC522 VCC and GND pins. |
| **Display colors inverted (blues look red)** | Check `flags.swap_color_bytes = 1` in JPEG config and `esp_lcd_panel_invert_color()` in `display_manager.c`. Panel clones differ between RGB and BGR. |
| **Card shows "PARSE FAILED"** | Corrupt card JSON in cache. The firmware auto-purges corrupt entries on reboot, or use **Deck Storage -> Wipe** to reset. |
| **Scanned card shows previously paired card** | Re-pairing a card now automatically purges the old cache. Ensure firmware is up to date, or clear via **Deck Storage -> Wipe**. |
| **Art crop doesn't show** | Ensure device has Wi-Fi connectivity to download from Scryfall. Images are cached locally on flash once downloaded. |
| **Flash fails: `Failed to connect to ESP32`** | Make sure no other terminal is monitoring COM4 (`Ctrl + ]` to exit monitor). If using older GPIO15/2 wiring, hold the BOOT button during connect. |