#pragma once // Drives one vendor GxEPD2 driver through the same low-level calls the // GxEPD2_BW/GxEPD2_3C wrapper templates make for a single non-paged full // update (writeImage() then refresh()) - bypassing the wrapper templates // themselves (and their Adafruit_GFX dependency) since we only need the // driver-level trace, not drawing helpers. After the full update it also // runs the window-encoder sweep (window_sweep.h) - adopted as the standard // capture step for every panel, to derive and cross-check the coordinate -> // window-byte math by observation rather than by hand. #include #include #include "spy/Arduino.h" #include "spy/SPI.h" #include "trace.h" #include "window_sweep.h" // Exposes GxEPD2_EPD's protected busy_level/reset_duration without needing // to parse anything - a subclass can read its own base class's protected // members directly. template struct Peek : Driver { using Driver::Driver; int busy_level() const { return this->_busy_level; } uint16_t reset_duration() const { return this->_reset_duration; } }; // planes=1 for monochrome drivers (color buffer still passed - harmless, // see e.g. GxEPD2_290_T94::writeImage(black,color,...) which just ignores // a non-null color pointer's absence). template void run_harness(const char *name) { printf("=== %s: WIDTH=%u HEIGHT=%u ===\n", name, (unsigned) Driver::WIDTH, (unsigned) Driver::HEIGHT); constexpr int16_t CS = 10, DC = 11, RST = 12, BUSY = 13; Trace::set_dc_pin(DC); Peek driver(CS, DC, RST, BUSY); printf("busy_level=%d reset_duration=%u\n", driver.busy_level(), driver.reset_duration()); // digitalRead(BUSY) should report "released" immediately - opposite of // busy_level - so _waitWhileBusy()'s loop exits after one check. Trace::last_busy_release_value = driver.busy_level() == HIGH ? LOW : HIGH; driver.selectSPI(SPI, SPISettings()); printf("--- init(0) ---\n"); driver.init(0); const uint32_t plane_bytes = (static_cast(Driver::WIDTH) * Driver::HEIGHT) / 8; auto *black = new uint8_t[plane_bytes]; auto *color = new uint8_t[plane_bytes]; // Distinctive, non-0x00/0xFF pattern - lets a plane's invert flag be // read directly off the trace (does the wire byte equal 0xA5 or 0x5A). memset(black, 0xA5, plane_bytes); memset(color, 0xA5, plane_bytes); printf("--- writeImage(black, color, 0, 0, WIDTH, HEIGHT) ---\n"); driver.writeImage(black, color, 0, 0, Driver::WIDTH, Driver::HEIGHT); printf("--- refresh(false) ---\n"); driver.refresh(false); // Standard window-encoder sweep for every panel (runs after the initial // full refresh above, which satisfies run_window_sweep's precondition). run_window_sweep(driver, Driver::WIDTH, Driver::HEIGHT); delete[] black; delete[] color; }