#pragma once // Drives a real GxEPD2_BW/GxEPD2_3C wrapper template - // the actual class GxEPD2 example sketches (and the pre-rewrite gxepd2 // component) instantiate - through one full-screen update via its real // public API (init/setFullWindow/firstPage/fillScreen+drawPixel/nextPage), // instead of calling the bare driver's writeImage()/refresh() ourselves. // This is what actually exercises whatever the wrapper's own firstPage()/ // nextPage() do internally (writeImageForFullRefresh, embedded priming, // etc.) - which run_harness.h's direct calls don't necessarily match. #include #include "spy/Adafruit_GFX.h" #include "spy/Arduino.h" #include "spy/SPI.h" #include "trace.h" template struct Peek : Driver { using Driver::Driver; int busy_level() const { return this->_busy_level; } uint16_t reset_duration() const { return this->_reset_duration; } }; // WrapperT: GxEPD2_BW or GxEPD2_3C - // the caller picks which, since that's a fact about the panel (its // catalog.json "wrapper" field), not something this harness infers. // PeekDriverT: the same Peek passed as WrapperT's first template // argument - repeated here since GxEPD2_BW/3C don't expose it as a nested // typedef we could pull back out. template void run_wrapper_harness(const char *name, bool three_color) { printf("=== %s (via wrapper template) ===\n", name); constexpr int16_t CS = 10, DC = 11, RST = 12, BUSY = 13; Trace::set_dc_pin(DC); WrapperT display(PeekDriverT(CS, DC, RST, BUSY)); printf("busy_level=%d reset_duration=%u\n", display.epd2.busy_level(), display.epd2.reset_duration()); Trace::last_busy_release_value = display.epd2.busy_level() == HIGH ? LOW : HIGH; display.epd2.selectSPI(SPI, SPISettings()); printf("--- init(0) ---\n"); display.init(0); printf("--- setFullWindow/firstPage/fillScreen+drawPixel/nextPage ---\n"); display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawPixel(0, 0, GxEPD_BLACK); if (three_color) display.drawPixel(1, 0, GxEPD_RED); } while (display.nextPage()); }