Files
pictureFrame-firmware/src/config.h
T
football2801 a0dc4e0115 feat(operation): X-Just-Provisioned + X-Claimed handshake
Closes the sell-to-friend gap where a buyer's freshly-reset device
would briefly display the seller's photos before the buyer reached
/setup/{mac} to claim. The firmware had no way to tell the server
"I just got reset" — now it does.

Flow:
  - WiFi-setup completion (handle_connect in main.cpp) writes
    NVS_KEY_JUST_PROVISIONED=1 alongside the SSID/PASS save.
  - Every poll while the flag is set sends X-Just-Provisioned: 1.
  - Server (DeviceImageController, paired commit on the webApp side)
    responds with 204 + X-Interval-Ms when the binding is stale,
    forcing the device to its setup-QR fallback. Once the user
    re-claims via /setup/{mac}, the binding is fresh, and the server
    answers with X-Claimed: 1 alongside whatever response code applies.
  - Firmware clears the NVS flag on seeing X-Claimed: 1 — once
    cleared, the device is back to normal long-stable polling.

Tests:
  - PROV-A: flag set in NVS → header on the request
  - PROV-B: no flag → no header (steady state)
  - PROV-C: response with X-Claimed: 1 → flag cleared
  - PROV-D: response without X-Claimed → flag stays (so the next
    poll keeps signaling "not yet acknowledged")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:03:22 -04:00

152 lines
6.4 KiB
C

#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 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
// 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 ────────────────────────────────────────────────────
// Verified on Waveshare 7.3" hardware. Same map on 13.3" Spectra 6.
#define COLOR_BLACK 0x0
#define COLOR_WHITE 0x1
#define COLOR_YELLOW 0x2
#define COLOR_RED 0x3
#define COLOR_BLUE 0x5
#define COLOR_GREEN 0x6
// ── NVS ──────────────────────────────────────────────────────────────────
#define NVS_NAMESPACE "pf"
#define NVS_KEY_SSID "ssid"
#define NVS_KEY_PASS "pass"
#define NVS_KEY_IMG_ID "img_id"
#define NVS_KEY_DRAW_NEEDED "draw"
#define NVS_KEY_ERR_BORDER "err" // set when display is showing a sync-fail border; force a clean redraw on next 200/304
#define NVS_KEY_SCHEMA_V "schema_v"
// Set on every fresh provisioning (WiFi-setup completion). Stays in NVS across
// reboots until the server explicitly acknowledges the device is claimed by
// returning X-Claimed: 1 — at which point the firmware clears the flag and
// resumes regular operation. Without this, a device that gets sold and reset
// would silently keep displaying the prior owner's photos until the new
// owner happens to navigate to /setup/{mac}.
#define NVS_KEY_JUST_PROVISIONED "just_prov"
// Bump when introducing a schema migration. Each new value can force a one-shot
// recovery action on first boot of the new firmware.
#define NVS_SCHEMA_VERSION 1
// Width of the sync-fail / no-WiFi border, in pixels.
#define BORDER_THICKNESS_PX 4
// ── Network ──────────────────────────────────────────────────────────────
#define APP_BASE_URL "https://pictureframe.edholm.me"
#define AP_IP "192.168.4.1"
#define WIFI_TIMEOUT_MS 30000
// Server's X-Interval-Ms is the primary schedule — driven by the user's
// rotationIntervalMinutes / wakeTimes settings. The constants below are
// only safety nets:
// - FALLBACK is used when the server omits the header (shouldn't happen
// in normal operation, but guards against a rolling deploy or hand-
// crafted response).
// - CLAMP_MIN/MAX bound the server value to sane physical limits — no
// runaway polling on a malformed 0/negative, no week-long naps on a
// misconfigured 999 days. CLAMP_MAX is just past 24 h to give DST
// transitions and edge-case wake-time math a little slack.
#ifndef FETCH_INTERVAL_MS_FALLBACK
#define FETCH_INTERVAL_MS_FALLBACK 60000ULL // 1 min, used only when no X-Interval-Ms header
#endif
#ifndef SLEEP_CLAMP_MIN_MS
#define SLEEP_CLAMP_MIN_MS 30000ULL // 30 s — protect against runaway polls
#endif
#ifndef SLEEP_CLAMP_MAX_MS
#define SLEEP_CLAMP_MAX_MS (25ULL * 60ULL * 60ULL * 1000ULL) // 25 h — past 24h with DST slack
#endif
#define IMAGE_PATH "/img.bin"