refactor(firmware): per-panel folder layout + parametrized config.h

Reorganizes the tree so adding a new panel is purely additive — drop in a
new src/panels/{vendor}/v{N}/ folder and a new platformio.ini env block,
no surgery to existing files.

Layout:
  src/                              shared across all panels
  src/panels/waveshare73/v1/        V1 driver, version, README
  data/waveshare73-v1/              LittleFS payload at this panel's size

src/config.h still defines the panel-agnostic bits (NVS keys, color
palette, network, sync-fail border) but EPD_WIDTH / EPD_HEIGHT / pin
assignments now come from each env's -D flags. Strict #error guards in
production builds; native tests get the V1 defaults via UNIT_TEST.

build_src_filter per env picks the right driver:
  waveshare73-v1   main + panels/waveshare73/v1/
  test-display     test_display + panels/waveshare73/v1/
  sim-yellow       sim_border + panels/waveshare73/v1/
  sim-red          sim_border + panels/waveshare73/v1/
  native-test      unchanged

When V2 hardware lands, the diff is a new env block, a new
src/panels/waveshare133/v1/epd_driver.cpp, and regenerated screens at
data/waveshare133-v1/. Existing V1 envs stay frozen — re-flashing old
units remains a one-liner.

scripts/gen_screens.py takes --panel to target the correct
data/{panel}/ subfolder; defaults to waveshare73-v1.

