run_partial_harness.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #pragma once
  2. // Drives a fast-partial-capable vendor driver PAST the full-refresh capture
  3. // cutoff, to record the sequences fast partial needs that a plain
  4. // writeImage()+refresh() trace (run_harness.h) deliberately discards:
  5. //
  6. // [B] the previous-buffer sync - writeImageAgain() writes the frame to the
  7. // controller's "previous" buffer (0x26) then "current" (0x24), so the
  8. // next differential refresh baselines correctly.
  9. // [C] the partial refresh waveform - refresh(x,y,w,h) -> _Update_Part(),
  10. // a different 0x22 "display update control 2" byte (and often a much
  11. // shorter busy wait) than the full _Update_Full().
  12. // [D] the parameterized RAM-window encoder - a COORDINATE SWEEP calling
  13. // the public refresh(x,y,w,h) at several distinct rects (its internal
  14. // _setPartialRamArea is private, so we drive it through the public
  15. // API; with x/w kept multiples of 8 the driver's coordinate rounding
  16. // is a no-op, so the window bytes in each trace are exactly our rect).
  17. // We diff the resulting traces to SOLVE the (x,y,w,h) -> wire-byte
  18. // formula by observation instead of hand-computing it (the latter is
  19. // what produced the GDEQ0583T31 0x8F-vs-0x87 off-by-one smear). This
  20. // sweep is NOT fast-partial-specific: every panel sets a window from
  21. // coordinates, so the same technique derives and cross-checks the
  22. // window math for any driver that exposes a coordinate-parameterized
  23. // window routine. The full-frame (0,0,W,H) case in the sweep is the
  24. // same window our existing full-refresh capture already records, so
  25. // it is a built-in cross-check on the derived encoder.
  26. #include <cstdint>
  27. #include <cstdio>
  28. #include <cstring>
  29. #include "spy/Arduino.h"
  30. #include "spy/SPI.h"
  31. #include "trace.h"
  32. #include "window_sweep.h"
  33. template<typename Driver> struct PartialPeek : Driver {
  34. using Driver::Driver;
  35. int busy_level() const { return this->_busy_level; }
  36. uint16_t reset_duration() const { return this->_reset_duration; }
  37. };
  38. template<typename Driver> void run_partial_harness(const char *name) {
  39. printf("=== %s: FAST-PARTIAL capture : WIDTH=%u HEIGHT=%u ===\n", name, (unsigned) Driver::WIDTH,
  40. (unsigned) Driver::HEIGHT);
  41. constexpr int16_t CS = 10, DC = 11, RST = 12, BUSY = 13;
  42. Trace::set_dc_pin(DC);
  43. PartialPeek<Driver> d(CS, DC, RST, BUSY);
  44. printf("busy_level=%d reset_duration=%u\n", d.busy_level(), d.reset_duration());
  45. Trace::last_busy_release_value = d.busy_level() == HIGH ? LOW : HIGH;
  46. d.selectSPI(SPI, SPISettings());
  47. const uint32_t plane_bytes = (static_cast<uint32_t>(Driver::WIDTH) * Driver::HEIGHT) / 8;
  48. auto *frame0 = new uint8_t[plane_bytes];
  49. auto *frame1 = new uint8_t[plane_bytes];
  50. memset(frame0, 0xA5, plane_bytes); // distinctive, != 0x00/0xFF
  51. memset(frame1, 0x5A, plane_bytes); // a different frame, to make the partial diff non-trivial
  52. // [PHASE A] Full init + full update. Same as the existing full-refresh
  53. // capture; also clears the driver's _initial_refresh so the partial
  54. // refresh in phase C actually takes the _Update_Part path (the vendor
  55. // driver forces the very first refresh to be full regardless).
  56. printf("\n--- [PHASE A] init(0) + writeImage(full) + refresh(false) (full baseline) ---\n");
  57. d.init(0);
  58. d.writeImage(frame0, 0, 0, Driver::WIDTH, Driver::HEIGHT);
  59. d.refresh(false);
  60. // [PHASE B] Previous-buffer sync.
  61. printf("\n--- [PHASE B] writeImageAgain(full) (previous 0x26 then current 0x24) ---\n");
  62. d.writeImageAgain(frame0, 0, 0, Driver::WIDTH, Driver::HEIGHT);
  63. // [PHASE C] A real partial update: new content to current, then a
  64. // windowed refresh -> _Update_Part waveform + the partial window bytes.
  65. printf("\n--- [PHASE C] writeImage(new) + refresh(16,24,32,48) (partial update) ---\n");
  66. d.writeImage(frame1, 0, 0, Driver::WIDTH, Driver::HEIGHT);
  67. d.refresh(16, 24, 32, 48);
  68. // [PHASE D] Window-encoder sweep - the shared run_window_sweep (window_sweep.h),
  69. // same routine the standard full-refresh capture now runs for every panel.
  70. // Here it also reveals each rect's _Update_Part waveform (0x22 0xFC).
  71. run_window_sweep(d, Driver::WIDTH, Driver::HEIGHT);
  72. delete[] frame0;
  73. delete[] frame1;
  74. }