|
|
2 săptămâni în urmă | |
|---|---|---|
| .. | ||
| spy | 3 săptămâni în urmă | |
| README.md | 2 săptămâni în urmă | |
| emit_descriptor.h | 2 săptămâni în urmă | |
| emit_palette_4c.h | 3 săptămâni în urmă | |
| emit_palette_7c.h | 3 săptămâni în urmă | |
| probe_plane_invert.h | 3 săptămâni în urmă | |
| run_154_z90c.cpp | 1 lună în urmă | |
| run_154_z90c_emit.cpp | 3 săptămâni în urmă | |
| run_213_z98c.cpp | 1 lună în urmă | |
| run_213_z98c_diag.cpp | 3 săptămâni în urmă | |
| run_213_z98c_probe.cpp | 3 săptămâni în urmă | |
| run_213c_gdey0213f52_emit.cpp | 3 săptămâni în urmă | |
| run_290_t94.cpp | 1 lună în urmă | |
| run_290_t94_diag.cpp | 3 săptămâni în urmă | |
| run_290_t94_partial.cpp | 3 săptămâni în urmă | |
| run_290_t94_wrapper.cpp | 1 lună în urmă | |
| run_290c_gdey029f51.cpp | 1 lună în urmă | |
| run_290c_gdey029f51_diagB.cpp | 3 săptămâni în urmă | |
| run_290c_gdey029f51_diagN.cpp | 3 săptămâni în urmă | |
| run_290c_gdey029f51_emit.cpp | 3 săptămâni în urmă | |
| run_426_gdeq0426t82.cpp | 1 lună în urmă | |
| run_426_gdeq0426t82_diag.cpp | 3 săptămâni în urmă | |
| run_565c_diagB.cpp | 3 săptămâni în urmă | |
| run_579c_gdey0579f51.cpp | 1 lună în urmă | |
| run_579c_gdey0579f51_diagN.cpp | 3 săptămâni în urmă | |
| run_583_gdeq0583t31.cpp | 1 lună în urmă | |
| run_583_gdeq0583t31_diag.cpp | 3 săptămâni în urmă | |
| run_730c_gdep073e01.cpp | 3 săptămâni în urmă | |
| run_diagB_harness.h | 3 săptămâni în urmă | |
| run_diagN_harness.h | 3 săptămâni în urmă | |
| run_diag_harness.h | 3 săptămâni în urmă | |
| run_harness.h | 3 săptămâni în urmă | |
| run_partial_harness.h | 3 săptămâni în urmă | |
| run_wrapper_harness.h | 1 lună în urmă | |
| trace.h | 3 săptămâni în urmă | |
| window_sweep.h | 3 săptămâni în urmă | |
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.
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). A 7-colour (epd7c/) panel works the same
way via emit_palette_7c.h / the driver's GxEPD2_7C wrapper, validated
against GXEPD2_PALETTE_7C (black/white/green/blue/red/yellow/orange, no
code collisions); a panel with a non-standard 7-colour map (e.g.
GDEP073E01's rotated codes) stays an explicit TODO with the observed table
rather than being mislabelled. For a panel with no colour wrapper at all
(still GxEPD2_BW/binary) that nonetheless packs >1 bit/pixel on the wire -
e.g. GxEPD2_583/UC8159c's _send8pixel, which expands each 1bpp buffer byte
into a wider wire format using only two of its codes - emit_descriptor.h's
make_resolver_bw_packed is the fallback resolver (used whenever no
colour-wrapper resolver applies): it drives the plain driver's own
writeImage with a uniform all-white/all-black 1bpp buffer directly (no
wrapper to instantiate), and if both wire bursts are internally uniform, the
byte-count ratio against the pixel count gives bits_per_pixel and each
fill's byte gives that colour's code - no source reading needed, and no
"two 1bpp planes" primitive required from the engine. A driver whose packing
depends on more than one bit at a time (dithering, error diffusion) fails the
uniformity check and stays an honest TODO. A dual-region panel (per-region select +
window, e.g. GDEY0579F51 / HX8717) is segmented too: its per-region init /
window / refresh, plane_width (decoded from the region window-set) and a
candidate line_order (PAIRED_EDGES when a region's burst is 2x its pixel
bytes) all come out, with only the exact paired-edges row order left for the
diag native-path pass to confirm. Review the result, add any packed-format
fields still left as TODO, 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.
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). Any panel the emitter
can't yet segment is listed in its KNOWN_DIFF and reported as XFAIL (none
at present — the dual-region GDEY0579F51 was promoted out once the emitter
modelled the region-select layer; an XPASS means a KNOWN_DIFF entry now
reproduces and should be removed). Panels with no GxEPD2 driver source of
their own (a synthetic model) are skipped. Run it after any
third_party/GxEPD2/ update.
tools/capture.py MODEL --sweep / --diag — runs run_harness.h's
window-encoder sweep, or run_diag_harness.h's Pattern-A row/byte-order
fill, for any capturable model with no run_<panel>.cpp to hand-write
(both headers are already templates over Driver; capture.py builds a
one-off generic main() the same way it does for descriptor emission).
Older panels still have a committed run_<panel>[_diag].cpp from before
this existed - either form works, prefer --sweep/--diag for anything
new. Output is the full byte-by-byte trace (large for a big/packed panel -
redirect to a file and grep for >>> SWEEP / [row-tag] rather than
reading it raw).tools/capture.py MODEL --power — prints just power_off_sequence/
hibernate_sequence (array + EpdCommand table + the two descriptor-field
lines to paste), for splicing into an EXISTING panel_*.h that shipped
before these fields existed, without regenerating - and losing any
hand-written commentary in - the rest of the file. Same noisy-trace caveat
as --sweep/--diag: redirect to a file and take the tail (everything
after the last digitalRead line is the actual result).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. Pattern A
(run_diag_harness.h) only covers the 1bpp byte-preserving path (see
CONTRIBUTING.md); Pattern B (run_diagB_harness.h) drives a driver's own
GxEPD2_4C/GxEPD2_7C wrapper and its named colours, so it doesn't apply
to a still-monochrome (GxEPD2_BW-wrapped) driver that packs internally
(e.g. GxEPD2_583/UC8159c's _send8pixel - a 1bpp buffer expanded to a 2-code
wire format). That case is covered by emit_descriptor.h's
make_resolver_bw_packed instead - folded into the one-command
tools/capture.py capture, same as 4-colour/7-colour - not a separate diag
program at all.spy/ — the host stand-ins for the Arduino/SPI APIs a GxEPD2 driver calls;
trace.h records what the driver does.