ZiB 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
..
spy f502ba3b63 Add GDEY075T7 (7.5" 800x480 mono, UC8179); define PROGMEM in the spy shim 3 tygodni temu
README.md 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
emit_descriptor.h 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
emit_palette_4c.h 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
probe_plane_invert.h db1cd5b6ec harness: fold plane_invert + 1bpp/packed detection into the emitter 3 tygodni temu
run_154_z90c.cpp 42c87bb88d Add a dynamic-tracing harness for extracting GxEPD2 per-panel protocol data 1 miesiąc temu
run_154_z90c_emit.cpp 5acc8432c4 Add GDEH0154Z90 3-color panel descriptor (emitter-derived) 3 tygodni temu
run_213_z98c.cpp 42c87bb88d Add a dynamic-tracing harness for extracting GxEPD2 per-panel protocol data 1 miesiąc temu
run_213_z98c_diag.cpp d6e65922fb harness: diagnostic-fill Pattern A (row/byte ordering) 4 tygodni temu
run_213_z98c_probe.cpp 54022b2ea1 harness: derive plane_invert by capture (probe) 3 tygodni temu
run_213c_gdey0213f52_emit.cpp 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
run_290_t94.cpp 42c87bb88d Add a dynamic-tracing harness for extracting GxEPD2 per-panel protocol data 1 miesiąc temu
run_290_t94_diag.cpp d6e65922fb harness: diagnostic-fill Pattern A (row/byte ordering) 4 tygodni temu
run_290_t94_partial.cpp 560f5e9fbe harness: add fast-partial capture program (GxEPD2_290_T94) 4 tygodni temu
run_290_t94_wrapper.cpp 42c87bb88d Add a dynamic-tracing harness for extracting GxEPD2 per-panel protocol data 1 miesiąc temu
run_290c_gdey029f51.cpp a4ac4b79e4 Add harness runners for the four panels on the bench today 1 miesiąc temu
run_290c_gdey029f51_diagB.cpp 15cc4d5a3d harness: diagnostic-fill Pattern B (pixel packing + codes) 4 tygodni temu
run_290c_gdey029f51_diagN.cpp ca79e6cea3 harness: native-path row ordering for packed panels 4 tygodni temu
run_290c_gdey029f51_emit.cpp 65918c7bdb emitter: auto-fill 4-colour fields, class-aware busy timeout, paste-ready PANELS line 3 tygodni temu
run_426_gdeq0426t82.cpp a4ac4b79e4 Add harness runners for the four panels on the bench today 1 miesiąc temu
run_426_gdeq0426t82_diag.cpp d6e65922fb harness: diagnostic-fill Pattern A (row/byte ordering) 4 tygodni temu
run_565c_diagB.cpp 9491ec9d41 harness: extend Pattern B to 7-colour ACeP 4 tygodni temu
run_579c_gdey0579f51.cpp a4ac4b79e4 Add harness runners for the four panels on the bench today 1 miesiąc temu
run_579c_gdey0579f51_diagN.cpp ca79e6cea3 harness: native-path row ordering for packed panels 4 tygodni temu
run_583_gdeq0583t31.cpp a4ac4b79e4 Add harness runners for the four panels on the bench today 1 miesiąc temu
run_583_gdeq0583t31_diag.cpp d6e65922fb harness: diagnostic-fill Pattern A (row/byte ordering) 4 tygodni temu
run_diagB_harness.h 9491ec9d41 harness: extend Pattern B to 7-colour ACeP 4 tygodni temu
run_diagN_harness.h ca79e6cea3 harness: native-path row ordering for packed panels 4 tygodni temu
run_diag_harness.h 00bd4e3be7 docs: refresh panel table for the 750/579 status; finish row_interleave->line_order 3 tygodni temu
run_harness.h c0c21c11cd harness: make the window-encoder sweep a standard capture step 4 tygodni temu
run_partial_harness.h c0c21c11cd harness: make the window-encoder sweep a standard capture step 4 tygodni temu
run_wrapper_harness.h 42c87bb88d Add a dynamic-tracing harness for extracting GxEPD2 per-panel protocol data 1 miesiąc temu
trace.h b3d1b32e22 harness: prototype descriptor emitter (single-plane panels) 3 tygodni temu
window_sweep.h c0c21c11cd harness: make the window-encoder sweep a standard capture step 4 tygodni temu

README.md

gxepd2 capture harness

Host-side tooling that generates a panel descriptor by observing a real GxEPD2 driver run, instead of hand-writing one. See ../../CONTRIBUTING.md for the full model; this is the how-to.

The vendored GxEPD2 source it compiles against lives in third_party/GxEPD2/. Everything here runs on a dev machine with plain g++ — no ESP toolchain.

Emit a descriptor

One command (from the code/ root) resolves the driver, builds+runs the harness, and prints a candidate descriptor:

tools/capture.py --list                      # capturable driver classes
tools/capture.py GxEPD2_154_Z90c             # candidate -> stdout
tools/capture.py GxEPD2_154_Z90c -o /tmp/panel_154_z90c.h
tools/capture.py GxEPD2_154_Z90c --debug     # also dump the capture structure

It finds the driver in catalog.json (or by globbing third_party/GxEPD2/ for one the catalog doesn't list), so there's no build line to hand-write. Under the hood it does exactly:

VSRC=third_party/GxEPD2/src
g++ -std=c++17 -I tools/gxepd2_harness/spy -I $VSRC -I tools/gxepd2_harness \
    <generated emit main>.cpp \
    $VSRC/GxEPD2_EPD.cpp $VSRC/<subdir>/GxEPD2_<Class>.cpp \
    -o /tmp/emit_<panel>

emit_descriptor.h phase-segments the captured command stream into the init / window / refresh sequences + plane-write command(s), reads resolution / busy-polarity / timeout from the driver, and derives plane_invert and 1bpp-vs-packed from a fill probe. For a 4-colour (epd4c/) panel it goes further: emit_palette_4c.h drives the driver's own GxEPD2_4C wrapper, reads the wire code for each named colour, validates it against the engine's GXEPD2_PALETTE_4C, and fills bits_per_pixel / palette / blank_code automatically (an unexpected code map stays a TODO carrying the observed table). Review the result, add any packed-format fields still left as TODO — bits_per_pixel / palette for a 7-colour panel (no resolver yet) and plane_width / line_order for dual-region — then save it as components/gxepd2/panel_<panel>.h. capture.py also prints the exact PANELS line to paste into display.py (key / descriptor macro / format filled from the capture; part / controller scraped from the driver header to sanity-check, status starting at structural).

EMIT_DEBUG=1 /tmp/emit_<panel> dumps the image-stage command/burst structure.

Regression check (CI)

tools/check_descriptors.py re-emits every shipped panel from its GxEPD2 driver and structurally diffs the result against the committed panel_*.h (command sequences + plane layout only, not the hand/diag-filled fields). It exits non-zero on any unexpected mismatch, so wire it into CI as a plain step:

tools/check_descriptors.py        # all panels; -v shows the diff on a mismatch

A DIFF means either an emitter regression or GxEPD2 upstream drift (a vendor bump changed that driver — review the panel). Dual-region panels the emitter doesn't fully model yet are listed in its KNOWN_DIFF and reported as XFAIL; panels with no GxEPD2 driver source (the synthetic MASTER_ONLY variant) are skipped. Run it after any third_party/GxEPD2/ update.

Other programs

  • run_<panel>.cpp + run_harness.h — bare-driver capture plus the window-encoder sweep (window_sweep.h), for deriving the coordinate → window-byte mapping.
  • run_<panel>_probe.cpp + probe_plane_invert.h — print the plane_invert probe result on its own.
  • run_*diag*.cpp — the diagnostic-fill passes that derive pixel packing, palette codes, and row order for packed / multi-region panels.
  • spy/ — the host stand-ins for the Arduino/SPI APIs a GxEPD2 driver calls; trace.h records what the driver does.