From 35f462ecc8e1fcd84b36ccba7c04fdaf75fa63c3 Mon Sep 17 00:00:00 2001 From: Kaj Schittecat Date: Sun, 18 Oct 2026 14:38:11 +0200 Subject: [PATCH] touch: OTA update no longer trips the task watchdog while it waits (#689) otaWorkerRun streamed the image with Update.writeStream(), which reads through Stream::timedRead: that spins without yielding until HTTPClient's 20 s timeout. The OTA runs on the core-0 tile worker, so a slow start starved IDLE0 and the 5 s task watchdog rebooted the device: "stuck at 0%, then a restart" on a T-Deck Plus (#689). The image is now copied by hand through an internal 4 KB buffer, waiting with vTaskDelay and yielding after every block, giving up after 15 s without data (the same loop as the SD download). Co-Authored-By: Claude Opus 5.5 --- src/ui-touch/UITask.cpp | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 55e91cd..11eb828 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -34691,8 +34691,39 @@ static void otaWorkerRun(WiFiClient& client, HTTPClient& http) { Update.onProgress([](size_t done, size_t total) { s_ota_pct = total ? (int)((uint64_t)done * 100 / total) : 0; }); + // Copy by hand, yielding, instead of Update.writeStream(): that reads through + // Stream::timedRead, which spins without yielding until http's 20 s timeout, so a + // slow start starved IDLE0 on this core-0 worker and the 5 s task watchdog + // rebooted the device, "stuck at 0%, then a restart" (#689). Same loop as the SD + // download below: wait with vTaskDelay, give up after 15 s without data. auto* stream = http.getStreamPtr(); // NetworkClient* on arduino 3.x (P4: C6Client behind it) - const size_t written = stream ? Update.writeStream(*stream) : 0; + size_t written = 0; + { + size_t bufsz = 4096; + uint8_t* buf = (uint8_t*)heap_caps_malloc(bufsz, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (!buf) { bufsz = 1024; buf = (uint8_t*)heap_caps_malloc(bufsz, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); } + unsigned long last_data = millis(); + while (buf && stream && written < (size_t)len) { + const int avail = stream->available(); + if (avail <= 0) { + if (!http.connected() || (millis() - last_data) > 15000) break; + vTaskDelay(pdMS_TO_TICKS(10)); + continue; + } + const size_t want = ((size_t)avail > bufsz) ? bufsz : (size_t)avail; + const int n = stream->read(buf, want); + if (n <= 0) { + if ((millis() - last_data) > 15000) break; + vTaskDelay(pdMS_TO_TICKS(5)); + continue; + } + last_data = millis(); + if (Update.write(buf, (size_t)n) != (size_t)n) break; // flash write failed: reported below + written += (size_t)n; + vTaskDelay(1); // let IDLE0 (and Wi-Fi) run between blocks + } + if (buf) heap_caps_free(buf); + } http.end(); if (written != (size_t)len) { snprintf(s_ota_msg, sizeof s_ota_msg, "short read %u/%d", (unsigned)written, len);