Public Access
Keep ESP32 OTA reachable whatever the firmware does
- Rollback: override verifyRollbackLater() so a new OTA image stays pending until it ran 60 s with WiFi; any earlier restart rolls back (the Arduino core marked every image valid at boot before) - Task watchdog (30 s) on loop(), paused during OTA uploads - Crash counter in RTC memory: OTA-only window after a crash, 10 min safe mode (WiFi + OTA only) after 3 crashes in a row - Restart when WiFi stays down for 10 min - Home Assistant sensor 'FlipDot Display Firmware' with version/state - logic/boot_policy with tests (60 tests total) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
683a47c055
commit
ddbdf7e65f
14 files changed
+517
-42
No files matched your search
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
#include "logic/boot_policy.h"
|
||||
#include "logic/display_controller.h"
|
||||
#include "logic/power_timer.h"
|
||||
#include "logic/schedule.h"
|
||||
@@ -171,6 +172,81 @@ void test_timer_across_millis_overflow()
|
||||
TEST_ASSERT_TRUE(t.expired(0x00000100u));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Boot policy (keeping OTA alive)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void test_power_on_starts_normally_and_clears_crashes()
|
||||
{
|
||||
BootDecision d = decideBoot(ResetKind::PowerOn, 2);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::Normal);
|
||||
TEST_ASSERT_EQUAL(0, d.crash_count);
|
||||
}
|
||||
|
||||
void test_software_reset_starts_normally_and_keeps_count()
|
||||
{
|
||||
// e.g. the restart after an OTA update
|
||||
BootDecision d = decideBoot(ResetKind::Software, 1);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::Normal);
|
||||
TEST_ASSERT_EQUAL(1, d.crash_count);
|
||||
}
|
||||
|
||||
void test_other_reset_starts_normally_and_keeps_count()
|
||||
{
|
||||
BootDecision d = decideBoot(ResetKind::Other, 2);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::Normal);
|
||||
TEST_ASSERT_EQUAL(2, d.crash_count);
|
||||
}
|
||||
|
||||
void test_first_crashes_give_a_panic_window()
|
||||
{
|
||||
BootDecision d = decideBoot(ResetKind::Crash, 0);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::PanicWindow);
|
||||
TEST_ASSERT_EQUAL(1, d.crash_count);
|
||||
d = decideBoot(ResetKind::Crash, d.crash_count);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::PanicWindow);
|
||||
TEST_ASSERT_EQUAL(2, d.crash_count);
|
||||
}
|
||||
|
||||
void test_repeated_crashes_give_safe_mode()
|
||||
{
|
||||
uint8_t count = 0;
|
||||
BootDecision d = {BootMode::Normal, 0};
|
||||
for (int i = 0; i < SAFE_MODE_CRASHES; i++)
|
||||
{
|
||||
d = decideBoot(ResetKind::Crash, count);
|
||||
count = d.crash_count;
|
||||
}
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::SafeMode);
|
||||
}
|
||||
|
||||
void test_after_safe_mode_one_more_crash_gives_safe_mode_again()
|
||||
{
|
||||
uint8_t count = crashCountAfterSafeMode();
|
||||
TEST_ASSERT_TRUE(decideBoot(ResetKind::Software, count).mode == BootMode::Normal);
|
||||
TEST_ASSERT_TRUE(decideBoot(ResetKind::Crash, count).mode == BootMode::SafeMode);
|
||||
}
|
||||
|
||||
void test_crash_count_does_not_overflow()
|
||||
{
|
||||
BootDecision d = decideBoot(ResetKind::Crash, 255);
|
||||
TEST_ASSERT_EQUAL(255, d.crash_count);
|
||||
TEST_ASSERT_TRUE(d.mode == BootMode::SafeMode);
|
||||
}
|
||||
|
||||
void test_new_firmware_needs_time_and_wifi_to_be_accepted()
|
||||
{
|
||||
TEST_ASSERT_FALSE(shouldMarkFirmwareValid(FIRMWARE_VALID_TIME - 1, true));
|
||||
TEST_ASSERT_FALSE(shouldMarkFirmwareValid(FIRMWARE_VALID_TIME, false));
|
||||
TEST_ASSERT_TRUE(shouldMarkFirmwareValid(FIRMWARE_VALID_TIME, true));
|
||||
}
|
||||
|
||||
void test_crash_count_cleared_after_running_long_enough()
|
||||
{
|
||||
TEST_ASSERT_FALSE(shouldClearCrashCount(CRASH_FREE_TIME - 1));
|
||||
TEST_ASSERT_TRUE(shouldClearCrashCount(CRASH_FREE_TIME));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Status LED
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -348,6 +424,16 @@ int main()
|
||||
RUN_TEST(test_timer_cancel);
|
||||
RUN_TEST(test_timer_across_millis_overflow);
|
||||
|
||||
RUN_TEST(test_power_on_starts_normally_and_clears_crashes);
|
||||
RUN_TEST(test_software_reset_starts_normally_and_keeps_count);
|
||||
RUN_TEST(test_other_reset_starts_normally_and_keeps_count);
|
||||
RUN_TEST(test_first_crashes_give_a_panic_window);
|
||||
RUN_TEST(test_repeated_crashes_give_safe_mode);
|
||||
RUN_TEST(test_after_safe_mode_one_more_crash_gives_safe_mode_again);
|
||||
RUN_TEST(test_crash_count_does_not_overflow);
|
||||
RUN_TEST(test_new_firmware_needs_time_and_wifi_to_be_accepted);
|
||||
RUN_TEST(test_crash_count_cleared_after_running_long_enough);
|
||||
|
||||
RUN_TEST(test_led_off_while_display_off);
|
||||
RUN_TEST(test_led_blinks_slow_with_wifi_and_fast_without);
|
||||
|
||||
|
||||
Reference in new issue
Block a user