7.2 KiB
AGENTS.md — MTG RFID Companion (ESP-IDF)
Context for AI Agents & Assistant Tools:
This file outlines the architecture, coding guidelines, dependencies, hardware constraints, and build procedures for the MTG RFID Companion project. Read this completely before generating code, refactoring, or suggesting dependencies.
1. Project Overview
The MTG RFID Companion is a hand-held hardware utility for Magic: The Gathering players. It uses an ESP32 microcontroller running ESP-IDF v5.x (FreeRTOS) to scan RFID/NFC tags embedded in card sleeves, query card data locally or via Scryfall's API, render data to a 2.0" ST7789 TFT LCD (240x320), and host a local registration web server.
2. Target Hardware & Specifications
- MCU: ESP32-WROOM-32 (Dual-Core Xtensa LX6, 240MHz, 520KB SRAM, 4MB Flash). No external PSRAM.
- Display: 2.0" ST7789 SPI TFT LCD (240x320 resolution, RGB565 format). Full-screen JPEG wallpapers supported via tjpgd decoder.
- RFID Reader: MFRC522 (13.56 MHz, SPI Interface, ISO/IEC 14443A).
- Target Tags: NTAG213 / NTAG215 micro FPC stickers or standard MIFARE ISO cards (7-byte or 4-byte UIDs).
- User Input: EC11 Rotary Encoder with integrated push button.
- Storage: On-chip SPI Flash partitioned with LittleFS (mounted at
/spiffs, size ~1.5 MB).
3. Peripheral Wiring & GPIO Pinout
CRITICAL: Do NOT modify GPIO pin assignments in code generation unless explicitly instructed. SPI bus is shared between ST7789 and MFRC522.
| Peripheral | Functional Pin | ESP32 GPIO Pin | Shared Bus / Notes |
|---|---|---|---|
| Shared SPI | SCK / MOSI / MISO | GPIO 18 / 23 / 19 | Shared SPI2_HOST (VSPI) |
| MFRC522 RFID | CS (SDA) / RST | GPIO 5 / GPIO 22 | Dedicated CS & Reset |
| ST7789 Display | CS / DC / RST | GPIO 15 / GPIO 2 / GPIO 4 | Dedicated CS, Data/Cmd & Reset |
| Rotary Encoder | CLK / DT / SW | GPIO 32 / GPIO 33 / GPIO 25 | Active low / Interrupt driven |
| Indicators | Neopixel (WS2812B) | GPIO 27 | RMT driver |
| Audio | Piezo Buzzer | GPIO 14 | LEDC PWM channel |
4. Software Architecture & FreeRTOS Task Allocation
The project strictly follows a multithreaded, event-driven model using FreeRTOS tasks and the ESP Event Loop.
Core Core Split
- Core 0 (System, I/O & Network):
rc522_task: Continuously polls RFID reader, emits events upon card detection.net_task: Manages Wi-Fi reconnects, Scryfall HTTPS fetches (esp_http_client), andesp_http_server.storage_task: Reads/writes JSON files to/spiffsvia VFS.
- Core 1 (User Interface & Rendering):
ui_task: Handles ST7789 display drawing usingesp_lcdand rotary encoder inputs. Maintains UI frame rates without blocking Core 0 I/O.
System State Machine
State transitions must be managed cleanly using FreeRTOS Event Groups or Queue messaging:
STATE_BOOT: Hardware setup, LittleFS mount, Wi-Fi auto-connect.STATE_SCANNER: Waiting for RFID tag read.STATE_CARD_VIEW: Displaying fetched/cached card attributes (P/T, Mana, Oracle text).STATE_LIFE_COUNTER: Interactive 20/40 life counter utilizing rotary encoder.STATE_REGISTRATION: Local SoftAP mode (192.168.4.1) active to pair unknown UIDs with card names via web browser.
5. Storage Structure (LittleFS /spiffs)
Do NOT assume an SD card is attached. All local database operations use standard C file I/O (fopen, fread, fwrite) over LittleFS.
Contents are pre-seeded from the repo storage/ folder via littlefs_create_partition_image(storage storage FLASH_IN_PROJECT) at build time.
/spiffs/mappings.json— Maps scanned UIDs to Card Names:{ "04A2B3C4": "Sol Ring", "04E1F2A3": "Atraxa, Praetors' Voice" } /spiffs/cards/[UID].json — Cached Scryfall card attribute details: JSON { "name": "Sol Ring", "mana_cost": "{1}", "type": "Artifact", "oracle": "Tap: Add CC.", "price_usd": "1.25" } /spiffs/cards/[UID].jpg — Cached Scryfall cover art (streamed via tjpgd).
- Coding Standards & Conventions
When generating or editing code for this repository:
Framework: Pure ESP-IDF v5.x (C99/C11 standard). Do NOT use Arduino.h headers, functions, or Arduino libraries (Serial.print, delay(), Wire, etc.).
Error Handling: Always wrap ESP-IDF API functions in ESP_ERROR_CHECK() or handle errors gracefully using esp_err_t ret. Log errors via ESP_LOGE().
Memory Management: SRAM is tight (~520KB total, no PSRAM).
Do NOT allocate huge static buffers on the FreeRTOS task stack.
Allocate HTTP response buffers and cJSON trees dynamically on the heap (heap_caps_malloc(..., MALLOC_CAP_8BIT)), and always free them immediately after use.
JSON Parsing: Use native cJSON. Check every pointer return for NULL before accessing object fields.
Logging Tag: Define a static tag per source file:
C
static const char *TAG = "MODULE_NAME";
- Project Dependencies & Configuration
Managed via idf_component.yml:
abobija/rc522: SPI RFID reader driver.
joltwallet/littlefs: LittleFS VFS port for ESP-IDF.
espressif/esp_lcd: Official display subsystem (ST7789 controller driver).
Build Commands
Build Project: idf.py build
Flash to Device: idf.py -p <PORT> flash
Monitor Logs: idf.py -p <PORT> monitor
Partition Table: Uses custom partitions.csv (Flash allocation: 2MB App, 1.5MB LittleFS data).
-
Guidance for AI Agents Generating Code
When asked to build features: Write full, compile-ready C files (.c) and header files (.h) targeting ESP-IDF v5.x.
When modifying hardware code: Cross-check the shared SPI bus configurations to prevent SPI2_HOST bus conflicts between ST7789 and MFRC522.
When implementing network code: Use non-blocking esp_http_client requests running on a dedicated FreeRTOS task to keep screen rendering smooth.
-
Module Map (main/)
| File | Responsibility | Task / Core |
|---|---|---|
main.c |
Boot orchestration | app_main |
hw_pins.h |
GPIO assignments | - |
spi_bus_manager.c |
Shared SPI2_HOST bus init | - |
storage_manager.c |
LittleFS mount + JSON mapping/card helpers | - |
rfid_manager.c |
MFRC522, UID hex, Core-0 pinning | rc522_polling_task / 0 |
display_manager.c |
ST7789 240x320 primitives, 5x7 text, big digits, tjpgd stream | ui_task / 1 |
ui_task.c |
State machine + all screens | ui_task / 1 |
wifi_manager.c |
STA auto-connect + reconnect | event loop |
scryfall_client.c |
Scryfall HTTPS, cJSON cache, prefetch | net_task / 0 |
web_server.c |
SoftAP MTG-Companion 192.168.4.1 + pairing SPA | httpd task |
encoder.c |
EC11 ISR decode + button | ISR |
led_manager.c |
WS2812B RMT | ISR + ui_task |
buzzer.c |
LEDC PWM tones | ui_task |
app_state.c |
STATE_* + life counter values | all |
Build & runtime notes:
idf.py menuconfig-> "MTG RFID Companion" setsMTG_WIFI_SSID/MTG_WIFI_PASS; leave empty to skip STA (SoftAP web pairing always runs).- Flash:
idf.py -p COMx flash monitor. Thestorage/folder is baked into the LittleFS partition image. - The ST7789 is driven in RGB565 big-endian wire order; if colors appear inverted on a given panel variant, toggle
esp_lcd_panel_invert_color()/LCD_RGB_ELEMENT_ORDER_*indisplay_manager.c.