From 4767be7c01684577c0db3fa24090d766046e9a4e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Jan 2026 23:12:56 +0000 Subject: [PATCH] Fix watchdog crashes during file uploads - Add esp_task_wdt_reset() calls throughout upload path: - Before/after SD card file creation (FAT allocation can be slow) - Before/after buffer flush writes - Every 64 iterations in handleClient loop - Reduce upload buffer from 8KB to 4KB - Keeps individual write times shorter - Reduces watchdog risk while maintaining batching benefit - Switch from time-based to iteration-based handleClient loop - More predictable behavior - 200 iterations with watchdog resets every 64 --- .../network/CrossPointWebServerActivity.cpp | 23 +++++++++---------- src/network/CrossPointWebServer.cpp | 11 ++++++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index 228f84d4..f22fd9b2 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -316,20 +317,18 @@ void CrossPointWebServerActivity::loop() { timeSinceLastHandleClient); } - // Time-based processing: handle requests for up to 50ms per loop iteration - // This is more efficient than a fixed iteration count because: - // 1. Processes more data when available (during uploads) - // 2. Returns quickly when idle (no wasted spinning) - // 3. yield() between calls lets WiFi stack receive more data - constexpr unsigned long TIME_BUDGET_MS = 50; - const unsigned long handleStart = millis(); - - while (webServer->isRunning() && (millis() - handleStart) < TIME_BUDGET_MS) { + // Process HTTP requests with watchdog safety + // Use iteration-based approach with watchdog resets to prevent crashes + // Higher iteration count improves throughput during uploads + constexpr int MAX_ITERATIONS = 200; + for (int i = 0; i < MAX_ITERATIONS && webServer->isRunning(); i++) { webServer->handleClient(); - // Yield between calls to let WiFi stack process incoming packets - // This is critical for throughput - without it, TCP flow control - // throttles the sender because our receive buffer fills up + // Yield every iteration to let WiFi stack receive more packets yield(); + // Reset watchdog every 50 iterations to prevent timeout during uploads + if ((i & 0x3F) == 0) { // Every 64 iterations + esp_task_wdt_reset(); + } } lastHandleClientTime = millis(); } diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 68db44f0..530c7c1c 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -304,8 +304,9 @@ static bool uploadSuccess = false; static String uploadError = ""; // Upload write buffer - batches small writes into larger SD card operations -// This improves throughput by reducing the number of SD write syscalls -constexpr size_t UPLOAD_BUFFER_SIZE = 8192; // 8KB buffer +// 4KB is a good balance: large enough to reduce syscall overhead, small enough +// to keep individual write times short and avoid watchdog issues +constexpr size_t UPLOAD_BUFFER_SIZE = 4096; // 4KB buffer static uint8_t uploadBuffer[UPLOAD_BUFFER_SIZE]; static size_t uploadBufferPos = 0; @@ -316,10 +317,12 @@ static size_t writeCount = 0; static bool flushUploadBuffer() { if (uploadBufferPos > 0 && uploadFile) { + esp_task_wdt_reset(); // Reset watchdog before potentially slow SD write const unsigned long writeStart = millis(); const size_t written = uploadFile.write(uploadBuffer, uploadBufferPos); totalWriteTime += millis() - writeStart; writeCount++; + esp_task_wdt_reset(); // Reset watchdog after SD write if (written != uploadBufferPos) { Serial.printf("[%lu] [WEB] [UPLOAD] Buffer flush failed: expected %d, wrote %d\n", millis(), uploadBufferPos, @@ -385,12 +388,14 @@ void CrossPointWebServer::handleUpload() const { SdMan.remove(filePath.c_str()); } - // Open file for writing + // Open file for writing - this can be slow due to FAT cluster allocation + esp_task_wdt_reset(); if (!SdMan.openFileForWrite("WEB", filePath, uploadFile)) { uploadError = "Failed to create file on SD card"; Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str()); return; } + esp_task_wdt_reset(); Serial.printf("[%lu] [WEB] [UPLOAD] File created successfully: %s\n", millis(), filePath.c_str()); } else if (upload.status == UPLOAD_FILE_WRITE) {