From 11bb56b4fc1cc02ab170ea7d852beb315647b1f2 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Fri, 22 May 2026 15:04:16 +0200 Subject: [PATCH] fix: HTTPS map tile loading with bounded polling loop Co-authored-by: Copilot --- include/graphics/map/URLService.h | 2 -- source/graphics/map/URLService.cpp | 51 ++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/include/graphics/map/URLService.h b/include/graphics/map/URLService.h index 38fb1db2..ac385150 100644 --- a/include/graphics/map/URLService.h +++ b/include/graphics/map/URLService.h @@ -4,7 +4,6 @@ #include #ifdef ARDUINO_ARCH_ESP32 -#include "HTTPClient.h" // not available on Linux/Portduino class URLService : public ITileService { @@ -16,7 +15,6 @@ class URLService : public ITileService virtual ~URLService(); private: - HTTPClient http; Callback saveCB = nullptr; }; diff --git a/source/graphics/map/URLService.cpp b/source/graphics/map/URLService.cpp index a7ddef97..cbfc6618 100644 --- a/source/graphics/map/URLService.cpp +++ b/source/graphics/map/URLService.cpp @@ -6,6 +6,7 @@ #ifdef ARDUINO_ARCH_ESP32 +#include "HTTPClient.h" // not available on Linux/Portduino #include "WiFi.h" // from ConvertPNG.c @@ -20,10 +21,7 @@ URLService::~URLService() {} bool URLService::load(const char *name, void *img) { - struct HttpEndGuard { - decltype(http) &client; - ~HttpEndGuard() { client.end(); } - } httpGuard{http}; + HTTPClient http; if (WiFi.status() != WL_CONNECTED) { ILOG_DEBUG("URLService::load skipped (WiFi not connected)"); @@ -42,7 +40,12 @@ bool URLService::load(const char *name, void *img) return false; } - http.begin(url.c_str()); + http.setReuse(false); + if (!http.begin(url.c_str())) { + ILOG_ERROR("ERROR begin %s", url.c_str()); + return false; + } + int httpCode = http.GET(); if (httpCode != HTTP_CODE_OK) { ILOG_ERROR("ERROR GET %s : %d", url.c_str(), httpCode); @@ -50,12 +53,14 @@ bool URLService::load(const char *name, void *img) } WiFiClient *stream = http.getStreamPtr(); - size_t len = http.getSize(); - if (len == 0) { + int contentLen = http.getSize(); + if (contentLen <= 0) { ILOG_WARN("GET %s : empty", url.c_str()); return false; } + size_t len = (size_t)contentLen; + uint8_t *pngImage = (uint8_t *)lv_malloc(len); LvFreeGuard pngGuard{pngImage}; if (!pngImage) { @@ -63,12 +68,40 @@ bool URLService::load(const char *name, void *img) return false; } - size_t bytesRead = stream->readBytes(pngImage, len); + // read .png file in chunks to increase reliability (avoid readBytes()) + size_t bytesRead = 0; + uint8_t idleSpins = 0; + const uint8_t maxIdleSpins = 3; + while (bytesRead < len) { + size_t available = stream->available(); + if (available == 0) { + if (++idleSpins > maxIdleSpins) { + break; + } + delay(5); + continue; + } + + idleSpins = 0; + size_t toRead = available; + size_t remaining = len - bytesRead; + if (toRead > remaining) { + toRead = remaining; + } + + int got = stream->read(pngImage + bytesRead, toRead); + if (got <= 0) { + break; + } + bytesRead += (size_t)got; + } + if (bytesRead != len) { ILOG_ERROR("http read error %s : %u != %u", url.c_str(), (unsigned int)bytesRead, (unsigned int)len); return false; } - ILOG_DEBUG("SUCCESS: GET %s (%u bytes)", url.c_str(), (unsigned int)bytesRead); + + ILOG_DEBUG("SUCCESS(%d): GET %s (%u bytes)", (int)idleSpins, url.c_str(), (unsigned int)len); // save png tile to SD card if (saveCB && MapTileSettings::saveOK()) {