Server: Frame.panel_type (new column + migration) is auto-derived from the device's reported board (X-Frame-Board), never user-set -- the panel is a property of the hardware, not a picker in the UI. image_pipeline's packing/render pipeline is parameterized by panel geometry instead of hardcoded 800x480 globals, with the real confirmed 13.3in geometry (1600x1200) registered alongside the original 7.3in panel. Existing 7.3in frames are unaffected (column default + board mapping both resolve to the original panel). Board identifiers are also renamed (devkit/xiao -> devkit_esp32c6/ xiao_esp32c6, plus new "ee02") since the EE02 board also carries a XIAO module -- "xiao" alone stopped disambiguating hardware. The server keeps accepting the legacy bare names indefinitely for already-flashed devices. Firmware: scaffolds a third build target (ee02, ESP32-S3 -- a real chip-target change, not just a same-chip Kconfig variant like xiao) and a new epd13in3e driver component skeleton. The actual panel init/LUT/ refresh register sequence isn't ported from vendor demo code yet (none was available), so that component deliberately fails to compile (#error) rather than risk sending unverified register values to real hardware -- devkit/xiao are unaffected and build identically to before. CI's ee02 build step is continue-on-error for the same reason.
90 lines
3.8 KiB
C
90 lines
3.8 KiB
C
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include "esp_err.h"
|
|
|
|
/* Waveshare 13.3" e-Paper (E) Spectra 6 panel, driven by Seeed's EE02
|
|
* board (XIAO ESP32-S3 Plus): 1600x1200, 4 bits/pixel packed
|
|
* 2-pixels-per-byte -- same packing convention and public function
|
|
* shapes as epd7in3e.h, just a different resolution, so main's own
|
|
* sources don't need to branch on which panel is active beyond
|
|
* main/epd_board.h's
|
|
* header selection. Confirmed from Waveshare's/Seeed's public product
|
|
* pages (270.40x202.80mm, 1600x1200px). NOT yet confirmed against the
|
|
* vendor's own reference driver code, which doesn't exist in this tree
|
|
* yet -- see epd13in3e.c's top comment and epd_init()'s stub. The panel
|
|
* is also driven as two halves over a shared bus with two independent
|
|
* chip-selects (see Kconfig's EPD_PIN_CS_MASTER/EPD_PIN_CS_SLAVE), unlike
|
|
* epd7in3e's single-CS interface -- that's an implementation detail of
|
|
* epd13in3e.c, not something callers of this header need to know about. */
|
|
#define EPD_WIDTH 1600
|
|
#define EPD_HEIGHT 1200
|
|
#define EPD_BYTES_PER_ROW ((EPD_WIDTH + 1) / 2)
|
|
#define EPD_FRAME_BYTES (EPD_BYTES_PER_ROW * EPD_HEIGHT)
|
|
|
|
/* Same 6-ink Spectra family as the 7.3" panel, so the same 6 named
|
|
* colors -- but whether this panel's controller uses the SAME nibble
|
|
* values as epd7in3e.h's epd_color_t is UNCONFIRMED (see this file's own
|
|
* top comment). Left identical to epd7in3e.h's values as the working
|
|
* assumption; correct these against the vendor demo code once it exists,
|
|
* alongside server/app/image_pipeline.py's PANEL_CODES if they turn out
|
|
* to differ (see that file's own comment on PANEL_CODES). */
|
|
typedef enum {
|
|
EPD_COLOR_BLACK = 0x0,
|
|
EPD_COLOR_WHITE = 0x1,
|
|
EPD_COLOR_YELLOW = 0x2,
|
|
EPD_COLOR_RED = 0x3,
|
|
EPD_COLOR_BLUE = 0x5,
|
|
EPD_COLOR_GREEN = 0x6,
|
|
} epd_color_t;
|
|
|
|
/** Configures SPI + GPIO and runs the panel's power-on register init sequence. */
|
|
esp_err_t epd_init(void);
|
|
|
|
/** Fills the whole panel with a single color and refreshes. */
|
|
esp_err_t epd_clear(epd_color_t color);
|
|
|
|
/**
|
|
* Called repeatedly by epd_display_stream() to fill up to chunk_size bytes
|
|
* into chunk. Must return the number of bytes written, or 0 once exhausted.
|
|
*/
|
|
typedef size_t (*epd_read_fn_t)(uint8_t *chunk, size_t chunk_size, void *ctx);
|
|
|
|
/**
|
|
* Streams a full frame (EPD_FRAME_BYTES bytes, packed 2 pixels/byte) to the
|
|
* panel via read_fn and refreshes. Pulling from a caller-supplied source
|
|
* instead of a single buffer lets callers feed the panel directly from an
|
|
* HTTP response without holding the whole ~960KB frame in RAM.
|
|
*/
|
|
esp_err_t epd_display_stream(epd_read_fn_t read_fn, void *ctx);
|
|
|
|
/**
|
|
* Like epd_display_stream(), but writes the frame into the panel's
|
|
* internal buffer over SPI WITHOUT triggering the physical refresh (the
|
|
* visible flash/flicker) -- call epd_turn_on_display() separately to make
|
|
* it visible. Returns ESP_ERR_INVALID_SIZE if read_fn didn't supply
|
|
* exactly EPD_FRAME_BYTES, same as epd_display_stream(); either way
|
|
* nothing is refreshed, so the visible screen is left untouched on
|
|
* error.
|
|
*
|
|
* If out_crc32 is non-NULL, it's set to a CRC32 of the bytes written --
|
|
* lets a caller compare against the last-displayed frame's CRC and skip
|
|
* the refresh entirely when nothing actually changed (e.g. redisplaying
|
|
* the same photo after a reboot).
|
|
*/
|
|
esp_err_t epd_write_frame(epd_read_fn_t read_fn, void *ctx, uint32_t *out_crc32);
|
|
|
|
/**
|
|
* Triggers the panel's physical refresh cycle (power on, refresh, power
|
|
* off) -- the visible flash/flicker sequence. Call after epd_write_frame()
|
|
* to make the written buffer visible.
|
|
*/
|
|
esp_err_t epd_turn_on_display(void);
|
|
|
|
/** Convenience wrapper around epd_display_stream() for an in-memory frame buffer. */
|
|
esp_err_t epd_display_buffer(const uint8_t *frame, size_t len);
|
|
|
|
/** Puts the panel into deep sleep to minimize power draw between refreshes. */
|
|
esp_err_t epd_sleep(void);
|