| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- #pragma once
- #include <cstdint>
- namespace esphome::gxepd2 {
- // One command byte plus its (fixed, compile-time) data bytes, as sent by
- // GxEPD2_EPD::_writeCommand()/_writeData(). delay_before_ms/delay_after_ms
- // and wait_busy_after mirror the fixed delay()s and _waitWhileBusy() calls
- // bracketing specific commands in the vendor source (which command gets
- // which varies per panel - e.g. GxEPD2_213_Z98c delays 10ms on both sides
- // of its SWRESET, while GxEPD2_154_Z90c busy-waits after its SWRESET
- // instead). At most one of delay_after_ms/wait_busy_after is expected to be
- // set on any one command.
- struct EpdCommand {
- uint8_t cmd;
- const uint8_t *data; // nullptr if the command takes no data bytes
- uint8_t data_len;
- uint16_t delay_before_ms{0};
- uint16_t delay_after_ms{0};
- bool wait_busy_after{false};
- };
- // Everything CycleEngine needs to drive one panel, hand-derived from a
- // GxEPD2 vendor driver's .cpp/.h (see panel_154_z90c.h). Only what this
- // first slice's engine actually uses - the RAM-window-set command layout
- // (0x44/0x45/0x4E/0x4F) is common to every panel inspected so far and is
- // hardcoded in CycleEngine itself rather than made part of this struct;
- // revisit if/when the extraction-tooling phase finds a controller family
- // that lays it out differently.
- struct EpdPanelDescriptor {
- uint16_t width;
- uint16_t height;
- bool busy_active_level; // digitalRead() level meaning "still busy"
- uint32_t busy_timeout_ms; // ceiling for every busy wait (init and refresh alike)
- const EpdCommand *init_sequence; // run once, after the reset pulse
- uint8_t init_sequence_len;
- // Sets the (always full-frame, since this engine has no partial-window
- // support) RAM addressing window, run once after init_sequence and before
- // the first plane byte burst. Was hardcoded into CycleEngine assuming
- // every controller shares SSD1680's 0x44/0x45/0x4E/0x4F byte-column
- // layout - GxEPD2_426_GDEQ0426T82 (SSD1677) turned out to address in raw
- // pixels with reversed Y and re-issues its entry-mode command here, and
- // GxEPD2_583_GDEQ0583T31 (UC8179) uses one 0x90 command bracketed by
- // 0x91/0x92 markers instead. Made per-panel data, same as init/refresh,
- // rather than special-cased in the engine.
- const EpdCommand *window_sequence;
- uint8_t window_sequence_len;
- uint8_t plane_count; // 1 (BW) or 2 (BW + one accent color)
- uint8_t plane_write_cmd[2]; // e.g. {0x24, 0x26}
- bool plane_invert[2]; // true if the byte must be bit-inverted on write
- // true for the JD79667/HX8717-family 4-color panels (GDEY029F51,
- // GDEY0579F51): pixels are 2 bits each, 4 per byte, built from a
- // white/black/red classification at draw time - a fundamentally
- // different buffer shape than the 1-bit-per-pixel plane(s) above, not
- // just a different invert/command byte. When true, plane_count/
- // plane_invert are unused (always effectively 1 packed plane,
- // plane_write_cmd[0] still names the write command) and
- // GxEPD2Display's buffer is width*height/4 bytes instead of /8.
- bool packed_2bpp_plane{false};
- const EpdCommand *refresh_sequence; // e.g. 0x22/0xF7 then trigger 0x20
- uint8_t refresh_sequence_len;
- };
- } // namespace esphome::gxepd2
|