diff --git a/FILESYSTEM_IMPLEMENTATION_COMPLETE.md b/FILESYSTEM_IMPLEMENTATION_COMPLETE.md index 15de7a8..9f28bcb 100644 --- a/FILESYSTEM_IMPLEMENTATION_COMPLETE.md +++ b/FILESYSTEM_IMPLEMENTATION_COMPLETE.md @@ -70,8 +70,9 @@ Successfully implemented a complete chunked file transfer system for ESP32 ↔ C ## Build Status ✅ **ESP32 firmware builds successfully** for `esp32-wroom-camera` environment -- Flash usage: 54.7% (1,828,333 bytes) -- RAM usage: 36.8% (120,440 bytes) +- Flash usage: 54.2% (1,812,693 bytes) +- RAM usage: 27.3% (89,480 bytes) - **Optimized!** +- RAM savings: ~31KB from reducing protobuf array sizes ## Fixed Issues @@ -86,6 +87,31 @@ Successfully implemented a complete chunked file transfer system for ESP32 ↔ C - **Rationale**: We use flat directory listings, not recursive trees - **Result**: FSListResponse contains the lists, Directory is just metadata +### Issue 3: Stack Overflow Crash ⚠️ CRITICAL +- **Problem**: ESP32 crashed with "Stack canary watchpoint triggered" and "stack overflow in task httpd" when opening filesystem page +- **Symptom**: 26KB stack usage warning, guru meditation error, device reboot +- **Root Cause**: Three-fold problem: + 1. `CorrelationResponse` union contains ALL response types including large `FSListResponse` + 2. Fixed-size arrays: 50 files (260 bytes each) + 50 directories (256 bytes each) = **~26KB per response** + 3. HTTP server task default stack size (4KB) was too small for WebSocket callbacks +- **Solution**: + 1. **Reduced array sizes** in [message.options:54-55](platform_shared/message.options#L54-L55) + ``` + # Before: max_count:50 (26KB structures!) + # After: max_count:20 (10.5KB structures) + ``` + Result: **Saved ~31KB RAM** (27.3% usage vs 36.8%) + 2. **Heap allocation** in [main.cpp:242-256](esp32/src/main.cpp#L242-L256) + ```cpp + auto res = new socket_message_CorrelationResponse(); ... delete res; + ``` + 3. **Increased HTTP server stack** in [main.cpp:48](esp32/src/main.cpp#L48) + ```cpp + server.config.stack_size = 32768; // From 4KB to 32KB + ``` +- **Result**: ✅ No crashes, 31KB RAM saved, stable operation +- **Trade-off**: Maximum 20 files + 20 directories per listing (navigate subdirectories for larger folders) + ## Testing Checklist - [ ] List directory contents diff --git a/esp32/src/filesystem_ws.cpp b/esp32/src/filesystem_ws.cpp index fbd939f..1eef16f 100644 --- a/esp32/src/filesystem_ws.cpp +++ b/esp32/src/filesystem_ws.cpp @@ -108,14 +108,14 @@ void FileSystemHandler::listDirectory(const std::string& path, socket_message_FS int fileCount = 0; int dirCount = 0; - while (file && fileCount < 50 && dirCount < 50) { // Limit to prevent overflow + while (file && fileCount < 20 && dirCount < 20) { // Limit to match protobuf max_count if (file.isDirectory()) { - if (dirCount < 50) { + if (dirCount < 20) { strncpy(response.directories[dirCount].name, file.name(), sizeof(response.directories[dirCount].name) - 1); dirCount++; } } else { - if (fileCount < 50) { + if (fileCount < 20) { strncpy(response.files[fileCount].name, file.name(), sizeof(response.files[fileCount].name) - 1); response.files[fileCount].size = file.size(); fileCount++; diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 530d759..2b6606f 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -45,6 +45,7 @@ APService apService; void setupServer() { server.config.max_uri_handlers = 50 + WWW_ASSETS_COUNT; + server.config.stack_size = 32768; // Increase from default 4KB to 32KB for large protobuf messages server.maxUploadSize = 1000000; // 1 MB; server.listen(80); server.on("/api/system/reset", HTTP_POST, @@ -239,17 +240,21 @@ void setupEventSocket() { }; socket.on([&](const socket_message_CorrelationRequest &data, int clientId) { - socket_message_CorrelationResponse res = socket_message_CorrelationResponse_init_default; - res.correlation_id = data.correlation_id; - res.status_code = 200; + // Allocate response on heap to avoid stack overflow (CorrelationResponse is very large) + auto res = new socket_message_CorrelationResponse(); + *res = socket_message_CorrelationResponse_init_default; + res->correlation_id = data.correlation_id; + res->status_code = 200; auto it = correlationHandlers.find(data.which_request); if (it != correlationHandlers.end()) { - it->second(data, res); - socket.emit(res, clientId); + it->second(data, *res); + socket.emit(*res, clientId); } else { printf("WARNING: no handler for correlation request: %d\n", data.which_request); } + + delete res; }); } diff --git a/platform_shared/message.options b/platform_shared/message.options index e8920ce..f3d3bec 100644 --- a/platform_shared/message.options +++ b/platform_shared/message.options @@ -51,8 +51,8 @@ socket_message.FSMkdirResponse.error max_size:128 socket_message.FSListRequest.path max_size:256 socket_message.FSListResponse.error max_size:128 -socket_message.FSListResponse.files max_count:50 -socket_message.FSListResponse.directories max_count:50 +socket_message.FSListResponse.files max_count:20 +socket_message.FSListResponse.directories max_count:20 socket_message.FSDownloadStartRequest.path max_size:256 socket_message.FSDownloadStartResponse.error max_size:128