Two radios went in. A lot more came out.
This is the release where sdrtop stopped being a tool for the two devices I
happen to own, and it took three goes to get there: a way to reach the layouts,
a way to reach the hardware, and then a fairly long argument with a gain knob.
🧭 There is a menu
sdrtop had fifteen layouts and ten number keys to reach them with. You can see
the arithmetic. One layout never got a key at all, and ? opened a help overlay
that had been quietly wrong for several releases, because nothing tied it to the
keys the app actually handled.
Esc now opens a menu. Layouts are grouped into Command Rail, Lab,
Sweep and Micro, and each section has its own 1 to 9. The same nine
digits, four times over, instead of one row that had run out.
The key reference is a pane in that menu, and the test suite checks it against
the app's own dispatch in both directions. A key with no entry fails the build.
An entry for a key that no longer exists fails it too. The overlay it replaces
had no such check, which is exactly why it was wrong.
📡 It speaks SoapySDR
Airspy, SDRplay, PlutoSDR, LimeSDR, bladeRF, USRP, and SoapyRemote for a radio
on another machine. If libSoapySDR is installed, your devices appear in the
picker. If it is not, nothing changes and the same binary keeps working: it is
opened at runtime, not linked, so there is no new build dependency and no new
runtime requirement.
Which means I broke my own rule, the one that said hardware support lands
only after physical testing. It was a good rule. It was also why the answer was
always no.
What I did instead of pretending I had tested an Airspy:
- Nothing about your radio is hardcoded. Frequency range, sample rates, gain
elements, whether there is an AGC, the sample format and how many of its bits
mean anything: all asked at open. There is no device table in the source,
because a table would be me guessing about hardware I have never held. - What cannot be asked is refused, not invented. An undeterminable reading
says unavailable. It never falls back to a plausible number, a plausible
number being the single worst thing a measurement tool can produce. - Failures name the driver, the call and the driver's own error text.
Verified end to end on a HackRF through SoapyHackRF. Everything else is
unverified and the docs say so at some length. If you own one of these, an issue
either way is worth a great deal to me.
🎚 The gain is yours now
Then I sat down with one of those devices, and this is the part where the
release slipped.
Handing a driver a total and letting it decide the split is the standard thing
to do. On a HackRF through SoapyHackRF what it decides is to put most of it in
the VGA and leave the LNA low, which is the arrangement with the worst noise
figure of the ones available. It was also not monotonic. Turning the knob up
could make the LNA go down.
sdrtop no longer asks a driver to split anything.
↑/↓move the whole chain, filling the front stage first. Front first is
the arrangement with the best noise figure.,and.in the Command Rail pick one gain element by name, and then
↑/↓move that one alone. This is the only way to reach a third gain
element, and some radios have one.- The config says it in the same words:
gain = "LNA=32,VGA=20".
The names are the driver's, not mine. A radio that calls its stages IF1 and
IF2 gets rows labelled IF1 and IF2, because guessing which one is "really"
the LNA is the kind of bug that costs somebody an afternoon.
⏱ The timing bench was measuring the wrong thing
A HackRF pushes blocks at you and can be late. A SoapySDR device is read in a
loop and cannot be, because a slow reader simply waits less. There is no
deadline to miss.
The bench had been grading pull traffic against a deadline that does not exist,
which is how a perfectly healthy link came to report a permanent USB overload.
It now measures the opposite quantity: how much of each read cycle went on
working rather than waiting. Low is healthy.
The verdict names its own reason too, so a clock that is a few hundred ppm off
no longer shares a grade and a sentence with a link that is genuinely losing
samples. Those two are not remotely the same problem and they used to look
identical.
📐 And the RF bench learned to measure
The bench had gone nearly blank on anything that was not a HackRF, because the
whole panel was gated on knowing the chain's noise figures stage by stage. Only
two of its blocks need that. The level line-up, the staging advice and the
verdict are measured, not modelled, and they work on any radio that names its
stages. Those two blocks now say which fact is missing and why, and everything
else stays.
Then a new one. Press K and sdrtop runs a measurement rather than
reporting one: it walks the front gain stage across its settings and watches
what the noise floor does. What comes back is the knee, the lowest gain at
which your radio's front end rather than its converter decides how faint a
signal you can hear. Under it you are throwing sensitivity away. Over it you are
only spending headroom. About five seconds.
It moves the way physics says it should, which was a relief. On my HackRF the
knee sat at LNA 24 dB on a busy FM channel and 32 dB on a quiet stretch of UHF,
same afternoon, same antenna: a quieter band needs more gain before the front
end clears the converter. That is why the panel always names the frequency it
measured at.
It is not a noise figure and it says so on screen. A noise figure needs a
known source at the input, which sdrtop has no way to provide and no way to ask
you for.
📋 Upgrading
[radio].gain replaces lna_gain and vga_gain. The old fields still load and
still work, so your config opens exactly where you left it; they are simply no
longer written, and the first time you quit they become one gain line.
Nothing to do. This is the whole of the migration, and it is the reason this is
0.5.0 rather than 0.4.5.
The number keys changed meaning, though, so there is some muscle memory to
re-learn. Esc shows you what they mean now.
cargo install sdrtop --lockedOr the installer, which resolves libhackrf and librtlsdr through whatever
package manager your machine has and builds from source when the prebuilt binary
cannot run there.
As ever: if something looks broken, it is either a bug or an undocumented
feature. Flip a coin, then open an issue. ❤️
Full Changelog: v0.4.2...v0.5.0