Phase 1: ESP-IDF v5 project scaffold, custom partitions, managed deps, AGENTS.md hardware context

This commit is contained in:
2026-09-09 16:30:25 +02:00
commit 1771525c06
9 changed files with 2495 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build/
managed_components/
sdkconfig.old
sdkconfig.defaults.bak
dependencies.lock

131
AGENTS.md Normal file
View File

@@ -0,0 +1,131 @@
# 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`), and `esp_http_server`.
* `storage_task`: Reads/writes JSON files to `/spiffs` via VFS.
* **Core 1 (User Interface & Rendering):**
* `ui_task`: Handles ST7789 display drawing using `esp_lcd` and 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:
1. `STATE_BOOT`: Hardware setup, LittleFS mount, Wi-Fi auto-connect.
2. `STATE_SCANNER`: Waiting for RFID tag read.
3. `STATE_CARD_VIEW`: Displaying fetched/cached card attributes (P/T, Mana, Oracle text).
4. `STATE_LIFE_COUNTER`: Interactive 20/40 life counter utilizing rotary encoder.
5. `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.
* `/spiffs/mappings.json` — Maps scanned UIDs to Card Names:
```json
{
"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"
}
6. 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";
7. 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).
8. 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.

7
CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mtg-rfid-companion)
idf_build_set_property(PROJECT_DESCRIPTION "MTG RFID Companion")
idf_build_set_property(PROJECT_HOMEPAGE_URL "https://scryfall.com")

4
main/CMakeLists.txt Normal file
View File

@@ -0,0 +1,4 @@
idf_component_register(SRCS
"main.c"
INCLUDE_DIRS "."
)

6
main/idf_component.yml Normal file
View File

@@ -0,0 +1,6 @@
## IDF Component Manager dependencies for MTG RFID Companion
## NOTE: espressif/esp_lcd is a built-in IDF component - do NOT declare it here.
dependencies:
idf: ">=5.0"
abobija/rc522: "*"
joltwallet/littlefs: "*"

20
main/main.c Normal file
View File

@@ -0,0 +1,20 @@
/*
* MTG RFID Companion - Entry point
*
* Phase 1: Boot scaffold. Subsequent phases attach managers here.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
static const char *TAG = "MAIN";
void app_main(void)
{
ESP_LOGI(TAG, "MTG RFID Companion booting...");
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

4
partitions.csv Normal file
View File

@@ -0,0 +1,4 @@
# Name, Type, SubType, Offset, Size
# 2MB factory (app) partition + 1.5MB LittleFS data partition on 4MB flash
factory, app, factory, 0x10000, 0x200000
storage, data, littlefs, 0x210000, 0x1F0000
1 # Name, Type, SubType, Offset, Size
2 # 2MB factory (app) partition + 1.5MB LittleFS data partition on 4MB flash
3 factory, app, factory, 0x10000, 0x200000
4 storage, data, littlefs, 0x210000, 0x1F0000

2312
sdkconfig Normal file

File diff suppressed because it is too large Load Diff

6
sdkconfig.defaults Normal file
View File

@@ -0,0 +1,6 @@
# MTG RFID Companion - ESP32 SDK defaults
CONFIG_IDF_TARGET="esp32"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y