Never physically refresh the panel with a short/wrong-size frame

Found on hardware: the Tools Server field was pointed at Immich's own
port instead of the frame server's, so /frame/image was actually hitting
Immich and getting back a small error response (~10KB) instead of a
192,000-byte frame. epd_display_stream() logged a size-mismatch warning
but called epd_turn_on_display() anyway, physically refreshing the panel
with a buffer that was ~95% whatever was left over from before -- visible
as "garbage" on screen, overwriting a previously-good image.

epd_display_stream() now returns ESP_ERR_INVALID_SIZE instead of
refreshing when the stream doesn't supply exactly EPD_FRAME_BYTES. Since
this check happens before epd_turn_on_display() is ever called, the
pixel data that *did* arrive only ever reached the panel's internal RAM
over SPI, not the physically visible display, so aborting here leaves the
screen exactly as it was.

This also means fetch_and_display() failing now always implies the panel
was never touched -- simplified frame_client_run() accordingly (dropped
the now-always-true/false out-param that used to distinguish "failed
before vs. during streaming", and always shows the FAILED status screen
on any fetch/display error, since it's now guaranteed safe to do so).
This commit is contained in:
2026-07-18 16:38:43 -04:00
parent 55d4b28f37
commit 51fbd0657c
2 changed files with 23 additions and 19 deletions
+11 -1
View File
@@ -234,7 +234,17 @@ esp_err_t epd_display_stream(epd_read_fn_t read_fn, void *ctx)
EPD_CHECK(err);
if (total != EPD_FRAME_BYTES) {
ESP_LOGW(TAG, "Stream supplied %u bytes, expected %u", (unsigned)total, (unsigned)EPD_FRAME_BYTES);
/* Whatever was received has already been clocked into the panel's
* internal RAM over SPI, but epd_turn_on_display() (the actual
* physical refresh trigger) hasn't been called yet -- returning
* here instead leaves the visible screen exactly as it was, rather
* than refreshing onto a mostly-garbage buffer. Confirmed on
* hardware: a misdirected fetch that returned a ~10KB error page
* instead of a 192,000-byte frame still triggered a refresh before
* this check existed, painting garbage over a previously-good image. */
ESP_LOGE(TAG, "Stream supplied %u bytes, expected %u -- aborting refresh",
(unsigned)total, (unsigned)EPD_FRAME_BYTES);
return ESP_ERR_INVALID_SIZE;
}
return epd_turn_on_display();