29/29 native tests pass. All four hardware envs build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 12:31:23 -04:00
parent 27d01057e4
commit a6ed67a3f4
13 changed files with 229 additions and 66 deletions
+91 -13
View File
@@ -1,21 +1,99 @@
#pragma once
// repo: pictureFrame-firmware
//
// Hardware specifics (panel dimensions + GPIO pinout) come from the build
// env's -D flags in platformio.ini, not from this file. That keeps the
// shared sources panel-agnostic and lets each `src/panels/{vendor}/v{N}/`
// subtree stay focused on its own driver.
//
// Strict: missing a -D flag is a compile error here, not a silent fallback
// to V1 values. A bad env config fails fast at build time. Native tests
// (UNIT_TEST defined) get harmless defaults — they don't drive real
// hardware, so the values never matter beyond satisfying the compiler.
// ── EPD pins (Waveshare 7.3" ACeP) ──────────────────────────────────────────
#define EPD_WIDTH 800
#define EPD_HEIGHT 480
#define PIN_SCK 18
#define PIN_MOSI 23
#define PIN_CS 5
#define PIN_DC 17
#define PIN_RST 16
#define PIN_BUSY 4
// ── EPD pixel dimensions ─────────────────────────────────────────────────
#ifndef EPD_WIDTH
# ifdef UNIT_TEST
# define EPD_WIDTH 800
# else
# error "EPD_WIDTH not defined — set -DEPD_WIDTH=… in platformio.ini build_flags"
# endif
#endif
#ifndef EPD_HEIGHT
# ifdef UNIT_TEST
# define EPD_HEIGHT 480
# else
# error "EPD_HEIGHT not defined — set -DEPD_HEIGHT=… in platformio.ini build_flags"
# endif
#endif
// ── Reset button (BOOT button = GPIO 0 on most dev boards) ──────────────────
// Largest panel width any build env may target. Static buffers in the
// driver use this to size themselves at compile time so we don't pay for
// heap allocation on every draw. Default: assume the active env's panel
// (so V1 builds get an 800-wide buffer; V2 builds will set it to 1872).
#ifndef MAX_PANEL_WIDTH
#define MAX_PANEL_WIDTH EPD_WIDTH
#endif
// ── GPIO pinout ──────────────────────────────────────────────────────────
// Same UNIT_TEST escape: native tests get the V1 dev-board pinout so
// shared sources compile, even though no real GPIO is touched.
#ifndef PIN_SCK
# ifdef UNIT_TEST
# define PIN_SCK 18
# else
# error "PIN_SCK not defined — set -DPIN_SCK=… in platformio.ini build_flags"
# endif
#endif
#ifndef PIN_MOSI
# ifdef UNIT_TEST
# define PIN_MOSI 23
# else
# error "PIN_MOSI not defined — set -DPIN_MOSI=… in platformio.ini build_flags"
# endif
#endif
#ifndef PIN_CS
# ifdef UNIT_TEST
# define PIN_CS 5
# else
# error "PIN_CS not defined — set -DPIN_CS=… in platformio.ini build_flags"
# endif
#endif
#ifndef PIN_DC
# ifdef UNIT_TEST
# define PIN_DC 17
# else
# error "PIN_DC not defined — set -DPIN_DC=… in platformio.ini build_flags"
# endif
#endif
#ifndef PIN_RST
# ifdef UNIT_TEST
# define PIN_RST 16
# else
# error "PIN_RST not defined — set -DPIN_RST=… in platformio.ini build_flags"
# endif
#endif
#ifndef PIN_BUSY
# ifdef UNIT_TEST
# define PIN_BUSY 4
# else
# error "PIN_BUSY not defined — set -DPIN_BUSY=… in platformio.ini build_flags"
# endif
#endif
// ── Panel telemetry strings ──────────────────────────────────────────────
// Reported to the server at provisioning. PANEL_ID identifies the hardware
// model (vendor + size); PANEL_FW_VERSION lives in src/panels/{…}/v{N}/version.h
// and ticks when the panel-specific driver code changes.
#ifndef PANEL_ID
#define PANEL_ID "unknown"
#endif
// ── Reset button (BOOT button = GPIO 0 on most dev boards) ──────────────
#define PIN_BTN_RESET 0
#define RESET_HOLD_MS 5000
// ── EPD color nibbles ────────────────────────────────────────────────────────
// ── EPD color nibbles ────────────────────────────────────────────────────
// Verified on Waveshare 7.3" hardware. Same map on 13.3" Spectra 6.
#define COLOR_BLACK 0x0
#define COLOR_WHITE 0x1
@@ -24,7 +102,7 @@
#define COLOR_BLUE 0x5
#define COLOR_GREEN 0x6
// ── NVS ──────────────────────────────────────────────────────────────────────
// ── NVS ──────────────────────────────────────────────────────────────────
#define NVS_NAMESPACE "pf"
#define NVS_KEY_SSID "ssid"
#define NVS_KEY_PASS "pass"
@@ -40,7 +118,7 @@
// Width of the sync-fail / no-WiFi border, in pixels.
#define BORDER_THICKNESS_PX 4
// ── Network ──────────────────────────────────────────────────────────────────
// ── Network ──────────────────────────────────────────────────────────────
#define APP_BASE_URL "https://pictureframe.edholm.me"
#define AP_IP "192.168.4.1"
#define WIFI_TIMEOUT_MS 30000
+48
View File
@@ -0,0 +1,48 @@
# waveshare73 / v1
Driver for the Waveshare 7.3" 6-color e-ink panel (800×480, Spectra-6) on a
discrete ESP32 dev-board breakout. This is the original V1 firmware that
shipped on Matt's prototype unit.
## What lives here
- `epd_driver.cpp` — implements the `epd.h` interface for this panel:
`epd_init`, `epd_sleep`, `epd_fill`, `epd_draw_image_from_file`,
`epd_draw_image_with_border`, `epd_draw_qr`, `epd_draw_ap_screen`,
`epd_draw_setup_screen`. The init byte sequence at the top of `epd_init()`
is verified for this specific controller; do not blind-paste from another
panel.
- `version.h``PANEL_FW_VERSION` string transmitted during provisioning.
Bump when the driver changes in a way the server should know about.
## Per-panel data (lives elsewhere)
Pre-rendered LittleFS payloads for this panel size live at
`data/waveshare73-v1/`:
- `ap_bg.bin`, `setup_bg.bin` — captive-portal and account-binding
background screens at 800×480
- `img.bin`, `img_portrait.bin` — test images used by the `test-display`
build env
Regenerate with `scripts/gen_screens.py --width 800 --height 480` after
changing the source artwork.
## Build env
```bash
pio run -e waveshare73-v1 --target upload # production firmware
pio run -e test-display --target upload # single-image hardware test
pio run -e sim-yellow --target upload # sync-fail border test
pio run -e sim-red --target upload # no-WiFi border test
```
The build flags supplied by `platformio.ini` parametrize `src/config.h`
this folder doesn't redefine pins or dimensions itself.
## QR positions
`epd_draw_ap_screen` and `epd_draw_setup_screen` have hardcoded QR
coordinates (cell size, x, y) tuned for 800×480 + the bg screens at
`data/waveshare73-v1/`. If the bg art changes, the matching constants
in `gen_screens.py` and the driver must be re-tuned together.
+10
View File
@@ -0,0 +1,10 @@
#pragma once
// Panel-specific firmware version. Bump when the V1 7.3" driver changes
// in a way the server should know about. Reported to the server during
// provisioning so support can correlate field-reported issues with the
// exact panel-driver build a device is running.
//
// Independent of the shared firmware version (HTTP / NVS / sleep / etc.)
// — that's tracked by git SHA, not this string.
#define PANEL_FW_VERSION "v1.0"