| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- #pragma once
- // Drives a fast-partial-capable vendor driver PAST the full-refresh capture
- // cutoff, to record the sequences fast partial needs that a plain
- // writeImage()+refresh() trace (run_harness.h) deliberately discards:
- //
- // [B] the previous-buffer sync - writeImageAgain() writes the frame to the
- // controller's "previous" buffer (0x26) then "current" (0x24), so the
- // next differential refresh baselines correctly.
- // [C] the partial refresh waveform - refresh(x,y,w,h) -> _Update_Part(),
- // a different 0x22 "display update control 2" byte (and often a much
- // shorter busy wait) than the full _Update_Full().
- // [D] the parameterized RAM-window encoder - a COORDINATE SWEEP calling
- // the public refresh(x,y,w,h) at several distinct rects (its internal
- // _setPartialRamArea is private, so we drive it through the public
- // API; with x/w kept multiples of 8 the driver's coordinate rounding
- // is a no-op, so the window bytes in each trace are exactly our rect).
- // We diff the resulting traces to SOLVE the (x,y,w,h) -> wire-byte
- // formula by observation instead of hand-computing it (the latter is
- // what produced the GDEQ0583T31 0x8F-vs-0x87 off-by-one smear). This
- // sweep is NOT fast-partial-specific: every panel sets a window from
- // coordinates, so the same technique derives and cross-checks the
- // window math for any driver that exposes a coordinate-parameterized
- // window routine. The full-frame (0,0,W,H) case in the sweep is the
- // same window our existing full-refresh capture already records, so
- // it is a built-in cross-check on the derived encoder.
- #include <cstdint>
- #include <cstdio>
- #include <cstring>
- #include "spy/Arduino.h"
- #include "spy/SPI.h"
- #include "trace.h"
- #include "window_sweep.h"
- template<typename Driver> struct PartialPeek : Driver {
- using Driver::Driver;
- int busy_level() const { return this->_busy_level; }
- uint16_t reset_duration() const { return this->_reset_duration; }
- };
- template<typename Driver> void run_partial_harness(const char *name) {
- printf("=== %s: FAST-PARTIAL capture : 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);
- PartialPeek<Driver> d(CS, DC, RST, BUSY);
- printf("busy_level=%d reset_duration=%u\n", d.busy_level(), d.reset_duration());
- Trace::last_busy_release_value = d.busy_level() == HIGH ? LOW : HIGH;
- d.selectSPI(SPI, SPISettings());
- const uint32_t plane_bytes = (static_cast<uint32_t>(Driver::WIDTH) * Driver::HEIGHT) / 8;
- auto *frame0 = new uint8_t[plane_bytes];
- auto *frame1 = new uint8_t[plane_bytes];
- memset(frame0, 0xA5, plane_bytes); // distinctive, != 0x00/0xFF
- memset(frame1, 0x5A, plane_bytes); // a different frame, to make the partial diff non-trivial
- // [PHASE A] Full init + full update. Same as the existing full-refresh
- // capture; also clears the driver's _initial_refresh so the partial
- // refresh in phase C actually takes the _Update_Part path (the vendor
- // driver forces the very first refresh to be full regardless).
- printf("\n--- [PHASE A] init(0) + writeImage(full) + refresh(false) (full baseline) ---\n");
- d.init(0);
- d.writeImage(frame0, 0, 0, Driver::WIDTH, Driver::HEIGHT);
- d.refresh(false);
- // [PHASE B] Previous-buffer sync.
- printf("\n--- [PHASE B] writeImageAgain(full) (previous 0x26 then current 0x24) ---\n");
- d.writeImageAgain(frame0, 0, 0, Driver::WIDTH, Driver::HEIGHT);
- // [PHASE C] A real partial update: new content to current, then a
- // windowed refresh -> _Update_Part waveform + the partial window bytes.
- printf("\n--- [PHASE C] writeImage(new) + refresh(16,24,32,48) (partial update) ---\n");
- d.writeImage(frame1, 0, 0, Driver::WIDTH, Driver::HEIGHT);
- d.refresh(16, 24, 32, 48);
- // [PHASE D] Window-encoder sweep - the shared run_window_sweep (window_sweep.h),
- // same routine the standard full-refresh capture now runs for every panel.
- // Here it also reveals each rect's _Update_Part waveform (0x22 0xFC).
- run_window_sweep(d, Driver::WIDTH, Driver::HEIGHT);
- delete[] frame0;
- delete[] frame1;
- }
|