From c4cd9b73e819580de9270dde666da5018fee0fbd Mon Sep 17 00:00:00 2001 From: Thomas Faour Date: Sat, 18 Jul 2026 23:59:48 -0400 Subject: [PATCH] Invalidate the tracked display CRC when a non-photo screen is drawn The QR onboarding and "CONNECTING..." status screens write to the panel through a separate path that never touched the last-displayed-photo CRC added in the previous commit. That left it stale relative to what's actually on screen after either one draws -- most visibly after a factory reset: reprovisioning and reconnecting could fetch a photo whose CRC happened to match the one from before the reset, skip the refresh, and leave the QR code frozen on screen indefinitely. Both screens now invalidate the tracked CRC right after drawing, so the next photo fetch is always guaranteed to actually refresh. --- firmware/main/qr_onboarding.c | 8 ++++++++ firmware/main/status_screen.c | 8 ++++++++ firmware/main/wifi_provisioning.c | 11 +++++++++++ firmware/main/wifi_provisioning.h | 10 ++++++++++ 4 files changed, 37 insertions(+) diff --git a/firmware/main/qr_onboarding.c b/firmware/main/qr_onboarding.c index 155f264..2674adc 100644 --- a/firmware/main/qr_onboarding.c +++ b/firmware/main/qr_onboarding.c @@ -8,6 +8,7 @@ #include "epd_draw.h" #include "fonts.h" #include "qrcodegen.h" +#include "wifi_provisioning.h" #include "qr_onboarding.h" @@ -105,5 +106,12 @@ esp_err_t qr_onboarding_show(const char *ssid, const char *password, const char err = epd_display_buffer(frame, EPD_FRAME_BYTES); free(frame); + if (err == ESP_OK) { + /* This just overwrote the panel with non-photo content -- the + * tracked last-displayed-photo CRC no longer describes what's + * actually on screen. */ + frame_config_invalidate_last_display_crc32(); + } + return err; } diff --git a/firmware/main/status_screen.c b/firmware/main/status_screen.c index d82d612..579b1d6 100644 --- a/firmware/main/status_screen.c +++ b/firmware/main/status_screen.c @@ -6,6 +6,7 @@ #include "epd7in3e.h" #include "epd_draw.h" #include "fonts.h" +#include "wifi_provisioning.h" #include "status_screen.h" @@ -58,5 +59,12 @@ esp_err_t status_screen_show(const char *wifi_ssid, status_state_t wifi_state, c esp_err_t err = epd_display_buffer(frame, EPD_FRAME_BYTES); free(frame); + if (err == ESP_OK) { + /* This just overwrote the panel with non-photo content -- the + * tracked last-displayed-photo CRC no longer describes what's + * actually on screen. */ + frame_config_invalidate_last_display_crc32(); + } + return err; } diff --git a/firmware/main/wifi_provisioning.c b/firmware/main/wifi_provisioning.c index 792280e..3f93021 100644 --- a/firmware/main/wifi_provisioning.c +++ b/firmware/main/wifi_provisioning.c @@ -167,6 +167,17 @@ void frame_config_set_last_display_crc32(uint32_t crc32) nvs_close(handle); } +void frame_config_invalidate_last_display_crc32(void) +{ + nvs_handle_t handle; + if (nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle) != ESP_OK) { + return; + } + nvs_erase_key(handle, "last_crc32"); + nvs_commit(handle); + nvs_close(handle); +} + static void generate_ap_password(char *out, size_t out_size) { size_t len = MIN(FRAME_AP_PASSWORD_LEN, out_size - 1); diff --git a/firmware/main/wifi_provisioning.h b/firmware/main/wifi_provisioning.h index 45654d2..1538444 100644 --- a/firmware/main/wifi_provisioning.h +++ b/firmware/main/wifi_provisioning.h @@ -57,6 +57,16 @@ esp_err_t frame_config_get_last_display_crc32(uint32_t *out); /** Records the CRC32 of the frame just displayed, for next time. */ void frame_config_set_last_display_crc32(uint32_t crc32); +/** + * Invalidates the tracked last-displayed-photo CRC. Call this whenever + * something other than a tracked photo fetch writes to the panel (status + * screens, QR onboarding) -- otherwise a later photo fetch that happens + * to produce the same CRC as whatever photo was showing *before* the + * panel got overwritten would wrongly skip refreshing back onto it, + * leaving the other screen stuck on-screen indefinitely. + */ +void frame_config_invalidate_last_display_crc32(void); + /** * Returns this device's provisioning AP identity: a fixed SSID (from * Kconfig) and a password that's generated once on first use and persisted