diff --git a/include/config.h b/include/config.h index 6555c0342..5e14fbf1b 100644 --- a/include/config.h +++ b/include/config.h @@ -50,8 +50,6 @@ constexpr double kDefaultRadarLon = 4.9041; /** Poll adsb.fi (API public limit: 1 req/s). */ constexpr unsigned long kAdsbFetchIntervalMs = 3000; -/** Legacy scale unused — fetch uses radar::fetchRadiusKm() to screen edge. */ -constexpr float kAdsbFetchRadiusScale = 1.0f; /** false = hide aircraft with alt_baro "ground"; true = show them too. */ constexpr bool kAdsbShowGroundAircraft = false; diff --git a/include/services/adsb_client.h b/include/services/adsb_client.h index 2b5dd787c..ff750c602 100644 --- a/include/services/adsb_client.h +++ b/include/services/adsb_client.h @@ -27,4 +27,7 @@ void setPollFn(PollFn fn); /** Fetch aircraft within fetch_radius_km of center_lat/lon from adsb.fi. */ bool fetchUpdate(double center_lat, double center_lon, float fetch_radius_km); +/** millis() of the last successful fetch (0 = never). */ +unsigned long lastSuccessMs(); + } // namespace services::adsb diff --git a/include/ui/radar_range.h b/include/ui/radar_range.h index a95c53275..291f167f4 100644 --- a/include/ui/radar_range.h +++ b/include/ui/radar_range.h @@ -39,7 +39,6 @@ void rangeInit(); /** Cycle preset and save to flash. */ void rangeNext(); const RangePreset& rangeCurrent(); -uint8_t rangeIndex(); /** ADSB fetch radius (km): scaled to screen edge so beyond-ring dots have data. */ float fetchRadiusKm(); diff --git a/src/services/adsb_client.cpp b/src/services/adsb_client.cpp index dcbbfcbea..ba9147011 100644 --- a/src/services/adsb_client.cpp +++ b/src/services/adsb_client.cpp @@ -21,6 +21,7 @@ constexpr unsigned long kRequestTimeoutMs = 10000; Aircraft s_aircraft[kMaxAircraft]; size_t s_aircraft_count = 0; PollFn s_poll_fn = nullptr; +unsigned long s_last_success_ms = 0; void pollNetwork() { if (s_poll_fn != nullptr) { @@ -30,8 +31,8 @@ void pollNetwork() { int performGetWithPoll(HTTPClient& http) { http.setConnectTimeout(kConnectAttemptMs); - const unsigned long deadline = millis() + kRequestTimeoutMs; - while (millis() < deadline) { + const unsigned long start = millis(); + while (millis() - start < kRequestTimeoutMs) { pollNetwork(); const int code = http.GET(); if (code > 0) { @@ -58,8 +59,8 @@ bool readResponseBodyWithPoll(HTTPClient& http, String& payload) { } uint8_t buffer[512]; - const unsigned long deadline = millis() + kRequestTimeoutMs; - while (millis() < deadline) { + const unsigned long start = millis(); + while (millis() - start < kRequestTimeoutMs) { pollNetwork(); const int available = stream->available(); if (available > 0) { @@ -276,8 +277,11 @@ bool fetchUpdate(double center_lat, double center_lon, float fetch_radius_km) { } s_aircraft_count = n; + s_last_success_ms = millis(); Serial.printf("adsb: %u aircraft\n", static_cast(n)); return true; } +unsigned long lastSuccessMs() { return s_last_success_ms; } + } // namespace services::adsb diff --git a/src/ui/radar_display.cpp b/src/ui/radar_display.cpp index 3ececd6e8..57fde604f 100644 --- a/src/ui/radar_display.cpp +++ b/src/ui/radar_display.cpp @@ -46,9 +46,6 @@ const lgfx::GFXfont* s_tag_gfx = &fonts::FreeSansBold12pt7b; bool s_tag_label_metrics_ready = false; bool s_tag_use_vlw = false; -int s_scale_label_max_w = 0; -int s_scale_label_h = 0; - lgfx::LovyanGFX* s_draw = &tft; LGFX_Sprite s_frame(&tft); bool s_frame_ready = false; @@ -135,21 +132,6 @@ void initLabelMetrics() { s_scale_use_vlw = false; } - applyScaleStyle(); - s_scale_label_h = tft.fontHeight(); - s_scale_label_max_w = 0; - char label[12]; - for (size_t i = 0; i < radar::kRangePresetCount; ++i) { - for (bool miles : {false, true}) { - radar::formatRing3Label(label, sizeof(label), radar::kRangePresets[i].ring3_km, - miles); - const int w = tft.textWidth(label); - if (w > s_scale_label_max_w) { - s_scale_label_max_w = w; - } - } - } - s_label_metrics_ready = true; } @@ -382,7 +364,6 @@ void applyTagStyle() { } int measureTagBlockWidth(const services::adsb::Aircraft& plane) { - applyTagStyle(); int max_w = 0; if (plane.callsign[0] != '\0') { const int w = s_draw->textWidth(plane.callsign); @@ -406,9 +387,6 @@ int measureTagBlockWidth(const services::adsb::Aircraft& plane) { } void drawAircraftTag(int x, int y, const services::adsb::Aircraft& plane) { - initTagLabelMetrics(); - applyTagStyle(); - const int line_h = s_draw->fontHeight(); const int block_w = measureTagBlockWidth(plane); const int block_h = line_h * 3; @@ -488,7 +466,13 @@ void sortBeyondDotsFarFirst(BeyondDotDrawItem* items, size_t count) { void drawAircraft() { initLabelMetrics(); - const size_t n = services::adsb::aircraftCount(); + // Stale data (no successful fetch recently) shows an empty scope rather + // than aircraft frozen at their last known positions. + constexpr unsigned long kAircraftStaleAfterMs = 15000; + const size_t n = + (millis() - services::adsb::lastSuccessMs() > kAircraftStaleAfterMs) + ? 0 + : services::adsb::aircraftCount(); const services::adsb::Aircraft* planes = services::adsb::aircraftList(); AircraftDrawItem items[services::adsb::kMaxAircraft]; @@ -531,6 +515,8 @@ void drawAircraft() { drawBeyondRingDot(dots[d].x, dots[d].y); } + initTagLabelMetrics(); + applyTagStyle(); // once per frame; tag text metrics stay valid below sortDrawItemsFarFirst(items, draw_count); for (size_t d = 0; d < draw_count; ++d) { const size_t i = items[d].index; @@ -651,7 +637,6 @@ void drawStaticGrid(Gfx& gfx) { gfx.fillScreen(radar::kColorBackground); drawRings(cx, cy, grid_r); drawCrosshairs(cx, cy, grid_r, radar::kColorGrid); - initPalette(); runway::drawLargeAirportRunways(gfx); drawCenterDot(cx, cy); drawCardinalLabels(); diff --git a/src/ui/radar_range.cpp b/src/ui/radar_range.cpp index d8bf002e2..bf7b1d9f2 100644 --- a/src/ui/radar_range.cpp +++ b/src/ui/radar_range.cpp @@ -80,8 +80,6 @@ void rangeNext() { const RangePreset& rangeCurrent() { return kRangePresets[s_range_index]; } -uint8_t rangeIndex() { return s_range_index; } - float fetchRadiusKm() { const float outer_km = rangeCurrent().outer_km; const float screen_r_px = diff --git a/src/ui/runway_overlay.cpp b/src/ui/runway_overlay.cpp index d32828551..c7d04fdd5 100644 --- a/src/ui/runway_overlay.cpp +++ b/src/ui/runway_overlay.cpp @@ -145,20 +145,21 @@ bool segmentIntersectsDisc(int x0, int y0, int x1, int y1) { const int dy = y1 - y0; const int fx = x0 - cx; const int fy = y0 - cy; - const int a = dx * dx + dy * dy; - if (a == 0) { + const float a = static_cast(dx) * dx + static_cast(dy) * dy; + if (a == 0.0f) { return false; } - const int b = 2 * (fx * dx + fy * dy); - const int c = fx * fx + fy * fy - r_sq; - int disc = b * b - 4 * a * c; - if (disc < 0) { + const float b = 2.0f * (static_cast(fx) * dx + static_cast(fy) * dy); + const float c = static_cast(fx) * fx + static_cast(fy) * fy - + static_cast(r_sq); + const float disc = b * b - 4.0f * a * c; + if (disc < 0.0f) { return false; } - disc = static_cast(sqrtf(static_cast(disc))); - const float inv2a = 1.0f / (2.0f * static_cast(a)); - const float t0 = (-static_cast(b) - disc) * inv2a; - const float t1 = (-static_cast(b) + disc) * inv2a; + const float sq = sqrtf(disc); + const float inv2a = 1.0f / (2.0f * a); + const float t0 = (-b - sq) * inv2a; + const float t1 = (-b + sq) * inv2a; return (t0 >= 0.0f && t0 <= 1.0f) || (t1 >= 0.0f && t1 <= 1.0f); }