Skip to content

[xvtr] Add XVTR diagnostic logging for waterfall mapping#1964

Merged
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/xvtr-diagnostic-logging
Apr 25, 2026
Merged

[xvtr] Add XVTR diagnostic logging for waterfall mapping#1964
ten9876 merged 1 commit intoten9876:mainfrom
jensenpat:aether/xvtr-diagnostic-logging

Conversation

@jensenpat
Copy link
Copy Markdown
Collaborator

Summary

This is stacked on #1960 and adds the logging/diagnostic layer for the XVTR waterfall work.

  • Log parsed XVTR status with index, order, name, RF/IF frequencies, computed offset, rx-only, max power, is_valid, whether the current status contained is_valid, and whether this session has ever seen is_valid.
  • Add a raw-command-debug-gated WaterfallXVTR decision log for out-of-pan waterfall rows. It is rate-limited to one line per stream/pan/reason every 20 seconds, with immediate output when the decision state changes.
  • Log band-stack XVTR selection/refusal with the chosen Flex band= key and available XVTR candidates.
  • Add parsed XVTR state to the troubleshooting snapshot and issue summary.
  • Expose XVTR offset match details from XvtrPolicy so diagnostics and tests share the same decision metadata.

Why

The recent XVTR/waterfall debugging showed that raw protocol logs were not enough by themselves. We could see xvtr ... is_valid=... when command logging was enabled, but we could not easily answer:

  • Did the app parse is_valid, or was the key absent?
  • Which XVTR entry and setup order did the band switch use?
  • Did a waterfall row shift because the IF/RF offset matched, because an XVT antenna fallback authorized it, or did it stay unchanged because there was no XVTR evidence?
  • What XVTR state was present in a troubleshooting snapshot after the fact?

This PR keeps the noisy waterfall decision logging behind the existing raw command/debug gate, while making low-volume XVTR status and support snapshot state easier to inspect.

Validation

  • cmake -S . -B build -G Ninja
  • cmake --build build --parallel 10
  • ./build/xvtr_policy_test
  • ctest --test-dir build --output-on-failure -j10 reports no registered tests in this build tree

Stack

Parent PR: #1960

Logging-only comparison: jensenpat/AetherSDR@aether/xvtr-policy-regression-tests...aether/xvtr-diagnostic-logging

👨🏼‍💻 Generated with OpenAI Codex (GPT-5.5 Pro 4/23) and tested by @jensenpat

@jensenpat jensenpat changed the title [xvtr] Add diagnostic logging for waterfall mapping [xvtr] Add XVTR diagnostic logging for waterfall mapping Apr 25, 2026
@jensenpat jensenpat marked this pull request as ready for review April 25, 2026 16:07
@jensenpat jensenpat requested a review from ten9876 as a code owner April 25, 2026 16:07
Copy link
Copy Markdown
Contributor

@aethersdr-agent aethersdr-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good diagnostic logging layer on top of the #1960 policy extraction. The rate-limited waterfall decision log with state-change detection is well thought out, and including XVTR state in the troubleshooting snapshot will save real debugging time. A few observations:

static QHash in logXvtrWaterfallDecision — thread safety

MainWindow.cpp around line 241: logStateByStream is a static QHash inside a free function. Since waterfall tile callbacks arrive on the VITA-49 stream thread (not the GUI thread), this static is mutated from at least two contexts without synchronization. In practice today this is likely fine because the lambda capturing the call site runs on the main thread via QueuedConnection, but if the connection type ever changes or this function gets called from a background path, this becomes a data race. Worth a brief comment noting the single-thread assumption, or switching to a member variable on MainWindow to make the lifetime/thread ownership explicit.

xvtrPolicyBandsFrom allocates on every waterfall tile

The conversion xvtrPolicyBandsFrom(m_radioModel.xvtrList()) is called inside the waterfall tile lambda (line ~1721) and again in the band-switch path (line ~8271). In the waterfall path this runs per tile per panadapter match. For the typical case (0-3 XVTRs) this is negligible, but worth noting — if someone configures many XVTRs and has multiple waterfall streams, the QVector allocation per tile adds up. Not a blocker, just something to be aware of for future optimization if profiling shows it.

formatXvtrBulletQString::arg with >9 positional args

SliceTroubleshootingDialog.cpp line ~108: The format string uses %10 which with Qt's QString::arg chaining will work correctly here because the args are applied sequentially. Just noting for future maintainers that this is at the edge of arg()'s positional numbering — adding an 11th field would need the multi-arg overload or split formatting.

hasIsValid field addition — good

The hasIsValid field on XvtrInfo (RadioModel.h:574) cleanly distinguishes "radio says is_valid=0" from "radio never sent is_valid". This is exactly the kind of diagnostic metadata that was missing. The sticky-true semantics (x.hasIsValid = true once seen) are correct for a session-scoped flag.

Scope check

All files are within the stated PR scope (XVTR diagnostic logging + snapshot). CMakeLists.txt changes are limited to adding the new source and test target. No out-of-scope modifications detected.

Tests

The test target follows the existing passive_spots_policy_test pattern (standalone, no CTest registration, Qt6::Core only). Consistent with the project approach.

Overall this is a clean logging-only addition with good rate limiting and structured diagnostic output. Thanks for the thorough PR description and validation steps, @jensenpat.

@ten9876 ten9876 force-pushed the aether/xvtr-diagnostic-logging branch from 128c43b to 7080a2f Compare April 25, 2026 16:53
@ten9876
Copy link
Copy Markdown
Owner

ten9876 commented Apr 25, 2026

Hey @jensenpat — Claude here. Rebased your branch onto current main since #1960 just merged. Squashed the two commits into one (the regression-tests commit had a duplicate xvtrPolicyBandsFrom definition after dedup against the squash-merged #1960; the diagnostic-logging commit then removed the dup). Squashing avoided the broken intermediate state for bisect.

Authorship + commit message preserved. Build verified locally before push.

Once CI clears we'll review the diagnostic-logging delta and merge.

73, Jeremy KK7GWY & Claude (AI dev partner)

@ten9876 ten9876 merged commit e9f6217 into ten9876:main Apr 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants