BLE stability: desync connect cooldown prevents crash-on-connect

Add 30-second cooldown after NimBLE host desync recovery before
allowing new connection attempts. During desync, client->connect()
blocks waiting for a host-task completion event that never arrives,
causing WDT crashes. The cooldown skips connection attempts while
the host is desynced or recently recovered.

Also adds ESP reset reason logging at boot to diagnose crash types
(WDT, panic, brownout, etc.) in soak test logs.

Soak test results: Run 3 (before) had 17 reboots in ~4 hours with
a 12-crash-in-14-minutes loop. Run 4 (after) has 1 early reboot
then 19+ hours of continuous uptime with the same desync frequency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
torlando-tech
2026-03-03 18:34:40 -05:00
co-authored by Claude Opus 4.6
parent 74d832fb63
commit 2cc9441f0a
3 changed files with 34 additions and 0 deletions
+23
View File
@@ -1196,6 +1196,29 @@ void setup() {
INFO("╚══════════════════════════════════════╝");
INFO("");
// Log ESP reset reason — helps diagnose crashes in soak tests
{
esp_reset_reason_t reason = esp_reset_reason();
const char* reason_str = "UNKNOWN";
switch (reason) {
case ESP_RST_POWERON: reason_str = "POWERON"; break;
case ESP_RST_SW: reason_str = "SOFTWARE"; break;
case ESP_RST_PANIC: reason_str = "PANIC"; break;
case ESP_RST_INT_WDT: reason_str = "INT_WDT"; break;
case ESP_RST_TASK_WDT: reason_str = "TASK_WDT"; break;
case ESP_RST_WDT: reason_str = "WDT"; break;
case ESP_RST_DEEPSLEEP: reason_str = "DEEPSLEEP"; break;
case ESP_RST_BROWNOUT: reason_str = "BROWNOUT"; break;
case ESP_RST_SDIO: reason_str = "SDIO"; break;
default: break;
}
if (reason != ESP_RST_POWERON) {
WARNING("Reset reason: " + std::string(reason_str) + " (" + std::to_string(reason) + ")");
} else {
INFO("Reset reason: " + std::string(reason_str));
}
}
// Check for LXST crash breadcrumb from previous boot
{
Preferences _dbg;