From a758f148dbc63d4100e0445fca3d61917bee5a79 Mon Sep 17 00:00:00 2001 From: "torlando-agent[bot]" <281092095+torlando-agent[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:46:55 +0000 Subject: [PATCH] fix: bound map request failure latency --- .../Hardware/TDeck/MapTileHttpArduino.cpp | 9 ++++++++ .../Hardware/TDeck/MapTileHttpArduino.h | 1 + lib/tdeck_ui/UI/LXMF/MapScreen.cpp | 21 +++++++++++++++---- lib/tdeck_ui/UI/LXMF/MapScreen.h | 1 + .../test_map_tile_downloader_contract.py | 5 +++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.cpp b/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.cpp index b7ef9b39..dda59946 100644 --- a/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.cpp +++ b/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.cpp @@ -99,6 +99,15 @@ void MapTileHttpArduino::close() { content_type_[0] = '\0'; } +void MapTileHttpArduino::disconnectIdle() { + client_.stop(); + http_.end(); + stream_ = NULL; + remaining_ = -1; + open_ = false; + content_type_[0] = '\0'; +} + MapTileMillisClock::MapTileMillisClock() : previous_(millis()), high_(0U) {} std::uint64_t MapTileMillisClock::nowMs() const { const std::uint32_t current = millis(); diff --git a/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.h b/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.h index a001ac3e..466e1ba6 100644 --- a/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.h +++ b/lib/tdeck_ui/Hardware/TDeck/MapTileHttpArduino.h @@ -25,6 +25,7 @@ public: virtual TileTransportResult read(std::uint8_t* output, std::size_t capacity, std::size_t& count, bool& eof); virtual void close(); + void disconnectIdle(); private: WiFiClientSecure client_; HTTPClient http_; diff --git a/lib/tdeck_ui/UI/LXMF/MapScreen.cpp b/lib/tdeck_ui/UI/LXMF/MapScreen.cpp index cc138ce4..b48f2aa9 100644 --- a/lib/tdeck_ui/UI/LXMF/MapScreen.cpp +++ b/lib/tdeck_ui/UI/LXMF/MapScreen.cpp @@ -77,7 +77,8 @@ MapScreen::MapScreen(lv_obj_t* parent) download_config_(makeDownloadConfig()), downloader_(download_store_, download_transport_, download_clock_, download_policy_, download_config_), - downloads_enabled_(false), decode_failed_keys_{}, decode_failed_generations_{}, + downloads_enabled_(false), download_failed_frame_epoch_(0U), + decode_failed_keys_{}, decode_failed_generations_{}, compressed_staging_(nullptr), state_mutex_(nullptr), worker_task_(nullptr), stop_requested_(false), worker_exited_(true), worker_started_(false), store_initialized_(false), @@ -313,10 +314,13 @@ void MapScreen::workerLoop() { completion.slot_index = request.slot_index; completion.key = request.key; completion.result = loadTile(request); + bool frame_drained = false; if (lockState(portMAX_DELAY)) { (void)presenter_.publishCompletion(completion); + frame_drained = presenter_.requestCount() == 0U; unlockState(); } + if (frame_drained) download_transport_.disconnectIdle(); } worker_exited_.store(true, std::memory_order_release); vTaskDelete(nullptr); @@ -360,6 +364,9 @@ Pyxis::MapTileLoadResult MapScreen::downloadTile( const bool enabled = downloads_enabled_.load(std::memory_order_acquire); downloader_.setEnabled(enabled); if (!enabled) return Pyxis::MapTileLoadResult::MISS; + if (download_failed_frame_epoch_ == request.frame_epoch) { + return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED; + } Hardware::TDeck::MapTileDownloadResult ignored{}; while (downloader_.takeResult(ignored)) {} @@ -383,6 +390,7 @@ Pyxis::MapTileLoadResult MapScreen::downloadTile( } if (stale) { (void)downloader_.cancelGeneration(request.frame_epoch); + download_transport_.disconnectIdle(); } (void)downloader_.pump(); if (downloader_.isBusy()) vTaskDelay(pdMS_TO_TICKS(1)); @@ -393,11 +401,16 @@ Pyxis::MapTileLoadResult MapScreen::downloadTile( if (result.generation == request.frame_epoch && result.key.zoom == request.key.zoom && result.key.x == request.key.x && result.key.y == request.key.y) { - return result.code == Hardware::TDeck::MapTileResultCode::SUCCESS - ? Pyxis::MapTileLoadResult::READY - : Pyxis::MapTileLoadResult::DOWNLOAD_FAILED; + if (result.code == Hardware::TDeck::MapTileResultCode::SUCCESS) { + return Pyxis::MapTileLoadResult::READY; + } + download_failed_frame_epoch_ = request.frame_epoch; + download_transport_.disconnectIdle(); + return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED; } } + download_failed_frame_epoch_ = request.frame_epoch; + download_transport_.disconnectIdle(); return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED; } diff --git a/lib/tdeck_ui/UI/LXMF/MapScreen.h b/lib/tdeck_ui/UI/LXMF/MapScreen.h index de1e56e4..8e2eb8c8 100644 --- a/lib/tdeck_ui/UI/LXMF/MapScreen.h +++ b/lib/tdeck_ui/UI/LXMF/MapScreen.h @@ -87,6 +87,7 @@ private: Hardware::TDeck::MapTileDownloadConfig download_config_; Hardware::TDeck::MapTileDownloader downloader_; std::atomic downloads_enabled_; + std::uint32_t download_failed_frame_epoch_; Hardware::TDeck::TileKey decode_failed_keys_[TILE_COUNT]; std::uint32_t decode_failed_generations_[TILE_COUNT]; std::uint8_t* compressed_staging_; diff --git a/tests/build_scripts/test_map_tile_downloader_contract.py b/tests/build_scripts/test_map_tile_downloader_contract.py index 9e6c04e0..3cc2985c 100644 --- a/tests/build_scripts/test_map_tile_downloader_contract.py +++ b/tests/build_scripts/test_map_tile_downloader_contract.py @@ -37,6 +37,8 @@ def test_https_adapter_verifies_peer_with_explicit_ca_and_has_no_credentials(): assert "setTimeout" in source assert "setReuse(true)" in source assert "useHTTP10(true)" not in source + assert "disconnectIdle" in source + assert "client_.stop()" in source for forbidden in ("Authorization", "Cookie", "username", "password", "SD.begin", "format(", "LittleFS"): assert forbidden not in source @@ -71,6 +73,9 @@ def test_downloader_is_explicitly_opt_in_and_wired_only_for_visible_misses(): assert "downloadTile(request)" in screen assert "downloader_.enqueue(request.key, request.frame_epoch)" in screen assert "presenter_.frameEpoch() != request.frame_epoch" in screen + assert "download_failed_frame_epoch_ == request.frame_epoch" in screen + assert "presenter_.requestCount() == 0U" in screen + assert "download_transport_.disconnectIdle()" in screen assert 'KEY_MAP_DOWNLOAD = "map_dl"' in settings assert "prefs.getBool(KEY_MAP_DOWNLOAD, false)" in settings assert "Download map tiles:" in settings