Harden USB logging and persist watchdog events in management reports

This commit is contained in:
mikecarper committed 2026-10-03 15:29:19 -07:00
1 parent bd55369aa9
commit 3add4695cc
98 files changed
+7207 -372

No files matched your search

+27 -27
View File
@@ -826,13 +826,13 @@ bool WebConfigServer::startSetupMode(char reply[]) {
const esp_err_t sta_protocol_result = esp_wifi_set_protocol(
WIFI_IF_STA, mesh::wifi::kProtocolMask);
if (ap_protocol_result == ESP_OK && sta_protocol_result == ESP_OK) break;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig protocol reset failed: AP=%d STA=%d\n",
(int)ap_protocol_result, (int)sta_protocol_result);
ap_ok = false;
}
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig AP attempt %u failed: mode_ok=%d disconnect_ok=%d mode=%d heap=%u largest=%u\n",
(unsigned)attempt, mode_ok, disconnect_ok, (int)WiFi.getMode(),
(unsigned)ESP.getFreeHeap(),
@@ -1038,7 +1038,7 @@ void WebConfigServer::tick(uint32_t now) {
break;
case WebConfigBatch::StopAction::Warn:
_stop_warned = true;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: stop waiting for %lu handler(s); retaining session safely\n",
(unsigned long)refs);
break;
@@ -1067,11 +1067,11 @@ void WebConfigServer::tick(uint32_t now) {
createServer();
_connect_deadline = 0;
_last_activity = now;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig ready: http://%s/\n",
WiFi.localIP().toString().c_str());
} else if (_connect_deadline && (int32_t)(now - _connect_deadline) >= 0) {
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: WiFi '%s' unavailable; opening setup AP\n", _wifi_ssid);
const bool retry_saved_wifi = _wifi_ssid[0] != 0;
// Keep the WiFi driver running while changing from STA to AP+STA.
@@ -1085,7 +1085,7 @@ void WebConfigServer::tick(uint32_t now) {
if (startSetupMode(ignored)) {
_retry_saved_wifi_in_setup = retry_saved_wifi;
}
mesh::usbLoggingPort().println(ignored);
mesh::usbDebugPort().println(ignored);
}
return;
}
@@ -1101,7 +1101,7 @@ void WebConfigServer::tick(uint32_t now) {
_wifi_reconnect_tracker.noteDisconnected(now);
if (_wifi_reconnect_tracker.retryDue(now)) {
_wifi_reconnect_tracker.noteAttempt(now);
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: WiFi still unavailable; retrying '%s'\n",
_wifi_ssid);
WiFi.mode(WIFI_STA);
@@ -1139,7 +1139,7 @@ void WebConfigServer::tick(uint32_t now) {
_wifi_reconnect_tracker.noteConnected();
_mode = MODE_LAN;
_last_activity = now;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: saved WiFi recovered; ready at http://%s/\n",
WiFi.localIP().toString().c_str());
} else if (_owns_wifi && _setup_reconnect_in_progress
@@ -1147,14 +1147,14 @@ void WebConfigServer::tick(uint32_t now) {
WiFi.disconnect(false, false);
_setup_reconnect_in_progress = false;
_setup_reconnect_deadline = 0;
mesh::usbLoggingPort().println(
mesh::usbDebugPort().println(
"WebConfig: saved WiFi still unavailable; setup AP remains active");
} else if (_owns_wifi && !_setup_reconnect_in_progress
&& _wifi_reconnect_tracker.retryDue(now)) {
_wifi_reconnect_tracker.noteAttempt(now);
_setup_reconnect_in_progress = true;
_setup_reconnect_deadline = now + 20000UL;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: retrying saved WiFi '%s'\n", _wifi_ssid);
mesh::wifi::beginStation(_wifi_ssid, _wifi_password);
}
@@ -1172,7 +1172,7 @@ void WebConfigServer::tick(uint32_t now) {
// Consume this request first so a full filesystem cannot turn tick() into
// a tight loop of repeated flush attempts.
_reboot_at = 0;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: rebooting now (%s)\n",
_batch_reboot_armed ? "confirmed" : "fallback");
_cb->rebootNow();
@@ -1180,7 +1180,7 @@ void WebConfigServer::tick(uint32_t now) {
if ((int32_t)(_diag_until - now) > 0 && (now - _diag_last) >= 1000) {
_diag_last = now;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: diag sta=%d heap=%u batch=%d/%d state=%d\n",
(int)WiFi.softAPgetStationNum(), (unsigned)ESP.getFreeHeap(),
(int)_batch_next, (int)_batch_count, (int)_batch_state);
@@ -1201,7 +1201,7 @@ void WebConfigServer::tick(uint32_t now) {
_mode == MODE_SETUP, _wifi_ssid[0] != 0, now,
_setup_started_at,
(uint32_t)WEBCONFIG_UNCONFIGURED_SETUP_TIMEOUT_MS)) {
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: WiFi still unconfigured after %lu minutes; powering off until reboot or explicit restart\n",
(unsigned long)((uint32_t)WEBCONFIG_UNCONFIGURED_SETUP_TIMEOUT_MS / 60000UL));
requestStop();
@@ -1232,7 +1232,7 @@ void WebConfigServer::tick(uint32_t now) {
_setup_reconnect_deadline = 0;
_mode = MODE_LAN;
_last_activity = now;
mesh::usbLoggingPort().println(
mesh::usbDebugPort().println(
"WebConfig: setup AP idle; saved WiFi recovery continues");
} else {
requestStop();
@@ -1268,7 +1268,7 @@ void WebConfigServer::serviceSetupWiFiHandoff(uint32_t now) {
_setup_wifi_handoff_pending = false;
_setup_wifi_handoff_deadline = 0;
}
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: joined '%s' at %s; waiting for browser handoff\n",
_wifi_ssid, ip);
finishBatch(now);
@@ -1297,7 +1297,7 @@ void WebConfigServer::serviceSetupWiFiHandoff(uint32_t now) {
_setup_wifi_handoff_deadline = 0;
_setup_wifi_handoff_ip[0] = 0;
}
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: could not join '%s'; setup AP remains active\n",
_wifi_ssid);
finishBatch(now);
@@ -1404,11 +1404,11 @@ void WebConfigServer::drainBatch(uint32_t now) {
// `set wifi.pwd` or `password` from the terminal must not reach the serial
// log, which is a different audience from the browser session.
if (_batch_kind == BATCH_CLI) {
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: cli %d/%d took %lums\n", (int)_batch_next,
(int)_batch_count, (unsigned long)(_batch_last_cmd - t0));
} else {
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: cmd %d/%d '%s' took %lums\n", (int)_batch_next,
(int)_batch_count, e.key,
(unsigned long)(_batch_last_cmd - t0));
@@ -1461,7 +1461,7 @@ void WebConfigServer::drainBatch(uint32_t now) {
// that will be shown to the operator before the setup AP is shut down.
WiFi.mode(WIFI_AP_STA);
WiFi.setAutoReconnect(false);
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WebConfig: testing saved WiFi '%s' before reboot\n", _wifi_ssid);
mesh::wifi::beginStation(_wifi_ssid, _wifi_password);
return;
@@ -1477,7 +1477,7 @@ void WebConfigServer::drainBatch(uint32_t now) {
// Distinguishes "client stopped sending" from "server stopped accepting" when
// a save's confirmation polls go missing on hardware.
static void wcLogReq(AsyncWebServerRequest* r) {
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: http %s %s\n", r->methodToString(), r->url().c_str());
}
@@ -2102,7 +2102,7 @@ void WebConfigServer::handleConfigPost(AsyncWebServerRequest* req) {
uint32_t du = millis() + 60000;
if (du == 0) du = 1;
_diag_until = du;
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: config POST accepted, %d cmds, reboot=%d\n",
count, (int)reboot_after);
@@ -2117,12 +2117,12 @@ void WebConfigServer::handleConfigPost(AsyncWebServerRequest* req) {
void WebConfigServer::handleConfigResult(AsyncWebServerRequest* req) {
if (_mode == MODE_OFF) {
mesh::usbLoggingPort().println("WC: result read -> 503 (mode off)");
mesh::usbDebugPort().println("WC: result read -> 503 (mode off)");
req->send(503);
return;
}
if (!checkAuth(req)) {
mesh::usbLoggingPort().println("WC: result read -> 401");
mesh::usbDebugPort().println("WC: result read -> 401");
req->send(401, "application/json", "{\"error\":\"auth\"}");
return;
}
@@ -2138,7 +2138,7 @@ void WebConfigServer::handleConfigResult(AsyncWebServerRequest* req) {
// Entry print BEFORE the lock (racy state read is fine for diag): if this
// fires but no branch print follows, the handler is blocked on _mux.
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: result entry mode=%d state=%d\n",
(int)_mode, (int)_batch_state);
WCLock lock(_mux);
@@ -2150,7 +2150,7 @@ void WebConfigServer::handleConfigResult(AsyncWebServerRequest* req) {
const WebConfigBatch::ResultOutcome outcome =
WebConfigBatch::classifyResult(toSpecState(_batch_state), mine);
if (outcome == WebConfigBatch::ResultOutcome::Idle) {
mesh::usbLoggingPort().println("WC: result read -> idle");
mesh::usbDebugPort().println("WC: result read -> idle");
StaticJsonDocument<64> idle;
idle["state"] = "idle";
idle["reqid"] = requested_reqid;
@@ -2172,7 +2172,7 @@ void WebConfigServer::handleConfigResult(AsyncWebServerRequest* req) {
req->send(200, "application/json", out);
return;
}
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: result read -> done (reboot=%d armed=%d all_ok=%d)\n",
(int)_batch_reboot, (int)_batch_reboot_armed,
(int)_batch_all_ok);
@@ -2557,7 +2557,7 @@ void WebConfigServer::handleCliPost(AsyncWebServerRequest* req) {
strncpy(_batch_reqid, reqid, sizeof(_batch_reqid) - 1);
_batch_reqid[sizeof(_batch_reqid) - 1] = 0;
_batch_state = BATCH_PENDING; // tick() picks it up on the loop task
mesh::usbLoggingPort().printf(
mesh::usbDebugPort().printf(
"WC: cli POST accepted, %d cmds, reboot=%d\n",
count, (int)defer_reboot);