epd_command.h 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #pragma once
  2. #include <cstdint>
  3. namespace esphome::gxepd2 {
  4. // One command byte plus its (fixed, compile-time) data bytes, as sent by
  5. // GxEPD2_EPD::_writeCommand()/_writeData(). delay_before_ms/delay_after_ms
  6. // and wait_busy_after mirror the fixed delay()s and _waitWhileBusy() calls
  7. // bracketing specific commands in the vendor source (which command gets
  8. // which varies per panel - e.g. GxEPD2_213_Z98c delays 10ms on both sides
  9. // of its SWRESET, while GxEPD2_154_Z90c busy-waits after its SWRESET
  10. // instead). At most one of delay_after_ms/wait_busy_after is expected to be
  11. // set on any one command.
  12. struct EpdCommand {
  13. uint8_t cmd;
  14. const uint8_t *data; // nullptr if the command takes no data bytes
  15. uint8_t data_len;
  16. uint16_t delay_before_ms{0};
  17. uint16_t delay_after_ms{0};
  18. bool wait_busy_after{false};
  19. };
  20. // Everything CycleEngine needs to drive one panel, hand-derived from a
  21. // GxEPD2 vendor driver's .cpp/.h (see panel_154_z90c.h). Only what this
  22. // first slice's engine actually uses - the RAM-window-set command layout
  23. // (0x44/0x45/0x4E/0x4F) is common to every panel inspected so far and is
  24. // hardcoded in CycleEngine itself rather than made part of this struct;
  25. // revisit if/when the extraction-tooling phase finds a controller family
  26. // that lays it out differently.
  27. struct EpdPanelDescriptor {
  28. uint16_t width;
  29. uint16_t height;
  30. bool busy_active_level; // digitalRead() level meaning "still busy"
  31. uint32_t busy_timeout_ms; // ceiling for every busy wait (init and refresh alike)
  32. const EpdCommand *init_sequence; // run once, after the reset pulse
  33. uint8_t init_sequence_len;
  34. // Sets the (always full-frame, since this engine has no partial-window
  35. // support) RAM addressing window. window_sequence[0] runs once after
  36. // init_sequence and before the first plane's byte burst; index 1 is only
  37. // used when window_per_plane is true (see below). Was hardcoded into
  38. // CycleEngine assuming every controller shares SSD1680's
  39. // 0x44/0x45/0x4E/0x4F byte-column layout - GxEPD2_426_GDEQ0426T82
  40. // (SSD1677) turned out to address in raw pixels with reversed Y and
  41. // re-issues its entry-mode command here, and GxEPD2_583_GDEQ0583T31
  42. // (UC8179) uses one 0x90 command bracketed by 0x91/0x92 markers instead.
  43. // Made per-panel data, same as init/refresh, rather than special-cased
  44. // in the engine.
  45. const EpdCommand *window_sequence[2];
  46. uint8_t window_sequence_len[2];
  47. // true if each plane needs window_sequence[plane index] re-run before
  48. // its own byte burst, instead of one window_sequence[0] covering every
  49. // plane's burst (the default, e.g. a BW+red panel's shared full-frame
  50. // window). This is how GxEPD2_579c_GDEY0579F51's real master/slave
  51. // regions are handled: two genuinely separate physical RAM windows, not
  52. // just two color planes sharing one - "plane" here just means "one more
  53. // buffer with its own byte burst," which happens to fit a two-physical-
  54. // region panel as well as a two-color-plane one. See
  55. // panel_579c_gdey0579f51.h.
  56. bool window_per_plane{false};
  57. uint8_t plane_count; // 1 (BW), 2 (BW + accent color), or 2 physical regions
  58. uint8_t plane_write_cmd[2]; // e.g. {0x24, 0x26}
  59. bool plane_invert[2]; // true if the byte must be bit-inverted on write
  60. // When window_per_plane is true, each plane's own buffer is sized for
  61. // this width, not the descriptor's overall `width` (which is the full
  62. // logical canvas ESPHome draws into and get_width_internal() reports) -
  63. // e.g. 396 for GDEY0579F51's master/slave halves, each 396x272 on its
  64. // own, not the full 792x272. Unused otherwise.
  65. uint16_t plane_width{0};
  66. // true for the JD79667/HX8717-family 4-color panels (GDEY029F51,
  67. // GDEY0579F51): pixels are 2 bits each, 4 per byte, built from a
  68. // white/black/yellow/red classification at draw time - a fundamentally
  69. // different buffer shape than the 1-bit-per-pixel plane(s) above, not
  70. // just a different invert/command byte. When true, plane_invert is
  71. // unused and GxEPD2Display's buffer(s) are width*height/4 bytes instead
  72. // of /8 (per-plane width*height/4 when window_per_plane is also true).
  73. bool packed_2bpp_plane{false};
  74. const EpdCommand *refresh_sequence; // e.g. 0x22/0xF7 then trigger 0x20
  75. uint8_t refresh_sequence_len;
  76. };
  77. } // namespace esphome::gxepd2