test_pattern_bar_ladder_diagonal.esp32-idf.yaml 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # Canonical bench visual-check pattern, not a minimal smoke test like the
  2. # other fixtures in this directory. Scales to any panel via
  3. # it.get_width()/it.get_height(); each zone targets a specific bug class -
  4. # see claude/DESIGN.md's "Bench test pattern" section for the full
  5. # rationale. This is the actual pattern (previously only ever staged
  6. # on-device, never committed) whose row ladder + diagonal caught the
  7. # GDEY0579F51 row-interleave bug and confirmed the fix - see the
  8. # gxepd2-bench-validation-status memory.
  9. #
  10. # Wired here against GDEY0579F51 (4-color, dual-CS master+slave,
  11. # row_interleave: true) since that's the panel this pattern was built to
  12. # debug, but the lambda itself is panel-agnostic - copy it into any other
  13. # color-capable fixture's `lambda:` unchanged.
  14. esphome:
  15. name: gxepd2-test-pattern
  16. esp32:
  17. board: esp32dev
  18. framework:
  19. type: esp-idf
  20. external_components:
  21. - source:
  22. type: local
  23. path: ../components
  24. components: [gxepd2]
  25. spi:
  26. clk_pin: 18
  27. mosi_pin: 23
  28. logger:
  29. display:
  30. - platform: gxepd2
  31. model: GxEPD2_579c_GDEY0579F51
  32. cs_pin: 5
  33. dc_pin: 17
  34. reset_pin: 16
  35. busy_pin: 4
  36. update_interval: 60s
  37. lambda: |-
  38. const int w = it.get_width();
  39. const int h = it.get_height();
  40. const int n = 4;
  41. // Wire-code order (see gxepd2_display.h's packed-2bpp classification):
  42. // black=0x00, white=0x01, yellow=0x02, red=0x03 - matched here so a
  43. // wrong bar points straight at the wire code it corresponds to.
  44. Color colors[n] = {Color::BLACK, Color::WHITE, Color(0xFF, 0xFF, 0x00), Color(0xFF, 0x00, 0x00)};
  45. it.fill(Color::WHITE);
  46. // Row ladder: 1px-tall rows cycling the full palette, full width.
  47. // The row-interleave detector - a dropped/duplicated/reordered row
  48. // breaks the regular N-row cadence.
  49. const int ladder_h = h / 3;
  50. for (int y = 0; y < ladder_h; y++)
  51. it.horizontal_line(0, y, w, colors[y % n]);
  52. // Column ladder: same idea rotated 90 degrees, directly below.
  53. // Catches nibble-order/byte-stride bugs the row ladder can't (packed
  54. // 2bpp stores 4 pixels/byte, so a column-order bug can leave every
  55. // row looking individually correct).
  56. for (int x = 0; x < w; x++)
  57. it.vertical_line(x, ladder_h, ladder_h, colors[x % n]);
  58. // Color bars: one solid block per available color, in wire-code
  59. // order (not perceptual brightness order).
  60. const int bars_y = ladder_h * 2;
  61. const int bars_h = h - bars_y;
  62. const int bar_w = w / n;
  63. for (int i = 0; i < n; i++) {
  64. int bw = (i == n - 1) ? (w - i * bar_w) : bar_w;
  65. it.filled_rectangle(i * bar_w, bars_y, bw, bars_h, colors[i]);
  66. }
  67. // Corner markers: three distinct corners, fourth left blank. The
  68. // bars/ladders above are symmetric enough that a 90/180-degree
  69. // rotation or mirror could otherwise still "look right" at a glance.
  70. const int mark = (w < h ? w : h) / 8;
  71. it.filled_rectangle(0, 0, mark, mark, colors[2]); // top-left: yellow
  72. it.filled_rectangle(w - mark, 0, mark, mark, colors[3]); // top-right: red
  73. it.filled_rectangle(0, h - mark, mark, mark, colors[0]); // bottom-left: black
  74. // bottom-right intentionally left blank - the "no marker" 4th state.
  75. // Corner-to-corner diagonal, drawn on top of everything: the
  76. // cheapest possible check for a coordinate-transform bug. A real
  77. // diagonal stays a clean line; any row/column reordering breaks it
  78. // into visible steps exactly where the reordering happens.
  79. it.line(0, 0, w - 1, h - 1, Color::BLACK);
  80. it.line(w - 1, 0, 0, h - 1, Color::BLACK);
  81. // Border frame, drawn last so it stays a clean unbroken rectangle
  82. // touching all four edges even where bars/ladders fill to the edge.
  83. // Catches a clipped or offset draw origin.
  84. it.rectangle(0, 0, w, h, Color::BLACK);