From 7afe6b7d17124ede3b1a69d49c7f16d8c93754b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Sun, 4 Oct 2026 02:08:28 +0200 Subject: [PATCH] OTA: keep new images on Probation; Arduino validated them before setup() Arduino-ESP32's initArduino() marks a PENDING_VERIFY image valid unless the sketch overrides the weak verifyRollbackLater(). Every update was therefore VALID before bootGuard() or Probation ever ran (otadata read back state 0x2 on a crash-looping test build), and nothing rolled back. The bootloader was never the problem. Override it to return true, so Probation decides. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- lib/ota/src/probation.h | 2 +- src/main.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/ota/src/probation.h b/lib/ota/src/probation.h index d507cfe..e5cb3d5 100644 --- a/lib/ota/src/probation.h +++ b/lib/ota/src/probation.h @@ -14,7 +14,7 @@ class Probation { // Checked first thing at boot, before anything that could crash. `attemptsBefore` counts earlier // boots of this image on Probation; a second start means the first one died before confirming. - // (The prebuilt bootloader doesn't roll back by itself, so the firmware does.) + // (A second line behind the bootloader's own rollback, which aborts an image still pending.) static bool rollBackAtBoot(bool onProbation, int attemptsBefore) { return onProbation && attemptsBefore >= 1; } static Verdict judge(uint32_t uptimeMs, bool firstFrameDrawn, bool wifiConfigured, bool wifiConnected) { diff --git a/src/main.cpp b/src/main.cpp index 7ee1b70..f11cdc0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,6 +90,10 @@ static StatusInfo currentStatus() { return s; } +// Arduino-ESP32 marks a new image valid before setup() unless this returns true. Probation +// (UpdateService::tick) decides instead, and an unconfirmed image stays PENDING_VERIFY. +extern "C" bool verifyRollbackLater() { return true; } // C linkage, or the weak default wins + void setup() { nvs.begin(); UpdateService::bootGuard(nvs); // first: before anything that could crash on new firmware