Overview
v1.6 introduces major DX tracking enhancements, new award widgets, real-time alerts, and improved REST API support.
New Features
DX Operations Suite
- DX Enhancements — Complete suite of DX cluster features and optimizations
- Improved entity tracking and display
- Enhanced visual feedback for DX activity
- LoTW QSO & ADIF Map Pin Enhancements — Map pin visualization improvements
- ADIF/LoTW Map Pin Hover Tooltips: Hovering over world map pins displays a tooltip showing the callsign, date, band, and mode of the contact, dynamically validated against active band/mode filters.
-
LoTW QSO Map Toggle: Added "LOTW QSOs" checkbox in the Map View options menu to toggle the display of LoTW QSO map pins, persisted as
showLotwQsosin AppConfig. -
DX Info Manual Entry — Manual target selection with callbook integration
- Enter DX callsigns directly via a centered modal dialog (auto-uppercasing)
- Automatic location lookup via
api.hamdb.org(CallbookProvider) for accurate grid/coordinates - Visual Feedback: Widget border highlights amber when the manually-entered callsign appears in live DX Cluster spots (30s auto-fade)
-
Resolves location for hams who have moved but kept their original call prefix
-
DX Pedition UI — Enhanced DX Pedition tracking
- Active status indicator for active peditions
- Date display for expedition context
-
K-Index alert thresholds for band condition awareness
-
WAS Progress Widget — Work All States award tracking
- Visual representation of worked/confirmed states
- Real-time updates from ADIF logs
-
State-by-state status display
-
WAC Radar Widget — Work All Continents award tracking
- 6-segment pie chart visualization (NA, SA, EU, AF, AS, OC)
- Color-coded status: Gray (default), Yellow (worked), Cyan (confirmed)
-
Polar coordinate rendering via new RenderUtils primitives
-
Zone Heatmap Widget — Work All Zones award tracking
- Dual-mode grid display: CQ zones (1–40) and ITU zones (1–75)
- Color-coded cells: Gray (default), Yellow (worked), Cyan (confirmed)
- Click title to toggle between CQ and ITU modes
-
Work/confirm summary stats
-
DX ATNO Alerts — Real-time "All-Time New One" detection
- Live detection of needed DXCC entities from DX cluster spots
- Ephemeral, high-contrast alert banners on map overlay
- Voice notification: "New one! [CALL] on [MODE]"
- Dismissible via click on alert banner
-
Integrated through SDL event loop (AE_DX_ALERT)
-
LoTW Auto-Sync Widget — Automatic confirmation tracking
- Displays last sync time, synced QSO count, and connection status
- Background fetching from LoTW (ARRL) with 1-hour refresh cycle
- Self-registers for any display pane
- Completes the "Big Four" DX-chaser widgets (LoTW Overlay, Grid Tracker, Clublog, LoTW Sync)
Weather & Forecasting
- Global Weather Forecast Widget — Worldwide 7-day weather forecasting now available via Open-Meteo API (replaces US-only NWS provider).
- Works for any latitude/longitude without authentication or API key
- Displays high/low temperatures, weather conditions (clear sky, rain, snow, thunderstorm), and precipitation probability
- Single HTTP GET request every 4 hours (efficient, low-bandwidth)
- 14-period display: 7 days with day/night splitting for daytime-aware color dimming
- Non-US users no longer see "Loading..." indefinitely — global coverage now complete
Map Overlays
- Local Propagation Gauge — new map overlay appearing at the map bottom, showing the current MUF, LUF, and recommended bands for the DE station's location. Toggled via the Map View menu; saved to config (
showLocalPropGauge).
REST API Enhancements
- Custom RSS Feed Support — User-defined RSS feed ingestion via REST API
- Dynamic feed configuration
- Real-time feed updates
- Debug Memory Endpoint — Added
/debug/memoryendpoint returning cache RAM usage and item counts for troubleshooting.
Presets System Improvements
- DE Station Status Preset — New built-in preset for award tracking workflows
- DXCC, WAS, Grid, WAC, Zone Heatmap progress tracking
- LoTW Sync and ADIF Tracking for QSO management
- Band Conditions overlay for band awareness
- Factory Preset Deletion Tracking — User-deleted factory presets are remembered across app updates
- Deleted presets don't reappear when new presets are added
- Transparent persistence in
config.jsonviadeletedFactoryPresetsset - Presets Modal UX Improvements
- Expanded visible rows from 5 to 8
- Alphabetical sorting of preset list for quick navigation
- Fixed deletion integration to properly track factory presets
Core Improvements
- Global Volume Control — Adjustable audio levels (0-100) for alarms and TTS.
- Fixes volume resetting on Windows by explicitly managing SAPI voice levels.
- Dedicated slider in Setup -> Identity tab.
- Credit: Greg, N7IDB.
- Cache Statistics — Added texture, vertex, and command buffer usage stats to the SysInfoPanel to aid in debugging performance on high-density "Master Hub" deployments.
- Enable Debug API Build Option — Added a
--enable-debug-apibuild flag to all.shscripts inscripts/to enable building with the Debug API (ENABLE_DEBUG_API=ON) for local testing.
Technical Improvements
ADIF Tracking
- Extended ADIFStats to track:
- Worked/confirmed continents (6-way)
- Worked/confirmed CQ zones (1–40)
- Worked/confirmed ITU zones (1–75)
- ADIFProvider now parses CQZ and ITUZ tags from ADIF logs
Rendering Utilities
- New RenderUtils primitives for polar UI rendering:
drawPie()— filled pie segmentsdrawArcOutline()— arc outlines for polar charts
DX Cluster Integration
- DXClusterProvider now receives ADIFStore reference for real-time need detection
- PrefixManager methods leveraged for continent/DXCC lookups
- Event-driven alert dispatch via SDL user events
- Manual DX Tracking:
DXClusterDataStoreextended withwatchedCallandwatchedSpottedstate for persistent highlight tracking across UI refreshes - Callbook Integration:
CallbookProvider::lookup()enables asynchronous location resolution for manually entered calls viaapi.hamdb.org
LoTW Integration
- New
LoTWProviderservice for asynchronous ADIF fetching from ARRL servers - Configurable credentials (callsign/password) stored in
config.json - Integrated status reporting (Last Sync, Count, Status)
Weather Forecast Provider Migration
- OpenMeteoForecastProvider replaces US-only NWS provider for global 7-day forecasts
- New provider uses Open-Meteo daily endpoint (free, no auth, global coverage)
- Generates 14 periods from daily max/min: "Monday" (high, isDaytime=true) + "Monday Night" (low, isDaytime=false)
- WMO weather code → description mapping (identical to WeatherProvider)
- 4-hour cache TTL with periodic refresh in DashboardContext update loop
- Fires same
AE_FORECAST_DATA_READYevent;ForecastPanelUI fully backward-compatible - Removed
ForecastProvider.h/cpp(two-step NWS/points+/forecastAPI no longer needed)
VOACAP DE-DX UX
- X-axis reorientation — "Cartesian origin at now": current UTC hour at left edge, future hours rightward with 24-hour wrap-around. User always sees real-time propagation starting from the left margin without scanning for a floating cursor.
- Legend alignment — legend items centered under their corresponding graph columns; <10% reliability swatch changed from black to dark grey (64,64,64) for improved dark-theme readability.
- "Now" cursor — restored as a white vertical line at the left edge (column 0) for spot/band frequency intersection visualization.
Core Stability Improvements
- RAII Event Handler Migration — Refactored 20+ custom application event handlers in
DashboardContextfrom rawdeletepointers tostd::unique_ptr, eliminating potential memory leaks from exception paths and forgotten deallocations. - Provider Error Handling — Established Network Callback Policy banning blanket
catch (...)blocks. RefactoredNOAAProviderandForecastProviderto catch typedstd::exception, log errors viaLOG_E, and maintain UI valid state on network/parse failures. - UI Layout Constants — Added global layout constant definitions to
Constants.hto eliminate magic numbers throughout panel rendering, improving maintainability and reducing visual inconsistencies. - Defensive Type Safety — Hardened
SpaceWeatherPanelwith null-pointer guards on data store and font catalog access paths.
Hub Master Network & Memory Optimization
- Streaming Response Serialization — Replaced
res.set_contentwithres.set_content_providerin/api/hub/fetch, moving response body construction into an HTTP lambda to stream directly to client socket. Eliminates per-request 10MB+ string allocations and deep copies, reducing latency and transient heap pressure. - Conditional GET Caching — Modified
NetworkManager::fetchAsyncto preserve cache metadata (ETag, Last-Modified) when entries go stale. Enables correct Conditional GET (304 Not Modified) responses on re-request, preventing unnecessary full re-downloads during client restarts. - Force-Refresh Semantics — Updated client proxy logic to pass
max_age=0to/api/hub/fetch?force=truerequests, ensuring the Master actually fetches fresh upstream data instead of returning cached/stale content. - SharedString Memory Model — Replaced
std::stringwithSharedString(std::shared_ptr<const std::string>) throughout the NetworkManager and response-handling stack. Multiple concurrent clients can now stream from the exact same shared memory buffer, reducing per-client RAM from N × Size to 1 × Size. - Extended In-Process Cache — Increased
MAX_RAM_BYTESto 50MB and enabled automatic RAM-caching of large payloads (>512KB) on Hub Masters. Sequential client requests are served from memory instead of forcing redundant disk I/O and buffer reallocation, dramatically improving throughput during rapid client restarts. - Metadata-Only Validation — Implemented early cache validation in
/api/hub/fetchto return 304 responses without triggering disk reads if the Master's cached entry is fresh, further reducing I/O and latency. - Verification Results — Hub Master RAM usage stabilized at ~350–380 MB regardless of client restart patterns or concurrent map fetch requests (previously exhibited 443MB "crawl" during sequential restarts). Build verified clean; 304 Conditional GET behavior confirmed via logging.
- Network Caching & Reliability Overhaul — Overhauled NetworkManager caching to prevent unbounded metadata bloat: enforced a strict
MAX_CACHE_ENTRIEScap of 5,000 entries (evicting oldest), introduced metadata-only LRU tracking, bypassed RAM cache for files >512KB and image files (while maintaining disk caching), used binary-safewrite()for image persistence on disk, and replaced file write-time checks with robust epoch-independent timestamp parsing to prevent local cache bypass on application restart while protecting SOTA/POTA 7/30-day caches. - Memory Overhaul & Churn Reduction — Implemented a comprehensive memory overhaul: custom high-speed
isoToTimeTreplacesmktime/tzsetin LoTWActivityProvider; zero-allocationsplitCSVLineSVusingstd::string_viewfor processing massive SOTA/POTA CSVs; static thread-local buffers inRenderUtilsfor circles and polylines to eliminate frame-to-frame heap churn;std::moveoptimization inLoTWActivityStoreto avoid deep copies; throttledMoonPanelupdates to 60s.
Bug Fixes
UI Standards Compliance
- Theming Standards — SetupScreen_Appearance.cpp dimTimeInput and brightTimeInput (lines 163, 171) incorrectly used
themes.textDimfor inactiveBorder instead ofthemes.border. Fixed to enforce proper active/inactive state distinction across all input fields. - Text Input Standards — DXInfo manual entry modal replaced custom string input with TextInput class. Removed hard-coded background color
{64, 64, 64, 255}and replaced withthemes.rowStripe1. Implemented proper active/inactive border coloring:themes.accent(active) andthemes.border(inactive). Delegated keyboard/text handling to TextInput for proper cursor, selection, and clipboard support.
Memory Stability (Hub / Long-Running)
Note on verification: Memory issues in long-running Hub Masters are notoriously difficult to reproduce and confirm. Each fix required the Hub to run under realistic load for 6–24 hours before RSS trends stabilized enough to confirm the regression was gone. Short-run tests are insufficient — leaks and LRU desyncs only manifest after hundreds of cache eviction cycles or multiple screen-wake events.
- Screen Wake Memory Growth Eliminated — Hub instances running with
--softwarewere growing ~50MB of RSS per screen off→on cycle with no reclaim. Root causes: SDL KMSDRM page-flip chain disruption (fixed with periodic 2s black-frame keep-alive during screen-off) and glibc heap fragmentation from simultaneous large provider fetch burst on wake (fixed withmalloc_trim(0)after the 15-min cascade). - Software Renderer Texture Cache — Auto-detects
SDL_RENDERER_SOFTWAREat startup and reduces TextureManager LRU cache from 50 → 20 textures. Prevents up to ~120MB of unnecessary system RAM usage on hub hardware running without GPU. - NetworkManager RAM Counter Fix — Entry-count eviction path was not decrementing
totalRamBytes_for evicted entries that held body data, causing the RAM counter to inflate over time and triggering premature cache evictions. Fixed in bothfetchDirectand hub-client proxy loops. - VRAM Tracking Completeness —
propTexture_(two sizes) andauroraTexture_were created via rawSDL_CreateTexturewithoutMemoryMonitor::addVram(). VRAM stats in SysInfo now accurately reflect all allocated textures.
GPU Resource Management
- Per-frame texture leak in SetupScreen Services tab — renderText() return value discarded in SetupScreen_Services.cpp:97, leaking one GPU DMA buffer object per frame. Fixed by capturing and destroying via MemoryMonitor.
- VRAM accounting bypass in CloudProvider — Direct SDL_DestroyTexture() calls (3 locations) bypassed MemoryMonitor tracking, corrupting VRAM counters. All replaced with MemoryMonitor::destroyTexture() to maintain consistent texture lifecycle accounting.
C++ Safety & Stability
- C++ Safety Audit — Resolved multiple safety hazards identified during a deep audit:
- Async Fetch Robustness:
CallbookProvidernested callbacks refactored to prevent potential pointer dangling ifNetworkManageris re-initialized. - Web Server Locking: Audited HTTP route handlers in
WebServer_Routes.cppto ensuredataMutex_is consistently held before accessing shared service pointers. - Thread Shutdown Hygiene: Verified
NetworkManagerinflight_counter andalive_flag logic to ensure detached threads cannot accessthisafter object destruction. - Memory & Texture Leaks — Resolved high-frequency heap churn in the DX Cluster data processing path and a texture leak in the weather overlay system.
- Credential Persistence & Web API — Fixed persistence of service credentials in
config.jsonand synchronized the Web API to support remote credential management. - LoTW Auto-Sync Callback Wiring — Wired the
LoTWSyncPanelto theLoTWProvidercallback to display real sync time, QSO count, and connection status in the widget (fixing the issue where the panel was created but never received updates). - WSPR LiveSpots Empty Response Handling — Updated
LiveSpotProvider::fetchWSPR()to correctly treat 0-byte ClickHouse CSV responses as 0 active spots (a normal state for inactive locators) rather than flagging a network error. - Network Cache Double-Deduction — Fixed double-deduction of cache size when entries become stale, resolving the issue where
totalRamBytes_wrapped to exabytes. - 400 MB Memory Pressure Flush — Unified the
DashboardContextmemory heartbeat to a single 400 MB RSS threshold. AddedNetworkManager::clearRamCache()to purge heavy string buffers without losing cache indexes; incorporatedmalloc_trim(0)to return freed glibc heap pages to the kernel immediately on threshold breach. - libcurl Signal Crash (CURLOPT_NOSIGNAL) — Set
CURLOPT_NOSIGNAL=1across all four libcurl instantiation sites (NetworkManager,FccProvider,UpdateChecker). Resolves the "Unexpected error 9 on netlink descriptor 21" crash caused by signal interruptions during high-concurrency DNS lookups triggered by memory cache purges. - Network Thread Explosion & LRU Desync — Migrated all
NetworkManagerdetached threads to theWorkerServicethread pool (size =hardware_concurrency, capped 2–4) to prevent unbounded thread spawning under load. FixedclearRamCache()to purge both the metadata map and LRU list, eliminating zombie metadata that silently disabled the RAM cache. Fixed duplicate LRU insertions infetchDirectand hub-client proxy paths. Resolves 433 MB RSS "not dropping" on long-running Master Hub nodes. - DXClusterPanel Filter Regression — Fixed
update()short-circuit that silently ignored band/mode filter clicks after the memory-optimization refactor. The explicitforceUpdatepath (triggered by zeroinglastUpdate_inonMouseUp()) now bypasses the version check and regenerates rows correctly. - MapWidget Segfault on Early Interaction — Added null-pointer guards in
MapWidget::onMouseMoveandonMouseUpbefore dereferencingcurrentSpotSnapshot_andcurrentDxcSnapshot_; snapshots are now initialized immediately when stores are assigned viasetSpotStore/setDXClusterStore. Resolves a crash that could occur if the user moved the mouse before the first update tick. - DX Cluster Zombie Feed & Stale Ages — Added 60-second in-memory pruning inside active Telnet threads and a 10-minute idle watchdog that reconnects TCP loops on dead streams. Clock-drift tolerance (±30 min) prevents backdating of spots; receipt-time override forces immediate age start for future-timestamped spots.
- DX Cluster Parsing & Empty Grids — Implemented local Maidenhead grid resolution (
txGrid/rxGrid) fallback insideDXClusterProviderto correctly compute coordinates for spots provided by a central hub server with empty grid fields. Added standard ANSI escape sequence stripping to ensure robust prefix lookups even when connecting to colorized DX cluster telnet feeds. - Weather Forecast Windows Bug — Fixed a cross-platform mismatch in
std::get_timebehavior on Windows (MSVC) causing repeating Sundays in the forecast widget. Replaced withstd::mktimeto accurately compute the weekday. - UpdateChecker Thread UAF — Fixed a Use-After-Free crash in
UpdateCheckerby explicitly tracking and canceling the detached download thread during destruction instead of leaving it running. - Concurrent mbedTLS Corruption (SIGABRT) — Serialized
curl_easy_performinNetworkManagerto prevent concurrent background thread fetches from corrupting non-thread-safe static mbedTLS state, eliminating random SIGABRT crashes on ARM platforms. - WASM Build Compatibility — Fixed build issues for WebAssembly/Emscripten environments.
Known Issues
- DX alert banner offset (+100px) may clip on very small windows (no bounds check)
Contributors
- Dave (K4DRW)
Migration Notes
For Users:
- Manual DX Entry: Click anywhere on the DX Info widget to open the manual callsign entry dialog.
- Zone Heatmap widget now available in widget selector
- LoTW Auto-Sync widget provides real-time confirmation status
- New award tracking widgets complement existing progress displays
- DX alerts appear automatically when cluster provides new entities
- Presets: New "DE Station Status" preset available in Presets modal (★ button); factory presets deleted by users won't reappear on future updates
For Developers:
- New ADIF tracking requires ADIF file re-scan or cache clear
LoTWProviderimplements standard background fetch pattern with status caching- DXClusterProvider constructor signature changed (added ADIFStore parameter)
- Event handler required for AE_DX_ALERT (see DashboardContext for pattern)