sdroxide-brown

SDRoxide User Manual

SDRoxide is a PowerSDR/Thetis-style software-defined-radio transceiver. It gives you a panadapter and waterfall, dual VFOs, a full set of receive and transmit controls, FT8/FT4/FT2 digital modes with an integrated logbook, a wideband CW skimmer, and the ability to drive either a SoapySDR device or a CAT-controlled radio (such as a Xiegu, Icom, Yaesu, Kenwood, Elecraft, ELAD, an RS-HFIQ, or a QRP Labs QMX) with audio over a USB sound card. The same interface runs as a native desktop application, streams to a web browser, or connects to a remote sdroxide server.


Table of contents

  1. Feature overview
  2. Basic operation
  3. Digital modes (FT8, FT4, FT2, JT65, JT9, FST4, MSK144, FSK441, Q65, UVPACKET, JTTY, PSK31, RTTY, Olivia, THOR, FSQ, Hellschreiber, SSTV, RIFP, weather fax, JS8, RF Paint, WSPR, PI4, packet, APRS, ADS-B, NAVTEX, DSC, ACARS, VDL2, AIS, HFDL, AtCHAT NET)
  4. Skimmers (CW, PSK, RTTY)
  5. ISM band decoder (315 / 345 / 433 / 868 / 915 MHz devices)
  6. Settings
  7. Solar system 3D view
  8. Remote operation
  9. Web operation
  10. Spotting, awards, and QSL upload
  11. Winlink radio email
  12. Command-line reference
  13. Configuration files
  14. Troubleshooting
  15. Radio-specific notes
  16. Appendix: keyboard shortcuts, modes, bands
  17. Addendum: a headless station on a Raspberry Pi Zero 2 W

1. Feature overview

The main window: panadapter, waterfall, and the top control bar


2. Basic operation

2.1 Launching

Start the native application with no arguments to use your configured radio:

sdroxide

To try the interface with no hardware, use the built-in signal generator:

sdroxide --siggen

See the command-line reference for all options.

2.2 The main window

The window has two parts: a top control bar of captioned modules that reflow onto more rows as the window narrows, and the panadapter (spectrum plus waterfall) filling the rest of the window. In FT8/FT4/FT2 the lower part of the window is shared with the digital operating panel.

The top control bar modules

The control-bar modules, left to right, are: Frequency, S-meter, Band/Mode, VFO, RIT/XIT, Receiver + Filter/Noise, Rig (only on a radio with an aerial selector or a remote power switch), Transmit (TX-capable rigs only), Display, FFT, and System.

Copying a tooltip. Almost every control explains itself in a tooltip when the pointer rests on it. The text of a tooltip cannot be selected, so while one is on screen press Ctrl+C (⌘C on a Mac): its whole text goes to the clipboard, ready to paste into a translator, and a short Copied note appears by the pointer. With no tooltip on screen Ctrl+C does what it always does. This works in the desktop program and in the browser (the browser needs the page served over https to reach the clipboard); a phone has no Ctrl+C.

2.3 Tuning

The frequency readout is a ten-digit display. Hover over any digit and:

The smaller grey number below the readout is the inactive VFO’s frequency.

On the panadapter:

Bandwidth measurement tool

Keyboard tuning (ignored while typing in a text field):

Each of these lands on a multiple of its own step, so a dial left on an odd frequency by a drag is put back on a round one by the next key press. Wheel tuning does the same, and one notch of the wheel is one step of it.

Tuning on the panadapter, showing the VFO marker and filter passband

Band-plan strip. A colour-coded strip along the bottom of the waterfall (its top when the waterfall is flipped — see §2.8) labels the allocations. Zoomed out it shows coarse bands (ham, broadcast, CB, AM); zoomed into a ham band it splits into the CW / digital / SSB / beacon sub-segments, or an all-modes block where the plan gives one. When you zoom in close (a span of ~100 kHz or less), the digital sub-band is broken out into the individual popular modes — FT8, FT4, FT2, JS8, WSPR, QRSS, PSK, RTTY, SSTV, RIFP, FREEDV — each in its own colour.

Everything on the strip follows the IARU region on the General tab (6.1) — the ham blocks, their sub-segments, and the shortwave broadcast blocks that overlap an amateur band in one region and not another (3.900–4.000 and 7.200–7.300 are broadcasting in Regions 1 and 3 and amateur in Region 2).

Memory marks. Every stored memory whose frequency falls on the visible span is labelled just inside the band-plan strip, reading Mem: folder / name — or Mem: name for one that is not filed in a folder — on a thin green line drawn at the frequency itself. Channels close together stagger into stacked rows rather than overprinting; a name too long for its label is cut short with an ellipsis, and anything that would need a fifth row is left out.

Click a mark to recall that memory — dial, mode and filter together, exactly as pressing it in the memory list does; the label brightens as you point at it. Shift-click one to put the second receiver on its frequency instead, as shift-clicking anywhere else on the panadapter does. §2.12 is where a channel is stored, renamed and filed.

2.4 Bands and modes

Click the Band / Mode button (which reads, for example, 20M · USB) to open the band/mode popup. One list of every band and mode had grown past a screenful, so it is split into two halves, chosen by the LISTEN and OPERATE tabs at its top:

The band row of both tabs leads with HF · VHF · UHF · ALL. HF, VHF and UHF narrow which band buttons are shown — HF is everything below 30 MHz (longwave and medium wave included), VHF 30–300 MHz, UHF above that — and the lit chip toggles itself back to all. ALL is general coverage: it clears the band so the dial can go anywhere. The filter only hides buttons and never moves the dial.

On a desktop layout the popup’s DOCK chip keeps the selector open as a resizable column beside the waterfall rather than a popup that closes on the next click — handy while working a band plan or a set of channels. In the column, UNDOCK returns it to the popup and × hides it until the top-bar band chip brings it back; while docked, that chip toggles the column. Docking is offered on the desktop layouts alone: a window narrow enough to be a phone undocks and keeps the popup.

In the OPERATE tab a pair that cannot work is not offered: a mode that does not apply on the current band is greyed, with the reason on hover. FM broadcast is WFM alone, both airbands are AM, and 11 m is AM, NFM, SSB, CW and the WSJT-CB digital exchange — so AM is dead on the FM broadcast band and WFM is dead on 11 m. The engine refuses the same pair if a remote client sends it directly. The amateur allocations and general coverage take any mode; there, a band plan’s own segments are the only thing narrowing the choice. Selecting a band is never blocked this way — it is how you leave a service mode — and the band you pick adopts a mode that fits it, as the FM broadcast band has always come up WFM. The LISTEN tab is deliberately exempt from the rule: it offers every mode on every band, and the mode change goes through a command that skips the band check, because exploring is what that screen is for. Transmit legality is untouched — the band lockout and the TX rails still decide what may be keyed, and a mode that cannot transmit simply does not.

The OPERATE tab’s rows:

On a desktop or tablet layout the popup carries a DOCK chip. It moves the selector into a resizable column beside the waterfall so it stays open while you tune, instead of closing after every choice. UNDOCK in the column’s header returns it to the popup, and × hides the column — the Band / Mode button then shows and hides it. The column is 180 to 320 points wide and always leaves the waterfall at least 600, so docking needs a window of about 780 points or more, and never happens on a phone layout. In a narrower window the column is hidden and the Band / Mode button opens the popup again; widen the window and the column comes back.

The band and mode selector popup

See the appendix for what each mode is.

2.5 VFOs, split, and the sub-receiver

The VFO module has:

Each VFO keeps its own mode, its own filter width, and its own antenna. A VFO is a whole listening position rather than just a number — CW on A while B sits on an SSB net is what the pair is for — so switching between them puts the receiver into the mode that VFO was left in and back on the socket it was heard on, exactly as the A/B button on a transceiver does. Swap and Copy A to B move all of it along with the frequency: after a swap each VFO holds what the other one had, and after a copy B is A in every respect.

The antenna is remembered per band as well (6.2), and the two memories divide the work by what you have just done. An A/B press that stays inside one band keeps each VFO’s socket — Antenna A on a broadcast station and Antenna B on the amateur allocation below it is one band and two sockets, which the band memory alone cannot express. Crossing a band edge recalls the band’s socket instead, whether you got there by the dial or by pressing A/B onto a VFO parked on another band: which aerial hears 2 m is a fact about the station rather than about a VFO. Choosing a socket by hand is what writes the band’s entry, so the band always holds your last explicit choice on it.

Both VFOs, the mode and socket each was left in, and which of the two was selected are remembered per radio in session.json, so a station left listening on B — or set up for split, with the other VFO on the DX’s transmit frequency — comes back the same way at the next start rather than with B collapsed onto A. --freq and --mode still override the dial and the mode for a run, and they apply to whichever VFO was active.

The sub-receiver tunes independently of A/B: swapping VFOs or turning the dial leaves it where you parked it. Switching it on reveals a SUB module in the top bar with everything it has of its own:

On the panadapter the sub is drawn in violet, with the same passband wash, draggable filter edges and tuning line the main receiver has, labelled SUB. Drag inside its passband (or on its tuning line) to tune it — that drag moves the sub instead of panning the view, so each receiver is tuned by dragging its own filter area. Released mid-motion it coasts on like the main dial, stopping at the edge of the receiver’s span. Shift+click anywhere sends the sub straight there.

Both receivers are tuned by DDCs on the same IQ stream, so the sub can reach anything inside the receiver’s span and nothing outside it. A band change that moves the hardware out from under the sub re-parks it on the inactive VFO.

2.6 RIT and XIT

The RIT / XIT module offsets receive (RIT) and, on TX-capable rigs, transmit (XIT) without moving the dial. Toggle RIT (or XIT) on, then set the offset in the adjacent field (±9999 Hz in 5 Hz steps).

When either is enabled, the offset is drawn on the panadapter: RIT shows a dashed grey dial reference line (the receive marker and passband already sit at dial + RIT) with a blue labelled bracket back to the dial, and XIT shows a green TX marker line with a green labelled bracket from the transmit base to dial + XIT — so you can see at a glance how far RX and TX are shifted.

RIT/XIT visualization

On an SDR, all three offsets — RIT, XIT and split — are software: the receiver and transmitter are tuned inside the IQ stream and the hardware never moves. A CAT radio has no such stream, only its dial, so sdroxide puts them on the dial instead: it sits on your receive frequency (VFO + RIT) while you listen and moves to the transmit frequency (the other VFO when split is on, plus XIT) for the length of each over, then comes straight back. The radio’s frequency display follows, which is also how you can see it working. sdroxide switches the radio’s own RIT, XIT and split off when it connects, so an offset left over on the rig can’t quietly add itself to the one you set here.

The same box carries the DUPLEX and TONE buttons — the fourth thing that moves the transmit frequency, and what has to ride under it. See 2.18 Repeater operation.

2.7 Receiver controls

The receiver and its filter/noise controls share one box of two rows. Which row a button lands on is not fixed: the top row carries the level controls the radio offers — the volume, a front-end gain rail where there is a gain to set, decimation where there is a span to throw away, the AGC where the mode has one — and on a rig with few of those, the buttons from the row below move up to fill it rather than leave half the box empty and the box itself twice as wide as the strip can afford. So the same button can sit on the top row on a CAT rig and on the bottom row on an SDR with a gain slider, and it moves when you change mode. What is in the box never changes; only where the two rows are cut does.

The receive filter is set by dragging the passband edges directly on the panadapter: two vertical grip lines mark the filter’s low and high edges (they brighten to orange when you can grab them). Drag an edge to widen or narrow the passband. The grips work on both the spectrum and the waterfall.

For an exact figure, use the BW chip in the receive box instead — it reads the current width and opens three things: this mode’s presets (2.4k, 2.7k, 500, …), a width field in hertz, and the two edges, each of them typeable. A drag can only creep up on 2700 Hz; the field is where it is said. Changing the width keeps the passband where it is rather than moving the signal inside it: a channel about the carrier grows either side of it, CW and RTTY grow about the tone they are centred on, and on a sideband the cut nearest the carrier stays put while the far edge moves — which is what a transceiver’s own bandwidth control does. The presets are taken as written except in CW, where they are re-centred on your own sidetone pitch, so a 250 Hz filter is 250 Hz about the note you copy at rather than about somebody else’s 700.

In AM, SAM, DSB, ISB and the FM modes the two edges move together: the passband is a channel carved out about the carrier, both halves carry the same signal, and narrowing one alone would throw away half the audio while letting the interference on the other side straight through. So whichever grip you take sets the half width and the other edge mirrors it — which is also why every filter preset these modes offer is symmetric. In SSB, CW and the data modes the passband sits to one side of the carrier by definition and each edge stays yours to place on its own.

Hold Ctrl (Cmd on a Mac) while you drag and the mirroring is suspended for that drag: the grip you have hold of moves and the other stays where it is, even in the modes that normally pair them. That is the answer to a station splattering on one side of an AM carrier — close the passband on that side and leave the other open, trading half the audio for none of the interference. The figure beside the grip tells you which rule is in force: ±3000 Hz while the edges are paired, -3000 Hz while the one you are holding moves alone.

ISB is the odd one in that list. Its two edges move together like AM’s, but what they set is the width of each sideband rather than of one shared channel — the preset marked 2.7k gives you 2.7 kHz on each side, so 5.4 kHz of spectrum. The two sidebands are separate transmissions and are demodulated separately: the lower goes to your left ear and the upper to your right, the way they sit on the waterfall, and the ST indicator lights to say the two ears really are carrying different things. A residual carrier on the dial is notched out rather than let through as a hum in both. Noise reduction and the auto-notch turn ISB back into mono for as long as they are on, for the same reason they do to WFM stereo: they run on one channel of the pair and the delay would collapse the other into a comb filter. ISB is receive only — transmitting it needs two modulators feeding one linear amplifier, which is a station rather than a setting.

The volume, AGC mode and manual gain, the squelch, the noise reduction and the decimation are remembered in session.json and restored the next time you start, along with the front end’s own gain stages (§6.2.1). They are settings you arrive at by ear against your own antenna and noise floor, so sdroxide brings the receiver back up where you left it rather than on defaults.

The RIG box: the radio’s own aerial and power switches

A transceiver with an aerial selector, a separate receiving antenna, or a power switch sdroxide can reach over the control link, gets a RIG box of its own on the control bar — next to the receive controls on a desktop layout, and behind a RIG button in the menu strip on a narrow window. Like DIV and SUB, it appears only for hardware that has what it drives; a radio with one socket, no receive aerial and no remote power never sees it.

These are the same controls that live under Settings → Radio (§6.2.2), where the longer explanation of what each one needs from the radio is; they are here so that changing bands and reaching for the other aerial do not mean opening a dialog.

Per-mode settings (the reset chip)

The settings in this box are a matter of taste, but not the same taste in every mode: a little noise reduction helps a weak SSB voice and only gets in the way of an FT8 decoder, and a slow AGC is kinder to a signal sitting in the noise than the fast one that sounds right on a strong local. So each mode carries a set of starting values for AGC, Man, SQL, NR, ANC, BIN, WFM’s ST, and the receive tone and LOUDNESS of the EQ popup, and selecting a mode — here, or on a CAT rig’s own controls — lays its own on the receiver. The tone and LOUDNESS are off in every mode until you switch them on, so ticking LOUDNESS for a broadcast in AM leaves your SSB and FT8 exactly as they were.

The built-in defaults are deliberately plain. A slow AGC on the weak-signal digital modes, whose whole point is signals near the noise, and the stock medium everywhere else. Noise reduction off in every mode: it is the setting most dependent on your taste, it carries a make-up gain and can add artefacts, and changing mode should not change how loud the radio is — set it in the modes where you want it and it is remembered there. The squelch open and the notch off everywhere, the notch because it cancels constant tones and in CW, RTTY and the other FSK modes the signal is one. Nothing is re-applied to a mode you are already in, so a rig reporting its own mode back never disturbs a setting you have just made.

Change any of them and the change is remembered for the mode you were in, not globally: turn the noise reduction up on 20 m SSB and FT8 still comes up with it off. Put a setting back to the mode’s default and it stops being an override on its own. On the first start after upgrading to a version with per-mode settings, what you had set becomes the values for the mode you were in, and every other mode starts from its own defaults. When anything in the current mode has been changed, a chip with a circular arrow appears at the end of the filter/noise row: hovering it names what differs, and clicking it puts the mode’s own values back and forgets what you had set. Its place in the row is kept while it is hidden, so the box does not change width — and the strip does not rearrange itself — as it comes and goes. A station’s per-mode values live in modeprofiles.json beside its other per-radio files and travel with Settings → Import/Export; Settings → General → Per-mode settings has a RESET EVERY MODE button that clears them all at once.

2.8 The display and FFT controls

Display module:

VIEW module:

The waterfall colour scheme and the spectrum background gradient are set on the UI tab of the Settings window (see §6.3). The colour scheme is one of Classic, Viridis, Gray, Icom, Neon, Synthwave, Matrix, Tron, Amber, or Rainbow; the gradient fills the spectrum area from a top colour down to a bottom colour (default dark red → black) and can be turned off. The same tab also themes the UI itself — colour theme, button shape and window shape — independently of the waterfall’s palette; the screenshots in this manual show the Default theme.

The frequency-scale strip between the spectrum line and the waterfall is both a divider and an axis, and a drag on it picks one the moment it has a direction: up and down resizes the split between the two layers, sideways slides the band along under the picture. The sideways drag moves the window and never the dial — it is how to look somewhere else without leaving the frequency you are listening to — and once the view is the whole span it takes the receiver’s own centre with it, so it keeps going rather than stopping at the edge. Either layer can also be hidden altogether from the SPEC popup in the Display module.

The scale carries a labelled frequency every hundred points or so with unlabelled ticks between them, so a wide panadapter gets more markers to read against than a narrow one rather than the same handful stretched across it.

Waterfall colour schemes

Waterfall level

A thin vertical slider sits on the right edge of the panadapter, beside the waterfall: the SDR-style level control, without opening a popup.

It writes the same db_floor and db_ceil as the VIEW popup’s sliders and the keyboard bindings, so all of them agree. On a window too small to spare the column — a phone, or a very narrow pane — it is not shown, and the popup sliders are still there.

Panadapter detail

How many columns the panadapter and its waterfall are drawn with, on the detail row of the SPEC popup. AUTO is the default and is what nearly everyone should leave it on: it reads this machine’s graphics — the largest texture it will hold, whether it is drawing on a real GPU or in software, which renderer is in use, whether the radio is across a network — together with how wide the panadapter actually is in pixels, and picks the most the machine can carry. The number it settled on is shown beside the buttons.

The steps are 2048, 4096 and 8192 columns. 2048 is what every sdroxide before this one drew, and about what a 1080p panadapter can show; 4096 is one column per pixel of a 4K panel, which is the point of the setting; 8192 is two per pixel, which keeps a carrier sharp while the view is panned off the pixel grid. A step this machine cannot hold is shown greyed, with the reason on hover — a Raspberry Pi, an older graphics chip, a browser without WebGPU and a machine drawing without a GPU at all are all held to 2048, because a wider waterfall there costs the frame rate and buys a picture the renderer cannot draw anyway.

AUTO stops at 4096 even on a very large screen; 8192 is there to be chosen. AUTO also stays at 2048 when the radio is on the other end of a network, because every column is a byte in every frame — 4096 columns at 60 fps is about a quarter of a megabyte a second — and there is no way to measure the link from this end. On a LAN, set it by hand.

Detail costs memory on the graphics card: 8 MB per radio tab at 2048, 16 at 4096, 32 at 8192. Changing it restarts the waterfall’s history from black, once.

The 3D spectrum

The 3D button in the SPEC popup swaps the flat spectrum line for a receding surface: the newest spectrum lies across the front at full width, and the ones before it flow away from you, narrowing towards a vanishing point. The last few seconds of the band are on screen at once as a landscape — how many is the flow row below — so a carrier that comes and goes reads as a ridge with a length to it rather than as a line that twitches, and a signal a couple of dB out of the noise is a bump you can follow backwards in time. The waterfall says the same thing in colour; this says it in shape.

The 3D spectrum: the solid surface above, the line rendering below

The surface row picks between the two renderings:

The flow row sets how fast the surface travels: Slow (6 rows a second), Medium (12), Fast (24) or Faster (48). The surface is a fixed 48 rows deep, so this is also how much band it holds — eight seconds at Slow, one at Faster — and the two ends of the row are two different instruments. Slow is a memory: a signal that came up once in the last few seconds is still on screen to be looked at. Faster is a motion display: the surface moves visibly, which is what makes a fade or a keying pattern something you watch rather than something you infer. The rate is in rows a second and not rows a frame, so the picture is the same on a browser client at 30 fps as on a desktop at 60; past the frame rate the extra rows are copies, which is why the buttons stop where they do. The waterfall keeps its own scroll rate, and neither touches the other.

Both hide what is behind them, which is what makes the picture read as depth: a strong signal in front stands over the band it is covering, and a flat stretch in front lets the rows behind it show over the top. The dB scale down the left edge belongs to the front row — the newest spectrum — and so does everything else drawn on the spectrum: the passband wash, the filter edge grips and the tuning lines are kept to the front of the surface rather than cut through rows the filter was never set on. The flat grid and the PEAK HOLD trace both describe a single line and are not drawn at all while the surface is; the surface brings its own floor and its own amplitude axis instead.

This is drawn on the client — the browser client has it too, on the same buttons — and it is off by default. It is not free, and it is the one display here that can double the client’s own processor load: measured against the flat line on the same band, at 60 frames a second and a 1696-point-wide panadapter, 35% of a core for the flat line, 70% for the solid surface and 52% for the line one. Nothing reaches the radio, though — no extra work is asked of the engine, and nothing more goes over the link to a remote station, so a client that is struggling cannot slow the station down.

Waterfall scroll speed

How fast the waterfall scrolls, in lines a second, on the scroll row of the SPEC popup: Slow (5), Medium (28), Fast (56), Faster (112) or Fastest (224). Faster trades screen time for vertical resolution, which is what you want when a CW or FT8 trace is smearing into the line above it; Slow keeps several minutes of band on screen at once.

The two fastest settings are past the rate any screen redraws at, and that is deliberate: the radio clocks the waterfall’s lines itself rather than one per redraw, so 224 a second is 224 different lines rather than 56 of them drawn four times. Each line is also the strongest thing its slice of time contained rather than a snapshot at the end of it, so a CW dot or the edge of a burst that is shorter than the gap between two lines still gets drawn instead of falling between them.

What limits it is the receiver, not the screen. A line can never show more than one transform of the FFT, and a front end produces sample rate ÷ half the FFT size of those a second — an RX-888 at 8 MHz through a 32768-point window makes about 500, so it can feed any of these settings, while a 24 kHz I.F. through the same window makes under one and repeats lines at every setting. Two costs worth knowing: the waterfall keeps a fixed number of lines, so history shortens as the rate rises (73 seconds at Medium, 9 at Fastest), and to a remote client every line is a byte per column on the link.

2.9 The S-meter

The S-meter reads S0 (−127 dBm) through S9 (−73 dBm) and beyond, turning red past S9. It shows the S-unit (for example S9+20) and the level in dBm.

S-Meter calib (Settings → Radio, under Antenna is) corrects a meter that reads too high or too low, per radio: −5 to +5 S-units of 6 dB, 0 being the meter as measured. A noise floor shown at S5 where it should be S2 wants −3. Only the reading moves — the needle, the S and dBm figures, the level a reception report starts from and the spoken S-meter. The signal, the squelch, recording and the decoders are not touched. It is saved with the radio on the machine it is attached to and takes effect at once.

Where the dBm normally sits you may instead see OVL in red. That is the converter clipping: the signal reaching it is bigger than it can represent, and everything downstream is reading a distorted version of it. The dBm is taken away rather than shown beside the warning because it is no longer a measurement — a clipped carrier reads lower than it really is, so the number would be arguing with the warning next to it. Turn the RF gain down, or switch in an attenuator, until it goes.

It is worth taking seriously even when nothing sounds wrong, because on FM almost nothing will: the audio stays clean well past the point where the data riding above it has already gone. See the RDS diagnostics tab (2.7) for the same warning where its effects show first.

OVL answers to two different measurements, and either one lights it. The first is what sdroxide measures here, from the samples the radio sends: how many of them sat at full scale over the last meter window. The second is the radio’s own overflow flag, on the few front ends that report one — a Hermes Lite 2 does. That second one matters on a direct-sampling radio, where the converter takes a whole band at once and then hands over a narrow slice of it: a broadcaster three bands away can be driving the ADC into its rails while every sample that reaches sdroxide sits at a tenth of full scale, so only the board can tell you. A Hermes Lite 2 can also be left to fix it by itself — see Overload protection in 6.2.3.

Board temperature. A radio with a temperature sensor of its own has the reading in the meter’s bottom-left corner, in degrees Celsius — a Hermes-Lite 2 is the one this driver meets that reports one, on every face and in receive as well as transmit. It is grey in normal use, amber past 55 °C and red past 70 °C. Those are attention thresholds and not limits the radio enforces: it is the board’s own sensor beside the output stage, so it lags a key-down by some seconds and reads below the transistors themselves. What it is good for is the slow half — an HL2 running FT8 all afternoon heats up and stays hot, and this is where that shows. A radio with no sensor shows nothing here.

Clicking the meter cycles three faces:

The face you pick is remembered. It belongs to the screen rather than to one radio — it is written to smeter_style in the [ui] table of config.toml the moment you click, so it survives a restart however the last session ended, and every radio comes back up wearing it.

On transmit all three switch to a transmit meter, stacked in two rows. The top row is ALC. On a rig that reports its own ALC over CAT — Icom CI-V rigs do — that is the rig’s figure, which is the one that answers “am I overdriving it”; on anything else it is sdroxide’s own drive level, which is how hard the audio being sent is driving the modulator. The two are different measurements, and on a CAT rig driving an external radio only the rig’s says anything about whether the audio is too hot for it.

The lower row is whichever meter the rig actually gives us. Where the rig reports a power-output meter it goes there, as a percentage of the rig’s own full scale rather than in watts — Icom calibrate that meter’s face in percent, with no calibrated wattage behind it, and the relation to watts moves with band, mode, supply voltage and drive, so a wattage would look measured without being so. It answers what the drive slider cannot: the slider is what the rig was asked for, and this is what it is delivering. The two part company whenever the rig folds back — heat, a high SWR, or an ATU still hunting. The ramp carries no red, because a rig at full output is doing what it was asked; what you are watching for is the needle falling while drive stays put.

Where there is no power meter but there is an SWR bridge, the lower row is SWR instead, on a logarithmic scale with 1:1 at the left stop, 3:1 at mid-scale and everything past 3:1 in red. Either way the SWR keeps its place as a number in the header button. Rigs with neither show the drive row alone, grown to fill the space.

Hover the meter and it says what it is showing. The face is dense — a chip, a figure, one or two bars and a scale — and a needle sitting at 50 during an over does not say by itself whether that is half the power, half the modulation or something else. The tooltip names each quantity and its units, and on transmit it says outright when the radio measures nothing: an SDR that sdroxide modulates itself — a HackRF, a Pluto, a LimeSDR, an RTL-SDR-class transmitter — has no SWR bridge and no power sensor at all, so those rows are absent because there is nothing to put in them rather than because a reading has gone missing. SWR and forward power appear when the radio measures them: a rig over CAT, TCI or a LAN link, or an HPSDR board.

Where the reading comes from depends on the interface. An SDR delivers IQ and the receiver measures the signal in its own passband, calibrated to dBm by cal_offset_db in config.toml.

cal_offset_db starts at 0, which means an SDR’s meter starts out reading dBFS — how loud the signal is against the converter’s full scale — with a dBm label on it. On a receiver with plenty of gain ahead of an 8-bit converter, an RTL-SDR among them, its own noise sits high enough on that scale to read S9 with nothing plugged into the antenna socket. Nothing is wrong with the receiver; the scale has not been told where zero is. Set cal_offset_db to the difference between what the meter shows and a level you know — a signal generator, or a band-noise reading you trust — and it will read in dBm from then on. It is one number for the station, so where two radios differ, set it for the one you judge signals on. Changing the front end’s gain moves the reading with it, exactly as an attenuator ahead of a real receiver would.

Except on an SDRplay RSP, which is the one front end here that reports what its own gain currently is. That figure is taken off before the reading is shown, so the meter is referred back to the antenna socket: it stays put when the gain moves, and it stays put while the RSP’s own AGC — on by default — moves it for you. What that costs is that the numbers are tens of dB lower than the same RSP showed before, because they no longer have the front end’s 20 to 60 dB of gain in them. They are the more honest number, and cal_offset_db set for an RSP before this has to be set again. See 15.15.

The same applies with a knob more in the way when the I/Q arrives over a virtual audio cable from another program (PowerSDR, HDSDR): what the meter measures is the level that program is writing into the cable, which it has already put through its own gain and AGC. A reading tens of dB above the S meter in the program feeding it is that offset and not a fault — set cal_offset_db to the difference and the two agree.

A CAT rig on a sound card sends audio it has already demodulated and levelled, so there is nothing left on this side to measure: Icom rigs are asked for their own S-meter over CI-V instead, which is the reading on the radio’s front panel, and rigs whose CAT dialect has no meter read fall back to the level of the audio itself — that one follows the signal but is not calibrated in dBm, being whatever the rig’s AGC left.

2.10 Transmit

On a TX-capable rig the Transmit module appears:

Transmit EQ (Settings → Radio, above the per-interface section, since it applies the same way whichever radio interface is selected) is a 3-band parametric equalizer on the microphone audio, ahead of the modulator: Low shelf (cuts/boosts rumble and handling noise), Mid peak (presence, a narrow bump or dip somewhere in the voice band), and High shelf (brightness/de-ess). Each band has its own frequency and gain (dB), and the mid band also has a Q (how narrow the bump is) while the two shelves have a Slope instead (how sharply they roll off). Off by default, and flat (0 dB every band) the first time you turn it on, so enabling it changes nothing until you actually move a slider. Voice modes only (SSB/AM/FM); digital modes and CW carry synthesized or keyed audio that never reaches it. Applies immediately, like the IARU region setting: there is no Apply step — including while you are transmitting, so you can set it by ear against the transmit monitor.

It sits after Mic gain and before whatever modulates the audio, on every interface: a radio sdroxide modulates itself, and a rig that modulates its own audio (a CAT rig over its sound card, TCI, Icom LAN, SmartSDR) alike. Boosting a band therefore raises the level going into the transmitter, and there is nothing behind it but a limiter at full scale — on a transmitter, clipping is splatter on your neighbours’ frequencies. After boosting anything, watch the ALC/TX meter and take the same amount back off Mic gain. Cutting is free; a cut band and a little more mic gain gets the same tone with none of the risk.

Transmit safety: by default sdroxide refuses to transmit outside the amateur bands (tx_ham_only), and stops the transmission if the radio reports a high SWR (swr_guard, below). Transmit hardware gains start at minimum and the tune drive defaults low. Raise drive deliberately. The one exception built in is the 11 m citizens’ band — a transmitting service, but not an amateur one — which opens when the station switches on Allow transmit on 11 m (CB) (confirmed once); it opens 11 m and nothing else. The general band lockout can otherwise only be lifted from the command line, one run at a time, with --oob-tx (12).

The SWR guard stops the over when the antenna system is not what it should be — a feeder that has come off, a coax switch left on the wrong port, a dipole leg that has parted in the wind. It is armed by default at 2.5:1 and is set in Settings → General (6.1).

TUNE is treated differently, because feeding a mismatch is the whole point of it. An antenna tuner has nothing to work on until the rig keys into the very mismatch the tuner exists to remove, and a sweep that begins at 10:1 is what tuning looks like. So a tune gets double the limit — 5:1 with the default 2.5:1 setting, shown next to the figure in Settings so you never see a number you cannot find — and about five seconds before the guard applies at all, instead of a fifth of one. What survives is the case worth keeping: a feeder that is simply not connected still reads at the top of the scale once the tuner has had its five seconds, and still stops the carrier.

A manual tuner can easily take longer than five seconds to find a match. That is the one case the guard gets wrong, and the answer is to turn it off for the session rather than to raise the limit — you are deliberately sitting at a high SWR for as long as it takes, which is the situation the guard exists to end.

On a rig with its own power control — a TCI rig, or a CAT rig on any of the three dialects — Drive and Tune command the rig’s output power directly rather than scaling anything on this side, and the slider adopts the rig’s own setting when sdroxide connects: a level set in ExpertSDR3, or on the radio’s front panel, carries over instead of being overwritten. The level that applies is asserted before every over, including a CW message handed to the rig’s own keyer — which is the one place where the rig’s power is the only transmit control there is, the sound card having no part in CW at all. After a TUNE the operating level is put back, so the radio is not left at the tune level for the next call.

The level is asserted behind the mode, not only when you move the slider, because a rig keeps its output power per mode: a radio set to 100 W in USB and 25 W in USB-DATA transmits at whichever of the two the mode command last left it in, and one put into AM is held to a quarter of its rated power on top of that. So a mode command and a power command go out in that order at every key-down, and the level lands in the register the over will actually transmit on. This matters most on a quadrature rig, where sdroxide demodulates the I/Q itself and the radio only learns which mode to transmit in when the transmitter comes up: there every over changes the rig’s mode, and so the register its power comes out of.

On a CAT rig the power is a fraction of what the radio can do. Icom carries it that way natively; Yaesu and Kenwood take a number of watts and have no way to say how many they have, so their sliders are read against 100 W — right for nearly every rig those dialects cover, and low (never high) for the few that go above it, such as an FTDX101MP or a TS-480HX. Elecraft takes watts too but can be asked: the option-module query at connect says whether there is a KPA3 or a KXPA100 on the end of the cable, which is the difference between a slider that spans 110 W and one that spans a KX2’s 12.

Drive and the hardware’s TX gain are not the same control. On an IQ radio — a Pluto, an HPSDR board, an SDRplay or a SoapySDR device — Drive is digital: it scales the modulated baseband on its way to the converter, with a hard limiter at digital full scale so it cannot overflow. The radio’s own output level is a separate slider on the Radio tab (TX gain, or whatever that device calls it), and the two multiply. Set TX gain once for the antenna and the amplifier you are feeding, and use Drive as the level you actually work with; the sensible starting point is Drive near the top and TX gain low, not the other way around, because backing off in the digital domain throws away converter resolution and Drive is the one with the limiter behind it.

What Mic gain does depends on the mode. In SSB it sets how hard the microphone drives the modulator, so Drive and Mic between them decide both level and how much the limiter is working. In FM it sets deviation — sdroxide’s FM modulator is constant-envelope, so Drive changes the power and does nothing to the audio, while Mic gain alone decides how wide the signal is. 50% is unity gain, which puts a full-scale recording at the ±5 kHz peak deviation NFM wants; higher over-deviates and distorts however low Drive is. In FreeDV RADE it sets how hard the microphone is fed to the vocoder, the same 50% being unity. In every other digital mode it does nothing at all — the burst is synthesized and the microphone is discarded — which is why the rail becomes TX audio there.

CESSB — more average power for the same peak. The CESSB rail is controlled-envelope single sideband, David Hershberger W9GR’s 2014 technique. It is the second vertical rail in the Transmit module, standing beside Mic on a desktop window, and a rail in the TX menu on a tablet or a phone. The thing an amplifier runs out of is the envelope — the magnitude of the sideband signal — and that is not the audio waveform, so a limiter on the microphone does not limit what the amplifier sees. The envelope of clipped speech overshoots by a long way, an SSB transmitter has to be backed off for peaks nobody hears, and the average power reaching the far end is a fraction of the transmitter’s rating.

CESSB works on the envelope directly: it clips it, filters the resulting splatter away, and then removes the peaks the filter put back by subtracting a band-limited copy of the excess — a subtraction rather than a gain, which is what keeps the transmission inside your own filter instead of spreading it to twice the width. The measured result here is about 3.8 dB more average power at the same peak at 9 dB of compression, with out-of-band energy at the arithmetic’s own floor.

The control is one number: how many decibels the voice is driven into the processor, 0 being off, which is where it starts. 6 dB is a sensible first try and 9 dB is about as far as most voices want to go — past that it starts to sound like a processor rather than like you. It is set by ear, remembered per radio, and it does not touch Drive: what leaves the processor is still held at full scale, so your power setting means what it did before.

It applies where sdroxide makes the sideband itself — an HPSDR board or Hermes Lite 2, a Pluto, a LimeSDR, a SoapySDR device. A transceiver that modulates the audio from its own sound card is making the envelope in its own DSP, where this cannot reach it. The rail is drawn where it can do something and nowhere else, so on such a radio — or in any mode but voice USB and LSB, whose payload is the envelope this flattens — there is no CESSB rail to find.

2.11 Voice keyer

The ▶ button in the Transmit module opens the voice keyer: ten recorded messages you can put on the air with one press — a CQ call, your callsign, a contest exchange, a 73.

Each row is one slot:

Recordings are stored as plain 48 kHz mono WAV files in ~/.config/sdroxide-brown/voice (see 12. Configuration files), one per slot, so you can also record a message in an audio editor, name it slot3.wav, and drop it in.

Triggering a message. Out of the box the digits 1–9 and 0 play slots 1–10 and − stops one; on a full keyboard those are the numpad keys (the platform reports numpad and top-row digits identically, so either works). Like every other binding these can be changed — or moved onto a MIDI pad or footswitch — on the Controls tab; see 6.4. A key over an empty slot does nothing at all, which is why the digits can ship bound when PTT deliberately does not.

External programs can trigger the keyer too: with the built-in Hamlib server running (6.9), \send_voice_mem <1–10> plays a slot and \stop_voice_mem stops it.

NOTE: The keyer is available in every voice mode and in RADE digital voice, where the message is fed to the codec exactly as a live over would be. The other digital modes generate their own transmit audio, so the button is hidden there (and the window closes if you switch into one). Recording is refused while you are transmitting — it is the same microphone.

2.12 Memory channels

Open MEM (System module) for the memory channels window. Type a name and press Store to save the current frequency and mode. Each saved row has a RCL (recall) button, an EDT (edit) button and a DEL (delete) button.

EDT turns the row into an editor: the name, the frequency in MHz and the mode, with SAVE to keep the change (Enter does it too, from the name field) and ✖ to abandon it (so does Escape). It is the same channel afterwards — same place in the list, same folder — so correcting a typo, or a frequency that has moved, costs one edit instead of a delete and a fresh store from that frequency. The filter follows the mode: change the mode and the channel takes the new mode’s default passband, leave the mode alone and a filter you chose yourself is kept.

On a receiver with more than one antenna port the editor has an antenna drop-down as well: which socket this channel is listened to on. Storing a memory captures whichever socket the radio was on at the time, and this is where you say it should have been another — the wire for a 40 m net, the beam for a 2 m repeater. The dash (—) is not the first port: it means leave the antenna alone, and it is what every channel stored on a single-socket receiver holds, so working down a list that never mentioned antennas never moves a relay. The socket is shown in square brackets at the end of the row. A receiver with one antenna has nothing to choose and gets no drop-down.

The editor also carries a RPT button, which folds out the repeater set-up stored with the channel: the shift and its offset, the CTCSS tone or DCS code to transmit, and whether every over opens on the 1750 Hz burst. A channel that already has one comes up with the section open. Storing a memory captures whatever the DUPLEX and TONE controls are set to at the time — including plainly simplex with no tone, which is what lets the next recall take a shift back off rather than leaving the last repeater’s on a simplex channel. Every recall sets DUPLEX and TONE, including a channel from a memories.json written before this existed and one whose RPT section was never opened: those are read as plain simplex with no tone, because that is what the list is showing you. The list shows what is stored beside the mode, so two memories on one dial read as the different channels they are. See 2.18 Repeater operation.

Importing and exporting a channel list

IMPORT reads a channel list from a CHIRP CSV file (.csv) — the format CHIRP writes and the one every repeater directory hands out. RepeaterBook exports it by county, most national societies publish their machine lists in it, and the marine, PMR and aviation channel tables circulate as it too, so a list of local repeaters is usually one download away rather than four hundred stores.

Each channel brings its frequency, its mode, the repeater shift and offset, and the CTCSS tone or DCS code to transmit. A channel already on the list — same frequency, same mode — is skipped, so re-importing an updated directory adds what is new instead of doubling what is not; the names of the channels you already have are left alone. A line the file’s own format cannot account for (a blank row, a trailing note, a frequency that is not a number) is skipped and counted rather than failing the import, and the network log at the bottom of the window says how many channels were read and how many lines were not.

The columns are matched by name, from the file’s header row, so a file that carries only some of them or carries them in another order still reads. A file with no header row is refused — its first line would be a real channel, and mistaking one for a heading would silently lose it.

EXPORT writes the list back out in the same format, to load into a handheld or to keep as a backup. Not everything survives the trip: CHIRP’s format has no place for a folder, an RTTY modem setup or an antenna socket, and its Mode column is the modulation, so a channel stored in a digital mode exports as the sideband it rides on. The frequency, the name, the shift and the tone all do.

The Sort row above the list says what order it is drawn in — Stored (as stored, the historic order), Name (ignoring case), Freq, or Band (each band’s channels together, general coverage last, by frequency inside each) — and the ▲ button reads that order backwards. It is a preference of this screen, remembered in config.toml under [ui]: the store keeps its channels in the order they were stored, a memory scan works through them in that order whatever the list shows, and somebody at another screen on the same station sorts the same memories their own way.

Memories can be filed into folders. Type a name into the second field and press New folder, then drag a memory row onto the folder to file it under that folder — and drop it on the area below the folders to take it out again. Every folder header has a REN button (rename in place — Enter or clicking away keeps the new name, Escape abandons it) and a DEL button, which deletes only the folder: the memories filed under it move back to the top level. Folders collapse and expand with the arrow at the left of their header, and a memory scan works through every memory regardless of the folder it sits in.

Every memory on the visible span is also marked along the bottom of the waterfall, as Mem: folder / name — see 2.3 Tuning.

The memory channels window


2.13 Scanning

Open SCAN (System module) to work through channels and stop where somebody is transmitting. Two kinds:

A range scan is fast, and not in the way a handheld scanner is. A scanner has one receiver and has to visit each channel in turn, which is why sweeping 2 m takes minutes. Here the FFT that already draws the panadapter sees over a megahertz at once, so the radio moves one span at a time and reads every channel in that span together — the whole of 2 m in well under a second. A CAT rig feeding demodulated audio has no such span, so it falls back to visiting channels one at a time, and behaves like the handheld.

A memory scan stops on each channel in its own set-up. Stopping on a channel sets the mode, the filter and the DUPLEX and TONE stored with it, so a scan across a mixed list leaves you on a repeater channel with its shift and tone on and on a simplex one with both off. That matters more here than on a recall, because a scan hands you whichever channel called and you answer it by reaching straight for the PTT — a shift left standing from the last stop would put the over 600 kHz away from the station calling you. A channel stored before the set-up existed counts as plain simplex with no tone, exactly as a recall reads it (2.12). The antenna is the one thing a stop does not touch, unlike a recall: a scan is not worth a relay per channel.

A memory scan can be pointed at chosen folders. With folders in use (2.12) a Folders row appears above the channel list: ALL, then one button per folder with the number of channels in it, and Unfiled for the top level. Pick one or several and the scan runs over those alone — the marine channels while you are on the water, the local repeaters while you are not — and the list below narrows to the channels it will actually visit, so what you are looking at is what the scan will do. ALL is not every button lit: it means no selection, which is also where a folder you make tomorrow lands, so a new folder is scanned rather than silently left out. A folder you delete drops out of the selection with it, since its channels are back at the top level by then. The row is not drawn at all until there is a folder to choose.

FAST reads the list off the spectrum. A memory scan normally does what a handheld does: tune to each channel, listen, move on — a settling time apiece, so a hundred channels is fifteen seconds a lap. Press FAST and a receiver with I/Q of its own instead puts every channel that falls inside one window on the same transform the panadapter is already made from, and only tunes to the ones something is on. A list that fits in one window then costs one tune a lap however long it is, and a list spread over four bands costs four. The scan still listens on each candidate before it stops, so what makes it stop is unchanged.

It is off by default and worth knowing why. The sweep measures a channel through the FFT rather than through the receiver’s own filter and AGC, so a Stops at level that was right for the slow scan is not automatically right for this one — if a fast scan stops on nothing, raise it; if it stops everywhere, lower it. Two kinds of channel are never judged from the sweep at all and always get a listen: one out at the edge of the window, where the anti-alias filter makes everything read low, and one sitting exactly on the receiver’s centre, where a zero-IF front end’s own local oscillator is. A CAT rig feeding demodulated audio has no spectrum to read, so the button is greyed there and its memory scan visits every channel as before.

Stops at is how loud a channel has to be. Either give a level directly, or press SQL to use the receiver’s own squelch, which makes the scan stop exactly where the audio would have opened — one control instead of two. Note that with the squelch slider at off the scan will stop on the first channel it looks at, since every channel then counts as busy. The squelch is one of the per-mode settings (see Per-mode settings (the reset chip)), so SQL uses the squelch of the mode being scanned: a frequency scan in NFM started from SSB stops at NFM’s squelch, which is open until you set one there, and a memory scan judges each channel by the squelch of the mode it was stored in. Set it once while the scan is running in that mode and it is remembered for next time.

Listens for is how long it stays on a candidate before judging it. Below about a tenth of a second the level meter has not settled and weak signals get missed; the default 150 ms is a reasonable balance.

Resumes decides what ends a stop:

While a scan is running, NEXT moves on now and SKIP moves on and adds the channel to the skip list. Touching the dial, changing band, recalling a memory or transmitting all stop the scan where it is — as on any scanner, and so that the radio is not fighting you for the VFO.

SKIP works in a range scan too, and it is remembered. There is no stored channel to mark, so the frequency itself goes on a skip list shown under the range — a row of buttons, one per channel, with CLEAR to empty it. The list is saved with the rest of the settings, so a data channel, a pager or a birdie dismissed once stays dismissed for the rest of the evening and for every later run over the same range, instead of costing a stop every pass. Click a button to put its channel back into the scan.

The list belongs to the range it was taken in: change the From, the to or the Step and it is emptied, because a channel dismissed on 2 m says nothing about 70 cm — and a scanner quietly refusing to stop somewhere you do not remember dismissing is worse than one that stops too often.

The SCAN button in the System module lights while a scan is running, in cyan while it is sweeping and green while it is stopped on something, so you can close the window and still see what it is doing. Settings are remembered in scanner.json.


2.14 CW: decoding and keyboard sending

Choose CW from the Band/Mode popup and the panadapter gains a cursor and a panel underneath it. CW is not a digital mode — the tone stays audible, the waterfall stays on the whole band, and nothing about the way you tune changes — but a decoder reads what you are listening to, and a keyboard sends.

The CW panel: decoded text above, what you are sending below

The cursor is the frequency. The cyan line on the waterfall marks the tone being copied. It is also the tone you transmit on, because in CW those are the same frequency: you answer a station where you heard it. Everything follows the cursor together — the passband moves with it, so what is decoded is always what is audible.

What the header tells you. A CW decoder cannot fail quietly the way a framed digital mode does — fed noise, a naive one produces confident nonsense — so the panel says how sure it is:

Sending. Type in the lower box. Characters go out as you type rather than a line at a time, and the ones already on the air turn green — so when you pause you can watch the sending catch up.

SEND ON RETURN changes that bargain: nothing leaves the box until you press Return, and then the whole line goes out in one piece. Type at your own pace, correct what you like, and commit it when it reads right. The line break is keyed as a word space; Shift+Return breaks a line without sending it; and TX commits the box the same way if you would rather press it than reach for Return. Transmit then releases as soon as the line has gone out, rather than after the IDLE hang above — that hang is there to bridge the gaps between typed characters, and there are none to bridge when the line was composed before it was sent. The setting is shared with the keyboard modes (3.3).

Message buttons — your own text, one press. Under the sending controls is a row of buttons you write yourself: a contest exchange, a reply with your name and QTH, TNX 73 GL, the standard calls — whatever the session needs. Press MSG to open the editor window and fill in as many as ten rows; each has a short button label (what the chip says) and the sends text (what goes on the air). Leave the label empty and the chip names itself from the first few characters of the text.

It is off by default, because sending as you type is how a CW operator sends: the first letter of a callsign is on the air while the rest is still being typed. Turn it on if you are keying a transceiver’s own keyer — the usual case for a CAT radio in CW (6.2.2). There, every hand-off to the rig is a transmit-receive cycle of its own, so a line committed whole switches the relay once where typing it live switches it once per word. Set the rig’s break-in delay long enough to bridge the characters as well, or it will drop out between them however the text arrives.

Speed and spacing are set from the buttons at the right of the header:

The keyboard as a straight key. KEY, beside TX in the sending row, turns a key on your keyboard into a hand key: the carrier is on while you hold it and off when you let go, and the timing is entirely yours — WPM and Farnsworth do not apply. Switching it on drops whatever the keyer still had queued, so a half-sent message never surfaces between your elements, and locks the transmit box so a space cannot type into it.

Which key. The space bar, unless you say otherwise: it is the CW straight key action in Settings → Controls (6.4.1), so you can put it on any key you like. A space bar’s travel is long for keying, and a key with a shorter throw is easier to send a decent fist on.

A MIDI key. The same action can be bound to a MIDI note — the key-down note of a keyer or paddle interface — in Settings → Controls (6.4.3). The note keys while it is on, whatever button mode the binding has, and its first press switches KEY on by itself. A keyer that also sends a PTT note can have it bound to PTT: in CW, PTT keys the transmitter with no carrier of its own and holds it — no idle hang — while the key note sends inside it, and releasing PTT ends the over at once. Without a PTT binding the key note keys the over by itself, as above.

It works wherever sdroxide makes the CW signal itself: an IQ radio, or a CAT radio keyed as MCW audio. A CAT radio sending text through its own keyer has nothing a hand key can drive: KEY is greyed out there, and says so on hover along with the setting that changes it.

Transmitting on an IQ radio (SoapySDR, HPSDR, TCI, SmartSDR) is the keyer building its own sideband signal. On a CAT radio the keyer transmits by the route the CW keying setting picks: text handed to the rig’s own keyer with the rig in CW, or the keyed tone as audio (MCW) with the rig held on a sideband (§6.2.2).

A paddle on the radio. Settings → CW chooses where the key comes from: the keyboard’s CW straight key binding, or a USB paddle — a keyer box that reports its two contacts, with the app making the iambic timing. Pick the device, the key type (Straight, Iambic A or Iambic B), the REVERSE switch the paddle carries, and the keyer speed. With KEY THE TRANSMITTER on, the CW panel’s KEY arms the key and the paddle sends: it is the same manual-key path the keyboard straight key uses, so the band lockout and the 30 s watchdog apply unchanged. A rig that keys itself from text refuses hand-keying by design — set Settings → Radio → CW keying to Sound card (MCW) for a rig keyed by audio or VOX. With the transmitter off, the paddle drives only the trainer’s SEND drill and never keys anything. A USB paddle pane is desktop Linux only.

Two settings on the radio then decide whether any of it reaches the air, and neither is on this page:

A straight key plugged into a paddle box works without any of the above changing: a box with a straight key in it reports that key on a single contact — the middle one where the box has a middle jack, the dit contact where it does not — and sdroxide reads whichever it reports.

Learning Morse (the trainer). The TRAINER chip in the CW panel opens a learning tool, not a sending one: it plays Morse through this computer’s speakers only and never keys the radio, so it works on a receive-only set and in SWL mode. TRANSLATE converts text to Morse and back with the same ITU alphabet the decoder and keyer use — letters, digits, punctuation and the common prosigns. PRACTICE plays a message at your own pace, with the tone, the character speed and Farnsworth spacing: the letters go out at full speed and the gaps are stretched, so a beginner hears the letter as a whole before they can send it that fast. LEARN is the Koch drill — it starts with two characters, plays each three times, and a run of ten correct answers adds the next; the score and how far the set has unlocked are remembered between sessions.

Sending with a real paddle (SEND). The fourth pane reads a paddle that is plugged into the computer’s USB — a keyer box that reports its two contacts (often, to the computer, as the buttons of a mouse that does nothing else). Pick it from the list, press START KEY, and key the character on the target: NEW asks for another, REVERSE swaps dit and dah for the switch on the paddle, and the tone and speed controls are the practice pane’s. The keyer makes clean dits and dahs from your two contacts — you choose the paddles and the pauses — so a beginner’s rhythm cannot turn a dah into a dit; this is where you learn the characters before the timing.

While START KEY is on the paddle is taken exclusively, so its contacts cannot also click in other windows; it is released when you stop, leave the pane, or close the window. This pane is desktop Linux only: it reads the kernel input layer directly, and the browser and the other systems have no equivalent. It plays through this computer’s speakers and never keys the radio.

2.15 Band conditions

Band Conditions

The propagation heat map answers “what has got through”. The BANDS window (the BANDS button in the System box) puts that next to a second, different answer: the calculated band conditions published by N0NBH at hamqsl.com, which are a forecast from the solar indices rather than a measurement of anything.

Column What it is
CONDX The published verdict — Good, Fair or Poor — for this band, for whichever half of the day it is at your QTH
WSPR Global WSPR activity on the band over the last 15 minutes, from wspr.live: how many reception reports the world’s WSPR network produced. A measurement that needs nobody at your receiver. Shown brighter the busier the band is; hover for the report, transmitter and receiver counts
PSK The same figure for the activity modes, from PSK Reporter: FT8, FT4 and the CW/RTTY reporting that WSPR’s beacons do not cover, including the freeband reporters on 11 m. Same shape, same brightening, same hover
PATHS Decayed count of receptions in this band’s field: how much got through
REACH Share of the world with evidence on it: how widely it got through
BEST Best decode margin anywhere in the band, dB above the mode’s own floor

PATHS and REACH are both there because either alone misleads: a contest pile-up is a great many paths through one small piece of sky, and a band quietly open everywhere is the reverse.

WSPR, PSK, PATHS and REACH are all measurements, but of different things: WSPR is the whole world’s WSPR network, PSK is the activity modes from PSK Reporter, and PATHS/REACH are what this station (and the Reverse Beacon Network, when it is on) actually heard. WSPR and PSK are never blank merely because your own antenna is deaf to the band.

The same verdicts colour the band buttons in the band/mode menu, so choosing a band shows its forecast where you are already looking. Green is Good, yellow Fair, pink Poor. Hovering gives the verdict in words along with its source.

Three things this deliberately does not do.

Day or night is worked out from the Sun’s elevation at your own locator, so the correct half of the published table is read wherever you are.

Where the numbers come from. hamqsl.com, fetched in the background once an hour for as long as the program is running. This is the one exception to the rule that sdroxide’s space-weather requests happen only while the 3D view is open: the band menu is always there, so these have to be too. It stays one request an hour — the two share a cache, so with the 3D view open the second one comes back “not modified” — and hourly is the interval the publisher asks for.

The WSPR column is a second request, to the public wspr.live database, fetched every ten minutes for as long as the program is running. It asks for one thing — the reception-report count per band over the last fifteen minutes — and is cached on disk like the rest.

The PSK column is PSK Reporter’s receive-side: the reports in the same fifteen-minute window for 160 m through 10 m — and the 11 m citizens’ band, which wears the same code, so freeband FT8 is counted where the operator is actually working — one request every ten minutes, cached and interpreted exactly like the WSPR one. PSK Reporter asks its clients to query no more than once every few minutes, so ten is comfortably inside it.

The document is cached on disk, so the last verdicts are on screen immediately at startup and survive being offline. Everywhere they appear they are labelled with their age.

Meteor showers

At the foot of the BANDS window is the one propagation forecast that has nothing to do with the ionosphere: the annual meteor showers currently active, from the International Meteor Organization’s working list. A shower’s window and its radiant are fixed, so nothing here is fetched — it is a table and a clock.

Each active shower shows its name and IMO code, its peak ZHR (the meteors an observer would see with the radiant overhead under a perfect sky — a brightness, not a count to expect), a green PEAK on the peak date, and whether the radiant is above your horizon right now, with its altitude and compass bearing from your locator. Hover a row for the parent body and the geocentric velocity.

The radiant’s altitude is the part that changes: a shower is worth listening for when its radiant is up, because a radiant below the horizon sends its trails up through the Earth. A fast shower (above about 40 km/s) leaves longer-lived ionised trails, which is what makes meteor scatter work on 6 m and 2 m and what gives the brief 10 m and 11 m openings their seconds-long returns.

The dates are the shower’s published activity window, not a fitted rate curve: inside the window the rate is the peak figure, outside it there is nothing.

IBP beacons

Below the showers is the NCDXF/IARU International Beacon Project — eighteen beacons on five bands, on a schedule that is entirely deterministic: a three-minute cycle of eighteen ten-second slots, aligned to UTC midnight, in which exactly one beacon is transmitting on each band at any instant. Nothing is fetched here either.

Each band’s row shows the metre band, the frequency, the callsign now transmitting, its location, and the compass bearing and distance from your own locator. The header counts down to the next beacon, and the whole list refreshes every second, so it stays live while the window is open. A beacon you can hear is a path that is open, measured rather than forecast — and the 10 m beacon at 28.200 MHz is the closest amateur-band proxy there is for 11 m conditions, which is why it is worth watching from a CB or SWL station.

Every beacon, whatever its proper name, works every band once per cycle: at the start of a cycle the 20 m beacon is the first in the list and the higher bands are showing beacons that started three, six, nine and twelve seconds earlier.

2.16 Satellite operation (SAT)

Satellite mode window

The SAT button in the System box opens the satellite window: pick a bird, lock on, and every voice and digital mode works through it with Doppler corrected continuously. The button glows green while a lock is running, because the correction keeps being applied whether or not the window is open.

The window has three tabs. SATELLITES is the picker and the live lock described below. PASSES lists every pass over the next 24 h or 48 h, soonest first, from every satellite with frequencies on file (tick all satellites for the whole list, which takes longer to search): when it rises in UTC and local time, how long until then, how long it lasts, how high it peaks, and which way it rises and sets. PEAK ≥ hides the low ones — 10° by default. Click a row to pick that satellite on the SATELLITES tab, with its pass diagram and links. QO-100 is the beacon calibration (2.22) — a geostationary bird needs no Doppler, but it does need its LNB offset measured, and that is the whole of working it. Either tab carries a dot while its own work is running, and the SAT button glows for both.

And a locked satellite labels your panadapter. With a lock running, the satellite’s downlink transponder segments are drawn along the frequency scale with their own labels — “CW beacon” as a mark, “linear transponder” as a bounded span — so a passband reads as where the CW segment ends and the SSB begins instead of an unexplained slab. They move with the Doppler correction, so they stay on the signals they name. Only downlinks: a transponder’s uplink is on another band, and a label here for it would point at a frequency you are not listening to. If you have your own frequency table for a bird it wins over the built-in one, as it does everywhere else.

The picker lists every satellite the station tracks — the amateur group subscription, anything you pasted into the TLE tab (6.10), and the curated set — with a search box and, once your grid locator is set, live elevation and the next pass for each. Pass times are worked out in UTC and shown in UTC with your own local time beside them (13:08 UTC (14:08 local)). Pick one and its published links appear: transponders, repeaters, beacons, each with its passbands and mode, inverting transponders marked inv. TUNE just sets the dial and mode to the link, nothing more. LOCK ON is the mode itself. An SSTV link — the ISS lists both its 70 cm (437.550 MHz) and 2 m (145.800 MHz) SSTV downlinks — tunes and locks in SSTV FM, so the picture is decoded with the Doppler corrected.

What a lock does. The engine — not the screen — propagates the orbit with SGP4 a few times a second and:

The window shows it all live: azimuth and elevation with a compass point, range and range rate, both corrections in hertz, the nominal downlink and the computed uplink, and the pass in progress or the next one. Locks survive stale elements gracefully — corrections are suspended (never frozen) and resume by themselves when a TLE refresh brings a fresher set.

The 3D view joins in: the locked bird is highlighted with a line drawn from your QTH to it — the sightline your antenna points along — and with AUTO the camera flies to frame you and the satellite together and holds the shot through the pass. The pass window there gets a LOCK ON button of its own, so a satellite found by searching the globe is one click from being operated.

QO-100 and anything else behind a converter. The dial is the published frequency throughout, so a station hearing the 10 GHz downlink through an LNB sets that LNB as its Converter offset and locks on exactly as it would on a low-orbit bird — the transponder mapping then derives the 2.4 GHz uplink from wherever the dial sits. What it also needs is the Transmit row beside that offset (6.2) set to what is in the transmit line, or transmit stays switched off: for the usual QO-100 station that is its own offset, of nought.

Locking needs your grid locator (Settings ▸ General) and current element sets (Settings ▸ TLE). On a CAT rig the lock still tracks, predicts and steers the rotator, but Doppler stays uncorrected — riding a serial dial a few times a second is not something most rigs enjoy; an IQ front end does it for free in the DDC. And if satellite software is steering the dial through the built-in rigctld server at the same time, the window warns you: two Doppler corrections is one too many.

2.16.1 Rotator control

Rotator setup

sdroxide points motorized antennas two ways, chosen in Settings ▸ Servers.

A Hamlib rotctld daemon (the default) — run it next to the hardware:

rotctld -m 603 -r /dev/ttyUSB0    # a Yaesu GS-232B interface
rotctld -m 202 -r /dev/ttyUSB0    # an EasyComm II controller (SatNOGS-style)
rotctld -m 1                      # Hamlib's dummy rotator, for trying it out

One daemon reaches everything Hamlib drives — GS-232, EasyComm, SPID, AlfaSpid and the rest — so this is the route to reach for first.

A controller on a serial port directly — EasyComm II or Yaesu GS-232A/B, for a station that would rather not run a daemon. Pick the connection, then the port (e.g. /dev/ttyUSB0) and baud (9600 on most controllers). These land the same commands the daemon would and are offered for convenience; the rotctld route above is the one exercised here, so treat the serial paths as not yet proven against real hardware.

The shared settings are a minimum elevation below which the rotator parks (set it to your local roofline), an azimuth offset for a rotator whose north is off, the smallest movement worth commanding (motors last longer not chasing tenths of a degree), and an optional park position.

The ROTATOR window — open it from 🪟 WINDOWS ▸ Antenna rotator (or Settings ▸ UI) — is the manual side. A compass shows the hardware’s own reported bearing against the one you have asked for; drag or click the dial to point, type a bearing, or pick a DX country and the beam swings to its bearing from your own locator. STOP halts where the antenna is, PARK drives to the park bearing, and AUTO hands the antenna back to the satellite lock. While the satellite lock is steering, a manual point takes over and the lock will not drag the beam off it — re-affirm the lock (AUTO, or its ROTATOR switch) to hand it back.

You can also point the beam from where you are working. On the FT8/FT4 map a right-click aims the antenna at that spot; a decode row’s BEAM chip (on the station card) aims it at the station’s locator. Both need a rotator configured and your grid locator set.

PSTRotator works too: choose it under Program, with the host it runs on and its UDP control port (12000 unless you changed it). In PSTRotator, turn on UDP Control in Setup. sdroxide takes over from PSTRotator’s own tracking when it starts pointing, and asks where the antenna is once a second; PSTRotator answers on the next port up (12001), which must be free on the machine sdroxide runs on. Until it answers the status line says so — PSTRotator stays silent while it has no controller connected — but the pointing commands still go out.

2.17 Running more than one radio

SDR Oxide can run several radios at once — an HF transceiver and a VHF dongle, a network rig at the station and an RTL-SDR on the desk, or two receivers inside the same box. Each radio is complete and independent: its own interface, its own tuning, mode and band, its own panadapter and waterfall, its own receive audio, its own sub-receiver, digital modes and scanner. They appear as tabs, and with a single radio configured — the way every installation starts — the tab strip stays out of the way entirely and the window looks exactly as it always has.

Adding a radio. Open Settings → Radio. Across the top of the tab is a row of buttons, one per radio, ending in +. Press + and a new radio is created and focused, with the dialog already open on its (empty) Radio tab. A new radio deliberately starts with no interface — silent, rather than grabbing the first device it finds, which is usually the device another radio is already using. Pick its interface, configure it, press Apply / reconnect, and it is on the air. From then on the same strip appears across the top of the main window as well.

While a station somewhere else is also open in a tab (8.2), the same + asks where first: On this computer, or On that station. The two are as different as plugging a dongle in here and plugging one in at the remote site — one radio appears in this machine’s roster, the other in that station’s, where its engine runs and where its settings are saved. A radio added on a station comes back as a tab of its own within a second or so, with the Radio page already open on it, exactly as a local one does. The + on the main window’s tab strip always means this computer; the choice lives in Settings → Radio, which is where the two rosters are side by side.

The + only acts on the press when the radio is going on the computer you are sitting at. Where it would go on a station instead — which is always the case in the browser client (8), since a browser has no hardware of its own — it names the station and asks first. Creating a radio is not something to do to somebody else’s machine by accident: it opens a configuration there and starts an engine, and everyone else connected to that station gets a tab for it.

Rearranging the strip. The buttons in Settings → Radio can be dragged into any order you like: pick one up, and a cyan caret shows where it will land. The main window’s tab strip follows the same order, and it is remembered between sessions. A short drag that never really moves is still a click, so switching radios costs exactly what it did before.

What the order does not change is which radio is the station’s first. That one holds the shared network services, takes the command line’s settings and the configuration paths every earlier version used, and is the one radio that cannot be closed — wherever on the strip you put it. Connections to other stations can be dragged about too, but they are in no roster here, so they come back at the end of the strip next time.

Adding somebody else’s station. A radio in a tab does not have to be attached to this machine. Settings → General takes the address of an sdroxide server and gives it a tab of its own, exactly like a local radio (8.2) — the engine stays where the antenna is, and what crosses the network is the spectrum, the audio and the commands. Such a tab is closed from the roster like any other, which hangs up and changes nothing on the server.

Closing a radio that lives on a station. Hanging up and closing a radio are different things, so the × on a connection’s button asks which you meant:

Closing a radio on a station does what closing a local radio does here: the roster entry goes, its configuration stays on that machine, its engine stops and its device is released, and every client on that station — not just this one — sees the radio leave. A station’s first radio is never offered: it runs the station-wide services and answers at the plain /ws that every client arrives at. A station that does not allow this at all — one whose sdroxide was not started as a server, or an older one — offers only “Close this tab”.

Radios you did not mean to create live on the station, not on the screen that made them, so closing their tabs is not enough — they are announced again on the next connection. Close it on station is what removes them. If you want to know when they appeared, the server logs each one: journalctl -u sdroxide | grep "radio added to the roster".

The tab strip. Each radio gets a tab of its own, and the open one is joined to the page below it. Click anywhere on a tab — not just its name — to switch to that radio; the small buttons a tab carries keep their own clicks. Everything else keeps running behind the radio you are looking at — audio keeps playing, digital modes keep decoding, skimmers keep skimming, the scanner keeps scanning. Besides its name, each tab carries:

Closing a radio is deliberately not on the strip — that lives in Settings → Radio, behind a dialog rather than one stray click away.

Putting a radio down. A station does not always have every radio it is set up for plugged in. Each tab carries a LINK switch — lit while sdroxide’s link to that radio is open, dark when it is not — and pressing it changes that. With the link closed, the radio’s interface is closed with it: no device claimed, no CAT port held, no network rig dialled, and no reconnecting in the background. Everything it is configured as stays exactly where it is. The tab stays too, with its name greyed, and its whole Settings → Radio page is still there to be read and edited. Press the switch again and the radio opens where it left off.

It says LINK rather than on and off because it is sdroxide’s switch rather than the radio’s, and the difference matters on a station with more than one rig on it. On/off in sdroxide means one thing and one control: PWR, which throws the set’s own switch over the control link (2.7). What it lets go of is this end of the connection — the USB device, the serial CAT port, the LAN session — so sdroxide is demonstrably no longer holding that radio: the dongle can be unplugged, the port is free for another program, and the rig’s network session is hung up. A transceiver with a power switch of its own is not touched by it and stays on, receiving into its own speaker; sdroxide has no way to press that switch and, having pressed it, no way to press it back. What is guaranteed is the transmit side: a radio that is off has no transmitter as far as sdroxide is concerned, so nothing — not PTT, not TUNE, not a digital-mode sequence, not a program on its built-in server — can key it until it is switched back on. That is on top of the station-wide interlock below, which applies to every radio that is switched on.

The same switch is in the roster at the top of Settings → Radio, which is where the choice is easiest to see across all the radios at once — and on the main window itself, as the ⛓ link button above the A/B selector in the Frequency module (at the top of the VFO menu on a tablet- or phone-width layout), which switches whichever radio the pane it sits on is showing. All three are one switch: press any of them and the others follow. There are three because a single-radio station has neither a tab strip nor a roster switch — the button in the Frequency module is the only one it gets — while a station with several wants it on the strip, next to the radio it belongs to. It is remembered: a radio switched off is still switched off after a restart, and sdroxide never touches its device at start-up. That is what makes it the right place to leave the rig that is boxed for the summer, or the dongle somebody has borrowed — rather than deleting the radio and setting it up again later.

A radio that is switched off has no mute button (there is nothing coming out of it) and shows no ⚠: it is not reaching for a device and failing, it has been told not to reach. Its spectrum and waterfall hold the last picture they drew and stop scrolling — the waterfall’s vertical axis is time, and rows repeated while nothing is being received would be time that never happened. The first radio is not treated specially here — the station’s own radio can be switched off like any other, and its shared services keep running. One tab has no switch: a receiver lent out as another radio’s panadapter, whose front end is the borrower’s to hold. With a single radio the strip stays out of the way entirely and the Settings roster offers no switch — the Frequency module’s power button is then the one place the radio is switched off and back on.

A radio at a station. The switch works the same way over a connection, from a native remote client and from the browser client alike: pressing it asks the station to switch that radio, and what comes back is the station’s answer — so the button shows where the switch really stands, not what this screen asked for a moment ago. Everyone connected sees it move, including whoever is sitting at the station. This is how a headless station’s radio is put down at all: with no screen of its own, the browser is the only place its switch exists. A station running an older sdroxide than this screen offers no switch, and none is drawn rather than one that would be quietly ignored.

Split view. The ⊞ toggle gives a radio a pane of its own: toggle it on a second radio and the main area splits into two equal columns, side by side; a third radio makes three. Every pane carries its own copy of the radio strip, so any pane can be switched to any radio that is not already on screen — a radio is never shown twice, and its name is greyed out in the other panes’ strips while it is up. Keyboard shortcuts and MIDI go to one pane at a time: the one whose open tab carries the accent outline, and clicking anywhere in a pane moves them there. Close the split views (or their radios) and the last pane left takes the whole window back.

Naming. A tab names itself after its radio’s interface — PlutoSDR, TCI, HPSDR — so a strip full of different hardware needs no housekeeping to be readable. To name one yourself, use the Name box under the button row in Settings → Radio; clear the box and the tab goes back to naming itself.

The first radio is the station. The first tab is where the shared, station-level things live: the spot feeds (DX cluster, POTA, SOTA, PSK Reporter, FreeDV Reporter), WSPRnet, TLE refresh and the antenna rotator all run on it, because a station has one of each of those no matter how many radios it has. Its configuration also lives where a single-radio installation keeps it, so adding and removing other radios never touches it. It is the one tab that cannot be closed. The spots it collects are shown on every radio’s waterfall and SPOTS list, not only its own (issue #410).

One transmitter on the air at a time. The radios share a station-wide transmit interlock. Keying any radio — PTT, TUNE, a digital-mode sequence, the voice keyer, or a program connected to one radio’s built-in server — claims it; while it is held, a key-up on any other radio is refused with a notice naming the radio that is on the air, and nothing on the refused radio changes state. The interlock releases on unkey.

What is shared and what is per-radio. Memory channels, memory folders, band stacks, the digital-mode operator settings (callsign, grid, templates), the saved profiles (6.12), the logbook, spots and awards belong to the operator, and are shared: save a memory on one radio and it appears on the others. The dial, mode, filter, session restore, scanner setup and the built-in servers (TCI, rigctld, WSJT-X) belong to each radio. Each radio’s servers have their own configuration precisely so two radios can serve two copies of WSJT-X on two ports — which also means an additional radio’s TCI server starts disabled, because the default port would collide with the first radio’s; enable it and pick a free port in §6.8.2.

Background tabs. A hidden radio’s waterfall freezes — the pixels are only drawn for the tab you are watching — and resumes with a clean gap when you switch back; the spectrum data underneath it never stops. Keyboard shortcuts and MIDI controls go to the focused tab only.

Closing a radio. The × beside the radio’s name in Settings → Radio shuts the radio down and removes it from the strip. Its configuration directory is kept on disk — a closed tab is not a request to destroy the configuration behind it — but a radio added later starts fresh rather than inheriting it.

Several receivers from one box. Some hardware carries more than one receiver on a single connection, and each of those receivers can be a radio tab of its own. Configure two radios with the same address and they share the connection rather than fighting over it — closing either tab leaves the other streaming, and the transmitter belongs to the first receiver’s radio:

One radio can receive for another. A transceiver with no wideband output — a CAT rig on a sound card — can borrow another radio’s receiver and use it as its panadapter, on the same antenna or fed from the rig’s I.F. socket. The two then behave as one radio: the spectrum, the waterfall and the sub receiver come from the receiver, the dial, the mode and the transmitter stay with the transceiver, and you can listen to whichever of the two you prefer. A radio that has been lent out this way leaves the tab strip — its front end belongs to the radio that borrowed it — and stays in the roster in Settings → Radio, marked 🔗, which is where it is configured and where the pairing is undone. See §6.2.15.

A server serves every radio in the roster, each on an address of its own — --server brings up the same radios the GUI would (8.1). A native client that dials such a station gets all of its radios as tabs, the same as if they were plugged into this machine (8.2) — one connection per radio, made for you. That is the same mechanism that lets one screen hold this machine’s radios and somebody else’s at the same time. A browser tab holds one radio at a time and picks it with ?radio=<id> (9.1).

2.18 Repeater operation (DUPLEX and TONE)

A repeater listens on one frequency and answers on another, so working one means transmitting where you are not listening — and usually proving who you are on the way in, with a sub-audible tone under the voice or a whistle at the start of the over. Both live in the DUPLEX and TONE buttons in the VFO/RIT module, beside split, RIT and XIT: the other three things that decide where this station transmits relative to where it listens.

Everything here is per radio and is remembered across a restart, and a memory channel stores the whole set-up with the frequency (2.12).

The shift — DUPLEX

Press DUPLEX for the shift controls.

Underneath, the popup shows the receive and transmit frequencies as they now stand. The DUPLEX button lights amber whenever the two differ, and the panadapter draws the transmit frequency the way it draws XIT — a marker line and a labelled bracket when it is on screen, and just the label when it is not, which on 70 cm (a 7.6 MHz shift in Region 1) it never is.

NOTE: The built-in shifts are transcribed from published band plans and have not been checked against a repeater. They cover the sub-bands whose shift is settled across a whole region — 10 m, 6 m and 4 m in Region 1, 2 m and 70 cm in all three (in Regions 2 and 3 alike, outputs above 147 MHz take their inputs 600 kHz up), 1.25 m and 33 cm in Region 2, 23 cm — and say nothing anywhere else, deliberately: a missing entry leaves you simplex, which is obvious the moment nobody comes back, while a wrong one transmits confidently onto somebody else’s channel. Set the region under Settings → General (6.1), and set the shift by hand wherever your local plan differs.

On a CAT-controlled rig, sdroxide owns the shift. These controls work by moving the radio’s dial for the length of the over — the same way RIT, XIT and split do on a rig whose VFO is its whole frequency control — so the radio’s own duplex setting has to be off, or the two would be added together and the over would go out a shift away from where you asked for it. sdroxide therefore puts an Icom back to simplex whenever the dial moves — on HF once per band, and on VHF and up every time the dial moves at all, including into the transmit frequency at the start of an over.

That matters on a radio that puts a duplex setting back by itself. An IC-9700 remembers one per band, so switching to 70 cm or 23 cm recalls whatever that band was last left on, normally DUP−; and the auto-repeater function fitted to several regional versions arms on the frequency, so simply tuning from one 2 m channel to the next puts a shift back without ever crossing a band edge. Set the shift here rather than on the radio; the radio’s own DUP button will be overridden the next time the dial moves.

The tone — TONE

Press TONE for what goes out under the voice, the 1750 Hz burst, and the receive tone squelch — the three things a repeater directory’s one line about tones actually asks for.

The sub-audible tone is sent on NFM only — it is a slice of an FM channel’s deviation budget and means nothing on a sideband — and the transmitted voice is high-passed and trimmed while it is on, so an over with a tone under it occupies the same channel width as one without. The settings can be arranged in any mode; they simply take effect when you are in FM.

NOTE: On a radio that modulates its own audio — a CAT rig fed through its microphone or data input, or a TCI rig — a sub-audible tone has to survive that input’s own high-pass filter, and most microphone inputs are built to keep exactly this sort of thing out. sdroxide sends it regardless, because where the input passes it (a data or line input, or a rig fed at baseband) it works. If the repeater will not open, use the rig’s own CTCSS encoder, set at the radio. The 1750 Hz burst is in-band and passes either way.

NOTE: DCS is a data stream rather than a tone, and the bit order it is encoded with here is transcribed from the standard rather than measured against a repeater — the same ambiguity that stops the decoder naming which of the 104 codes a signal carries (2.7). If a machine will not open on DCS, try the other polarity, and then CTCSS, which has no such ambiguity.

2.19 DRM (Digital Radio Mondiale)

DRM is digital shortwave broadcasting: a few hundred OFDM carriers filling 9 or 10 kHz, carrying AAC-coded audio together with the station’s name, a scrolling text message and the broadcaster’s clock. Where a shortwave AM signal fades into mush, DRM either arrives as clean audio or does not arrive at all.

It is a broadcast mode, so it works like WFM rather than like the digital modes in section 3: there is nothing to transmit, no QSO to sequence and no transcript. Select DRM on the MODE button and listen.

Tuning. Put the dial on the channel centre, not on one edge and not on a sideband. DRM’s carriers sit symmetrically around the frequency the broadcaster publishes, so the published figure is the number to dial. The passband shading shows the default 10 kHz channel; the filter presets offer the six widths the standard allows (4.5, 5, 9, 10, 18 and 20 kHz), which affect what the display shades and what the S-meter reads — the decoder reads the real width out of the transmission itself and does not need to be told.

It is not instant. DRM spreads each frame over 400 ms or two full seconds before transmitting it, and the receiver has to collect all of that before it can decode any of it. Expect a few seconds between landing on a signal and hearing anything, and a second or two of standing delay after that. Nothing here reacts the way an AM signal does, and that is the transmission rather than the radio.

The DRM window (the DRM button, 2.7) is what to read while tuning one in. Across the top is a row of indicators for the stages of the decode, in the order they lock:

Stage What it means
IO Samples are reaching the decoder.
TIME Symbol timing has been recovered.
FRAME Transmission frames have been found.
FAC The Fast Access Channel decoded — the transmission has said what it is.
SDC The Service Description Channel decoded — it has said what its services are.
AUDIO Audio frames are decoding.

They fill in left to right, and where they stop is the diagnosis. Nothing lit at all means no signal on this frequency. TIME and FRAME lit with FAC dark usually means the signal is there but too weak or too distorted to read — DRM needs a genuinely clean channel, and about 15 dB SNR for a reliable 10 kHz decode. Everything lit except AUDIO means the multiplex is being read but its audio is not decoding, which usually means a signal too intermittent to carry audio through even though the control channels are getting through. If instead the DRM window says the codec is not decodable, that is a different problem with a fix — see Codecs below.

Below the indicators, once the signal is locked:

Then the service itself: the station’s name, its country and language codes, the codec, the bit rate — typically 8 to 25 kbit/s, which is why DRM sounds like speech radio rather than like FM — and whether it is mono or stereo. Underneath is the text message the audio stream carries, which broadcasters use for the programme name, a website or a contact address, and the broadcaster’s own clock where the multiplex carries one.

More than one service. A few multiplexes carry two programmes, or a programme alongside a data service. When they do, a row of numbered buttons appears; click one to decode that service instead. Most broadcasts carry one and the row does not appear.

QUALITY plots SNR and MER over the last minute. Two traces on one scale, because the gap between them is the reading: SNR is what the receiver measures of the channel, MER what the demodulator actually achieved on it. On a clean path they track each other. MER falling away from SNR means something the noise figure does not describe — multipath, a drifting transmitter, an overloaded front end — is costing the decoder margin, and that is a different problem from a weak signal. The trace restarts rather than joining across a dropout, so a gap in it is a real loss of sync and not a slow patch.

CONSTELLATION is the picture of how well the signal is being decoded, as opposed to whether it is. It plots the equalised symbols of one of the three logical channels — FAC, SDC or MSC, chosen with the buttons — against faint rings marking where an ideal symbol would land. The MSC is the one to watch: it carries the programme, and it uses the densest constellation, so it runs out of margin first.

Read it by shape:

The number of clusters is the constellation’s order, which the transmission chooses: 4-QAM is four, 16-QAM sixteen, 64-QAM the sixty-four you will usually see on the MSC. The FAC is always 4-QAM, because it has to be readable before anything has said what the rest of the multiplex uses.

The MSC carries a couple of thousand cells per frame; the plot shows 512 of them, taken evenly across the whole frame rather than from the front, so fading spread across the frame shows up rather than being cropped out. The decoder is only asked for them while the window is open — on a remote link that is a few hundred numbers several times a second, worth carrying while you are watching and pure waste when you are not.

Audio. The decoder’s output goes to the speaker in place of the demodulated signal, and the AGC is bypassed — what you hear is the level the broadcaster mixed, not a level the receiver invented. If a station is stereo, it is played in stereo.

Codecs. AAC is built in and needs nothing. xHE-AAC, which most of the surviving DRM30 broadcasters have moved to, is decoded through libfdk-aac if that library is on the system — it cannot be built in, because its licence and this program’s are incompatible, so it is looked up when the radio starts and used if it is there. Install it and restart:

   
Debian / Ubuntu sudo apt install libfdk-aac2
Arch sudo pacman -S libfdk-aac
macOS brew install fdk-aac
Windows put libfdk-aac-2.dll beside sdroxide.exe

Opus is not part of the DRM standard — it is an extension a few experimental transmissions use — and decodes if libopus is installed, the same way.

When a station’s codec cannot be decoded, the DRM window says so in place of guesswork: the codec is named, followed by not decodable, and the panel tells you which library is missing. The DRM button in the top bar stays dark in that state, because nothing is being heard.

What is not here. Transmit: DRM is a broadcast system and there is no amateur DRM to send. Journaline, MOT slideshows and the electronic programme guide are carried by the standard but not shown. The CELP and HVXC speech codecs of the original standard were withdrawn from it and nothing transmits them.

2.20 HD Radio (NRSC-5)

HD Radio is the digital sidecar of an FM broadcast: a set of OFDM carriers placed in the spectrum on either side of the ordinary analog FM carrier, about 20 dB below it in power. They carry HDC-coded audio together with the station’s own name, a slogan and a short message. Most digital FM stations in the United States and Mexico transmit it, and a hybrid station sounds better on the digital side than on the analog one — provided it can be heard at all, because the sidebands are far weaker than the carrier they share.

Select HD RADIO on the MODE button and listen. It is a broadcast mode, like WFM and DRM: there is nothing to transmit and no transcript. The panel is receive-only.

It needs nrsc5 installed. The decoder is libnrsc5, from the nrsc5 project, and sdroxide does not include it: HD Radio’s audio codec is proprietary, so the library is looked for on the computer the radio runs on when sdroxide starts, and used if it is there. Without it HD RADIO stays on the MODE button but greyed out — hover it for the reason — and the keyboard’s next/previous-mode keys step past it. On Arch it is the nrsc5-git AUR package; elsewhere it is usually built from the nrsc5 source, whose sudo make install puts it in /usr/local/lib, where sdroxide looks. On Windows, put libnrsc5.dll and the DLLs it needs beside sdroxide.exe; anywhere, libnrsc5 beside the executable is found, and the SDROXIDE_NRSC5_LIB environment variable names a library in any other place. Restart sdroxide after installing it — the library is looked for once, at startup. With a remote client it is the station’s computer that needs it, not the one the client runs on.

An nrsc5 built without its audio decoder (-DUSE_FAAD2=OFF, which a distribution unwilling to ship the patched codec might do) can find a station and read its name but never play it. sdroxide notices after a couple of seconds of locked signal with no audio at all, stops decoding, and the HD Radio window says so.

Tuning. Put the dial on the analog carrier’s centre, the same number you would use for plain WFM. Unlike DRM, the digital carriers are not centred on that frequency but spread out around it — roughly 129 to 198 kHz either side — so the front end has to capture a span of at least about ±200 kHz to see them at all. A complex sample rate of 1 Msps or more is ample. Below 400 kHz the decoder is not started at all — both sidebands cannot fit, so it could never lock — and the window says so, naming the rate this receiver delivers; that is also what a CAT rig handing over demodulated audio gets. The default passband is ±200 kHz, which is the channel the sidebands occupy, and there are no filter presets — the decoder reads the real channel out of the transmission.

It is not instant. The decoder needs a few seconds on a clean signal to find the OFDM frame and get the audio stream running, and it holds a fraction of a second of delay after that. A station that is perfectly listenable in analog WFM can still be too noisy for the digital side: front-end overload and strong neighbours on the FM band are the usual reasons. A band-notch filter is another — a wideband receiver with its FM broadcast notch engaged is deaf across 88–108 MHz, so a bad CBER can be a front-end setting rather than the decoder.

The HD Radio window (the HD button, 2.7) is what to read while tuning one in. Across the top are two indicators for the stages of the decode, in the order they lock:

Stage What it means
SYNC The OFDM frame is being read.
AUDIO The selected programme’s audio is decoding — not the silence the decoder fills a lost or failed packet with.

Sync without audio is a real state — the frame is locked but the programme’s audio is not coming through, often because the signal is marginal — so the HD chip in the top bar lights only when audio is actually decoding.

Below the indicators, once the signal is locked:

Then the station’s own text: its name, its slogan, and a message it is currently airing. If the multiplex carries more than one programme — HD-1 and an HD-2 subchannel, say — a row of HD-n chips lets you pick which to hear. Tuning to another station puts it back on HD-1.

The audio is stereo (HDC carries two channels) and plays as two; a mono transmission simply has equal channels, so it sounds the same.

The decoding itself runs on a thread of its own, so it does not hold up the panadapter or any other decoder on the same receiver; a machine too slow to keep up with it loses samples and re-acquires rather than stalling the radio.

What is not here. Transmit: HD Radio is a broadcast system. HD on the AM band (medium wave) is not wired up yet; this build decodes the FM hybrid only. The album art and programme-service data (track titles) the multiplex can carry are not shown, and the receiver does not blend back to analog when the digital side drops — the mode decodes the digital side or is silent.

2.21 Recording the audio and the spectrum

REC, in the receiver box beside MUTE, opens a small picker with the two things that can be recorded — and they are different things, so either or both may run:

The button lights while either is running and hovering it names the files. On a narrow window the whole receiver box folds into the RX menu chip, and there the same two rows are at the bottom of that menu, under Record audio and Record spectrum, rather than behind a button of their own. It has no keyboard shortcut by default, but Record on/off is in the bindable action list, so it can be put on a key, a mouse button or a MIDI pad (6.4).

What goes into it. On receive, the audio at the end of the receive chain — past the AGC, the noise blanker, the auto-notch and noise reduction — but taken before the volume control and MUTE. Turning the AF down, muting the receiver, or a spoken announcement ducking the speakers changes what you hear and nothing about the file, and the sub receiver’s own volume and mute are equally invisible to it. What you were listening to is what gets archived, at the level the receiver delivered it. The squelch is the one control that does reach the recording: what a closed squelch silences is recorded as silence. Where a mode replaces what you hear rather than filtering it — decoded FreeDV/RADE speech, or a voice-keyer message you are monitoring — the recording follows the speaker.

On transmit, it takes the audio sdroxide sends: the microphone after mic gain and the transmit EQ, with any CTCSS tone or 1750 Hz burst that goes under it; a digital mode’s burst; the CW keyer’s sidetone; and, for a tune-up, a 1 kHz tone at the tune level standing in for the unmodulated carrier — without which the file would go quiet for the tune and drift out of step with real time, a little further with every one. Receive is held out of the recording for the length of the over, so a full-duplex radio hearing its own signal cannot land on top of your voice. One kind of over leaves no trace: CW handed to the radio’s own keyer travels as text over the CAT link (6.2), and text has no audio to record.

The two channels. The recording is stereo unless you ask otherwise, and what is in the two channels depends on whether anything is running that needs them apart:

MONO, beside MP3 in the picker, writes a single channel instead, with receive and transmit taking turns on it: a smaller file, and the honest format for a recording that is going to be played back in mono anyway.

Either way the layout is settled when the recording starts — which is why MONO is greyed out while a recording runs. A file already being written keeps the channel count it began with, so switching the sub receiver on, or a broadcast’s stereo pilot coming and going, cannot change it halfway through.

Where it goes. Recordings land in <Music>/sdroxide/ (or ~/.config/sdroxide-brown/recordings on a platform with no music folder) — or wherever Settings → General → Recordings → CHOOSE… points; DEFAULT puts it back. The setting is a path on the machine the radio is attached to, so a remote client sets it on the station rather than on its own laptop. Files are named for when they started and what the radio was doing:

sdroxide_2026-08-23_14-32-05Z_14.074000MHz_USB.mp3

— the UTC date and time, then the dial frequency and mode at the moment you pressed REC. Tuning or changing mode later does not rename the file. All radios share the one folder, so the second and later radios of a multi-radio session put their number in the name (sdroxide_radio1_…); recording is per radio, and each tab has its own REC writing its own file.

The file is 48 kHz MP3 at 192 kbps, encoded on a thread of its own so that neither the encoder nor the disk can interrupt the audio. If the disk does stall for longer than the few seconds of slack in front of it, the recording takes a clean gap rather than a stutter stitched out of whatever fitted.

Started from a remote or browser client, a recording is written on the machine the radio is on — the server’s music folder, not yours (8). REC needs an audio output to tap: with none configured it says so rather than recording silence. It stops by itself if the audio output device is changed under it, and one still running when you quit is closed properly, so there is never a half-written file to repair.

Auto-record. The Auto-record row of the picker follows the receiver’s squelch and gives each transmission its own file: a recording starts when the squelch opens, and closes after the number of seconds of silence you pick — 2 s, 3 s, 5 s, 10 s, or off. A monitoring session then becomes one stamped file per transmission rather than a single file that grows all afternoon through the gaps. It follows its own radio, so a monitor left on a tab behind another keeps splitting its files while you are watching something else. The squelch is what defines silence here, so the chips are only offered when one is set; with the squelch wide open there is nothing to follow and the row says so. It is a session setting like Stop after, not a stored preference, and arming one clears the other — they are two answers to when a recording ends. Turning Auto-record off, though, clears neither: a Stop after timer you set and can watch counting down is left to run, and a quick clip already asked for is left to finish. Choosing none of them is not choosing the other. It needs a front end whose squelch the program itself applies (an SDR); a CAT radio’s squelch belongs to the radio and its meters carry no passband level to follow, so the row says that rather than arming a recorder that would never close. The REC chip shows the difference: armed but waiting is a steady red outline, while a file actually being written fills the chip red and the fill breathes.

Quick clip. The Quick clip row is for a short sample rather than a session: press 30 s or 1 min and the recording starts by itself and stops at the end of that span — small enough to attach to a reception report, with no second press to stop it. Pressing the lit clip again starts the span over. The Stop after row below is the other way to end a recording — 15 through 90 min, or no stop, with a countdown beside the chips — and a clip, a timer and the Auto-record row are three answers to when a recording ends, so arming any one clears the others. All are session settings, not stored preferences.

Recording the spectrum

I/Q WAV, the second row of the REC picker, records the whole span the receiver is delivering rather than the audio of one signal in it: a band you can replay afterwards and tune around inside, decode differently, or hand to someone else. Beside the button is what it costs at the current sample rate before you start it, and the megabytes and minutes written once it is running.

The file is a stereo 32-bit float WAV — I in the left channel, Q in the right — at the receiver’s own sample rate, which is what SDR#, SDRuno, HDSDR, SDRangel and GNU Radio all read. The centre frequency travels both in the name and in the file’s auxi chunk, because those are the two places those programs look, so a capture opens tuned to where it was made:

SDRoxide_20260829_134507Z_14074000Hz_2400000sps_IQ.wav

It also plays back here, with nothing to type — sdroxide --file <capture> takes the rate and the frequency out of the header. --rate and --freq still win if you give them.

It is large: eight bytes a sample. At 2.4 Msps that is 19 MB a second, a gigabyte a minute. A WAV’s sizes are 32-bit and so stop at 4 GB — three and a half minutes at that rate — so a capture that outgrows one is written as RF64 instead, which every program above opens. Nothing to choose: the file is an ordinary WAV until it needs not to be.

A radio that hands over demodulated audio rather than I/Q — a transceiver on a sound card — has no spectrum to record. Started from a remote or browser client the capture is written on the machine the receiver is plugged into, for the same reason the MP3 is, and rather more urgently: a gigabyte a minute is not something to send over a link.

This is the same data --record-iq (12) writes, in a container other programs can open — --record-iq writes the bare samples and starts with the program, which is what a headless capture wants.

Playing a recording back into the decoders

The MP3 is not only an archive. ▶ RECORDINGS…, at the bottom of the REC picker under Play back, opens the PLAYBACK window: the files in the recordings folder, newest first, each read by what its name records — the time, the frequency and the mode — rather than by its file name. Press ▶ PLAY on one and it goes back through the decoders as though it were on the air: the SSTV picture that was missed paints again line by line, CW, RTTY, PSK, Olivia, FT8 and every other mode that decodes from audio decode it afresh, and the waterfall and the decode log fill as they did at the time.

What happens when it plays:

A stereo recording plays back in stereo: a WFM stereo broadcast comes back with its two channels, and ST lights while it does. ST still forces mono, and noise reduction or the auto-notch take it back to mono, exactly as on the air. The decoders always take the left channel — the receiver; on a recording made while transmitting, the right is your own transmit. Playback reads the recorder’s MP3 and also WAV, OGG Vorbis and FLAC made elsewhere: copy one into the recordings folder and it is in the list. A file whose name carries no stamp plays in the mode you are in. An I/Q capture is listed but cannot be played here — it is spectrum, not audio, and plays with --file. A recording is played where the receiver is: from a browser, the list is the station’s recordings folder and the engine opens the file there.

This is a replay of the demodulated audio, not of the band: the frequency offset, the passband and the demodulator were fixed when the recording was made. To tune around inside a recording afterwards, record the spectrum instead.

2.22 QO-100 beacon plugin

The QO-100 (Es’hail-2) narrowband transponder carries a beacon on its lower edge, at 10489.750 MHz, transmitted as 400 baud Manchester BPSK. Every ground station receives it through an LNB whose local oscillator is only roughly on frequency and drifts with temperature — so the dial and the signal disagree by a few kHz, and by different amounts on a cold morning and a warm afternoon. The QO-100 tab of the SAT window (2.16) measures exactly where the beacon really is, corrects the converter/LNB offset so the dial and the signal agree, and then keeps correcting it as the LNB drifts. It lives in the SAT window because QO-100 is a satellite — a geostationary one, which is why it needs no Doppler correction and why keeping its LNB calibrated is the whole of working it.

Everything runs off the raw IQ the hardware is already delivering, so the main dial is never moved and the plugin keeps working with the receiver parked anywhere the beacon is still inside the captured span.

Note: like the skimmers and the ISM decoder, this is a wideband feature. It needs a true IQ source and is unavailable when a CAT radio is feeding demodulated audio.

For a task-oriented walkthrough of getting a Pluto + LNB station onto QO-100 from scratch, see the QO-100 quick-start guide (Türkçe); this section is the reference detail behind its beacon-sync step.

How it works: ON and AUTO

  1. Get the beacon roughly onto frequency first. In Settings ▸ Radio, set the converter/LNB offset for your own LNB and get it as close as you can, so the beacon lands somewhere near 10489.750 MHz on the dial. The plugin corrects a residual error of a few kHz to tens of kHz — not a wild guess.
  2. Open the SAT window and switch to the QO-100 tab.
  3. Press ON. For a fast first approach, step the width value at the top (− / +, in ±5 kHz clicks up to ±50 kHz) until you can clearly see the beacon’s two lobes in the strip. Widen only as far as you need to find it.
  4. Double-click the middle of the beacon in the strip. That plants a “the beacon is here” mark — the two lobes with the null between them, centred on the null. Then press APPLY CORRECTION at the bottom. The receiver reopens on the corrected offset and the beacon jumps toward the centre.
  5. Narrow the width back down (toward ±5 kHz), double-click the middle of the beacon once more to centre it precisely, and APPLY CORRECTION again. Two passes — a coarse one wide, a fine one narrow — get it within a few hundred Hz.
  6. Press AUTO. From now on the offset is corrected continuously as the LNB drifts. You can shrink the window to the corner and leave it running in the background — the correction keeps going with the window closed, and the SAT chip stays lit and the QO-100 tab keeps its dot while it does.

The panel

┌─ SAT ─────────────────────────────────────────────────────────┐
│  [ SATELLITES • ]  [ QO-100 • ]                               │
│                                                               │
│  [ ON ]  [ TELEMETRY ]  [ AUTO ]     width [−] ±25 kHz [+]     │
│  park [lo −][lo +] +5 … +20 kHz [hi −][hi +]                   │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │  mini waterfall — shaded = park lane,                    │  │
│  │  dashed line = 10489.750 MHz target,                     │  │
│  │  double-click the beacon's centre to mark it             │  │
│  └─────────────────────────────────────────────────────────┘  │
│  searching / locked — N blocks tried, M locked                │
│                                                               │
│  TRACKER   +1.2 kHz   (null 12 dB  sym 0.94  snr 15 dB)       │
│  DRIFT     -6 Hz/s  -0.4 Hz/s²                                 │
│  AUTO      -3.19 kHz over 4 corrections   last +80 Hz (7s)     │
│  RECEIVER  10489.750000 MHz                                    │
│  TARGET    10489.750000 MHz                                    │
│  MEASURED  10489.751200 MHz  (tracker)                        │
│  DRIFT     +1.2 kHz                                            │
│  CONVERTER OFFSET  -9749920000 Hz                             │
│  DECODE    ● carrier  ○ sync  ○ CRC    sync 4/32 err ×0       │
│  TELEMETRY <beacon status text, when the decoder locks>       │
│                                                               │
│                 [  APPLY CORRECTION  ]                         │
└───────────────────────────────────────────────────────────────┘

APPLY CORRECTION

APPLY CORRECTION writes the corrected converter offset and reopens the receiver — the same brief interruption Settings ▸ Radio ▸ Apply makes. It uses whichever measurement is current: a decoder lock if the telemetry decoded, otherwise the beacon mark you double-clicked on the strip. From a decoder lock it stays disabled until there have been two locks and the latest carried telemetry text — a 32-bit sync within three bit errors plus a 16-bit CRC pass by pure chance roughly once every couple of hours, and one lock is not enough to change a setting on. After it acts, the window shows what changed and when.

Once AUTO is armed you rarely touch APPLY again — it is the manual path for the first coarse/fine passes, and for stations where the telemetry never decodes and the twin-lobe shape is all you have.

Remote and browser clients

The plugin runs on the machine the radio is on. Its readout is not sent to remote or browser clients yet, so on those the window opens, the strip draws from the shared spectrum, and the status line says the readout is local to the receiving station.



3. Digital modes

sdroxide has several families of digital mode. What they all share — how a mode is entered, the calling-frequency buttons, and the bands with more than one agreed frequency — is in 3.1. FT8, FT4 and FT2 are automatic, timeslot-based modes with QSO sequencing, a world map, and automatic logging; they and the logbook they write into — which also serves every other mode and your manual QSOs — are 3.2. PSK31, RTTY, Olivia, THOR and FSQ are live keyboard modes: you tune onto a signal, read the decoded text, and type a reply that transmits as you go (3.3–3.4). Hellschreiber is a facsimile mode with no decoder at all — it paints letters onto a scrolling strip and you read them by eye (3.5). SSTV is an image mode: received pictures build up in a gallery and you transmit composed images (3.6). RIFP carries pictures as numbered, checksummed packets over its own FSK modem rather than as an analogue scan, and is the one mode here that is not single sideband (3.7). Weather fax receives the charts the meteorological services broadcast on short wave, and transmits nothing (3.8). JS8 uses FT8’s waveform but carries a conversation instead of a contest exchange (3.9). RF Paint is a transmit-only mode that draws text and pictures directly onto the far station’s waterfall (3.10). WSPR is not a QSO mode at all — it is a beacon that measures propagation, and what it produces is a list of paths rather than contacts (3.11).

3.1 General considerations

On 11 m, where the family is worked on the citizens’ band rather than an amateur allocation, the FT8/FT4/FT2 (and JS8) exchange follows WSJT-CB’s conventions instead — grid-less, one call at a time, its own hashed pairs and free-text reports — see 3.2.9.

Every digital mode is entered the same way: open the Band/Mode popup and choose the mode from the DIGITAL row. The panadapter locks to the digital sub-band (the audio range just above the dial), and the mode’s operating panel appears in the lower part of the window; a draggable divider sets how much height the panel gets.

While in a digital mode the BAND row of the Band/Mode popup doubles as a frequency picker. Bands where the mode has a standard calling frequency carry a cyan underline: clicking one jumps the dial straight to that frequency, staying in the mode, and the button highlights when the dial is already on it. Every band is available in every mode — clicking a band without an underline jumps to that band’s default frequency, also staying in the mode, and you tune from there. Where a mode’s convention differs by region — PSK31 and RTTY on 40 m, SSTV on 80 m and 40 m — the button uses the one for the IARU region set on the General tab (6.1).

Two more things hold across the modes. Your callsign and grid are one identity for the whole program: the General settings tab and the FT8/FT4/FT2 setup window (3.2.1) edit the same values, and they fill the keyboard modes’ CQ macros, the FT8/FT4/FT2 exchange, and everything the station reports or uploads. And every digital transmission goes through the normal transmit path, so the ham-band lockout and the usual transmit safety apply in every mode.

Setting your transmit level

On a radio that modulates the audio you hand it — a CAT rig on its sound card, a FLEX, an Icom on its network port — Drive is not the audio control. It reaches the radio’s power register, and a data signal that is overdriving the transmitter will go on overdriving it wherever Drive sits. The control you want is TX audio, in the transmit module in place of the Mic rail (2.10), and the adjustment is: bring it down until the rig’s ALC is barely moving, then set the power at the radio.

Each mode remembers its own level, saved as you set it, because FT8, RTTY, PSK and MCW do not load a transmitter the same way. A mode you have never set starts from the level for the carrier it goes out on — sideband for most modes, FM for VHF packet, APRS and RIFP, where the same control is the deviation instead. All of it lives in digi.json (13).

Choosing a slotted mode tunes the radio

FT8, FT4, FT2, JS8 and WSPR are worked on one dial frequency per band, in lockstep with everyone else on it — a receiver a few kilohertz off is not off-centre, it is deaf — and each of them keeps its own. On 20 m that is 14.074, 14.080, 14.084, 14.078 and 14.095600 respectively, so even arriving from the mode next door is a move. Picking one of them from the DIGITAL menu therefore tunes the dial to that band’s agreed frequency, the same way APRS, ADS-B, VDL2 and AIS already do (3.12, 3.13, 3.15, 3.16).

SSTV and SSTV-FM are in this group too. They are worked on one agreed frequency per band for the same reason, and each keeps its own: 14.230 on 20 m, and on 11 m the community’s 27.700. So choosing SSTV moves the dial just as choosing FT8 does (3.6).

It moves the dial only when it has to, and only inside the band you are already on:

Every other mode leaves the dial exactly where you put it. PSK31, RTTY, Olivia, THOR and the rest are worked across a sub-band rather than on one spot, so a frequency you chose inside it is a frequency you meant. The button below is how those reach a convention — by asking.

The agreed frequencies for a mode, and your own

Every digital mode carries a ⇵ button in its operating panel. It lists every band’s agreed frequency for that mode — FT8, FT4, FT2, JS8, WSPR, PSK, RTTY, FSQ, SSTV (analog and FM), RIFP and APRS all have one — grouped by band with the band you are already in at the top, so changing band is one click rather than a band button and then a number you had to remember.

Several bands have more than one entry, and that is where the list earns its place twice over:

Mode Where it happens
FT8 The DXpedition (Fox/Hound) window on every HF band, 6 m’s second frequency at 50.323, 23 cm’s 1296.500 for where 1296.174 is unusable, and 13 cm’s two narrow-band segments (2320.174 and 2304.174)
RTTY The DX calling spots (3.590, 14.083)
SSTV The move-up-when-busy secondaries — a picture takes two minutes, so one frequency per band is occupied most of the time

The button’s face is the frequency you are on when the dial is already sitting on one of them, and reads ⇵ FREQ when it is not. Clicking a frequency moves the dial; where you sit inside the audio passband is a separate control and is left alone.

WEFAX has its own STATIONS button instead (3.8): its transmitters are not on any band plan, so they are listed by station rather than by band.

Saving your own. The bottom of the list has + Save this MHz, which remembers the dial you are on under the mode you are in. The club net that meets on 3.585 every Tuesday is not in anybody’s global table and never will be, so having found it once you should not have to find it again. Saved entries appear in the same list marked with a ★, in every band group like any other, and carry an ✕ to forget them — published conventions do not, because 14.074 is not this station’s to delete.

A mode the tables have nothing at all for — Olivia, THOR, Contestia, Hellschreiber — still has the button, with nothing in it but the save row. That is the only way the first entry for such a mode could ever be made.

Your saved frequencies belong to the station, not to the screen: they live in digi_presets.json beside the band plan (13), every radio at the station offers the same ones, and a remote client draws the same list the console does. They are also deliberately passive — the band buttons and the “choosing a slotted mode tunes the radio” rule above both stay on the published calling frequency, because those move the dial without being asked and one station’s own note is not where the band is worked. Being on a saved frequency is enough to stop the mode rule moving you off it.

The frequencies that differ by region — PSK31 and RTTY on 40 m, SSTV on 80 m and 40 m — are not offered as a choice, because the IARU region setting (6.1) already says which one applies to you. Set that and the list is your region’s.

An entry shown in amber is one your region’s band plan does not put narrow data on. That is not a mistake in the list: the WSJT-X DXpedition frequencies and the FSQCall set are global conventions built around the Region 2 band plan, and a few of them land in Region 1’s CW or phone segments (1.845, 3.567 and 24.911 for FT8 — of which only 3.567 and 24.911 are still amber in Region 2, where the top of each band is an all-modes segment). The DX will be there and so will everyone chasing it — but check your own band plan before you key, because sdroxide will not stop you.

Saving what a panel has decoded

The text and message panels carry a SAVE chip, next to CLEAR RX where the panel has one. It writes what the panel holds to a file, through the same save dialog the logbook and the ADIF export use, and the suggested file name carries the mode. With nothing decoded yet the chip is greyed out rather than saving an empty file. What goes in the file depends on the mode:

Panel What is saved
CW and the keyboard modes (RTTY, PSK, Olivia, THOR, …) The receive text as it stands, as a .txt file
FSQ One line per message: whether it was for you, sender, addressee and text. FSQ messages carry no time, so there is no time column
ACARS, packet, JS8 and APRS A .csv file, one row per message or frame, with its UTC time
NAVTEX, VDL2 and HFDL A tab-separated .txt file, one line per message, with its UTC time
WSPR and PI4 The reception list as a .csv file, in the RECEPTIONS header
The CW/RTTY skimmer Its spot list, from the Spots row of the skimmer’s settings

The FT8/FT4/FT2 decode list has its own CSV and ADIF buttons instead (3.2.2).

3.2 FT8, FT4 and FT2

FT8, FT4 and FT2 are the automatic modes: timeslot-based, with QSO sequencing, a world map, a transcript, and automatic logging. Choose one from the DIGITAL menu (3.1) and the operating panel appears in the lower part of the window.

Choosing one also puts the dial on that band’s agreed frequency — 14.074, 14.080 and 14.084 on 20 m — because these are worked on one spot per band and a receiver anywhere else decodes nothing. When it does that and when it leaves your dial alone is in 3.1.

The three are the same protocol at three speeds — same message format, same error-correcting code, same panel, same logbook. Only the clock and the bandwidth differ:

  FT8 FT4 FT2
Slot 15 s 7.5 s 3.75 s
Transmission 12.6 s 5.0 s 2.5 s
Tones 8 4 4
Bandwidth 50 Hz 83 Hz 167 Hz
Decodes down to about −21 dB about −17 dB about −14 dB

FT2 is the newest and the fastest — a complete contact takes about six seconds, and sixteen slots go by every minute. It buys that speed with sensitivity and with spectrum: each signal is twice as wide as an FT4 one and needs roughly 3 dB more of it, so it is a strong-signal mode for open bands and contests rather than a replacement for FT8. It also asks more of your clock: with 24 ms symbols, timing that would pass unnoticed on FT8 will cost you decodes (3.2.3).

WARNING — the clock that counts is the one decoding. FT8, FT4 and FT2 cut the audio into fixed periods by the clock of the machine running the decoder. On a station reached remotely (--server, a browser, the native client) that is the server, not your phone or your PC. If the server’s clock is a couple of seconds out, nothing decodes at all: the waterfall is full of signals, the audio sounds perfect, a phone app held to the speaker decodes the same audio — and sdroxide’s list stays empty, with no error in the log. The DT figure on the station card cannot warn you either, because it is measured from decodes and there are none.

Check it on the server before anything else:

timedatectl

It must read System clock synchronized: yes and NTP service: active. A minimal Linux install (a bare Debian server, for example) may have no time service at all — NTP service: n/a. Install one and switch it on:

apt install systemd-timesyncd
timedatectl set-ntp true
systemctl restart sdroxide

Decodes appear within a minute or two. See also Troubleshooting.

The FT8 operating panel

3.2.1 One-time setup: your callsign and grid

Click SETUP in the QSO area to open the FT8 / FT4 / FT2 Setup window:

The FT8 / FT4 setup window

These settings are saved to digi.json (see configuration files).

3.2.2 The operating panel

Across the top is the slot bar — how far through the current turn the clock is. Dim cyan while receiving, pink while you are transmitting, with a mark where your burst stops and the turnaround begins. It fills once per slot: 15 s on FT8, 7.5 s on FT4, 3.75 s on FT2. When it reaches the end the decoder speaks and the next transmission may start, which is why it is worth a glance on a quiet band — an empty decode list under a bar that is still filling is a slot that has not finished yet. WSPR and JS8 have the same bar.

The panel has two halves:

Beyond the everyday exchange, the decode list understands the other FT8 message layouts: compound and non-standard callsigns (DL/W1AW, W1AW/P), hashed callsigns (shown as <W1AW> once that station has been heard, and as <...> until then), free text (13 characters, listed as TEXT since it names no sender), contest exchanges (EU VHF, ARRL RTTY Roundup, Field Day) and DXpedition messages. Transmitting works the same way round: a message that the standard layout can’t carry is sent in the layout that can, and the transcript records what actually went on the air — addressing a compound call sends your own callsign hashed (DL/W1AW <AB1CD> RR73), which drops the signal report, and free text is cut to 13 characters.

The world map

The map in the QSO pane — and the one on the WSPR and APRS panels, which is the same map — is drawn as a dot matrix over the same coastline data the 3D globe is textured with, so a grid square lands on the same shoreline in both views. On the ground it draws:

The borders and rivers are drawn from the geometry they were surveyed as, not from a picture of it, so they are one dot wide at every zoom — a frontier stays a hairline in the right place whether the map is showing a hemisphere or a valley, instead of swelling into a band as you go in.

NIGHT, beside PROP above the map, shades the side of the Earth where the Sun is down, with the twilight between as a graded band, so the grey line shows on the map. Low bands go long and high bands close on the night side, and the terminator itself is where DX often turns up. It follows the clock, not the decodes, so it works with nothing heard yet; it is off by default and is the same switch on the FT8/FT4/FT2 and WSPR maps. The shade darkens land and sea alike, while the cities and the station marks stay on top of it at full strength. On a light theme it is lighter, because there the station marks are dark and would vanish into a dark night.

Drag (or one finger) to pan, wheel or pinch to zoom about the pointer, and double-click to hand the view back to the auto-fit.

3.2.3 Working stations

Transmission happens automatically in your chosen time slot (15 s on FT8, 7.5 s on FT4, 3.75 s on FT2) and goes through the normal transmit path, so the ham-band lockout and transmit safety still apply.

3.2.4 DXpedition mode (Hound and Fox)

FT8’s answer to a rare-entity pile-up. One station — the Fox — transmits up to five signals at once in the low part of the passband and works a queue of callers; everyone calling it — the Hounds — calls from above 1000 Hz. That split is what keeps the pile-up off the one station everybody wants. Set your role in the FT8 setup window. It applies to FT8 only.

While either role is selected the panadapter shades the two halves of the passband, FOX below 1000 Hz and HOUNDS above it, with the half you transmit in tinted more strongly.

As a Hound, click REPLY on the DXpedition’s decode and call from wherever in the calling zone you have set your transmit frequency — sdroxide refuses to move it down into the Fox’s half, and does not follow the Fox down when you answer it. Three things then differ from ordinary operation:

As a Fox, CALL CQ starts the pile-up and STOP QSO stands it down. Callers appear in a PILE-UP strip above the transcript — green for the stations being worked, grey for those waiting — and are taken strongest and rarest first, with anyone already in your log going last. Each transmission carries as many signals as Fox signals allows, spaced 60 Hz apart and sharing the transmitter’s power, so more signals means each one is weaker. Contacts are logged as their RR73 goes out; where a caller is waiting, that RR73 shares its signal with the report opening the next contact.

3.2.5 Contest operation (EU VHF)

European VHF contests do not exchange a grid and a signal report — they exchange a signal report, a serial number and a six-character locator. That does not fit the everyday FT8 message, so the mode has one of its own, and both ends have to be in it for the exchange to be read at all.

Set Contest to EU VHF Contest in the FT8 setup window and put a six-character locator in My grid (JN88DD, not JN88). Without one there is no honest message to send, so sdroxide sends the ordinary exchange instead and the setup window says so beside the serial number. The activity applies to FT8, FT4 and FT2; every other mode ignores it.

The exchange then runs:

CQ TEST G4ABC/P IO91
                             G4ABC/P PA9XYZ JO22
<PA9XYZ> <G4ABC/P> 590003 IO91NP
                             <G4ABC/P> <PA9XYZ> R 570007 JO22DB
PA9XYZ G4ABC/P RR73

The first two messages and the last are ordinary ones, carrying both callsigns in full. The two in the middle are the contest layout: the callsigns travel as hashes — which is what buys the room for the locator and the serial — and are shown in angle brackets. A station whose callsign you have not yet heard spelled out appears as <...>; that is the layout’s own bargain and not a fault. It is also why the exchange is preceded by the two ordinary messages.

The number in the middle is the exchange itself: 59 is the signal report, as the two digits of an RS, and 0003 is the serial number. sdroxide derives the report from the measured signal exactly as WSJT-X does, so it is a real report and not a formality.

The serial number advances by itself as each contact is logged, and is remembered between sessions — a contest runs over a weekend and across restarts. Set it by hand only to start a contest, or to pick up where a paper log got to. A contact keeps whatever serial it first sent, so a number that advances while an exchange is still in progress cannot change halfway through. It wraps back to 1 past 2047, which is as far as the layout’s field reaches.

In the log, a contest contact keeps what was actually exchanged: the reports are the two RS values that went over the air rather than the signal-to-noise ratios behind them, the serial numbers land in ADIF’s STX and SRX, and the exchanges whole in STX_STRING and SRX_STRING. The six-character locator becomes the station’s grid, so the map and the distance get the better answer.

The FT8 exchange takes a second decoding pass, so it only runs with the contest selected. The 77-bit layout the exchange rides in is one the FT8 decoder underneath sdroxide does not know how to write out, and it discards what it cannot write — so the exchange used to decode correctly and then be thrown away before anything could see it, in FT8 and only in FT8 (FT4 and FT2 take a different path and were never affected). sdroxide now runs a second pass over each slot that keeps exactly that layout and nothing else. It costs about what the ordinary decode costs, which is why it runs only while Contest is set to EU VHF Contest: switch the contest on to hear contest exchanges, not only to send them. A four-character grid is no obstacle to hearing them — it only stops you sending the exchange.

Only EU VHF is implemented. WSJT-X offers five other special operating activities — ARRL Field Day, the RTTY Roundup, NA VHF, WW Digi and ARRL Digi — each with its own message layout and its own exchange. sdroxide decodes the Field Day and RTTY Roundup layouts when it hears them; it does not transmit them.

3.2.6 Reporting what you hear

Enable Upload my FT8/FT4/FT2/JS8 decodes on the Network settings tab to report every station you decode to pskreporter.info, where your station then shows up as a receiver and your reports feed everyone else’s propagation maps. JS8 is reported too (issue #357), and it is reported a little differently: a JS8 decode is a single frame that names nobody, so the report goes out once per message, when the frames have been reassembled and there is a callsign to send — a station’s twelve-frame message is one reception, not twelve. Reports are batched and uploaded every five minutes (the interval the collector asks for), keeping the strongest report per station per band. The callsign and grid come from the General tab — both are required, since a report with no location can’t be placed on the map. The optional Antenna line is shown on your station’s page. The Collector host and port are there for testing: port 14739 is the project’s test collector, which accepts reports without publishing them.

3.2.7 Who your hashes can name — the KNOWN window

An FT8 message does not spell out the station it addresses. It carries a hash of the callsign — a number derived from it — and a receiver that has not heard that station spell its name cannot turn the number back into a callsign. There is no arithmetic that inverts it: <...> is all that will ever be recoverable from that message, and the same is true of WSJT-X and of every other FT8 program on the band.

The only way a <...> becomes a callsign is for the station to have been heard spelling it out at some point, in any message. The receiver remembers those callsigns, and that set is what resolves the hashes afterwards. On 11 m this is deliberate protocol: a station answers a CQ with its bare call — 26AT715, free text, addressing nobody — precisely so that everyone listening can resolve its hash in the exchange messages that follow, which are hashed. A station that never spells its call out stays <...> for good, and nothing can be done about that.

That set was invisible. You could watch a message resolve and had no way to see why, or to browse who you currently know. The KNOWN chip sits in the general decode’s filter row, beside New only, and opens a window listing every callsign a hash on this receiver can currently name — newest first, with its country:

The chip is on the general decode’s row because that is where the <...> is that gives you a reason to open it. It needs a receiver running a digital mode; on a phone it is one of the panes rather than a window.

3.2.8 Logging and the logbook

Completed FT8/FT4/FT2 QSOs are logged automatically. Open the full logbook with the LOG button (System module).

The logbook

The logbook lists QSOs grouped by day (newest first) and covers both digital and manual entries. You can:

A small status column on each row shows QSL state: a green ✓ once a QSO is confirmed (LoTW, eQSL or card), a dim ↑ once it has been uploaded but not yet confirmed. Hover it for the per-service detail.

Records also hold the fields used by lookup, upload and awards — DXCC entity, CQ/ITU zones, IOTA and POTA/SOTA references, and per-service QSL status. See §9. Spotting, awards, and QSL upload for the one-click upload buttons and award tracking.

The log is stored in qso_log.json.

3.2.9 11 m and the citizens’ band (WSJT-CB)

On 11 m the whole exchange follows the conventions of the community’s WSJT-CB client rather than the amateur FT8 ones — because that is who is on the band to work. Press 11M in the band row and the mode’s band buttons land on the citizens’ band’s own channels as usual (6.1 lists them), but everything the sequencer puts on the air changes:

Modifier suffixes are plain WSJT-CB, and they just work. A station may put the usual portable-style suffix on its 11 m call — 19DC373/P, /MM, /QRP, or an event marker like /F1 — and this build accepts it, because WSJT-CB does. It widens the standard callsign rules rather than replacing them, so those suffixes ride on a CB identifier unchanged. Nothing has to be switched on, and the country and flag on the decode row still resolve from the base call.

⚠ An 11 m callsign may not exceed 11 characters — including any /zzz

This is a hard limit of the FT8 callsign field, not a setting and not a limitation of this build: a CB call travels in clear as a 58-bit base-38 number, and 38^11 is just under 2^58, so eleven characters is the ceiling for the whole identifier. Any implementation refuses a longer one.

The suffix is counted. 19DC3733/P is 10 characters and fits. 19TST1001/QRP is 13 and cannot be sent by anyone — a station announcing it is announcing something that will not go out.

Plan the activation call to this budget before you announce it. The slash counts too: /P costs 2 of the 11, /F1 costs 3, /QRP costs 4, and the grammar allows up to 5 (/XXXX). However the call is written, base plus suffix must come to 11 characters or fewer:

Activation callsign Length Sendable
19DC373 8 yes
19DC373/P 10 yes
19DC3733/P 10 yes
19DC373/QRP 11 yes — exactly at the limit
19TST1001/QRP 13 no
19DCG3733/P 11 yes (needs the wide grammar, below)

The same rule is checked live in Settings → General: type a too-long 11 m call there and it is flagged as it is typed, before the first transmission rather than after it.

This applies to the citizens’ band only. An amateur callsign is not held to this and is not flagged.

The experimental wider CB callsign grammar. WSJT-CB’s identifier shape is N{1,3}L{1,2}N{1,3} — a country prefix, one or two letters, a unit number — and that is what runs by default. The 11 m community has grown past it, and some stations now use three-letter groups or four-digit unit numbers (26ABC715, 26ABC1000), which that grammar refuses. Settings → General → 11 m / WSJT-CB callsign grammar → WIDE CB CALLSIGNS — EXPERIMENTAL accepts the wider shape N{1,3}L{1,3}N{1,4} — and the matching slash form N{1,3}L{1,3}/L{2} — on top of the default one, so everything the strict grammar takes is still taken. It is experimental and off by default: WSJT-CB itself does not accept the wider shape, so switching it on widens what this station hears and lets it pack a wider call pair, but a call that needs it may not be understood by a station running WSJT-CB. The toggle is not what makes modifiers work — those are accepted either way, since they are WSJT-CB’s own behaviour. Nor does it buy any extra length: it changes the shape a call may have, and the 11-character ceiling above applies exactly as it does with the toggle off, so 19DCG3733/P (11) is sendable and 19TST1001/QRP (13) is not.

A note on what a CB call looks like on the wire, because it is not a hash and the older wording here said it was. A non-standard call is carried in clear, as a 58-bit base-38 number, which is why it is at most 11 characters and why two different calls can never be confused for one another. The 22-bit hash belongs to only one case — the grid-less layout used when both stations are CB, where one call is abbreviated — and it is a property of the FT8 family, not of this setting.

3.3 PSK31 and RTTY

Choose PSK or RTTY from the DIGITAL menu of the Band/Mode popup. As with FT8/FT4/FT2 the panadapter switches to a zoomed sub-band waterfall, but the lower panel is a live messaging area instead of a QSO sequencer.

The PSK/RTTY messaging panel

Receiving:

Transmitting (type-ahead):

Settings (PSK/RTTY setup dialog):

Skimmers: the PSK and RTTY skimmers (see Skimmers) label signals across each band’s PSK/RTTY calling sub-bands. Clicking a label from any mode switches to PSK or RTTY, tunes onto the signal, and opens this panel — onto the standard tone pair in RTTY, so the offset you land on is the one you will transmit. A label already in that mode leaves your own offset alone.

On VHF and UHF, use RTTY-FM instead. Some national societies still send their weekly bulletin as RTTY on a 2 m FM channel, and that is not the same signal as RTTY on a sideband — the tone pair modulates an FM carrier rather than riding on one edge of a passband. RTTY-FM is on the DIGITAL menu beside RTTY.

Everything about the modem is the same: the same Baudot alphabet, the same 2125/2295 Hz tone pair, the same shift, baud and Reverse controls and the same panel. What differs is the radio and the frequency:

Its band buttons are the FM calling channels — 50.150, 145.500 and 433.500 — because RTTY on FM has no worldwide convention at all: where it is still used the frequency comes from the society running the bulletin. Tune the real one and store it in a memory.

3.3a SYNOP and SHIP — coded weather reports (BETA)

BETA. The decoder is tested against four real published messages and decodes all of them, but no report has been read off the air by this code yet. If you try it and the numbers look wrong, or a report does not appear at all, please say so — that is what this note is for.

Ships and land stations broadcast the weather where they are as coded numbers on HF RTTY, every few hours. It is the plainest service on the shortwave band: no internet, no account, no timeslot booking — just a schedule you can read off a piece of paper.

Set RTTY, 50 baud, 170 Hz shift, and listen on one of:

kHz Who
4583 German weather service (DKD/DWD), 24 h
7646 the same, worldwide schedule
10100.8 the same, higher power

They go out roughly every six hours across two codes:

UTC Code What
02:00, 07:35 SHIP — WMO FM 13 ships
00:35, 12:10 SYNOP — WMO FM 12 land stations
08:15, 20:15 BUOY — FM 13 buoys

These are the quietest hours on the band. Leave it running.

The line arrives as a wall of figures and means nothing on its own:

BBXX BRAVO 20123 99252 10595 41494 81412 10285 20269 40100 53012 79586 8597/ …

When one is recognised, a WEATHER chip appears beside the message box with the number of reports heard. Press it and a window lists them newest first, each one giving:

A slash is an answer, not a gap. Groups like 8597/ mean not reported — neither zero nor missing — and are shown as not reported. A blank there would read as our fault rather than the station’s.

Anything the decoder does not recognise as a group is kept and shown as the station’s own words. Human-entered reports put the interesting part in exactly that way, and it is the part worth reading.

Nothing leaves the program: the list is for this session only, because a report read tomorrow is a lie about when it was observed.

3.4 Olivia, THOR and FSQ

Three more keyboard modes are on the DIGITAL menu. Olivia and THOR reuse the same messaging panel as PSK/RTTY — including SEND ON RETURN (3.3), which is worth a look in these modes in particular: at 32/1000 Olivia a typed correction takes long enough to send that it is better not to have sent the mistake. Each mode’s submode is chosen on its setup page (⚙ SETUP):

FSQ (Fast Simple QSO) has its own panel for the directed FSQCALL layer. It is a 33-tone incremental-FSK mode; choose the speed (FSQ-2/3/4.5/6) and an FSQ call on the setup page (defaults to your callsign):

These three modems are native-Rust and self-contained. On-air interoperability with fldigi is being validated; the first release targets clean-to-moderate signals.

3.5 Hellschreiber

Choose HELL from the DIGITAL menu for Hellschreiber — the oldest digital mode still in regular amateur use, and the only one you read with your eyes instead of a decoder.

Hell does not send characters. It sends pictures of characters: the transmitter scans a 7-column by 14-row dot matrix per letter, top to bottom then left to right, switching the carrier on and off as it goes. The receiver simply free-runs at the same dot rate and paints whatever it hears onto a scrolling strip. There is no synchronisation, no framing and no error correction — which is exactly why Hell stays readable in conditions that break real decoders. A burst of noise smudges a few dots instead of corrupting a whole character, and your eye does the rest.

The Hellschreiber panel: the scrolling receive raster above the transmit box

Reading the strip. Received text scrolls in from the right. Because nothing synchronises the vertical position, a character can straddle the top and bottom of the strip — so, like fldigi, sdroxide draws every column twice, stacked. Whatever the alignment happens to be, one complete legible copy of the text is always on screen. That is what the 2ROW button controls; turn it off for a single-height strip and drag the raster up or down to line the text up yourself.

Panel controls. The header carries the audio-tone readout with −/+ nudges, the variant buttons, and the decode squelch. Below that:

Transmitting works like the other keyboard modes: type in the box and press TX. Characters already sent turn green. CALL CQ loads a CQ using your callsign, and CLEAR empties the buffer and stops. While TX is held with nothing to send, Hell transmits blank paper rather than dropping the carrier, which is how it holds a channel between overs — so press TX again to release. Your own transmission is painted onto the same strip as it goes out, which is the only confirmation Hell offers that your timing and font are right.

SEND ON RETURN (3.3) applies here too, and Hell is the mode where the difference is plainest: a correction typed live is already on the paper — the receiving operator watched you make it — while one made before you press Return never existed. The strip then ends with the line: transmit releases once the text has been painted, rather than holding the channel with blank paper for as long as you take to type the next one. Pressing TX over an empty box still holds it, so the between-overs habit is there when you want it — it is simply no longer what composing a line does. The break itself has no glyph, so it goes out as one blank cell, which is the gap you would have typed between lines anyway.

Variants. Seven, matching fldigi’s set:

Variant Speed Bandwidth Keying
FELD 2.5 char/s 295 Hz on/off keyed
SLOW 0.3 char/s 35 Hz on/off keyed
X5 12.5 char/s 1470 Hz on/off keyed
X9 22.5 char/s 2645 Hz on/off keyed
FSK245 2.5 char/s 490 Hz frequency-shifted
FSK105 2.5 char/s 220 Hz frequency-shifted
HELL80 5 char/s 1200 Hz frequency-shifted

FELD (classic Feld Hell) is what essentially all on-air activity uses; the others are worth knowing about but you will rarely meet them. SLOW trades speed for a 35 Hz bandwidth that survives conditions nothing else will. X5 and X9 are fast but wide — X9 occupies nearly the whole SSB passband, so the tune control clamps it near the middle where it fits. The FSK variants keep the carrier up and shift it instead of keying it, which suits a linear amplifier better and gives a noticeably cleaner raster.

Hell transmits on USB. The band buttons are preset from the hellschreiber.com narrow-band digimode band plan (18 March 2019), using its common calling and operating frequencies:

Band Preset Band Preset
160 m 1.840 17 m 18.104
80 m 3.574 15 m 21.063
60 m 5.3515 12 m 24.924
40 m 7.040 10 m 28.063
30 m 10.144 6 m 50.286
20 m 14.073    

These are IARU Region 1 values where that band plan splits by region, and — unlike the band plans and the other modes’ calling frequencies — they do not follow the IARU region setting: Hell has no per-region table published to follow. Region 2 and 3 differ on 160 m and 80 m in particular. Bands quoted as a range use its low edge, so tune up from the preset to find activity. 6 m is not in that band plan and comes from the Feld Hell Club.

On 15 m and 10 m the presets are 21.063 and 28.063 rather than the 21.074 / 28.074 the band plan names as calling frequencies, because those two sit squarely in the FT8 sub-band — and fall outside the operating ranges the same table lists beside them.

Hell is a “fuzzy mode” (J2B), so it may be sent in either the CW or the phone segments; band plans are recommendations, and listening before you key matters more here than the numbers do. Check them against a current plan for your region.


3.6 SSTV

Choose SSTV from the DIGITAL menu to send and receive pictures. The panel has a received-image gallery on the left and a transmit compositor on the right, with a row of mode buttons across the top: Auto, Scottie 1, Scottie 2, Scottie DX, Martin 1, Martin 2, Robot 72, Robot 36, SC2-180, SC2-120, and the PD family — PD50, PD90, PD120, PD160, PD180, PD240 and PD290.

The SSTV panel: received-image gallery and the transmit compositor

Auto (the default) auto-detects the mode on receive — from the VIS header, or, if you tune in mid-picture, from the sync cadence — and transmits in Martin 1 until a mode has been detected. Selecting a specific mode instead pins both the receive decoder and the transmit compositor to that mode.

The PD family is worth knowing about if you have only ever used Scottie and Martin: it sends the colour information for two lines at once, which buys a bigger picture for the same air time. PD120 and PD180 are 640×496 and PD290 is 800×616, against 320×256 for everything else — and PD120 is one of the two or three modes you are most likely to meet on 3.730 and 14.230. Wraase SC2-180 is the other, at 320×256 in three minutes. The transmit compositor follows the mode’s size automatically, so picking PD180 gives you a 640×496 canvas to crop into.

If a mode arrives that sdroxide does not have, the panel says so where it would otherwise say listening… — for example Pasokon P3 — not decoded. That is not a fault at your end: the header was read perfectly and there is simply no decoder for that one. Before 1.6.9 nothing was said at all, which made an unimplemented mode look exactly like a broken receiver (issue #421).

Band buttons tune to that band’s common SSTV calling frequency, staying in SSTV. 14.230 MHz on 20 m, 21.340 on 15 m and 28.680 on 10 m are the same the world over; 80 m and 40 m split by region and follow the IARU region setting (6.1) — 3.730 and 7.165 in Region 1, 3.845 and 7.171 in Regions 2 and 3. Above HF, 144.500 on 2 m and 432.500 on 70 cm, the narrow-band SSTV activity centre.

Choosing the SSTV mode does the same thing. Selecting SSTV while already on a band moves the dial to that band’s SSTV frequency, so “pick the band, pick the mode” lands you on the pictures rather than wherever the last mode left you. On 11 m that is 27.700 MHz, the community’s picture frequency, with 27.255 (channel 23) and 27.375 (channel 37) as the in-band alternatives. This is the same rule the slotted digital modes and WSPR have always used, extended to SSTV and SSTV-FM; it only ever rescues a dial that is nowhere useful, because a dial already sitting on one of the mode’s own frequencies is never moved — nor one within 3 kHz of it, or one you saved yourself with ⇵ FREQ below.

To decode SSTV anywhere, light KEEP DIAL beside the ⇵ FREQ chip. With it on, choosing SSTV leaves the dial exactly where you tuned — a local net, a picture heard somewhere off the list — and the published frequencies stay one click away in the picker. It is remembered, and it covers SSTV and SSTV-FM only: FT8 and the other slotted modes still move, because off their frequency they decode nothing. Without it, the same is reached by choosing SSTV first and tuning afterwards — a dial moved once the mode is chosen is never moved back.

The ⇵ FREQ chip at the top left of the panel is where that frequency list lives: it shows the calling frequency and the alternates, tuning the dial when you pick one, and letting you save a frequency of your own — which is how you keep one a local group has settled on. The chip doubles as a readout, showing ⇵ 27.700 when the dial is on one of the listed frequencies and plain ⇵ FREQ when it is not.

Which sideband: SSTV is a phone emission and follows phone practice rather than the other digital modes’ fixed USB — LSB on 160, 80 and 40 m, USB on 20 m and up. sdroxide switches for you: the passband flips to the other side of the dial as you tune across the boundary, and a CAT-controlled rig is commanded into the matching sideband. Nothing to set, and nothing to undo when you go back up — a picture sent on the wrong sideband arrives at everyone else inverted.

Plain sideband or the rig’s data mode: the picture is modulated here and reaches the radio through its sound card, exactly as FT8 does, so SSTV obeys the Digimode mode setting (6.2) like every other digital mode. Leave it on DIGI and a rig with a DATA position is put in USB-D above 40 m and LSB-D at and below it, which is what takes the transmit audio from the USB/data input rather than the microphone. On USB the rig is put in the plain sideband instead — the right answer for a radio whose SSB modulation source is already set to USB, or one with no data mode at all.

On VHF and UHF, use SSTV-FM instead. Above 30 MHz a picture is normally sent on an FM carrier rather than a sideband, so the DIGITAL menu has a second entry — SSTV-FM — beside SSTV. Everything about the picture is the same: the same transmission modes, the same decoder, the same gallery and the same compositor. What differs is the radio underneath. SSTV puts a CAT-controlled rig in USB (or LSB); SSTV-FM puts it in FM, and the dial is the centre of a channel rather than the foot of a passband.

Its band buttons are the FM image channels: 50.510 on 6 m, 144.500 on 2 m and 433.400 on 70 cm — the IARU Region 1 plan’s own, the last of which it names as SSTV (FM/AFSK). Region 2’s plan appoints no image channel at all (the ARRL 2 m plan calls 145.50–145.80 “miscellaneous and experimental modes”), so a Region 2 station is offered 145.500 marked as common practice rather than as something a plan says. Region 3 names none, and none is offered.

Pick by what the other station is doing, not by the band alone: 2 m SSTV on sideband is a thing people do, and both modes are available everywhere. If a picture is audible but decodes as noise, the usual cause is being in the wrong one of the two.

Receiving:

Transmitting:

Note: SSTV decode/encode runs in the server engine, so the panel works the same in the native app and the browser client. RX quality depends on signal conditions — clean signals decode well; weak or drifting signals may slant or show noise (ongoing refinement).

3.7 RIFP (Radio Image Framing Protocol)

Choose RIFP from the DIGITAL menu to send and receive pictures over draft-dulaunoy-rifp-00 — a packetised image protocol, and the only mode here that is not single sideband. Its rifp-cpfsk-4800 radio profile keys the carrier itself: continuous-phase binary FSK, 4800 baud, ±4 kHz deviation, in a channel about 25 kHz wide. The dial is the middle of the signal, not its lower edge.

The panel is the SSTV panel — the same live picture, the same received gallery, the same five transmit slots with their own overlay messages — with a RIFP control strip in place of the SSTV mode buttons. Pictures you load are shared between the two modes.

⚠ Bandwidth. 25 kHz does not fit in a narrow-band segment. sdroxide will transmit RIFP wherever you tune it, and the panel says so in red whenever the dial is somewhere the channel does not fit. The segments it treats as wide enough are 10 m FM (29.510–29.700), the 6 m all-modes part (50.5–52.0), the 2 m all-modes part (144.500–144.794) — where the image and facsimile modes have always lived — and 70 cm (430–440). The band buttons in the Band/Mode popup land in each of those while staying in RIFP, and the 433.920 button jumps to the calling frequency the draft names. Allocations differ by country and your own licence may be narrower than 25 kHz even inside those — checking that is yours to do, not the software’s.

The controls:

Receiving:

Transmitting: identical to SSTV — pick a slot, load an image, type its message, press TX. The status line shows which frame of how many is going out and how long is left. Your callsign travels as the protocol’s Sender ID extension.

3.8 Weather fax (WEFAX / radiofax)

Choose WEFAX from the DIGITAL menu to receive the weather charts the meteorological services broadcast on short wave — surface analyses, wave heights, ice edges, satellite composites. It is receive only: these are commercial and military transmitters, and an amateur station has nothing to send back.

The weather-fax panel: a chart arriving, the station picker, and the gallery

Finding a signal. The STATIONS button lists the schedules — DWD Pinneberg, Northwood, the US Coast Guard transmitters, Halifax, Tokyo, the two Australian ones — and picking a frequency tunes the dial. Note that the frequencies in every published schedule are the assigned carrier, and USB reception needs the dial 1.9 kHz below it: 7880 kHz is tuned at 7878.1. The picker does that subtraction for you, which is worth knowing because getting it wrong is the commonest reason a chart comes out as a blank page.

Like NAVTEX, WEFAX is a timetable. A station sends its charts at set times on set frequencies, so for most of the day a picked frequency is simply quiet — that is normal, not a fault. The schedule is when to be there. It also changes (a station closes, a frequency moves), so treat the listed times as a good guide rather than a guarantee: if nothing comes at the advertised time, try the next frequency in the list before deciding anything is broken.

Tuning. The +0 Hz readout beside the START button is the subcarrier’s offset from where it should be. Tune for roughly zero, green: a fax subcarrier runs 1500 Hz for black to 2300 Hz for white, and a receiver a few hundred hertz off clips the picture to solid black or solid white. You will hear the signal as a warbling two-tone note.

Starting and stopping. A transmission opens with a five-second start tone and closes with a stop tone, and with AUTO START and AUTO STOP on sdroxide uses both — leave the mode running and charts appear on their own. Since a chart takes a quarter of an hour, though, you will usually have tuned to one already in progress: press START to begin recording mid-chart, and STOP to end it and save. Turn AUTO STOP off to record straight through a station sending several charts back to back.

A stop tone is five seconds long and it is the first thing a fade takes, so AUTO START does not wait for one: while a chart is being drawn sdroxide also listens for the next transmission — its start tone, and failing that the thirty seconds of phasing signal behind it, which is far too long to miss. When one turns up the page in progress is saved and the new one is phased from the top, so a station sending chart after chart gives you one straight page each rather than one endless page with every chart after the first shifted sideways. Turning AUTO START off turns that off too: the capture then runs until you press STOP, which is what an operator recording a continuous transmission wants.

Geometry. Nothing in the signal states the line rate, so:

Straightening the picture. Two controls, and both are normal to need:

On the globe. While you are tuned to a station in the list, the 3D solar view (7) draws the path from your QTH to that transmitter, exactly as it draws the station you are working in FT8. Weather fax carries no callsign and no grid square, so this is the only thing that turns an anonymous chart into “this came 900 km across the North Sea” — and it makes the propagation obvious when a station you can hear all night in winter vanishes at noon.

The picture. The chart paints line by line as it arrives, in a view you can scroll and zoom while it is still coming in — a chart takes a quarter of an hour, and there is no reason to wait for the bottom of it before reading the top. The VIEW controls decide how it is shown:

The gallery. Completed charts are written as grayscale PNG to ~/Pictures/sdroxide/wefax/ — with your pictures rather than in a hidden config directory, because a weather chart usually gets printed, mailed or opened next to a routing program, and all of that happens in a file manager. Each is named for when it was received and what it was tuned to:

wefax-20260729-141530Z-7878.1kHz-DWD.png

that is, UTC date and time, the dial frequency, and the station’s callsign when the dial is on a published schedule. The strip on the right of the panel lists them newest first, each labelled with its date, time and station; click one to open it full size, which you will need to — the fronts and isobars are unreadable at thumbnail scale — and ◀ NEWER / OLDER ▶ step through the rest without closing the window. PATH copies the directory.

A station that keys up over a dead band fills the directory with grey pages, so charts can be thrown away from the panel: right-click a card and choose Delete this chart, or use DELETE in the open chart’s window, which asks a second time before the file goes. The chart is deleted on the machine the radio is plugged into and disappears from every screen attached to it. Deleting the chart you are viewing leaves the window on the next-older one — the same place OLDER ▶ would have gone — so a run of blank pages goes in a sequence of clicks.

Charts saved by earlier versions in ~/.config/sdroxide-brown/wefax_rx/ are still listed alongside the new ones, so nothing you have already received disappears. Deleting one takes both copies, so a chart that was in the old directory too does not reappear on the next listing.

3.9 JS8

Choose JS8 from the DIGITAL menu. JS8 uses FT8’s waveform — the same eight tones in the same 79-symbol frame — but carries a conversation instead of a contest exchange: free text, questions you can ask another station, and a periodic “I am here” heartbeat. Because it is slotted like FT8 it decodes far below the noise floor, and because it is a conversation it is slow. A sentence takes about a minute. That is the trade. Selecting it puts the dial on the band’s JS8 frequency — 14.078 on 20 m, and the traffic in the 3 kHz above it (3.1).

Speeds. Four of them, on buttons in the panel header:

Speed Slot Width Use
SLOW 30 s 25 Hz The weak-signal end
NORMAL 15 s 50 Hz The band convention; nearly all traffic
FAST 10 s 80 Hz Good conditions, shorter waits
TURBO 6 s 160 Hz Local and VHF work

They are drawn in that order — slowest and narrowest first, fastest and widest last — because that is what they are: one dial, not four unrelated choices.

Both stations must be on the same speed to work each other — they are different waveforms on different slot clocks, not different settings of one receiver, so a station transmitting NORMAL is not something a TURBO receiver can hear. Normal is what you want unless you have agreed otherwise.

MULTI, the chip set apart to the right of the four speeds, decodes all of them at once (issue #358). All four speed buttons then light, because all four are being listened to, and a small ▸ marks the one you transmit at — click another to move it. Everything on the band is decoded whatever speed it is on, so a station calling you from another one appears in the heard list instead of not existing, and you can drop onto its speed to answer. In the conversation list each message then carries a one-letter tag after its time — S, N, F or T — saying which of the four it came in on; hover it for the name. Without it there is nothing on screen to tell a quiet band from three quarters of a busy one. It costs about four times the receive CPU — four separate decodes on four separate slot clocks — which is why it is off by default; a slot that arrives while the decoder is still behind is dropped rather than queued, so a machine that cannot keep up loses decodes instead of falling further and further behind the band.

The JS8 panel: stations heard on the left, the conversation on the right

The panel. Under the header is the slot bar, the same one FT8 has (3.2.2) — how far through the current turn the clock is, dim cyan receiving and pink transmitting. Here it also shows what the speed buttons actually do: the bar takes six seconds to cross on TURBO and thirty on SLOW.

Stations heard are listed on the left in the same rows the FT8 decode list uses — report, frequency, callsign, what they would be worth (DXCC / BAND / GRID / NEW / DUPE), the country’s flag, continent, grid, distance, and the last thing they said — so a band you have learned to read in FT8 reads the same way here. Hovering a row brings up the full station card: entity, zones, bearing, and whether you have worked them before. A row addressed to you is boxed in gold; a heartbeat or a CQ, which are invitations, get the red CQ background.

The conversation is on the right, newest at the bottom, with anything addressed to you marked ★. Each line reads sender · recipient · command · text — OH8STN answering KN4CRD shows as OH8STN: KN4CRD HEARTBEAT SNR -02 — because on a busy channel half a dozen stations answer the same beacon inside a minute and the report alone does not say which of them was being answered. The heard list summarises the same way. A message still arriving is shown greyed with a frame count, because a half-received sentence should not read like a complete one. CLEAR RX, at the end of the button row, empties the conversation, and is greyed while there is nothing in it. The heard list is left alone — it is a separate pane, and it is what HEARING? is answered from.

Replying. Clicking a message — or a station’s REPLY button — aims the composer at that station and drafts the reply the exchange expects. A heartbeat or a CQ is asking “can anyone hear me?”, so it drafts a signal report; SNR?, GRID?, STATUS? and HEARING? draft their answers; HW CPY? drafts a report; RR and QSL draft 73; AGN? puts back the last thing you sent. It is only ever a draft — it lands in the text box and you are free to rewrite it, because most of JS8 is conversation and there is no standard answer to “good evening from Vienna”. Free text drafts nothing and only selects the station. Clicking a row rather than its REPLY button selects without touching what you have already typed.

Sending. Nothing goes on the air until you press SEND or Enter. The buttons under the conversation only fill the text box, so what is about to be transmitted is always on screen first, and you can still change it. Beside the send button is an estimate — 3f · 45s — of how many frames the message needs and how long it will be on the air. Watch that number before you press send; it is the thing newcomers to JS8 find most surprising. The message goes to whoever the label in front of the box names: the selected station, or @ALLCALL when there is none.

With a station selected, the query buttons draft a question for it: SNR? for a signal report, GRID?, HEARING? for what it is copying, STATUS? for its status message, HW CPY? for “how do you copy me”, and RR / 73 to acknowledge and sign off. With nothing selected they are greyed. CQ drafts a general call and HB a single heartbeat, and both stay addressed to everyone even while a station is selected — selecting someone never turns a CQ into a message for them. Typing CQ or HB yourself does the same. CLEAR TO, past the rule at the end of the row, forgets the selected station and puts the composer back on @ALLCALL; it is greyed while nothing is selected.

Anything addressed to a callsign — typed, drafted or from a button — goes out as a JS8 directed frame, so the station at the other end sees a message meant for them rather than words that happen to name them. When the message opens with a command the mode knows, that command travels in the frame too; when it carries more than the frame can hold (a grid, a status line, a sentence) the rest follows as free text. The framing is byte-identical to JS8Call’s own, which is what the tests check it against. Relay and message-store commands are the exception: this station does not act on them, so it does not originate them either, and they go out as ordinary text.

On the map. Heard stations appear on the 3D globe (3D in the DISPLAY row) exactly as FT8 decodes do, and the station the composer is aimed at gets the contact arc from your QTH. Most JS8 traffic carries no locator — only heartbeats, CQs and GRID replies do — so if callsign lookup is configured (⚙ SETTINGS → Network → Uploads) the rest are resolved through it, one at a time, and their grid is shown greyed to mark it as looked up rather than heard. Because JS8 beacons every ten or fifteen minutes rather than every slot, a station stays lit far longer here than in FT8.

Answering automatically. In ⚙ SETUP, Auto-reply answers SNR?, GRID?, STATUS? and HEARING? queries addressed to you or to @ALLCALL — with the answer, not just the acknowledgement: a report rides in the frame itself, and a grid or a status line follows it as text. This is what makes a JS8 station worth leaving switched on, and it is on by default. It never answers another station’s traffic, and never answers itself.

Heartbeat reply answers a heard heartbeat with a signal report, so the station beaconing learns who copied them and how well. It is off by default, and deliberately hedged about: a busy band carries a heartbeat every slot, and a station that answered all of them would flood exactly the band heartbeats exist to keep quiet. So it answers a given station at most once every 15 minutes, never while a multi-frame message is still arriving, and never while you have something of your own queued to send — an answer that waited behind a long message would carry a stale report anyway. A CQ is never answered automatically at all: it asks for a contact, and starting one is your decision.

Beaconing. Heartbeat transmits your callsign and grid on an interval so others know you are receivable — off, 10, 15, 30 or 60 minutes, the choices JS8Call offers. It is off by default: an unattended beacon is something you should choose, not something a mode switches on for you. HB AUTO in the panel header turns it on and off without opening SETUP, and the countdown beside it says when the next one goes out — a transmitter that keys itself should say so where you are already looking.

The first heartbeat is a whole interval away rather than immediate, so choosing an interval never keys the radio before you can change your mind. Each one is scheduled with up to a slot of jitter, because stations that share an interval and started together would otherwise collide on every beacon. Turbo does not beacon at all, and cannot acknowledge one: it is the local and VHF speed, and an unattended transmitter there spends a lot of a small band to reach nobody far away.

Where beacons go. Not on your working frequency. Heartbeats and their acknowledgements move to a free slot in the 500–1000 Hz sub-band, the same convention JS8Call follows: it is where stations watching for beacons look, and it keeps an unattended transmitter off somebody else’s QSO. The slot is chosen at the moment the beacon goes out — a beacon can wait behind a long message for minutes, and a frequency picked when it was queued would be somebody else’s by then. A slot counts as taken if anything was decoded within one signal width of it in the last half-minute (longer at Slow, whose transmissions are longer than that), and if the whole sub-band is busy the beacon takes whichever slot has been quiet longest.

So a beacon appears on the waterfall somewhere other than your transmit marker. The panel header says where the last one went — HB 750 Hz beside the countdown — so you can tell your own beacon from a stranger’s. If you would rather keep everything you transmit in one place, ⚙ SETUP → Beacon frequency → Working freq switches it off.

Relayed messages and stored-message requests are decoded and shown, but this station will not act on them — forwarding traffic on someone else’s behalf is a decision for the operator.

3.10 RF Paint (spectrum painting)

Choose RFPAINT from the DIGITAL menu for RF Paint — a transmit-only mode that draws text and pictures directly onto a receiver’s waterfall. There is no decoder and no message format: the picture is the signal. Anyone watching their panadapter on your frequency simply sees what you paint, so it is a fun way to put a callsign, a grid, or a small graphic on the band.

The RF Paint panel: text-paint and image-paint areas with live preview waterfalls

RF Paint transmits on USB and fills a 3 kHz audio band (about 300–3300 Hz), so it sits inside a normal SSB channel. It has no calling frequency — use it on a clear frequency where you are allowed to transmit, and tell the other station where to look. The panel has two side-by-side areas:

Scan speed (the slider in the panel header) sets how fast the text or image is scanned onto the waterfall, from 100% (the base rate — fastest, shortest transmission) down to about 6%; 25% (the default) is a good compromise. Slower is more legible, because the receiver’s waterfall gets more scan lines to draw the picture — but it takes longer to send. A transmission runs from a few seconds to a couple of minutes depending on the length and the scan-speed setting.

While painting, a progress bar and a TX % readout track the transmission, and Abort stops it immediately. RF Paint goes through the normal transmit path, so the ham-band lockout and the usual transmit safety still apply. Because it is transmit-only, RF Paint receives nothing — you read other stations’ paintings on your own waterfall like any other signal.


3.11 WSPR (Weak Signal Propagation Reporter)

Choose WSPR from the DIGITAL menu. This is the one mode here that is not trying to make a contact. A WSPR transmission is 110.6 seconds of four-tone FSK six hertz wide, carrying a callsign, a four-character grid and a power level and nothing else, sent in a two-minute slot. It decodes about ten decibels below FT8 — well under the noise — and what comes out of it is a measurement of a path, not a message anybody sent you.

Selecting the mode puts the dial on the band’s WSPR frequency (14.095 600 MHz on 20 m, and so on — 3.1); every transmission in the world sits in the 200 Hz window 1400–1600 Hz above it. The receiver’s passband is narrowed to that window on purpose: with signals this weak, letting the QRSS beacons just below it work the AGC would cost you decodes.

The panel has three panes. On a wide screen the receptions run full height down the left and the map takes the top right, with the beacon’s status under it; narrower, the tab row picks one.

Receiving

The SPOTS pane lists receptions, newest first:

Column What it is
← / → ← a beacon this station decoded; → a station that decoded this one
Callsign, grid The far end of the path
km Great-circle distance from your locator
dB Signal-to-noise in a 2500 Hz bandwidth, as WSPR reports it
power What the beacon declared it was radiating

The report colours are WSPR’s own scale, not FT8’s: green above −10 dB, cyan to −20, yellow to −26, and pink below that — because −25 dB here is a perfectly good path rather than a marginal one.

The list holds five thousand receptions — a night of a busy band, which is the span this mode is usually left running over — and the count beside the heading is what it is holding.

A slot takes seconds of work to decode, so the status pane says decoding… rather than leaving you to wonder whether the band is shut. The slot bar below the status header shows where in the two-minute cycle the beacon is, with the time left beside it: dim cyan listening, yellow decoding, pink on the air — where the mark shows where the 110.6-second burst stops. Every slotted mode has this bar; only WSPR’s turn is long enough to want a countdown with it.

The map, and the propagation heat on it

The MAP pane shows every station heard, fading over ten minutes — a WSPR beacon is heard every few minutes at best, so the FT8 map’s two-minute fade would leave this one blank almost always.

Each dot wears the colour of the band it was heard on, in the same palette the propagation heat uses for ALL BANDS, with a key under the map naming them. This is the one mode whose map routinely mixes bands: a beacon that hops puts 40 m, 20 m and 10 m stations on one picture, and one colour for all of them cannot say which path opened. The key appears only when there is more than one band up.

Above the map is the PROP button. It shades the map by where signals are actually getting through; pressing it reveals the rest of the controls — ALL BANDS or ONE BAND, which band, and the absolute path count the brightest cell stands for. §7.8 explains what the shading means. The same picture, with more control over it, is on the 3D globe.

Beside PROP is HEARD ME, which rings every station that reported hearing this station on the current band, from PSK Reporter, at the reporter’s own grid. It is the inverse of the coloured PSK spots: those are stations this radio is hearing, while these heard us. The query behind it is refetched hourly and covers the last hour, so it needs the PSK feed switched on under Settings → Spots and a callsign set on the General tab; the chip only decides whether the rings are drawn. Hover a ring for the reporter’s callsign, frequency, mode and the SNR they gave. Deliberately its own control rather than another spot colour: a dot at the receiver is a marker at the wrong end of a report, so these never appear in the SPOTS list or on the panadapter.

Beside it is NIGHT, which shades the night side of the map and the twilight either side of it — the grey line, the terminator where the low bands go long and the high bands close. The shading is drawn over the propagation heat when PROP is on, so a band that is dead because the Sun is down reads that way, and under the coastlines so the geography stays legible. Like PROP it is off by default: it is scenery rather than something to leave switched on over a decode list, and it is drawn whether or not PROP is. The Sun’s position is the same one the band conditions are read from, so the shade and the “day”/”night” a verdict calls a band cannot disagree.

NIGHT is on every flat map, and the one switch turns it on for all of them: the operating panel’s FT8/FT4/FT2, WSPR and JS8 maps, and the ADS-B, AIS, APRS and HFDL maps — the last four carry their own NIGHT chip above the chart. Where a map has no chip row of its own (the four decoder maps), the chip sits just above it. Switching it on anywhere lights the same terminator everywhere.

Drag the strip under the map to resize it against the status pane.

Transmitting

Off until you ask for it: selecting a mode is not consent to put a carrier on the air.

Everything is in the STATUS pane; WSPR has no separate setup dialog.

TRANSMIT, POWER and the band-hop settings belong to the radio they are set on. With several radios open, each beacons — or doesn’t — on its own say: switching one on leaves the others as they were, and a radio added later starts with its beacon off.

Your callsign and grid come from the General tab of Settings — the same identity the rest of the program reports under. The panel says which it is transmitting as, and says so in yellow if either is still blank.

WSPR’s message carries a plain callsign and a 4-character locator and has room for nothing else. A longer locator is simply shortened — JN47cb goes out as JN47, which is what the extra precision means anyway — and the panel shows which form it is transmitting as. A compound callsign (PJ4/K1ABC) genuinely cannot be sent: it needs a message layout this station cannot encode, and the panel says so rather than transmitting something that is not you. Receiving is unaffected either way — all three message types decode.

One receive limitation worth knowing: a Type-3 message spends its callsign field on a 15-bit hash so it can carry a six-character grid instead of four. That hash is not invertible, and sdroxide cannot currently compute it either, so such a station is listed as <#0a3f7> rather than by name. Its grid arrives in the clear, so the path is real, the map places it and the propagation heat map counts it — only the name is missing. Those spots are deliberately not uploaded to WSPRnet: posting a placeholder would put a station that does not exist into a database everybody reads.

Band hopping

BAND HOP moves the dial from band to band between slots, so one receiver samples the whole spectrum instead of one slice of it. A row of band buttons appears under it when it is on, for choosing which bands the cycle visits. Turning the VFO yourself pauses it and says so — a beacon and its operator fighting over the dial is the one thing this must not do — and applying the setup again resumes it. It never moves under a transmission, and a band the radio cannot reach is skipped silently.

WSPRnet

Both are on the Spots tab of the Settings dialog as well as the panel, and both use the callsign and grid from the General tab.

3.12 APRS

Choose APRS from the DIGITAL menu. This is the Automatic Packet Reporting System: 1200 baud AX.25 on one shared FM channel per region, carrying positions, weather, telemetry, objects and short messages. It is not a QSO mode — almost everything on the channel is a broadcast that nobody answers — so the panel is a map, a station list and a message pane rather than a sequencer.

The APRS panel: the station list, the map and the messages

The frequency is chosen for you. APRS is a channel, not a band segment, and which channel depends on where you are. Selecting the mode tunes to your region’s:

Region Channel
1 — Europe, Africa, Middle East, Northern Asia 144.800 MHz (70 cm: 432.500)
2 — the Americas 144.390 MHz (70 cm: 445.925)
3 — Asia-Pacific 145.175 MHz (Japan and China: 144.640; South-East Asia: 144.390)

Set your region under Settings → General. If the dial is already on any region’s APRS channel — you tuned Japan’s 144.640 by hand — it is left alone, and so is any move you make once you are in the mode. The ⇵ FREQ button beside the frequency lists the other regions’ channels.

Unlike the slotted modes, the waterfall is not narrowed to the channel. APRS occupies about 12 kHz of a 2 m band you have every reason to be watching — the repeater outputs above it, the simplex calling frequency below — so the view opens on 300 kHz around the channel and zoom and pan stay live from there. It is re-framed only when you change mode or retune far enough to take the channel off the screen.

The panel

The panel header carries the channel itself: the receive level, how many stations are on the map, whether the channel is busy, and — on the right — the beacon interval and the buttons.

STATIONS is everything heard, most recent first: a table of icon, callsign, whatever the station last said, and how long ago. The bar down the left edge of each row is green for a station heard direct — no digipeater repeated it — which on a channel where almost everything is digipeated is how you tell who is actually within range; amber marks an object somebody else put on the map, and grey one that has been cancelled. Type in the filter box to narrow the list by callsign or comment. Clicking anywhere on a row selects that station.

Click a station and its card opens underneath: what it is, what it said, where it is, how far away and on what bearing, its course, speed and altitude, its weather if it sends any, how many frames it has sent, and the digipeater path the last one came through (a * marks a digipeater that actually repeated it). Selecting a station also addresses the message box to it.

The map places everything with a known position, on the same coastlines, borders, rivers and cities as the FT8 panel’s (the world map) — which matters more here than there, because an APRS map is usually zoomed in far enough for a river and a town name to be what tells you where a station is. It auto-frames what it can hear; drag to pan, wheel or pinch to zoom, and double-click to hand it back to the auto-fit. Icons fade as a station goes stale, over the same window the station list keeps, so a position that has not been refreshed in an hour visibly is an hour old. Anything that has moved leaves a trail behind it. A station that reported an ambiguous position — the protocol lets a sender blank out the last digits of its coordinates on purpose — is drawn inside the square it actually described rather than as a point in the middle of it.

Objects and items (a net control point, a storm, an event, put on the map by some other station) are drawn in a different colour and named after themselves. An object its owner has cancelled is greyed rather than removed: an object vanishing without trace looks like a receiver problem.

MESSAGES is the one part of APRS that is a conversation. Pick a station, or type a callsign in the to box, write in the message box and press SEND or Enter. A message carries an identifier, so the far end acknowledges it and sdroxide retries until it does — five attempts, thirty seconds apart to begin with and doubling, because the far end is usually a mobile behind a hill rather than somebody who is slow to answer. The mark beside your message says where it has got to:

Mark Meaning
… Queued, waiting for the channel to clear.
↑ / ↑3 On the air, waiting for an acknowledgement (and which attempt).
✓ Acknowledged by the far end.
✗ Refused, or no answer after every retry.

Messages addressed to you are answered with an acknowledgement automatically — switch that off under Setup if this station has no antenna on transmit. Bulletins (addressed BLN…) are shown and never acknowledged: a hundred stations acknowledging one bulletin would take the channel down. Other people’s messages stay out of this pane and go in the raw log instead.

RAW swaps the pane for every frame on the channel as it arrived, with what the decoder made of each — position, weather, message, object, or the reason it made nothing of it. That last one is how you find out that something on your channel is sending a format this build does not read.

Setup

SETUP in the panel header opens the APRS settings.

BEACON in the header sends one position report now, without waiting for the timer, and the box beside it is how often to beacon unattended — off by default. Both go through the channel-access rules like everything else: they wait for the channel to be clear, so a busy channel delays a beacon rather than doubling on somebody.

When nothing is decoding

The bar beside 1200 baud is the audio actually reaching the modem, and it is the first thing to look at. Flat means nothing is arriving at all — the radio’s data output is not the one sdroxide is listening to. It lights green while the modem hears a carrier, and BUSY appears beside it for the same reason.

If the bar is moving and the map stays empty, switch the message pane to RAW and watch the counts beside it. Frames arriving and failing their check sequence (N bad) mean the modem is reading the channel and the signal is marginal. Nothing at all, with a healthy level, usually means one of:

If your transmissions are the ones nobody can decode, the audio itself can be ruled in or out without another operator. Record an over (the REC button captures transmit audio as well as receive), extract the right-hand channel, and run it through an independent decoder:

ffmpeg -i <recording>.mp3 -af "pan=mono|c0=c1" -ar 44100 tx.wav
atest tx.wav          # from Direwolf

A frame printed there is a frame that left sdroxide correctly, and anything still wrong is between the radio’s modulation input and the air — the TX audio level above, the radio’s own input level, or its data-mode setting.

The log line to look for is digital transmit audio is being rate-matched to the radio. Some radios receive at one sample rate and transmit at another — an Icom on its 12 kHz IF output receives a stream decimated to 24 kHz while taking transmit audio at 48 — and the modems are built for the receive rate, because a digital mode keeps one clock for both directions. sdroxide rate-matches the transmit audio for you and says so once per over; before it did, a packet burst went out at exactly twice its baud rate, which is structurally perfect and readable by nothing.

What is decoded

Everything a station is likely to send: uncompressed and compressed positions, Mic-E (the format every commercial APRS radio transmits, which hides half the position in the AX.25 destination address), objects and items, status reports, Maidenhead grid reports, telemetry, queries, weather both attached to a position and standing alone, and messages, acknowledgements, rejections and bulletins. Weather is converted from the miles per hour, degrees Fahrenheit and hundredths of an inch the protocol carries.


3.13 ADS-B (aircraft on 1090 MHz)

Choose ADS-B from the end of the DIGITAL row. It sits apart from the rest of that row all the same: there is no QSO to work and no transmitter, only a signal to point the radio at. Every civil aircraft in the sky transmits its identity, altitude, velocity and position on 1090 MHz, twice a second, in clear and with a checksum. The panel is a target list on the left and a radar picture on the right.

The frequency is chosen for you. There is exactly one ADS-B channel, worldwide. Selecting the mode tunes to 1090.000 MHz unless the receiver is already looking at it, and the 1090.000 button in the panel header puts it back if you wander off.

What you need

An antenna for 1090 MHz, on the right socket. This matters more than anything else on this page. A quarter wave at 1090 MHz is 69 mm long, and an HF wire or a discone is tens of decibels deaf up there. On a receiver with separate inputs — the RX-888’s HF and VHF sockets, for instance — 1090 MHz arrives only through the VHF one, and an antenna on the other socket produces exactly the symptom you would expect from a broken decoder: an empty list, or one or two aircraft that come and go. Sixty-nine millimetres of wire in an SMA plug, against a window, is usually good for a hundred kilometres.

Turn any input attenuation off, and switch the bias tee on if your antenna or preamplifier wants it. Attenuation that is right on a crowded HF band is simply loss here.

A stream of at least 2.4 Msps at 1090 MHz. Mode S is a megabit a second and every bit is two half-microsecond chips, so this is about how many samples land inside a chip:

Stream What happens
below 2 Msps Refused. There is not one sample per chip; there is nothing to slice.
2.0 – 2.4 Msps Runs, and says it is degraded. A chip and a sample are the same width, so a burst arriving out of step with the sample clock has chips split equally across two samples that then read the same. Strong aircraft decode; the rest are lost.
2.4 Msps and up Full performance. Every arrival phase decodes.

An RTL-SDR at its default 2.4 Msps is the classic receiver for this and sits exactly on the line. So do an Airspy, a HackRF, an SDRplay, a Pluto and a LimeSDR. On a receiver whose window width you choose — the RX-888’s panadapter width setting, for example — pick 4 MHz or more; SDRoxide keeps whatever it is given, up to 9 MHz, because more samples per chip is strictly better here and nothing is gained by throwing them away.

What will never work is a transceiver handing over demodulated audio, or a front end decimated below 2 Msps. In each case the panel says so in a sentence rather than showing an empty list you would have to guess at.

The aircraft list

One row per aircraft, keyed on its ICAO address — the 24-bit number assigned when it was registered, unique worldwide and unchanging.

Column What it is
CALL The flight identification it is broadcasting. Empty for the first few seconds: an aircraft sends its position twice a second and its callsign every five, so the address arrives first. The row shows the address until the callsign does.
ICAO The address, in hex, once there is a callsign to distinguish it from.
ALT Altitude. Flight level above 18 000 feet (F350), hundreds of feet below it (045), and GND on the ground.
GS Ground speed in knots.
TRK Track over ground, degrees true.
V/S Rate of climb or descent, feet per minute.
SQK The squawk — the four-digit code the crew set for air traffic control. Only some frames carry it; see below.
KM Range from your station. Shown once My grid is filled in (§3.1).
AGE How long since anything at all was heard from it.

The buttons above the list sort it; clicking the one already selected reverses the order. Clicking a row opens the full card below it — everything the table has no room for, including geometric altitude, turn rate, signal level and the last frame as hex — and selects the aircraft on the map. CENTER in the card puts it in the middle of the picture.

A greyed row is an aircraft that is still being heard but has not reported a position for ten seconds. It stays on the list and comes off the map; see below.

The radar picture

The ADS-B panel: the aircraft list and the radar picture

Standard surveillance-display symbology, and each part of it is telling you something:

Drag to pan, scroll to zoom, double-click to reframe. Your own position is marked once My grid is set.

A target with a stale position is not drawn at all. Past the timeout it comes off the map — square, dots and block together — while staying on the list, greyed. It is deliberately not faded instead: a dim square at a half-minute-old position is still a claim about where an aeroplane is, made in the same ink as the true ones, and the map is the one place with no room for a hedge.

Setup

SETUP in the panel header opens the decoder’s own settings.

Setting Default What it does
Drop from map after 10 s Without a position report, the target leaves the map and its row greys.
Drop from list after 60 s With nothing heard at all, the aircraft is forgotten.
Trail length 40 points How many past positions are kept and drawn.
Speed vector 1 min How far ahead the leader line reaches. Zero switches leaders off.
Track at most 300 aircraft A ceiling, so a busy sector cannot grow without bound. The longest-silent go first.

What is decoded, and what is believed

Two kinds of transmission arrive on this channel, and SDRoxide treats them very differently.

Extended squitters (downlink formats 17 and 18) are what an aircraft broadcasts on its own: identity, category, barometric and geometric altitude, position, velocity, and its emergency state. They carry a plain 24-bit check sequence, so a frame either checks out or it does not. These prove themselves.

Surveillance replies (formats 0, 4, 5, 16, 20 and 21) are answers to a ground radar’s interrogation, and they carry an altitude or the squawk. Their check sequence has the aircraft’s address mixed into it, because the interrogator already knew who it had asked — which means that to a receiver listening passively there is nothing in the frame to check it against. Taken alone, any 56 bits of noise “decode” to some address.

So SDRoxide accepts one only when the address it yields already belongs to an aircraft heard from a verified squitter, recently. That is what buys you the squawk column and the faster altitude updates without inventing aeroplanes. It is also why a squawk appears for some aircraft and not others: it depends on whether a radar is interrogating them where you can hear the answer.

No error correction. Other decoders will flip a bit, or two, looking for a frame that checks out; it recovers some weak transmissions and it also invents aircraft, and an invented aircraft on a map looks exactly like a real one.

Two encodings are deliberately not decoded, and an aircraft using either shows no altitude rather than a wrong one: the 100-foot Gillham encoding, used above 50 175 feet and by a few older transponders, and the metric encoding, which the standard provides for and nothing transmits.

Trying it without an aerial

There is a signal generator in the source tree that synthesises a sky:

cargo run --release -p sdroxide-adsb --example adsb_iq -- /tmp/sky.iq
sdroxide --file /tmp/sky.iq --rate 2400000 --freq 1090000000 --mode ADS-B

Six aircraft at descending signal levels, flying. It proves the whole chain works; it does not prove the decoder works on air, because the transmitter and the receiver were written by the same hand.

For that there is a second test, against real off-air recordings made by somebody else with somebody else’s hardware, checked against what their decoder finds in them. Point it at a checkout of rsadsb/dump1090_rs:

SDROXIDE_ADSB_IQ=/path/to/dump1090_rs/test_iq \
  cargo test -p sdroxide-adsb --test reference_corpus -- --nocapture

SDRoxide finds all fourteen messages in those three captures, and nothing the reference does not also find.

If nothing is decoding

Record a few seconds and look at what the receiver actually heard:

sdroxide --server --freq 1090000000 --mode ADS-B --record-iq /tmp/air.iq
cargo run --release -p sdroxide-adsb --example adsb_replay -- /tmp/air.iq <rate>

The summary line at the end distinguishes the two failures. Preambles but no frames means the correlator is triggering on noise and nothing is checking out — there is no signal, and the antenna is the place to look. No preambles either means the receiver is not even seeing bursts. A working setup shows strong aircraft 30 dB or more above the noise floor; if the loudest thing in the capture is 10 dB above it, no decoder will find anything in it.


3.14 NAVTEX

Choose NAVTEX from the DIGITAL menu. It is the maritime safety broadcast every coast station in the world sends: navigational and meteorological warnings, search-and-rescue bulletins, ice reports, pilot notices.

Receive only, and deliberately. The service belongs to coast stations and sits next to distress traffic; an amateur transmitting on it would be putting out safety information nobody may act on. There is no transmit half of this panel and no callsign to set.

The channels. The band buttons are the three services: 518 kHz (international, always English), 490 kHz (national language, so whatever your nearest coast station broadcasts in) and 4209.5 kHz (tropical). What they tune is 1.7 kHz below the channel, because the quoted frequency is the assigned one — the centre of the two tones — and a receiver in upper sideband has to sit below it to put them at 1615 and 1785 Hz. That arithmetic is done for you, and the readout still says where the signal is. A dial a few hundred hertz off is fine too: the decoder follows the tones up to ±350 Hz away.

A dial that is a little off still decodes. The receiver tracks the tones itself, so a readout a few hundred hertz out — a rig that will not set exactly, or one of the tuning figures that rounds differently in different publications — is pulled in over the first second or so instead of returning nothing. It is not a reason to be careless: a mistuned signal still carries more errors than a clean one, and past about ±350 Hz the pull-in gives up.

NAVTEX is a timetable, not a conversation. This is the single thing newcomers miss most, and it looks exactly like a broken decoder: each coast station sends for ten minutes, once every four hours, on its own schedule. Most of the time nothing is transmitting — a silent panel is the normal state, not a fault. You have to be listening when your nearest station is due. The schedules are published (search “NAVTEX broadcast schedule” for your region); there is nothing to set here, only to know. And 518 kHz is a night band: daytime you will usually hear little or nothing, which is also not a fault.

What you see. Two panes:

The time a message states is shown beside its heading, where the body names one — 1200 UTC, 0900Z, 06:30 UTC. It is read out of the text, not a field of the format: a gale warning states when it was issued, a station’s time broadcast is an ordinary message that happens to carry a clock reading. Only a four-digit time marked as one is taken, so a position (5103N 00109E) or a serial is not mistaken for a time of day. It is shown for the reader and nothing else — sdroxide never sets the system clock from it.

A station repeats itself, and that is the point. Each transmitter has a ten minute slot every four hours, and it sends the same messages again on the next one. sdroxide keeps one entry per message — a repeat replaces the copy already held when it is better, meaning it reached its NNNN where the first did not, or lost fewer characters. So a warning that faded halfway through fills itself in over the next few hours instead of appearing four times half-copied.

The two numbers beside SYNC are what the mode’s error correction actually did. NAVTEX has no checksum: every character is sent twice, five character times apart, in an alphabet where exactly four of seven bits are marks — so a single bit error makes a code that cannot exist, and the repeat is what replaces it. Repaired counts the characters taken from the repeat and lost the ones where both copies were bad; a lost character stands in the text as *, marked rather than hidden, because half a gale warning has to look like half a gale warning.

REV swaps the mark and space tones, for a signal received on the other sideband. Off is upper sideband on the channel, which is what every published tuning instruction for the service says.

If it decodes as garbage, it is almost always the tuning. NAVTEX is quoted as a channel, and this receiver sits 1.7 kHz below it in upper sideband — so the 518 kHz service is read with the dial on 516.300, not 518 or 519. The band buttons (518 / 490 / 4209.5) set that for you; a rig tuned by hand wants 516.300 kHz USB. A steady, strong signal that still reads as nonsense is usually landing on the wrong sideband: press REV. And a band with no coast station transmitting — 518 kHz is busy mostly at night — is not a decoder fault.


3.15 VDL2 (what the aircraft are saying)

Choose VDL2 from the end of the DIGITAL row. VHF Data Link Mode 2 is the datalink airliners and ground stations exchange ACARS over — company messages, position reports, weather requests, fuel and arrival figures, and the link management that carries them — on fourteen 25 kHz channels between 136.650 and 136.975 MHz.

Receive only. These are commercial aeronautical channels. There is no transmit half of this panel and no callsign to set.

The frequency is chosen for you. Selecting the mode tunes to 136.8125 MHz, the middle of the group, and the decoder places its own window from there to take in as many of the fourteen channels as your receiver can reach. The 136.8125 button in the panel header puts it back if you wander off.

SDRoxide in VDL2: the whole datalink group on the waterfall, the message log and the stations sending it

The waterfall above the panel is the whole group at once, so the transmissions are visible as short bright dashes on whichever channel carried them — which is worth a glance before reading a single counter, because a band with no dashes in it has nothing for any decoder to find.

What you need

An antenna for the air band, outdoors and with a view. This matters more than anything else on this page. VDL2 is line-of-sight VHF: an aircraft at cruise is receivable a couple of hundred kilometres away, and a ground station only as far as the horizon. An indoor wire will hear the FM broadcast band perfectly well and nothing at all up here — the two facts are not related, and the first is not evidence for the second. A quarter wave at 136.8 MHz is 55 cm.

Turn any input attenuation off, and be careful with gain: the FM broadcast band 40 MHz below is enormous by comparison, and a tuner wound up to its limit will be overloaded by it rather than made more sensitive. If the whole air band rises together as you add gain, that is what has happened.

A stream of at least about 470 kHz. The plan is 350 kHz wide, and a receiver’s outer edges are where its own filter is rolling off, so a window has to be about a third wider than the plan to hold all of it:

Stream What happens
below 34 kHz Refused. There is not room for one channel.
34 – 467 kHz Runs, and says which channels it cannot reach, and between which two frequencies the ones it does reach lie. The window slides to take in as many as it can.
467 kHz and up All fourteen channels.

Almost any receiver clears the last row: an RTL-SDR at its default 2.4 Msps, an Airspy, a HackRF, an RX-888, a Pluto, an SDRplay. What matters far more is the aerial.

The channels

Every 25 kHz slot from 136.650 to 136.975 MHz, all listened to at once:

Channel Assigned to
136.650 An airport’s ground station — the North American assignment.
136.675 An airspace ground station, alongside the European twelve until 2027.
136.700, 136.725, 136.750, 136.775, 136.800 Airspace ground stations.
136.825 An airport’s ground station.
136.850 An airspace ground station.
136.875 An airport’s ground station.
136.900 An airspace ground station.
136.925 An airport’s ground station.
136.950 An airspace ground station.
136.975 The Common Signalling Channel — the one frequency in use worldwide, where every link starts. The one to keep if you keep only one.

“Airport” and “airspace” say which kind of ground station the slot is assigned to: one serving the aeroplanes on and around an aerodrome, or one serving an area from a remote site. Both carry aircraft as well, so neither label is a direction of travel — the published tables mark these GND and AIR, which reads backwards the first time you hear an airport’s ground station on an “AIR” channel.

Which of them are busy is a local matter, and not one this list can answer for you: a plate that is silent in one country is the only busy one in another. Leave them all on unless you have a reason not to.

The message log

One line per frame decoded, newest at the bottom, the way a conversation is read.

Column What it is
Time When the frame was decoded, UTC.
MHz Which of the fourteen channels it arrived on.
From → To The two 24-bit addresses. For an aircraft this is its ICAO address — the same number its ADS-B squitters carry, so an aeroplane heard on both bands is recognisably one aeroplane.
Type The link control field: I for information (with its sequence numbers), RR/REJ and friends for flow control, UI for a broadcast, XID for link management.
Message The ACARS label and text, the kind of XID exchange, or — for a payload SDRoxide does not read — what it appears to be and how long.

Click a line to open the full card below it: every field, the signal figures, and the frame as hex. The filter box searches an address, a registration, a flight identification, an ACARS label or the message text, and it filters the station list beside it at the same time.

HOLD stops the log where it is. Near a busy airport the next transmission arrives before you have finished reading the last one, and this is the answer to that: the list stops moving and stays where you scrolled it, while the decoder, the counters and the channel strip carry on behind it. The chip counts what has arrived meanwhile — HELD +23 — and letting go shows all of it.

Colour says what kind of traffic it is. Yellow is ACARS — the messages with words in them. Cyan is XID, which is aircraft and ground stations arranging links. Grey is a frame this pass does not read, or a supervisory frame with no payload at all.

The station list

One row per address heard, which is who is out there — a scrolling log makes that surprisingly hard to see on a busy channel.

Column What it is
NAME The flight identification, or the registration, or the address. The first two arrive only when the station sends an ACARS block, so a row showing an address is normal rather than broken.
ADDR The 24-bit address in hex.
TYPE AIR for an aircraft, GND for a ground station, ALL for a broadcast address.
MSGS Frames from this station this session.
SIG Signal-to-noise of the last one, dB.
AGE How long since anything was heard from it.

Clicking a row filters the log to that station.

The channel strip and the counters

The row under the header is the fourteen channels. Green means frames have come out of it, yellow means transmissions have been detected and none has decoded, and grey means it is not being listened to — hovering says which of the two reasons that is, and what the channel is assigned to.

A channel that shows nothing at all is the ordinary case, not a fault. Which of the fourteen carry traffic depends entirely on where you are: in most of Europe it is a handful of them, in North America usually 136.975 and one or two others, and the rest of the raster is somebody else’s local plan. Each channel is measured in its own bandwidth, so a strong station 25 kHz away is not counted as a burst here — a channel with a count on it really did hear something on that frequency. The counters beside them are arranged in the order the decoder fails in, and the first one that stops counting names the problem:

Reading What it means
no bursts Nothing is rising above the noise. The aerial, or a receiver that is not looking here.
bursts but no sync Something is on these channels and it is not VDL2.
sync but no frames, with HDLC bad climbing The transmission header is being read and the frame inside it is not. That is SDRoxide’s fault rather than the band’s, and worth reporting.
sync but no frames, with both low Real VDL2 arriving too damaged to decode — a weak signal or the wrong aerial.
bad FCS climbing with frames Frames arriving damaged. A few among many is ordinary at the edge of coverage.

One thing not to read too much into: SDRoxide’s Reed-Solomon parameters do not match what is actually on the air, so the error correction repairs nothing and every frame you see arrived intact and passed its own check sequence. That is why there is no “blocks repaired” counter to watch. It costs the marginal frames a stronger receiver would have rescued; it costs nothing in wrong ones, because the check sequence is what admits a frame either way. If you have a recording of a band SDRoxide decodes poorly, that is the thing most likely to fix it.

Setup

SETUP in the panel header opens the decoder’s own settings.

Setting Default What it does
Channels all fourteen One downconverter each. Switching one off saves a little processor time; it does not make the others more sensitive.
Burst threshold 9 dB How far above each channel’s own learned noise floor a transmission has to rise before the decoder looks at it. Lower catches weaker signals and costs time spent on noise.
Keep in the log 500 messages The oldest go first.
Track at most 300 stations Likewise, longest-silent first.
Forget a station after 30 min Aircraft can be quiet for a long cruise, so this is deliberately generous.
Show unread payloads on See below.

What is decoded, and what is not

The link layer, in full. Every AVLC frame that arrives is checked against its own frame check sequence and shown with its addresses and type.

ACARS, in full. The registration, flight identification, label, block, sequence number and text. This is where nearly all the readable content is.

XID, in summary. What kind of exchange it is — a ground station’s beacon, a link establishment, a handoff — and the parameters SDRoxide knows: connection management, sequencing, modulation support, alternate ground stations, aircraft and ground-station positions, and the frequency lists a station advertises. Parameters it does not know are shown with their identifier and their bytes and counted, so you can see how much of an exchange is going unread rather than being told a comfortable half-truth.

Not decoded: X.25, CLNP, and the applications above them — including CPDLC (controller-pilot datalink) and ADS-C. Those are ISO network layers carrying ASN.1 message sets, and reading them is a larger job than everything else on this page put together. Frames carrying them are listed with their addresses, named as far as their first bytes allow (CLNP, 84 octets), and shown as hex. That is the honest picture: turning them off would hide how much of the traffic they are.

Trying it without an aerial

There is a signal generator in the source tree that synthesises a band:

cargo run --release -p sdroxide-vdl2 --example vdl2_iq -- /tmp/vdl2.iq
sdroxide --file /tmp/vdl2.iq --rate 2400000 --freq 136825000 --mode VDL2

Ground stations beaconing, aircraft exchanging ACARS on four channels at descending signal levels, a link being established, two stations colliding, and one message long enough to need more than one block of error correction. Each station is given a carrier offset, a symbol clock error and a fractional arrival time of its own, because a transmitter that is exactly right is the one case that proves nothing.

It proves the whole chain works. It does not prove the decoder works on the air, because the transmitter and the receiver were written by the same hand — and for most of 2026 they were wrong together, agreeing about the bit order inside a symbol and about the frame’s HDLC wrapper while decoding nothing real at all (issue #265). What settled it was a listener’s recording, and two of the transmissions from it now sit in the test suite. If you have an aerial that hears VDL2 well, a minute of --record-iq is the single most useful thing you can contribute.

If nothing is decoding

Record a minute and look at what the receiver actually heard:

sdroxide --server --freq 136825000 --mode VDL2 --record-iq /var/tmp/air.iq
cargo run --release -p sdroxide-vdl2 --example vdl2_replay -- /var/tmp/air.iq <rate> 136825000

The replay prints the counters per channel and one sentence saying what to do next. The channel to watch is 136.975, the Common Signalling Channel: every ground station beacons on it and every link starts there, so if that one is silent while the others show bursts, what the others are showing is not VDL2.

3.16 AIS (ships on 162 MHz)

Choose AIS from the end of the DIGITAL row. The Automatic Identification System is what every ship of any size transmits about itself — its identity, position, course, speed, name, dimensions, draught and where it is going — on two 25 kHz channels either side of 162.000 MHz. The panel is a vessel list on the left and a marine chart on the right.

Receive only, and it will stay that way. AIS is a safety-of-life service. Putting false vessel traffic on it is not something an amateur licence covers, so there is no transmit half of this panel and no callsign to set.

The frequency is chosen for you. Selecting the mode tunes to 162.000 MHz — between the two channels, because nothing transmits there and a zero-IF receiver’s DC spike therefore lands on neither of them. The decoder places its own 150 kHz window from there and listens to both channels at once. The 162.000 button in the panel header puts the dial back if you wander off.

What you need

An antenna for marine VHF, outdoors and with a view of the water. This matters more than anything else on this page. AIS is line-of-sight: a ship’s Class A transmitter is 12.5 watts at deck height, so from a window you might reach fifteen kilometres and from a mast on a hill sixty. A quarter wave at 162 MHz is 46 cm. An indoor wire will hear the FM broadcast band perfectly well and nothing at all up here — the two facts are not related, and the first is not evidence for the second.

Turn any input attenuation off, and be careful with gain for the same reason the VDL2 page gives: the FM broadcast band below is enormous by comparison, and a tuner wound up to its limit is overloaded by it rather than made more sensitive.

A stream of at least about 100 kHz at 162 MHz.

Stream What happens
below 48 kHz Refused. There is not room for one channel.
48 – 100 kHz Runs on whichever channel the window is over, and says which one it is missing.
100 kHz and up Both channels.

Almost any receiver clears the last row. What matters far more is the aerial.

And the front end’s own filters. An SDRplay RSP1’s DAB notch, meant for Band III, reaches down far enough to take the AIS band with it: a receiver that looks deaf at 162 MHz can simply be filtered, with nothing on screen to say so. Turn the DAB notch off before blaming the aerial (issue #408).

Both channels, or half the shipping. A vessel alternates between AIS 1 and AIS 2 slot by slot, so a receiver reaching only one hears every ship at half its reporting rate. That does not look like half a signal — it looks like vessels that jump — which is why the two chips in the panel header, AIS A and AIS B, are lit only when a demodulator is actually running on each, and why the header says so out loud when one is out of reach.

The vessel list

One row per MMSI — the nine-digit identity every AIS station carries. Click a row to open its card and put the vessel on the chart.

Column What it is
NAME What it calls itself, once a static report has arrived. Until then, the MMSI: a ship reports its position every few seconds and its name only every six minutes, so a target with no name is normal rather than broken.
MMSI The identity, where the name is not already it.
TYPE A and B are Class A (ships over 300 tons, and every passenger vessel) and Class B (small craft). BASE is a shore station, ATON an aid to navigation — a buoy, a beacon, a lighthouse — SAR a search-and-rescue aircraft, and SART a distress beacon.
KT Speed over ground, knots.
COG Course over ground, degrees true.
SIG The last message’s level in dBFS.
KM Range from your grid, once My grid is filled in (3.2.1).
AGE How long since anything at all was heard from it.

A row greys when its position has aged out — five minutes by default — while staying on the list, because “heard, named, position not fresh” is real information and a vessel at anchor reports only every three minutes.

The card below the list carries everything the station has said across every message type: name, call sign, IMO number, ship type and whether it is carrying dangerous goods, navigational status, length and beam, draught, destination and ETA, and the position with its accuracy.

The last line of the card is the message as an !AIVDM sentence. That is the form every other AIS program in the world reads, and it is there on purpose: this decoder was written from ITU-R M.1371 rather than from a recording, so if you want to know whether sdroxide is reading a message correctly, copy that line into any other AIS decoder and compare. (Up to 1.6.6 every received byte was read the wrong way round, which put ships all over the world map or left it empty; the decoder is now checked against a published sentence decoded by gpsd — issues #345 and #408.)

The chart

The chart frames your station and every vessel with a fresh position, and keeps reframing as they move. Zoom with the wheel, a trackpad or a pinch — about the point under the pointer — and drag to pan; either one holds the view where you left it. The −, + and FIT chips in the top-right corner do the same without a wheel, zooming about the middle of the chart, and FIT (or a double-click) hands the view back to the automatic framing. The note in the bottom-left corner says how much the view spans, in degrees of longitude and roughly in kilometres, so a chart that looks fully zoomed in but is still half an ocean wide says so (issue #459).

Each vessel’s name — and its speed, where it has one — sits up and to the right of its symbol, or at another corner where the edge of the chart or a neighbour is in the way. On a busy chart a name with no room anywhere is left off rather than drawn over another name or symbol: marks (buoys, base stations) give way first, then everything that is not a SOLAS ship, while the selected vessel, the one under the pointer and any in distress always keep theirs. Zoom in and the names come back as the room does (issue #408).

Data fields

Setup

SETUP in the panel header opens the decoder’s own window.

Setting Default What it does
Channels both Which of AIS 1 and AIS 2 to listen on. Switching one off halves how often every vessel is heard.
Drop from chart after 300 s Seconds without a position report before a vessel leaves the chart and its row greys. Five minutes, not ADS-B’s ten seconds: a vessel at anchor reports every three.
Drop from list after 1800 s Seconds with nothing heard at all before it leaves the list. Half an hour, so a ship is not dropped just before it says what it is called.
Trail length 10 min How much history to draw behind each target — in minutes, not in points, because AIS reporting rates span two orders of magnitude and a fixed count would be eighty seconds of a ferry and two hours of an anchored tanker, drawn identically. Zero switches trails off.
Speed vector 6 min How far ahead the vector reaches. Zero switches vectors off.
Slot threshold 8 dB How far above the channel’s learned noise floor a slot has to be before it is demodulated.
Track at most 500 The ceiling on the vessel table. The stations heard longest ago go first.

Everything here is saved to ais.json and restored at startup.

What this decoder has and has not been proved against

Every layer of it — the GMSK demodulator, the bit timing, the HDLC framing, the check sequence and the message field offsets — is tested against a transmitter built independently from the same standard, including on a receiver four kilohertz off frequency and with two ships in adjacent slots. What that cannot prove is that the standard was read correctly: a field offset wrong in the same way at both ends agrees with itself.

3.17 AtCHAT NET

Choose ATCHAT from the DIGITAL menu. AtCHAT NET is a multi-station keyboard and file mode built out of nostalgia for the old packet-radio net: several stations share one channel, chat both openly and directly, and pass files and pictures around, all while the net itself works out who is in charge without anyone touching a setting. Underneath is a 2.7 kHz COFDM waveform (BPSK/QPSK), the same width as a DIGU/DIGL window; there is no tone offset to set — the carriers are fixed by the waveform — and like PSK31, RTTY and the other keyboard modes it leaves the dial exactly where you put it rather than jumping to a convention (3.1). Selecting the mode puts the station on the air using the callsign on the General tab (6.1), the same one every other mode reports with.

The net: master election and the roster

There is no separate “server” station — whichever station has been on the net longest becomes MASTER, the others fall in as backups, and if the master disappears one of them takes over without an operator doing anything. The panel header shows your own role (MASTER in green, BACKUP in yellow) and, once known, who the current master is. The ROSTER strip lists every station heard, green while active and grey once it has aged out of the net; clicking a callsign there opens a direct-message tab to it, the same tab row the panel carries below.

Before a station transmits it listens: ● CARRIER lights in the header whenever something else is already on the channel, and a send waits behind it rather than colliding. On the real radio that test is not a fixed threshold — a receiver’s own AGC settles well above any fixed level once it is on the air, so the gate instead tracks the ambient noise floor and calls a hop a carrier only when it rises well clear of it, learned in about half a second after the station joins.

Joining, leaving, and the virtual channel

The join badge in the header doubles as the leave/rejoin control: ON NET (green) while joined, REJOIN once off. Clicking it drops the link — the roster and conversation are kept — or rejoins if you have dropped it or the station could not start. ● TX lights while your own frame is actually going out.

VIRTUAL CHANNEL, below the header, swaps the radio for a channel_server-compatible TCP loopback — useful for trying the net, or developing against it, without keying a transmitter. Off (the default) puts the station on the air; on, it dials the address beside the toggle (127.0.0.1:6000 unless changed) instead. Because nothing keys a transmitter over the loopback, SEND and SEND FILE are available there even on a station with no TX-capable radio configured.

The panel

⚙ SETUP opens the callsign and virtual-channel-address fields just described. Below the header, the panel splits into a CHAT side and a FILES side (stacked instead of side by side on a narrow window).

CHAT carries a tab row above the transcript: a permanent CHAT tab for the common channel (messages to everyone), a closable tab per station you have opened a direct message with — from the roster or by replying to one — and a permanent LOG tab last, which is read-only and shows the station’s own on-air activity: master election, roster ageing, ARQ retries. An unread direct message marks its tab with a dot. Typing in the box at the bottom and pressing Enter (or SEND) sends to wherever the active tab points — everyone from CHAT, that one station from a direct-message tab.

Files and images

FILES lists transfers in progress — an arrow for direction, the filename, the peer, and a progress bar — followed by an IMAGES viewer with ◀ ▶ between the pictures that have arrived, each labelled with who sent it and when. SEND FILE opens a native file picker (there is no filesystem to pick from in the browser client) and sends to whichever chat tab is active, the same way a typed line does. Every transfer is block-CRC-ARQ: missing blocks are requested back and resent until the file checks out, so a transfer that survives fades and drop-outs rather than one that has to be started over.

A received file is written under a received/ folder — created next to wherever sdroxide was started from — named <transfer-id>_<filename>, so two stations sending a file with the same name never collide.

ACARS (Aircraft Communications Addressing and Reporting System) is the text datalink airliners and ground stations use on VHF airband. Aircraft send position reports, crew requests and company messages; ground stations answer with clearance data, gate assignments and weather. Every exchange is a short burst — a second or two of 2400-baud MSK (tones at 1200 and 2400 Hz) carried as the audio of an AM transmitter.

Where to listen. ACARS lives on a handful of airband channels shared with voice. 131.550 MHz is the primary almost everywhere; Europe also works 131.525, 131.725 and 131.825 MHz, and North America 129.125, 130.025, 130.450, 131.125 and 136.700 MHz. Pick ACARS in the mode picker (or start with --mode ACARS) and put the dial on the channel: the mode demodulates the AM carrier itself, so the carrier belongs on the dial exactly as it does for listening to AM voice. The chips in the panel tune straight to those channels. A transceiver driven over CAT is put in AM, whatever the digital modes’ sideband setting says.

What you see. The panel lists messages newest first: the time (UTC), the aircraft registration (F-GTAE, N12345), the mode character, the two-character label that says what kind of message it is (H1 to or from the crew, Q0 a link test, _d a general response), the acknowledgement (NAK when there is none), the block identifier, and the text. Only messages whose block check matches are listed; a damaged one is counted in the header’s bad figure instead. The level meter sits beside the counters — a channel with no ACARS traffic shows no messages, but the meter still moves with airband noise, so you know the passband is open.

Damaged blocks are not repaired. acarsdec corrects a bit error or two against the block check; this decoder does not yet, so a weak or fading signal that acarsdec would rescue shows up here as a bad block. A bad count that keeps climbing on a busy channel means the signal needs to be stronger.

Receive only. ACARS is an airline service shared with air traffic control — there is nothing here for an amateur licence to do. The mode does not transmit, and its channel chips tune the dial without touching the transmit side.

ACARS is also carried over VDL2 on higher frequencies — see 3.15 for the datalink version.

3.19 HFDL (aircraft on the shortwave band)

HFDL (High Frequency Data Link, ARINC 635) is the shortwave aircraft datalink: ground stations spread across the world on assigned frequencies between 2.8 and 22 MHz exchange position, performance, frequency and ACARS traffic with aircraft out over the ocean, where there is no VHF coverage. Each ground station sends a squitter — a status burst naming itself and the frequencies it is using — about every thirty seconds; the aircraft answer with logons, position fixes and housekeeping reports.

Where to listen. Choose HFDL from the digital row, in either tab. It is a receive-only lane like ADS-B, VDL2 and AIS — an engine-owned 24 kHz channel decoded from the raw I/Q, with no audio and no transmitter — but its channel is not one worldwide frequency. HFDL ground stations sit on a published plan of assigned frequencies, so the panel chooses the channel: the chips and the frequency field list the plan (21 931 kHz Riverhead is the default), and the dial follows the chosen frequency so the panadapter shows the signal. The panel’s LISTEN switch turns the decoder on and off; it costs a 24 kHz lane and a worker thread whether or not the panel is on screen, so it stays off until you ask for it. HFDL is shortwave, so a receiver that reaches 2.8–22 MHz (any HF front end, or an RTL-SDR with an upconverter) and an antenna for those bands are what it needs.

The decode log. Every burst the channel yields is listed newest first: the UTC time, the kind of record (a squitter, a logon, a position, performance-data, frequency-data, or an ACARS message), the ground station it names, the channel, the burst’s SNR and how many symbols the FEC corrected, and the payload’s own fields. The header counts the bursts heard and the ones that decoded, and shows the channel level — a low level with no decodes says plainly that the lane is up and nothing is in the channel, rather than looking merely idle.

The aircraft map. A performance-data or frequency-data record carries a position, and those are plotted on the world map beside the log: a square per aircraft, labelled with the flight, the ICAO address or the ground-station alias, refreshed as later fixes for the same aircraft arrive, and retired after half an hour of silence. Click a target to select it and hover for its position, channel, SNR, how many fixes it has sent and their age; the range and bearing appear when you have a grid set in Settings → General. Positions arrive only when an aircraft downlinks one, so a channel can run for a while showing squitters and no map traffic — that is the ground station idling, not a fault.

Receive only. HFDL is an airline and air traffic service. Nothing here transmits, and the lane is fed from the raw I/Q like the other aircraft lanes. --mode HFDL starts on it and --record-iq captures it, as for ADS-B (§3.13); a minute of --record-iq on a busy channel is the most useful thing to attach to a report.

3.20 PI4 (Next Generation Beacon)

Choose PI4 from the DIGITAL menu. Like WSPR this is not a QSO mode — a PI4 transmission carries a callsign (occasionally a status string instead) and nothing else — but unlike WSPR it is receive only here: this is a decoder for the “Next Generation Beacon” propagation-beacon network (rudius.net/oz2m/ngnb), not a beacon implementation.

A PI4 transmission is 146 symbols of four-tone FSK, 24.333 seconds long, sent once a minute as the first act of the IARU Region 1 VHF Committee’s one-minute mixed-mode beacon cycle — PI4, then a CW identification, then an unmodulated carrier. The error correction is the same rate-1/2, constraint-32 convolutional code WSPR and JT9 use, just with a shorter, eight-character message.

The panel has two panes: SPOTS, the reception list, and STATUS, the beacon’s one-minute cycle. There is no MAP — a PI4 message carries no grid square, so there is nowhere to place one.

Tuning

Tune so the beacon’s CW identification and the unmodulated carrier that follows it sit at 800 Hz audio — the beacon network’s own listening convention. The lowest two PI4 tones straddle that point, half a tone-spacing either side of it, and the other two climb above it — for the standard variant, tones at roughly 683, 917, 1152 and 1386 Hz. The decoder’s frequency search is centred on exactly where the convention puts them. A beacon on a wider channel (PI4-80, PI4-96, PI4-120 — 2 or 3 kHz spacing rather than the standard 1 kHz) needs a wider receive passband to keep its top tone inside it; the panel’s default covers the standard variant with room to spare.

Receiving

The SPOTS pane lists receptions, newest first:

Column What it is
Message Up to eight characters — ordinarily the beacon’s callsign
Variant Which beacon-spacing variant matched: PI4, PI4-80, PI4-96, PI4-120
dB A per-6-Hz-bin signal estimate — not the 2500 Hz-referenced figure WSPR reports, because there is no equivalent convention for this mode to be consistent with
fit How much of the received tone energy the decoded message accounts for

Fit is the important column. PI4’s error correction carries no checksum, so a sequential decode that converges is not automatically a real one — at the noise floor it can converge on a well-formed codeword built out of nothing but noise. Fit is what tells the two apart: it re-encodes the message and asks whether the tones it predicts are the tones that actually arrived. Every row shown here already cleared the decoder’s floor for it, so the colour says how much margin it cleared by, not whether it did.

Once a minute, the decoder searches a window of audio spanning a few seconds either side of the nominal boundary — for a beacon’s clock, or this station’s, running a little fast or slow — across all four beacon-spacing variants and a band of frequencies either side of the listening convention above. The STATUS pane’s slot bar shows where in the one-minute cycle the beacon is, turning yellow while that search is running.

What you need

Nothing beyond an SSB receiver and a station tuned to a real “Next Generation Beacon” transmission — there are beacons on 6 m through 23 cm and higher. Receive only: there is no transmit half of this panel, and there never will be — this decoder exists to listen to the network, not to join it.

3.21 DSC (marine distress and calling)

Choose DSC from the DIGITAL menu. Digital Selective Calling is the marine system behind every GMDSS distress alert: a short digital burst that carries an identity and, on a distress call, what is wrong and where. It is the one marine emergency channel a listener can decode, and the reason this mode is here at all.

Receive only, and deliberately. DSC is distress and safety traffic. An amateur putting a false alert on the channel is not making a mode choice but a hoax, so the panel has no transmit half and no callsign to set.

The channels. The signal is 1200-baud FFSK — mark 1300 Hz, space 2100 Hz — on marine VHF channel 70 (156.525 MHz) and the MF/HF distress channels 2187.5, 4207.5, 6312, 8414.5, 12577 and 16804.5 kHz. The chips in the panel tune to each. As with NAVTEX the quoted frequency is the centre of the two tones, so the dial sits 1.7 kHz below it and the readout still says where the signal is.

The MF/HF channels are the ones a shortwave listener reaches; in Europe 2187.5 kHz is the busiest overnight. DSC is sporadic — a burst is a second or two and the channel is silent between them — so leave it on a channel and wait.

What you see. Two panes, as NAVTEX has:

An MMSI is the vessel or coast station’s nine-digit identity, the same number that appears on a marine radio’s display. A distress alert carries no target — the address is the sender’s own ID — so the reading pane shows Caller MMSI and leaves the target out.

The position and time on a distress alert are the sender’s claim, not the receiver’s: a station that did not know where it was sends the all-nines “unknown” sentinel and the pane says not stated. The time the pane shows at the top of the reading is when sdroxide decoded it, which is the figure to compare the sender’s against.

Nothing to set. There is no tone reversal control, unlike NAVTEX: the detector reads both tone senses and the framer locks to whichever it sees. The tones and the baud are fixed by ITU-R M.493.

3.22 JT65 and JT9

Choose JT65 or JT9 from the DIGITAL menu. These are the two classic weak-signal modes from the WSJT family: JT65 is the EME (moonbounce) mode, and JT9 is its narrower, slower sibling for the weakest signals on HF. Both carry a short message — a callsign, another callsign, and a locator or a report — in a 60-second slot, and both are decoded here rather than sequenced, so this build is receive only for them.

Where they are. JT65 and JT9 are HF and low-VHF modes. JT65 is used on 6 m and up for moonbounce and on HF for weak-signal work; JT9 is HF. Tune the dial to the band and leave the audio cursor where the signals are — a JT signal is tiny, 16 Hz wide for JT9 and about 180 Hz for JT65, and the panel’s decoder searches the whole audio passband for it.

What you see. One pane, the DECODES list, newest first, exactly the list FT8 and FT4 use: the time, the SNR, the audio offset, and the decoded <to> <from> <grid|report>. There is no QSO pane and no transmit half — see below.

One slot at a time. Both modes keep the clock the other slotted modes do: the slot begins on the minute, and a decode arrives a few seconds after the slot ends. The decoder runs on its own thread, because a JT65 scan over a minute of audio is seconds of work — so the list fills in shortly after each minute rather than instantly, and a slot is skipped rather than queued if the machine cannot keep up.

No checksum, so a decode is a claim. Unlike FT8 and FT4, the 72-bit JT message carries no CRC — the error correction is a Reed–Solomon code (JT65) or a convolutional one (JT9), and either can converge on a well-formed message that was never sent when the band is empty or the signal is deep in the noise. The decoder orders what it finds by the strength of the sync and keeps the strongest few. On a real signal the true message is the strong one; on a dead band, do not read a lone weak row as a station.

Receive only. Transmit is not wired in this build. A JT65 exchange is a minutes-long, precisely-timed handshake, and getting the sequencing wrong on the air is worse than not offering it — so the panel decodes and the operator copies. The modes will gain a sequencer when it can be done properly.

3.23 FST4

Choose FST4 from the DIGITAL menu. FST4 is the slow weak-signal mode of the same WSJT family, built for the paths where JT65 and FT8 run out: EME (moonbounce), troposcatter, and LF/MF propagation experiments. It is even slower than JT65 and digs correspondingly deeper.

The period is the setting. FST4 runs on a T/R period of 15, 30, 60, 120 or 300 seconds, chosen by the chip row at the top of the panel. The period is the whole trade: a short one is a fast terrestrial signal, a long one is tens of dB under the noise for a moonbounce path that takes a quarter of an hour to exchange a callsign. 60 seconds is the band convention and the default. Both ends of a contact have to agree on it, so check what the other station is running before choosing.

What you see. The same DECODES list as JT65/JT9 — time, SNR, audio offset, and the decoded <to> <from> <grid|report>. FST4 carries the same 77-bit message as FT8 and JT65, so a decode reads the same way.

One slot at a time, and a long one. The decoder holds the whole slot and decodes it on a worker thread — an FST4-300 scan is tens of seconds of work over a five-minute slot — so on the longer periods expect the list to fill in well after the period ends, and a slot to be skipped rather than queued if the machine cannot keep up.

Receive only. As with JT65/JT9, transmit is not wired in this build: an FST4 contact is a precisely-timed, minutes-long handshake and the panel decodes rather than sequences.

3.24 MSK144

Choose MSK144 from the DIGITAL menu. MSK144 is the meteor-scatter mode: it works by bouncing a signal off the brief, random ionised trail a meteor leaves in the upper atmosphere, which exists for a fraction of a second to a few seconds at a time. It is the standard way to work 6 m and 2 m “meteor scatter” contacts, and it is fast for a weak-signal mode — a complete exchange can be done in a minute when the meteors cooperate, which is why it carries the same short 77-bit message as FT8.

Where it is. 6 m and 2 m, on the meteor-scatter calling frequencies — for example 50.260 MHz on 6 m and 144.200 MHz on 2 m. Tune the dial there and leave the audio cursor alone: the decoder searches the whole audio passband.

What you see. The same DECODES list as JT65/JT9 and FST4. One column reads differently from those modes: the DT is not an offset from a frame start — MSK144 has no fixed frame position — but how far into the 15-second period the meteor burst was found, so a row at 6.4 s is a ping that arrived 6.4 seconds after the period began.

How the period works. MSK144 runs on a 15-second T/R period, and an operator transmits continuously through it: the 72 ms frame repeats back to back, so whenever a meteor trail appears it catches part of one. The decoder scans the whole period for those captures — there is no slot-aligned decode the way FT8 has, and a whole period may pass with nothing.

Receive only. Transmit is not wired in this build, as for JT65/JT9 and FST4. What the panel does is copy the pings that arrive.

3.25 Q65

Choose Q65 from the DIGITAL menu. Q65 is the modern WSJT weak-signal mode: a 65-tone signal built for the paths where FT8 and JT65 run out — EME (moonbounce), ionoscatter, rainscatter and troposcatter — and the mode WSJT-X recommends for 6 m and up. It is more sensitive than JT65 and, unlike the older JT modes, carries a CRC, so a decode is checksummed rather than a claim.

The sub-mode is the setting. Q65 has two independent axes, and the chip row at the top of the panel picks the combination. The T/R period is 15, 30, 60, 120 or 300 seconds, and the tone-spacing letter (A–E) widens the signal — A is the narrow, sensitive terrestrial choice; E tolerates the most Doppler spread for fast-fading microwave paths. Q65-60A (60-second period, letter A) is the band convention and the default. Both ends of a contact have to agree, so check what the other station is running. Ten sub-modes are wired here: 15A, 30A, 60A–60E, 120D, 120E and 300A.

What you see. The same DECODES list as JT65/JT9 and FST4 — time, SNR, audio offset, and the decoded <to> <from> <grid|report>. Q65 carries the same 77-bit message as FT8.

One slot at a time, and a long one. The decoder holds the whole slot and decodes it on a worker thread — a Q65-300 scan is tens of seconds of work over a five-minute slot — so on the longer sub-modes expect the list to fill in well after the period ends, and a slot to be skipped rather than queued if the machine cannot keep up.

Receive only. As with JT65/JT9 and FST4, transmit is not wired in this build: a Q65 contact is a precisely-timed, minutes-long handshake and the panel decodes rather than sequences.

3.26 UVPacket

Choose UVPACKET from the DIGITAL menu. UVPacket is not one of the WSJT weak-signal modes: it is a packet protocol for private amateur VHF/UHF groups, carried as a short π/4-DQPSK burst. Where FT8 and its relatives carry a <to> <from> <grid> message, a UVPacket frame carries an application byte pipe — the sender’s own data, tagged with a small application number and a sequence number and split into 1–32 blocks of twelve bytes. What is inside is up to the group using it: a sentence, a short status line, or a packed binary struct.

Where it is. Anywhere a group has agreed a channel — typically on VHF/UHF, where a 1200-baud packet burst fits a narrow FM or SSB voice channel. There is no calling frequency and no band plan; tune the dial to the group’s channel. The modem’s tones sit 800–2600 Hz above the dial, so the panel’s decoder searches a fixed audio window regardless of the cursor.

What you see. Two panes. FRAMES is the rolling list of what has been decoded — time, sub-mode, application number, sequence, payload size and SNR — and FRAME is the one selected, with every header field and the payload shown two ways: as text when it is printable, and always as a hex dump. The sub-mode (Robust, Standard, Ultra, Express) is detected from the preamble, so there is nothing to choose: each frame is labelled with the one it arrived at.

Frames are not slotted. Unlike every other mode in this chapter, a UVPacket frame can begin at any instant, so there is no clock to watch and no turn headers. The receiver keeps a rolling window of the last several seconds of audio and re-scans it, so a frame appears a moment after it ends. A frame that arrives twice is shown once; a repeated transmission more than a few seconds later is a new frame.

Receive only. Transmit is not wired in this build: UVPacket is a byte pipe whose contents are the application’s, and this program has no application to put in it. The panel decodes what the group is sending.

3.27 FSK441

Choose FSK441 from the DIGITAL menu. FSK441 is the original meteor-scatter mode — MSK144’s older sibling — and it works the same way: the signal bounces off the brief ionised trail a meteor leaves about 100 km up, which lasts from a few milliseconds to a few hundred. It is the classic way to work 6 m and 2 m “meteor scatter”, and it carries plain text rather than the 77-bit message the newer modes use.

Where it is. 6 m and 2 m, on the meteor-scatter calling frequencies — for example 50.260 MHz on 6 m and 144.200 MHz on 2 m. The four tones sit 882–2205 Hz above the dial; leave the audio cursor alone, because the decoder searches the whole passband.

What you see. The same DECODES list as MSK144 and the JT modes. The DT is not an offset from a frame start — FSK441 has no fixed frame position — but how far into the period the meteor burst was found, so a row at 6.4 s is a ping that arrived 6.4 seconds after the period began. The message is free text: a callsign pair and a report or grid (W1ABC W9XYZ FN42), or one of the single-tone shorthand messages R26, R27, RRR and 73, which are sent as a pure carrier and are far easier to catch than text.

The period is the setting. FSK441 runs on a T/R period of 15 or 30 seconds — 30 is the band convention — and the chip row picks it. An operator transmits the message over and over through the whole period, so whenever a meteor trail appears it catches part of one. The decoder scans the whole period for those captures; there is no slot-aligned decode the way FT8 has, and a whole period may pass with nothing.

Transmitting. FSK441 is worked by sending the message over and over: you hold transmit and the message repeats for the length of the over, so a meteor’s brief trail catches whatever part of it is passing. The TX row under the decode list is a single line — type the message (W1ABC W9XYZ FN42, or one of the shorthand words R26/R27/RRR/73) and press TX; CALL CQ fills the box with a CQ and starts it. A shorthand word on its own is sent as its single tone rather than spelled out, which is how the mode works those replies. The message loops until you unkey, with a space sent between repeats so one pass’ last word does not run into the next one’s first, and unkeying ends the over — the loop does not run on. A key with an empty box is refused and says so rather than arming a transmitter that would sit on an empty carrier. There is no automatic sequencing and no station being called: a meteor-scatter contact is arranged by ear and by the shorthand, which is what the mode has always been.

3.28 JTTY

Experimental. JTTY is new — it arrived in the WSJT-X 3.2 release — and this implementation has been checked against the reference off the air only, not off-air. It is here to try, not yet to rely on: treat a decode as worth a second look and a first contact as a test.

Choose JTTY from the DIGITAL menu. JTTY is the asynchronous keyboard mode from the WSJT-X 3.2 release: it is worked like RTTY — either side types and sends whenever it likes — but carries forward error correction, so a signal that would be marginal and error-prone as 45.45-baud RTTY still copies. It is about 125 Hz wide, small enough to tuck into a gap in a crowded band.

It is not slotted. Unlike FT8/FT4 there is no even/odd turn and no period to agree on: a transmission starts at any instant and lasts a few seconds, so there is no clock to watch and nothing to synchronise. A message appears in the list a moment after it is heard.

What you see. A rolling log of the messages heard, each with its UTC time, audio frequency and SNR. The text is what was decoded: a CQ (CQ K1ABC CQ), a call, a contest exchange (599 123, 1D EMA, 599 FN42), or a control phrase such as AGN? or TU. A partial message — one whose end was not heard — is shown dimmed, so a run cut off by the next transmission reads as incomplete.

Transmitting. The TX row under the log is a single line: type the message (W1ABC W9XYZ FN42, or one of the exchange forms above) and press TX; CALL CQ fills the box with CQ <your call> CQ and sends it. The message is sent once — JTTY is asynchronous, so there is no period to wait for and nothing repeats; the over ends when the burst is done. The message is packed for the air automatically: a callsign, a contest exchange or a control phrase is sent as its compact typed form, and anything else is sent as plain text, so an 11 m CB identifier like 26AT715 goes out as it reads.

Where to find it. There is no calling frequency and the mode is very new; tune where the station you want says it will be, and leave the audio cursor where the signals are — the decoder searches the passband itself.

Where in the audio it sits. Like the reference, JTTY is centred at 1500 Hz, its four tones running 1500–1594 Hz — a 127 Hz signal inside a normal SSB passband. So in USB with the cursor near 1500 Hz it is where you would expect; it will not appear at the bottom of the passband, and a receiver or filter set to cut below about 1400 Hz will pass the audio but lose the signal. This build sends and receives at that centre.

4. Skimmers

The skimmers decode many signals at once across a wide (~192 kHz) window and label each one on the waterfall. There are three: CW, PSK31, and RTTY.

Where they listen. The window follows the waterfall: it is placed on the part of the band you are looking at, and only signals actually on screen are tracked and decoded. On a narrow receiver that is the whole span and there is nothing to choose, but a wide front end — an RX-888 handing over megahertz at a time — delivers far more band than a skimmer’s window covers, and the window goes where you are rather than sitting in the middle of the span. Pan across the band and it follows, once the pan has left the window it was on; zoom out past 192 kHz and it keeps your dial covered, so the part of a band-wide view that gets skimmed is the part you are tuned into.

The skimmer labelling signals on the waterfall

Band-aware gating. To avoid noise and false decodes — and to avoid paying for either — each skimmer only runs where its mode is used: the CW skimmer in CW sub-bands, and the PSK and RTTY skimmers in each band’s PSK/RTTY calling sub-bands — with the FT8, FT4, FT2, WSPR, and QRSS watering-holes excluded so their signals aren’t mistaken for PSK or RTTY (the WSPR window and the slow-CW/QRSS beacons just below it sit inside the RTTY sub-band on several bands, so they’re carved out explicitly). A skimmer whose window holds none of its own sub-bands stands down completely and costs nothing until you tune back onto one — so an SDR parked on the broadcast FM band, the air band or any other non-amateur allocation is not running a neural CW decoder over it. Which frequencies count is the band plan’s to say (bandplan.json), and it ships with the HF allocations only. The skimmer-decoded text is a coarse best-effort copy; switch to the mode (click a box) for a clean decode — the CW skimmer runs the same decoder as the CW panel, but over hundreds of signals at once and re-reading each one only twice a second, so a signal you care about is always better copied on the panel.

Note: the skimmers are a wideband feature and work only with true IQ/SDR sources (SoapySDR, HPSDR, TCI). They are unavailable when a CAT radio is feeding demodulated audio (see settings), because that mode has only a narrow audio slice rather than a wide IQ span.


5. ISM band decoder

The licence-exempt ISM bands are full of small unattended transmitters: weather and soil sensors, water and heat meters, doorbells, thermostats, alarm contacts, tyre-pressure sensors, gate remotes. Each one wakes up, sends a few milliseconds, and goes back to sleep for a minute. The ISM button in the System module opens a window that reads them and lists each device it has heard, with its readings in real units.

That button turns green while the decoder is running, not while the window is open — like SAT and SCAN, because it is spending a receiver on your behalf whether or not you are watching. Closing the window therefore leaves it lit. The switch is DECODING inside the window itself.

There are two sets of decoders behind that window. SDRoxide’s own read a handful of protocols on the European 868 MHz channels, in detail and with every checksum verified — those are what the rest of this section describes first. The rtl_433 decoders (§5.4) add several hundred more across 315, 345, 433, 868 and 915 MHz. Most people will want both switched on.

5.1 Where it listens, and where to tune

The ISM channels are at fixed frequencies, so the decoder parks a receiver on each of them rather than searching the band:

Channel What is on it
868.300 MHz Weather and soil sensors, wireless M-Bus mode S, KNX-RF, EnOcean, Homematic
868.420 MHz Z-Wave (EU)
868.950 MHz Wireless M-Bus modes T and C — most modern meters
869.525 MHz Wireless M-Bus mode N, Homematic long range

Those four span about 1.4 MHz, and the decoder can only reach the ones inside the IQ your receiver is actually delivering. The window lists every channel with a lamp: green for one being listened to, and a reason beside any that is not — outside the receiver's window if you are tuned elsewhere, not decoded yet if nothing in this build reads it.

Press 868 MHz EU in the band row to get there — it tunes the radio for you, and on a receiver handing over ~2 MHz the window then reaches the channels that matter. Those buttons are the only tuning control in this window; there is one per band, and they serve both sets of decoders at once.

There is one window and both sets of decoders share it, so on a receiver with room to spare — a PlutoSDR at 3.84 Msps, say — it is made wide enough to hold the channels above and rtl_433’s band at the same time. Where there is not room for both, the window goes where the most decoding gets done, which is why a channel with no decoder behind it never costs you one that has: switching rtl_433’s 868 MHz band on can push 869.525 MHz out of view, and that channel reads nothing either way.

Do not tune the dial to a channel to try to reach it. The window follows the receiver’s own centre frequency, not the dial, and on a zero-IF radio those are not the same place — a PlutoSDR parks its local oscillator 960 kHz above the dial, so putting the dial on 868.950 MHz moves the stream to 869.910 and takes the 868 MHz channels out of reach. The band buttons put both where they belong.

Note: like the skimmers, this is a wideband feature. It needs a true IQ source and is unavailable when a CAT radio is feeding demodulated audio.

On an RX-888, 868 MHz is reached through its VHF tuner, and its wideband downconverter delivers 2.025 Msps at the default panadapter width — enough for the whole channel plan, but only just, which is why the centre frequency matters there. A wider panadapter width (15.20) covers it with room to spare.

5.2 Reading the device list

One row per device, not per transmission: these things repeat themselves for months, and the question is what is around you and what it is reading. Each row shows how long ago the device was last heard, the frequency measured from the signal (not the channel it was found on, so two sensors 40 kHz apart read as two frequencies), the protocol, the device’s own identity, the signal strength, how many frames have been accepted from it, and the readings.

5.3 What is decoded so far

LaCrosse IT+ — the TX29-IT, TX35, TX35DTH-IT and the Conrad and TFA units that are the same radio in a different case. Temperature, humidity where the sensor has an element for it, and the battery state. Frames are accepted only when the length field, the CRC-8, the BCD temperature digits and the temperature range all agree, so a row in the list is a real reading rather than a lucky checksum.

Fine Offset — the Fine Offset Electronics sensors, which are also sold as Ecowitt, Froggit, Ambient Weather, SwitchDoc and Misol. Every frame in this family carries two independent checks, a CRC-8 and a byte sum, and both must pass — which is what makes it safe to decode on a band this busy.

Rainfall on the WS85 and WS90 is not decoded, and the row says so rather than reading zero. The layouts set aside five bytes for rain and name two of them as the total, but the only published capture of each was taken in the dry — so nothing there distinguishes a right guess from a wrong one, and on the WS90 a neighbouring byte would read as a plausible 18.6 mm. A rain total read out of the wrong bytes is worse than no rain total. If you have one of these and it rains, a recording made with --record-iq would settle it.

Bresser — the Weather Center 5-in-1, 6-in-1 and 7-in-1 outdoor sensors, the water-leakage sensor, and the units rebadged from them (Froggit among others).

The 7-in-1 is the weakest frame in the band that SDRoxide accepts, and worth knowing as such. A 5-in-1 carries about a hundred bits of redundancy and a leakage sensor a 16-bit CRC plus five checkable flag bits; a 7-in-1 has a 16-bit digest and nothing else, so one random burst in 65 536 passes it before any other check. Everything the format offers on top is taken — the sensor-type nibble must be a documented one, every BCD field must be wholly decimal or wholly 0xf, and a value outside the range its sensor can produce fails the whole frame rather than being dropped on its own — which together gets it to around one in 200 000. This is what the heard count in the device list is for: a device seen once may be a lucky digest, one seen fifty times is really there.

These sensors run at 8.2 kbaud — less than half the Fine Offset rate — behind the same channel, preamble and sync word. That mattered more than it sounds: see the note below.

Z-Wave — the European 868.42 MHz channel at the 9.6 kbit/s rate, which is Manchester-coded and so needs a decoder that slices at 19 200 chips a second rather than at the data rate. Each report names the home identifier, the source and destination nodes and the frame type, because Z-Wave encrypts at the application layer and not the link layer: the mesh has to be able to route a frame without opening it, so the routing header is in clear even on a secured network. The command class is named where it is a familiar one. A frame carrying a secured command class is marked payload encrypted — SDRoxide holds no keys.

This one was not transcribed from a write-up: the frame layout was derived from a capture taken off the air with ism_forensics, and confirmed by its own checksum reproducing.

Homematic BidCoS — 868.3 MHz, recognised and reported as present, not read. The recognition is solid: a 32-bit sync word at the right rate and deviation. The contents are obfuscated by the protocol, and rather than derive a de-obfuscation from prose and apply it to a single unverifiable capture — which would produce device addresses that look authoritative and might be nonsense — the frame is listed with its bytes and no interpretation.

Unidentified bursts — the UNKNOWN button. Off by default. With it on, every burst that gates but matches no decoder is listed anyway, classified and described by what could be measured about it:

Class Decided by
2-FSK two tones, constant envelope
OOK the envelope is keyed down to the channel’s own noise floor
chirp the frequency sweeps instead of settling on tones
carrier too little frequency spread to be two tones

None of that needs a symbol rate to have been recovered, which matters because a chirp has none to recover. The row also carries the deviation, the rate, and — where the burst is framed — the two bytes immediately after its preamble. Those two bytes are the sync word for every protocol in this band, so they identify the protocol even when nothing can read it, and they are used as the device identity so repeats collapse into one row with a count. A chirp or a carrier has no preamble to derive one from, so those are listed by rounded frequency instead.

On-off keying is measured differently. The symbol-rate estimator used everywhere else counts how often the frequency crosses the carrier — the right measurement for a constant-envelope signal that moves its frequency, and the wrong one for a signal that does the opposite. Over the silent half of a keyed burst the discriminator is reading noise. So a burst classified OOK has its rate taken from the envelope instead, as the shortest keying element or as the interval between rising edges, whichever verifies itself better — the second being what pulse-width coding needs, which is what nearly every cheap remote and sensor on these bands actually uses.

That is how the 868 MHz band around this author’s bench turned out to hold a 2c4c emitter at 10 kbaud that heartbeats every 60 seconds and a d391 one — 0xd391 being the factory default sync word of the TI CC1101, which a great many cheap 868 MHz devices never change. Neither is decoded. Knowing they are there, how often they speak and what to search for is most of the way to finding out what they are.

Wireless M-Bus and LoRa recognition are not implemented yet.

Why a sensor can be plainly visible and still not decode. Each protocol declares a symbol rate, and the bit slicer used to search only ±20 % around it. A Bresser sensor at 8.2 kbaud therefore stayed invisible on the very channel it shares with the 17.24 kbaud Fine Offset family — its sync word sitting in the trace with nothing ever slicing at a rate that could see it. The slicer now also tries the rate measured from the burst itself, which is what a sync word and a CRC are for. If you are writing a new protocol module, this is why the sym column in ism_replay --survey matters more than the nominal rate in any datasheet.

On encrypted meters: when wireless M-Bus support arrives, most modern German and Austrian meters will still only report their manufacturer, serial and device type — their readings are AES-encrypted and SDRoxide holds no keys. That is a useful meter inventory, but it is not a meter reading.

5.4 The rtl_433 decoders

Under RTL_433 DECODERS is a second set of decoders, from the rtl_433 project, built into SDRoxide. It adds several hundred device protocols and, unlike the decoders above, reads OOK as well as FSK — which is most of what is on the air below 868 MHz.

There is no switch: if your build has them, they decode whenever the ISM decoder is running. All you choose is which band to listen on.

Bands

The band buttons pick where to listen. Pressing one selects that band and tunes the radio to it, because the decoder listens inside whatever IQ the receiver is delivering. Only one band runs at a time: they are hundreds of megahertz apart and no receiver covers two at once.

Band Where it is used What is on it
433.92 MHz Europe, and worldwide for remotes Weather stations, thermometers, soil and pool sensors, doorbells, garage and gate remotes, alarm contacts, PIR sensors, tyre-pressure sensors, energy monitors, remote switches
868 MHz EU Europe The same weather families as the decoders above, plus Fine Offset and Bresser variants they do not cover, and assorted home-automation devices
915 MHz US North America, Australia Acurite, LaCrosse and Oregon Scientific weather stations, tyre-pressure sensors, utility meters (ERT/SCM), Honeywell alarm sensors
315 MHz US North America Tyre-pressure sensors, garage and gate remotes, alarm contacts
345 MHz US North America Honeywell/Ademco, 2GIG and Vivint alarm sensors — door and window contacts, glass-break detectors, motion sensors

433.92 MHz is the one worth trying first if you have never looked: it is busy almost everywhere, and none of SDRoxide’s own decoders reach it.

Bandwidth

bw is how wide a window rtl_433 gets around the band centre.

AUTO gives each band the width it normally needs: a quarter of a megahertz on 315, 345 and 433 MHz, where everything is slow OOK crowded around one frequency, and a full megahertz on 868 and 915 MHz, where the FSK devices are faster and spread over several channels. That is what rtl_433 itself uses, and it is the right answer nearly always.

Choose a width by hand for the two cases it is not:

Narrowing has the opposite catch: 250k on 868 MHz watches 868.525 to 868.775 MHz and so hears neither of the two busy European sub-bands. The band row and the frequency beside rtl_433 say what is actually being watched.

The figure shown there is not always the one you picked. The window is a whole-number division of the receiver’s stream, so a request for 250 kHz out of 1.4 Msps settles on 350, and 1024 kHz out of the RX-888’s 2.025 Msps takes the whole 2025 because half of it would be too little. It is never narrower than what you asked for — a lane given less than the band it was chosen for would be deaf at the band’s edges, and rtl_433’s own wireless M-Bus decoder wants at least 1.2 Msps whatever the band asks for.

What it adds

Broadly: weather (Acurite, Ambient Weather, Bresser, Ecowitt, Fine Offset, LaCrosse, Oregon Scientific, Nexus, Rubicson, TFA and many rebadges), tyre-pressure sensors from most car makers, utility and sub-metering (ERT/SCM gas, water and electricity meters, Efergy and Owl energy monitors), security and access (door and window contacts, PIR sensors, smoke alarms, gate and garage remotes, key fobs), environment (soil moisture, pool and fridge thermometers, air quality, lightning detectors) and a long tail of remotes, doorbells and thermostats.

Devices appear in the same list as everything else, with rtl_433 in the protocol column and the device’s model name beside it.

Where it takes over

Where both sets of decoders can read a device, rtl_433 reads it, because it knows far more variants — fifteen LaCrosse decoders to SDRoxide’s one, nineteen Fine Offset to seven, eight Bresser to four. The channel list says handled by rtl_433 for those, and the panel lists them under handled by rtl_433. This is why a sensor you know as Bresser may appear as rtl_433 with a model of Bresser-6in1 — same device, better decoder. Select a band somewhere else and SDRoxide’s own decoders take 868 MHz back.

Z-Wave and Homematic are never handed over — rtl_433 has no decoder for either, so those two stay with SDRoxide’s own regardless of what band is selected.

5.5 Adding your own decoders (flex specs)

If you have a device nothing decodes, you can describe it yourself — no code, no rebuild. A flex spec is a few lines of text saying how a device modulates and frames its data, and SDRoxide turns it into a working decoder.

They live in one file:

Platform Location
Linux ~/.config/sdroxide-brown/rtl433_flex.conf
macOS ~/Library/Application Support/org.sdroxide.sdroxide-brown/rtl433_flex.conf
Windows %APPDATA%\sdroxide\sdroxide\config-brown\rtl433_flex.conf

The file is created for you, with a worked example commented out, the first time the ISM decoder runs. SDRoxide never rewrites it, so what you put there stays exactly as you wrote it — including your comments and spacing.

The syntax

It is rtl_433’s own flex syntax, unchanged. That is the point: a spec published on a forum, in a blog post, or in rtl_433’s own conf/ directory can be pasted in as-is. Both shapes work — a decoder { ... } block:

decoder {
    name=doorbell,
    modulation=OOK_PWM,
    short=400,
    long=800,
    gap=1000,
    reset=7000,
    match={24}0xa9878c,
    get=@0:{24}:id,
    unique
}

or the single-line form, which is what rtl_433’s -X option takes:

decoder n=doorbell,m=OOK_PWM,s=400,l=800,g=1000,r=7000,match={24}0xa9878c

Put as many as you like in the file, one block each. # starts a comment.

The keys you will use most:

Key Means
name / n What the device is called in the list. Required.
modulation / m How it keys the carrier. Required — OOK_PWM, OOK_PPM, OOK_PCM, OOK_MC_ZEROBIT, FSK_PCM, FSK_PWM and a few more.
short / s, long / l The two pulse widths, in microseconds. Required (except for the Manchester modulations, which have one).
gap / g Longest gap still inside one message, in microseconds.
reset / r Quiet time that ends a message, in microseconds. Required.
bits, rows, repeats How much data to insist on before believing it. Also bits>, bits< and so on for a range.
match, preamble A fixed bit pattern the message must contain or start with, as {count}hex — the main defence against decoding noise.
get Pull a named field out of the bits: get=@0:{8}:temperature_C. Repeat for each field.
unique Report one line per message rather than one per repeat. Worth adding.

short, long, gap and reset are timings you measure from the device itself — the ism_replay --survey tool in §5.7 prints them from a recording.

Name your get= fields well. Call one temperature_C, humidity, pressure_hPa, power_W, battery_ok, wind_avg_km_h and so on, and it shows up as a proper reading with units, converted to the same units as every other row in the list. Any other name still appears, just as plain text.

Loading changes

Press RELOAD DECODERS in the ISM window after editing the file. The devices already in the list stay there, and the notice bar says how many decoders loaded and how many were refused.

Deleting the file and reloading gets you a fresh one with the commented example back.

When a spec is wrong

Every spec is checked before it is used. One that does not pass is listed in the ISM window with its line number and the reason, and skipped — the others still load, so one typo costs you one decoder rather than all of them.

The check is deliberately stricter than rtl_433’s own command line. rtl_433 reports a bad spec by printing a message and stopping the program, which is fine for a command-line tool and not fine for a receiver you are operating; so anything SDRoxide cannot confirm is safe gets refused with an explanation instead. If a spec is rejected that you believe is valid, the message says which part was not understood.

5.6 Nothing is being decoded

Work down this list; each step distinguishes two causes that look identical from the outside.

  1. Is anything live? The channel list needs at least one green lamp — the rtl_433 row counts. All grey with “outside the receiver’s window” means the dial is wrong: press the band button for the band you want, which tunes there. A band reading too wide for the receiver's window is the other one: the width under bw is more than this receiver can give, so set it back to AUTO or narrower (§5.4). A native channel reading handled by rtl_433 is not a fault; it means the other set of decoders has that one (§5.4).
  2. Is the gate opening? The bursts / decoded line says. 0 bursts means nothing is reaching the threshold: lower sql towards 6 dB. A healthy count with 0 decoded means the band is busy with devices this build cannot read — go to step 4.
  3. Are your sensors even on these channels? This is the common answer and the one the panel cannot give you. The 868 MHz band is wide, and a great deal of what fills it — the RFID readers at 865.6–867.6 MHz especially — is nowhere near the four channels the sensor protocols use. Record and survey:

    sdroxide --record-iq band.iq            # 8 bytes a sample: 16 MB/s at 2 Msps
    cargo run --release -p sdroxide-ism --example ism_replay -- band.iq 868880000 2025000 --survey
    

    --survey ignores the channel plan and tiles the whole window, finishing with a histogram of where the bursts actually were. If the traffic is all at 866.5 MHz, no amount of tuning the sensor channels will help — and now you know.

  4. What are they? For each undecoded burst the survey prints the measured deviation, symbol rate and envelope swing. Candidate frames (cand) above zero means the right modulation and a frame format this build does not know; cand 0 means a modulation this chain does not handle at all, which is what LoRa’s chirps look like. Those columns are what a new protocol module gets written from.

5.7 Checking it without waiting for a sensor

Two tools ship with the decoder. The first writes a synthetic 868 MHz band with four sensors whose readings are known, as an IQ file the radio can tune:

cargo run --release -p sdroxide-ism --example ism_iq -- band.iq 10
cargo run --release -- --file band.iq --rate 2025000 --freq 868880000 --mode NFM

Switch the ISM window on and the four sensors should appear with the readings the generator printed.

The second replays a real capture and reports every burst it finds, decoded or not — which is how you find out what your own neighbourhood is transmitting. Capture one with --record-iq (see 5.6), then:

cargo run --release -p sdroxide-ism --example ism_replay -- band.iq 868880000 2025000
cargo run --release -p sdroxide-ism --example ism_replay -- band.iq 868880000 2025000 --survey

The first listens on the channel plan, as the radio does. The second tiles the whole window instead and reports traffic anywhere in it.

The cand column is the useful one on an undecoded burst. Candidate frames mean the right modulation and a frame format this build does not know; no candidates at all means a modulation this chain does not handle, which is what LoRa’s chirps look like.


6. Settings

Everything that configures sdroxide lives in one window, opened with the ⚙ SETTINGS button in the System module (the ⚙ SETUP button in the SPOTS window opens the same dialog on its Spots tab).

The pages run down the left, in four groups, and the page you pick is on the right. On a window too narrow for a column — a phone, or a settings box dragged right down — they run across the top as a tab strip instead, which wraps rather than cutting labels off.

Group Pages
Station General · Radio · Audio · CW (the key and the keyer) · UI
Radio work Spots · FreeDV · T/R switch · Profiles
Sending Uploads · Winlink · Servers
Setup Alerts · Controls · TLE
Page What it holds
General Which version this is, your callsign, grid, IARU region and channel plan (11M/CB), and who may connect remotely. 6.1
Radio Which rig sdroxide talks to, and how. 6.2
Audio Your speakers and microphone, this radio’s sound card, and where recordings are written. 6.13
Radio Which rig sdroxide talks to, and how. 6.2
UI Frame rate, waterfall palette, spectrum background, spot label colours, 3D cloud rendering, and the spoken announcements. 6.3
Alerts Sounds that ring when a decode matters: a station calling you, a new DXCC entity or grid. Audible alerts
Controls Keyboard, mouse and MIDI bindings. 6.4
Spots DX cluster, POTA, SOTA and PSK Reporter feeds, and the broadcast station list. 6.5
FreeDV FreeDV Reporter (qso.freedv.org). 6.6
Uploads Callsign lookup, QSL upload, confirmation download. 6.7
Winlink The radio-email account, and whether it forwards over the internet or on the air. 6.8
Servers Hamlib rigctld, the built-in TCI server, and the WSJT-X UDP broadcast. 6.9
T/R switch The relay that grounds the SDR’s antenna while the station transmits, and the sequencer around it. 6.11
TLE Satellites to track beyond the amateur set, and their frequencies. 6.10
Profiles Named snapshots of how the station is set up, put back on in one click. 6.12

Most settings take effect the moment you change them. The ones that open or rebind a connection — the radio itself, the spot feeds, FreeDV Reporter, and the two servers — have their own APPLY or Apply / reconnect button, noted in each section below, and so does Winlink, whose account is read by the next forwarding session rather than the moment you type it. Nothing here needs a restart.

Settings are written to the per-user config directory (§13): display preferences to config.toml, the radio to radio.json, key/mouse/MIDI bindings to input.json, feeds and credentials to net.json, the two servers to rigctld.json, tciserver.json and wsjtx.json, the satellite additions to satellites.json, the transmit/receive switch to relay.json, and the saved setups to profiles.json.

Most of those files describe the station, not the screen: the feeds it connects to, the servers it offers, the satellites it tracks, the radio it has. They live on the machine the radio engine runs on, and the engine tells every client what they say — so the Radio, Spots, FreeDV, Uploads, Winlink, Servers, TLE and Profiles tabs show, and change, the real thing whether you are at the shack machine, on a native remote client or in a browser tab. The T/R switch tab is the same kind of thing — the relay is bolted to the antenna, not to your desk — with one difference worth knowing before you use it from away: its TEST buttons operate real hardware in a room you are not in. (The Radio tab keeps back the parts that are about a machine rather than about the radio: which interface to open, and the buttons that scan a bus or test an address. See 8.4.) input.json and the [ui], [speech] and [alerts] tables of config.toml are the exception, and belong to the screen in front of you: a display preference and a knob on your desk have nothing to do with the radio in the other room — and so does the [remote_server] address on the General tab, which is where this screen goes rather than anything about the station it arrives at. The rest of config.toml — including the [remote_access] sign-in — belongs to the engine’s machine, which is why the Remote access section of the General tab is only shown there.

6.1 General: station, audio and remote access

The General tab: callsign, grid square, the reception-report identity, and your own speakers and microphone

At the top is SDR Oxide Brown and the version number this copy was built from — the one to quote in a bug report, so there is no need to go looking for the binary to ask it. Brown names which build this is: this fork’s variant, told apart at a glance from the upstream program, since the two install happily side by side and read the same settings. It is a variant name, the way SDR++ Brown names that program’s second build — it says “this build, not upstream” without saying what is in it. It is also the window and taskbar title, which carries the version beside it, and --version on the command line prints it (with the _brown release suffix, e.g. SDR Oxide Brown 1.9.2_brown).

The release tags carry the same suffix: v1.9.2_brown rather than upstream’s v1.9.2. The version the program reports to other software — the SSTV id, the WSPR/PSK Reporter fields, the ADIF program id — is left as plain 1.9.2, because the suffix is for a person and a tag, not for anything a machine parses.

Station — your Callsign and Grid square. This is the identity the whole program uses: FT8/FT4/FT2 exchanges, the SSTV image header, the logbook, the DX cluster login, and FreeDV Reporter. The same pair is editable from the FT8 / SSTV setup dialog; there is only one copy of it.

IARU region — which of the three ITU regions your station is in:

  Where
Region 1 Europe, Africa, the Middle East, northern Asia
Region 2 The Americas
Region 3 Southern and eastern Asia, Australasia, the Pacific

The amateur allocations are not the same in all three, so this one setting decides every band plan sdroxide draws and enforces:

The default is Region 1, which is the band plan every sdroxide before this setting had; an existing installation is not moved by upgrading. It is a property of the station, stored as region in config.toml on the machine the radio is attached to and announced to every client, so a remote operator sees the band plan of the radio they are driving rather than of wherever they happen to be sitting. It takes effect immediately — no APPLY, no restart.

The band plan file

The numbers behind all of that live in bandplan.json in the config directory (§13), and they are yours to change. On first start sdroxide writes the built-in IARU tables there; from then on that file is the authority for every band edge, sub-segment and skimmer window in the program.

The General tab shows the path and a RELOAD BAND PLAN button, which re-reads the file on the machine the radio is attached to and applies it without a restart — so the loop is: edit, save, click, done.

The file is one row per line, in megahertz, and it explains itself in a readme field at the top (JSON has no comments). Each region has four lists:

List What it sets
bands The allocations. band is one of Lw Mw M160 M80 M60 M40 M30 M20 M17 M15 M12 M10 M11 M6 M4 Fm M2 M125 M70 Cm33 Cm23 Cm13 Cm9 Cm6 Cm3 — metres up to 2 m, then the band’s own name, Cm from 33 cm up because M6 was already 6 m, and Lw, Mw, Sw, Fm for the broadcast services (see the bullet above for what Sw deliberately overlapping the amateur bands does). Leave a band out and the region does not have it — with one exception, below.
segments The CW / data / phone / beacon / all-modes blocks on the waterfall strip. kind is Cw, Digi, Phone, Beacon or All.
psk_windows Where the PSK31 skimmer listens.
rtty_windows Where the RTTY skimmer listens.
"region1": {
  "bands": [
    {"band": "M2", "lo_mhz": 144.0, "hi_mhz": 144.4},
    ...

That edit is the common one: narrow a band to your own licence, and with tx_ham_only set (the default) sdroxide refuses to transmit outside it. The band buttons, the waterfall strip and the frequency displays all follow.

On a slotted digital mode the lockout vets what actually radiates, not the dial. FT8, FT4, FT2, JS8 and WSPR transmit at the dial plus an audio offset, so the check is dial + offset + the mode’s occupied bandwidth, and it is made against the sub-segments rather than the band edges — bandplan.json holds one range per band, and a licence like the UK’s 60 m needs eleven. Narrow the segments there and the lockout narrows with them; nothing about this is UK-specific. An emission may cross from one sub-segment into a touching one — a signal reaching out of the digital segment into the phone one is poor manners, not out of band — but it may not cross a gap. Where the table says nothing about your dial, no opinion is offered, so a band plan with a hole in it never becomes a lockout for someone legitimately in it. Auto TX FRQ obeys the same limit when it hunts for a slot, so it stops choosing frequencies the lockout would then refuse.

A band sdroxide adds later — 4 m (M4) was the first, and 1.25 m (M125), 33 cm (Cm33), 23 cm (Cm23), 13 cm (Cm13), 9 cm (Cm9), 6 cm (Cm6), 3 cm (Cm3), 11 m (M11) and the broadcast services Lw, Mw, Sw, Fm since — is not in a file written before it existed, and a file that has never heard of a band is not saying you have not got it. So a band on that short list is filled in from the built-in tables when your file names it in no region at all, exactly as a fresh file would have it. Give it a row anywhere and your file decides it everywhere again, in all three regions, like every other band.

If a row says something impossible — edges the wrong way round, a band listed twice, GEN where a real band belongs — that row is dropped, the rest of the file is used, and the notice bar says which one and why. If the file will not parse as JSON at all, sdroxide runs on the built-in tables for that session and tells you so; your file is left exactly as it is, unlike the files sdroxide writes for itself, because a half-finished edit should survive the start that could not read it. Delete the file to get a fresh copy of the defaults — one is written on the next reload or start.

This is the regional allocation, which is the widest set of edges the region’s amateurs share. Your own licence may grant less (and occasionally more), and national band plans differ inside a region. Nothing here is a substitute for your licence conditions — which is exactly why the file is editable.

SWR guard — Stop transmitting on high SWR, and the ratio it trips at. Armed by default at 2.5:1. When the radio reports an SWR at or above the figure, sdroxide stops the transmission and keeps transmit locked out until you acknowledge it — the point being that a fault which clears itself when you release PTT teaches you nothing and lets you carry on transmitting into it. See § 2.10 Transmit for what it does on the air and how to clear a trip; in config.toml the pair are swr_guard and swr_limit.

It needs a rig that measures SWR and reports it over CAT or TCI — the Icom CI-V dialect, the Yaesu/Kenwood/Elecraft/ELAD/QRP Labs dialects, rigctld, flrig, and TCI. On anything that never sends a figure (any IQ radio: HackRF, Pluto, RTL-SDR, an HPSDR board) the setting is simply inert, which is why it costs nothing to leave on.

Your audio, the radio’s sound card and recordings now have a page of their own — § 6.3 Audio — because they used to sit here under one heading and then, for the radio’s own half, on the Radio tab as well.

Remote access — the Username and Password a remote client has to give before this station will let it operate: the browser page, another sdroxide started with --connect, and the 3D view’s tab. See § 7.3 Sign-in.

Like every other password sdroxide stores — the cluster login, QRZ, eQSL — it is kept in the clear, so config.toml is worth the same file permissions as the rest of your config directory.

Signed-in station — which station this client is signed in to, and the way back out of it. Drawn whenever this screen is attached to a station rather than holding one, which in practice means the browser: a sign-in remembered for a day outlives a reload, so there is nothing to think about until you want to. SIGN OUT forgets this device’s sign-in — the cookie has to be taken back by the station, because the page cannot read it — and the connection you are on stays up until you close it. Where a station was too old to hand out a cookie, the line underneath says so and names it, rather than the browser quietly holding a password. See § 8.3 Sign-in.

Connect to a server — the same thing --connect does without the command line. The machine this screen runs on can drive an sdroxide somewhere else — the shack, a remote site — as a radio tab of its own. Enter the server’s Address and Port and press CONNECT; a pasted ws:// or wss:// URL is used exactly as typed and leaves those two boxes greyed out. See § 8.2 Connect a native remote client.

6.2 Radio: choosing and configuring the rig

In the native application the very top of the tab carries the radio roster — one button per radio, with the same TX / warning / mute markers as the main window’s tab strip, the ON/OFF switch that opens or closes each radio’s interface without disturbing anything on this page, an × on every radio but the first, and + to add one (§2.17). Everything below the roster configures the highlighted radio; click another button and the whole application switches to that radio, this dialog included. The Name box under the buttons renames the highlighted radio’s tab — left empty, the tab names itself after the interface selected below.

Radio interface, under the roster, selects how sdroxide talks to your radio. Everything below the selector changes to match the choice:

There is no auto-detect: you pick the interface, and an interface that cannot be opened falls back to a silent source rather than guessing at another one.

After changing the radio interface, serial port, sound format, or radio-audio device, press Apply / reconnect at the bottom of the Radio tab (or under the CAT radio-audio settings on the General tab). sdroxide rebuilds the radio live — no restart. If the new interface can’t be opened, the previous one keeps running and an error is shown; your tuning resets to the new radio’s default frequency, as it would on a fresh start.

Apply / reconnect is for changing the radio, not for attaching it. If the radio you already configured isn’t there when sdroxide starts — a network rig still booting, ExpertSDR3 launched a moment later, a USB cable plugged in afterwards — sdroxide keeps trying it in the background and attaches by itself, retrying at first every second and then more slowly. The same happens if the link drops mid-session: it reconnects when the radio comes back.

Converter and Offset, under the interface selector, are for an external frequency converter in the antenna line — an HF upconverter such as the Ham It Up or SpyVerter, a transverter, or a satellite LNB. Pick a converter from the list and the offset fills itself in; pick nothing and type one, which the list then shows as Manual. That entry is a label rather than a choice — it says what the box reads when the offset is not one of the presets, and cannot be picked; the Offset field below is always editable, which is where any other converter goes in.

The offset is in hertz, and it is the same number, with the same sign, that the converter’s own documentation and every other SDR program (SDR++, SDR#, GQRX) states: how far the converter moves the signal on its way to the receiver. A Ham It Up is 125000000. Positive means an upconverter — you type 10.1008 MHz and sdroxide quietly sends the receiver to 135.1008 MHz. Negative means a down-converter: a universal Ku-band LNB is -9750000000, so a 10.489 GHz downlink is received at 739 MHz while the dial reads 10.489 GHz. A transverter follows the same rule — one working 2 m into a 28 MHz I.F. is -116000000, because the radio ends up on dial + offset and 144 − 116 = 28. Dragging the box trims a hertz at a time, which is what a converter whose oscillator is a little off wants. The offset takes effect when you press Apply / reconnect, not as you type it.

Applying it does not move the receiver. At the moment you set it up you are listening to the converter’s output — 739.494 MHz through a 9750 MHz LNB — and saying what is in front of the radio re-labels that signal as what it really is: the dial jumps to 10489.494 MHz, the front end stays exactly where it was, and you carry on hearing what you were hearing. (What it must not do, and used to: ask the radio for 739.494 minus 9750 MHz, which is not a frequency. The radio clamped to the bottom of its range, the dial was left outside the converted receive range, and every tune after that was refused as “outside this radio’s receive range”.)

Everything downstream follows the dial, not the hardware: band buttons, the band plan, memories, the logbook, cluster and PSK Reporter spots, what gets uploaded after a digital contact, and the tuning range quoted if you ask for a frequency the radio cannot reach. Nothing needs a second correction anywhere.

Transmit, the row under the offset, is where you say what is in the transmit line — because a converter is a receive accessory and sdroxide cannot see what the other half of your station looks like. Three answers:

The amateur-band check still applies on top, on the frequency you are actually transmitting on, and so does the radio’s own transmit range — quoted in dial numbers, with the transmit offset taken off.

Working QO-100 (or any other split-band satellite) needs one more thing: the transmit frequency, which is nowhere near the dial. Two ways to get it there — switch Split on and put the uplink on VFO B (2400.050 MHz for a downlink of 10489.550), or lock onto the satellite (2.16) and let the transponder mapping derive the uplink from wherever you tune the downlink, which is what you want for anything that moves. Receive is torn down for the length of an over on a half-duplex front end, so you will not hear your own downlink while transmitting — unless the radio is a Pluto or LibreSDR on real Ethernet, where Full duplex (6.2.7) keeps the receiver running through it.

A few things to know:

This has been tested against sdroxide’s own simulated front ends, not against a physical converter. If you have one, reports are welcome.

Transverters, below the transmit row, are the other half of the same idea and the one a multi-band station wants. Offset above is one answer for the whole dial — an upconverter or an LNB is in front of everything — while a transverter is in front of one band and the radio is on its own below it. The table holds up to ten rows, and each has:

Rows are tried in the order they are listed, and a dial no row covers falls through to the single Offset above and then to the bare radio — which is what keeps HF working on a station whose only converter is a 2 m transverter. Everything downstream follows the dial as it always has: the band buttons, the band-plan strip, the logbook, spots, the transmit gate, and on an HPSDR board with anything on its open-collector outputs, the control word the accessory switches its filters, relays and transverters with — that follows the frequency on the air, not the intermediate frequency the radio is sitting on, on both protocols.

Two things the table does not do, on purpose. It does not switch the radio’s own PA off or hold its T/R relay in receive — on a Hermes-Lite that is the PA enable switch on the HPSDR page (6.2.3), which turns the onboard amplifier off and leaves transmit at the low-power RF1 output, which is how an external amplifier or a transverter is driven. And it does not choose the receive port: that is remembered per band already, so selecting the transverter’s antenna once on the band leaves it there (6.2). On a Hermes-Lite 2 with an HL2IOBoard that means its IO board RX input — offered on the ANT control once the setting is moved off Radio’s own input (6.2.3).

RX range and TX range, below the offset, are where you tell sdroxide which frequencies this radio actually covers. They are in megahertz, written low-high and separated by commas — 144-146, 430-440, which is 144000000-146000000 Hz and 430000000-440000000 Hz. (The offset above them is the one field on this tab in hertz.) Edges may be as fine as a hertz: 10.1-10.15 and 144.0-144.035 are both fine. An entry that doesn’t parse is named in red under the box, and the ranges take effect on Apply / reconnect like the offset.

A band that falls entirely outside the receive range in force gets a greyed-out button in the band/mode menu; hover it and it names the range and says whether that range came from this box or from the device, which is the difference between something you can widen and something you cannot. A band the radio reaches only part of keeps its button — a receiver that covers 50.1–51 MHz has 6 m, whatever its edges say.

Leave both empty — the default — and sdroxide uses whatever the device says about itself. There are two reasons to fill them in:

Two things a stated TX range is not. It is not a licence: transmitting outside the amateur bands is refused whatever you write here, unless you have set tx_ham_only = false in config.toml. And it does not give a receive-only device a transmitter — a device with no TX channel stays receive-only.

Ranges are dial frequencies — the numbers you read on screen, on your side of any converter offset. State the band you tune: a 2 m transverter on a 28 MHz I.F. gets 144-148, not 28-32, whatever the offset says. Only the device’s own published ranges are in the hardware’s domain, and those are moved onto the dial before yours replace them. (Before 1.6.3 a stated range was read as a hardware one and the offset was applied to it too, which put the limit an offset away from the band it named.)

They also belong to the interface they were typed for, not to the tab. Change Radio interface and the two boxes reload with whatever you had stated for the one you have just moved to — empty, on an interface you have never stated anything for. What you typed for the interface you left is kept and comes back with it. That matters most when a tab is pointed at a public receiver (15.21), which brings a range of its own: the transceiver that was in the tab gets its own ranges back when you switch the interface back to it.

Antenna is, the last row of the block, says where this radio actually listens from. At the station — the default — means the antenna is yours, so your own locator (My grid, 3.2.1) describes it. Somewhere else takes a Maidenhead locator beside it, and everything this radio hears is then reported from that square: PSK Reporter, WSPRnet and FreeDV Reporter, and the position the ADS-B and AIS charts measure ranges from.

Set it for an online receiver, or for your own set up on a hilltop — anything whose antenna is not where you are. Picking a receiver under PUBLIC SDR fills it in for you from the directory (15.21).

Left Somewhere else with the locator empty — which is what a directory entry that publishes no position gives you — nothing this radio hears is reported at all. That is deliberate: a report has to say where it was heard, and reporting somebody else’s antenna from your own square is worse than not reporting it.

Like the ranges above, it belongs to the interface it was typed for: changing Radio interface puts it back to At the station, because where the antenna was belonged to the receiver you have just left.

Transmit drive by band is a calibration table, one trim per band, that makes one Drive setting mean one output power everywhere. Every amplifier has a different gain on every band — 10 m typically wants several decibels more drive than 40 m for the same watts out — so without it a constant output across bands means remembering a different Drive number for each and setting it by hand on every band change.

To calibrate: put Drive where you want it on the band that needs the most drive (usually the highest one you work), and measure the output there. Then go to each other band, measure again, and type in how much that band is over — -3.0 on a band making twice the power, -6.0 on one making four times. Nothing but the bands you touch is affected: zero, the default everywhere, is no trim at all.

The numbers are decibels of output power — what a wattmeter reads — not “drive units”, so the same table means the same thing whether the drive control scales sdroxide’s own modulator (an HPSDR board, a Pluto, a SoapySDR device) or commands the rig’s power setting over CAT, TCI or a LAN. The range is −20 to +6 dB, and the trim applies to voice, digital modes and TUNE alike.

It follows the band you would transmit on, split and repeater shift included, and it is the band on the dial: behind a transverter that is the converted band, because that is the amplifier being calibrated. What the transverter’s own I.F. input can take is a separate and harder limit — the row’s max drive in the table above — and that still wins over anything set here. CLEAR ALL puts the whole table back to no calibration. Changes apply immediately; no reconnect.

6.2.1 SoapySDR devices

The Radio tab with the SoapySDR interface selected

With the SoapySDR interface the tab shows the controls the device itself exposes, and nothing it does not:

The antenna is remembered per band, everywhere it can be chosen. Whichever front end you are on — an Icom’s ANT1/ANT2, an RSPdx’s A/B/Hi-Z, a LimeSDR’s LNA ports — the socket you pick is remembered against the band you picked it on, and put back the next time the dial crosses into that band. It survives a restart, and a memory channel stored while the radio is on a socket carries that socket with it and selects it again on recall — and EDT on the channel is where you change your mind about which one that should be (2.12). A band you have never chosen a socket on is left exactly where the radio already is, so nothing moves a relay for you until you have said what belongs on that band. Each VFO remembers its socket too, which is what lets you keep A and B on different sockets at the same end of one band; a change of band hands the choice back to the band (2.5).

A driver is free to refuse a setting — a key that moved between versions, a hardware revision that lacks it, a value it will not take. It says so in a notice rather than failing quietly, and the rest are still applied.

Whichever ports and gains you pick are remembered in session.json and set again the next time you start, and re-applied if the radio drops out and the engine reconnects it — a freshly opened device is on whatever port and gains its driver defaults to, which need not be the feedline you were listening on or the levels you had settled on against your own noise floor. A gain stage your current front end does not have is kept rather than discarded, so switching back to the radio it belongs to brings it back; one outside this device’s range is clamped to what it can do. To pin the ports at start instead — on a headless server, where nobody is at the machine to pick — use --antenna and --tx-antenna; --probe lists the names a device offers.

A remote client gets this tab too, filled in from the server’s own radio.json rather than from any file beside the screen: the gains, the antennas and every setting the interface has, applied to the running device and saved where the radio is (8.4). What stays behind is the choice of interface and the buttons that scan a bus or test an address — those ask about a machine, and from a remote client it would be the wrong one.

The cyan heading above the gains names the device that is open right now, not the one selected — which is why the screenshot still reads TCI 127.0.0.1:50001 (192 kHz IQ): the interface has been switched to SoapySDR but Apply / reconnect has not been pressed yet.

Which device to open comes from config.toml (device_args) — for example device_args = "driver=hackrf"; an empty value uses the first device found. You can also override it on the command line with --device. The sample rate is on this tab, but --rate still wins over it, and an untouched Stream section leaves the app-wide sample_rate in charge exactly as before.

Why your VFO does not sit in the middle of the waterfall. On a SoapySDR device with a wide enough span, sdroxide parks the hardware LO a quarter of the span above the dial and tunes down to the signal in software, so your VFO marker sits a quarter of the way in from the left rather than dead centre. That is deliberate. Most SoapySDR hardware mixes straight to baseband, which piles its own LO leakage, converter offset and flicker noise up at the centre of the span — precisely where the dial would otherwise be. A narrow mode never notices, because that junk falls outside the demodulator’s passband, but an FM discriminator has no passband to hide behind: on a HackRF One tuned straight onto a strong FM broadcast station, the offset measures about the same amplitude as the station itself, and what comes out of the speaker is static. Moving the LO clear of the dial is worth about 14 dB of recovered signal over simply subtracting the offset, so sdroxide does both. Narrow streams (under 1 Msps) and devices whose analogue filter is too narrow to reach the offset keep the LO on the dial and rely on the offset subtraction alone.

The whole span is still yours — three quarters of it now sits above the dial, which is where band activity usually is — and the LO moves only when the dial would otherwise leave the usable span or come too close to the centre. Other interfaces (RTL-SDR, HPSDR, TCI, CAT) are unaffected: none of them puts the dial on a dirty LO.

6.2.2 CAT radios (serial control + USB audio)

The Radio tab with the CAT / Audio interface selected

A CAT radio is controlled over a serial port while its audio arrives over a USB sound card — chosen at the foot of this tab under Radio audio (sound card), separately from your computer’s own speakers and microphone (6.1).

Radio audio (sound card) — below the control settings, and only for this interface: every other backend carries its audio in the same stream as its I/Q and needs no card at all.

All four belong to this radio, which is why they are here rather than on the General tab where they used to be (issue #474): a station running two rigs at once is running two sound cards at once, and one pair of pickers on a shared page could only ever describe one of them. In radio.json they are radio_audio_in, radio_audio_out and rx_audio_gain_db, and they always were — only the page they were edited on was wrong.

Device names include the manufacturer, model, ALSA card id, and USB id — for example C-Media Electronics Inc. USB Audio Device, USB Audio [Device · 0d8c:0012] — so two identical adapters can be told apart. Where the operating system itself hands out the same name twice (Windows and macOS do, and two Icoms are two of the same USB codec) the second one carries a short tag of its own, as in USB Audio CODEC [#a3f1]. The tag comes from the device rather than from the order it was found in, so it stays the same across restarts and a radio keeps the sound card it was given.

IQ needs a stereo device. IQ format requires a two-channel capture interface (I and Q). A mono USB audio adapter cannot carry IQ; if you pick one for IQ, sdroxide refuses it and shows a warning banner. Use a stereo line-input interface for IQ, or choose Demod audio.

On a PipeWire system, the desktop audio server can hold a USB radio codec’s capture device open, which intermittently blocks sdroxide from opening it (the symptom is silent receive and a “waiting for spectrum” panadapter). For a sound card dedicated to the radio, the reliable fix is to tell WirePlumber to stop managing that card, leaving it for sdroxide. Create a drop-in such as ~/.config/wireplumber/wireplumber.conf.d/51-radio.conf that disables the card, then restart WirePlumber. See troubleshooting.

Sound format — how the radio’s audio is interpreted:

Transmit is the same on both. The sound format describes what the radio sends; what it takes back is always audio into its playback device, which the radio modulates itself. So the drive level, the mode and the sideband that goes on the air are the radio’s own settings, commanded over CAT, on a quadrature rig exactly as on a demod-audio one.

The mode travels in both directions on either sound format, subject to the Mode control setting below: change it on the radio and sdroxide follows on the next poll, change it in sdroxide and the radio follows. On a quadrature rig sdroxide is the one demodulating, so the mode is not what shapes what you hear — but it is what the radio’s own display shows, and it is the sideband the radio will transmit on, so the two readouts are not allowed to disagree. What sdroxide does not send a quadrature rig is the filter width: on that path the passband is sdroxide’s own, and narrowing the radio’s I.F. against it would cut into the span it is sending. A demod audio rig gets both, because there the radio’s filter is the only one in the path.

Neither the dial nor the mode is imposed when the port opens — sdroxide adopts whatever the radio is already sitting on rather than retuning it out of a saved session.

I/Q sample rate (IQ format only) — how fast the radio’s I/Q sound card is run, and so how wide the panadapter is. A quadrature stream spans its whole sample rate, centred on the dial, so 48 kHz shows ±24 kHz either side of the frequency you are tuned to, 96 kHz shows ±48, and 192 kHz shows ±96. Nothing else changes: the audio, the demodulators and the decoders all work exactly as before, on a receiver that now has more band to pick from.

The sound card decides what it will do. A card that cannot run at the rate you pick is opened at the nearest rate it does have, which leaves the panadapter narrower than you asked for — a startup log line says so when that happens, because a card quietly refusing looks identical to a setting you mis-clicked. Most USB codecs sold for radio work do 96 kHz; 192 kHz is common but not universal, and 384 kHz is rare.

A faster card is also more work for the computer, and the margin is not generous: at 192 kHz there is a quarter as much time to empty the card between callbacks as there is at 48 kHz. A machine that cannot keep up drops captured samples, and the two things reading the stream disagree completely about how much that matters — the panadapter is unaffected (every block it transforms is still real signal, so the waterfall looks perfect) while the demodulated audio, which has to be continuous, breaks up into clicks and stutters. Audio breaking up while the waterfall still looks right is that symptom and not a DSP fault; sdroxide logs a warning naming the count when it happens. If you see it, come back down a rate.

That warning counts only what is dropped while you are receiving. A rig that transmits through its sound card is not being listened to for the length of the over, so its capture buffer overflows every time you key — those frames say nothing about your computer and are not counted. A warning that arrives once per transmission, and only then, is not this. The same warning on a demod audio rig names no rate to come down to, because that path is always opened at 48 kHz: there it means something else on the machine is taking the CPU away.

Changing this takes effect on Apply, without restarting.

Invert spectrum (Swap I/Q) (IQ format only) — mirrors the panadapter about the tuned frequency, for a radio that carries I and Q the other way round on its sound card. Which channel a quadrature rig calls I is a wiring convention, and one that disagrees with sdroxide’s (I left, Q right) looks perfectly healthy until you read the waterfall: it fills with convincing signals that are all on the wrong side of the dial, and SSB comes out on the opposite sideband. Swapping the two cables at the sound card fixes it just as well — this is the same fix without the soldering iron. Leave it off unless you see that symptom.

It applies to receive only. Transmit hands the radio one real audio signal for it to modulate, and a real signal has no sideband to invert.

Every signal drawn twice, once either side of the dial? That is not a setting either of the two above can fix — it means the card is not carrying I/Q at all. A radio sending demodulated audio down a stereo cable puts the same signal on both channels, and two identical channels make a real signal, whose spectrum is symmetric about the dial by definition: there is no second sideband to recover, so Invert spectrum has nothing to swap and I/Q correction has no imbalance to trim. sdroxide notices it within a second of the stream starting and says so in the log window. Either put Sound format on Demod audio, which is what the card is actually carrying, or switch the radio to its raw I/Q output — in PowerSDR that is the Direct I/Q box in the VAC setup.

I/Q centre offset (IQ format only) — how far above the radio’s own dial its I/Q output is centred, for a rig whose receive I.F. has been moved off zero. Leave it at 0 unless you have turned such a setting on in the radio.

A quadrature rig normally puts its local oscillator on the dial, which piles the mixer’s DC offset, the LO’s own leakage and the sound card’s zero-hertz junk on exactly the signal you are listening to — the permanent spike in the middle of the waterfall. Rigs that offer a way out move the I.F. instead: on an Elecraft K3/KX3, MENU:RX SHFT set to 8.0 rather than NOR puts the oscillator 8 kHz from the dial, which takes the dial off the spike (and, per Elecraft, stops a strong nearby SSB or AM station being detected in the receiver). Set this field to 8000 to match, and the panadapter and everything reading from it stay on frequency.

The radio goes on displaying and transmitting the real frequency, so this is not a converter offset — the field under Radio → Converter retunes the radio itself, which is the one thing a shifted I.F. does not do, and using it here moves the whole display off by the offset instead of correcting it. Nothing typed here is ever sent to the radio: it only says where the samples arriving on the sound card sit, and the stream is shifted back onto the dial as it arrives. The rig’s DC spike lands the offset away from the dial, where it can be seen and ignored.

If signals end up at twice the offset from where they belong, the sign is the other way round for your radio — enter -8000 instead. Receive only, as above.

A QMX is the other kind of case, and sdroxide fills this field in for you: its receiver is a superhet with a 12 kHz I.F., so its synthesiser sits 12 kHz below the dial and everything on the sound card is 12 kHz above the middle of the span. Picking the QRP Labs family with the sound format on IQ sets this to -12000 and the sample rate to 48 kHz, which is the only rate that card runs at. One thing the single figure cannot follow: in CW the radio moves that I.F. by a further ~700 Hz so that zero-beat stays zero-beat, so if you run the panadapter with the radio in CW, add it by hand. In Digi — where a radio used as an I/Q front end normally sits — there is nothing to add.

The offset can be set up to half the I/Q sample rate either way, which is as far as the digitised window reaches: past that the dial is outside what the card is recording at all. Raising the rate raises that ceiling with it.

IQ correction (Cancel mirror images) (IQ format only) — cancels the copy of every signal that appears on the other side of the tuned frequency, and the permanent spike in the middle of the waterfall. On by default; leave it on.

A radio’s I/Q output is two analogue paths — the receiver’s quadrature mixer, then two channels of a sound card — and they are never quite equal in gain, nor exactly 90° apart. What that leaves is a mirror: a signal 8 kHz above the dial appears again 8 kHz below it, typically 30 to 40 dB down. That is weak enough to overlook on a quiet band and strong enough to be a problem on a busy one — it looks like a station, it decodes like one on FT8, and it moves when you tune, which is exactly what a real signal does. Radios with a pair of front-panel balance trimmers are adjusting this by hand; radios without them are why sdroxide does it in software.

Nothing needs setting. The correction measures the imbalance off whatever the receiver is hearing — noise will do — and converges in a second or two, then tracks it. It cannot measure one case, and does not try: a band that is a mirror image of itself, which is two equally strong carriers either side of the dial or an AM/DSB signal centred exactly on it, looks identical to an imbalance. Blocks like that are discarded rather than learned from, so the correction goes quiet instead of going wrong.

Turn it off when you are listening to AM tuned dead on the carrier: that carrier is DC, so it goes with the spike and the envelope detector distorts without it. Tuning a kilohertz off is the other answer, and the better one. It is also worth switching off for a moment to settle an argument about a weak signal — one that disappears with the correction on was the mirror of something else.

DC notch (IQ format only) — how much of the middle of the span to high-pass away, in hertz. 0 by default, which is not “no DC blocking”: the correction above already removes the offset with a corner a few tens of hertz wide, and that is enough for almost everyone.

Raise it for a radio whose centre spike is broader than the offset underneath it — some sound cards put mains hum and converter noise in the first couple of hundred hertz, and no amount of DC removal touches that. What this does is widen the corner: a first-order high-pass, 3 dB down at the figure set and falling further in below it, up to 500 Hz.

It costs signal, and it is worth knowing where. The notch is centred where the radio’s I/Q is centred, which is the dial itself unless I/Q centre offset has moved it — so whatever you are tuned to goes into the hole with the spike. A CW note at 600 Hz is inside a 600 Hz setting. If the middle of the span is unusable rather than merely untidy, the real fix is the offset above: shifting the radio’s I.F. moves the signal away from the spike instead of digging a crater around it.

Both settings take effect on Apply, without restarting, and both are receive only.

Serial (CAT) settings, in the order they appear:

Scroll down for Apply / reconnect, which reopens the rig with the new settings.

When you key the radio itself

Pressing the microphone button on the transceiver — or its foot switch, or letting its VOX or its own keyer key it — is an over sdroxide never asked for, and it is treated as one. sdroxide notices it within about a fifth of a second and follows it: the meter goes to transmit and reads the SWR of that over, and comes back to receive when you let go. It does not join in. No audio from the computer goes anywhere near it, and a PTT arriving in sdroxide meanwhile — the on-screen button, a key binding, a program on the rigctld or TCI server — is refused with a notice rather than queued, so an over cannot start the instant you release the microphone.

That refusal is only ever for as long as your hand is on the button. It is also fail-safe in the direction that matters: if the control port goes quiet while the radio is keyed, sdroxide gives up on it after two seconds, says so in the log, and goes back to receive rather than sitting there refusing to transmit.

Which radios can report it, and how:

Family Read Notes
Icom / Xiegu 1C 00 The read form of the command that keys the rig.
Yaesu TX;  
Elecraft TQ;  
Kenwood IF; One character of the status reply, taken by position. A rig whose status string is a different length reports nothing rather than a guess.
Hamlib rigctld t Whatever the daemon’s own backend supports.
flrig rig.get_ptt Whatever flrig’s own driver for the rig supports.
ELAD — No such read; an over keyed at the radio goes unnoticed.
QRP Labs TQ; A command of its own, like Elecraft’s.

These reads need to be verified against real radios. Each is taken from the manufacturer’s published command reference, and the end-to-end behaviour was proven against a simulator written from the same documents — which demonstrates that sdroxide does the right thing with the answer, not that the question is the right one to ask. The Icom read is the one to trust furthest: it is the read form of the command sdroxide already keys Icoms with. The Kenwood read is the one to trust least, because it alone depends on a field position rather than a command of its own.

A family that answers nothing at all simply leaves this feature switched off, and nothing else about the radio changes — which is also what a wrong guess degrades to, thanks to the length check on the Kenwood reply.

The one thing this does not do is hold the station transmit interlock across radios: with two radios configured, keying one at its own microphone does not lock the other out. Only overs sdroxide keys take that interlock.

CW keying. A transceiver told to be in CW keys its own transmitter: it does not modulate what arrives at its sound card, so a keyer’s sidetone sent there reaches nothing at all. Rig keyer (CAT) — the default — therefore hands the CW panel’s text to the radio and lets the radio’s own keyer send it, which is the only route that puts CW on the air from a rig that is in CW. There is no PTT around it: the rig switches to transmit for the length of the message itself.

On Sound card (MCW) the same rig is held on a sideband and the tone is modulated like any other audio, so it needs the rig’s own mode to be a sideband too — and on a radio sdroxide cannot command the mode of, that is a setting on the radio itself (6.2.21). The failure is worth recognising, because nothing reports it: the tone sounds, the send decodes back into text, the transmit indicators behave, and the air is silent.

What that needs on the radio:

Sound card (MCW) is the other route: the keyed sidetone goes out as audio, a tone on the sideband sitting at dial + pitch — which is exactly where the panadapter draws the stations, so a clicked station is answered on its own frequency. Because a rig in CW would ignore that audio entirely, selecting CW with this route follows the Digimode mode setting instead of switching the rig to CW: USB or DIGI command that sideband, Radio controlled leaves the rig on whatever mode you parked it in. It is here for radios whose keyer sdroxide cannot drive — on a Xiegu G90, set CW keying to Sound card (MCW) and Digimode mode to Radio controlled, and park the rig in its U-D position, exactly as for FT8: the G90’s U-D cannot be selected over CI-V, and its other modes take audio from the microphone rather than the interface. What you give up against a rig in CW is its CW filtering; the sideband filter is what does the selecting.

Note (Kenwood): at connect sdroxide turns the rig’s auto-information off (AI0), clears RIT and XIT, and selects VFO A for receive, which is also how this family turns split off. sdroxide carries RIT, XIT and split on the dial itself, and it tunes VFO A — so a rig left on VFO B or in memory mode would answer every frequency read and ignore every retune.

Note (Kenwood meters): the S-meter and the transmit SWR come from the radio’s own meters, and both are read against the model, which sdroxide asks for at connect (ID;). It has to: SM and RM answer with a count of lit bars, and full deflection is 20 bars on a TS-2000, 30 on a TS-590 and 70 on a TS-890 — so the same reading of 12 is a 3:1 fault on one rig and very nearly flat on another. Scales are carried for the TS-480, TS-590S/SG, TS-890S, TS-990S and TS-2000.

On a model sdroxide has no scales for, the S-meter still reads — on a generic straight line, so approximately — and the SWR meter stays blank rather than showing a number with no meaning behind it. The log line Kenwood CAT: rig reports model ID … carries the number, which is what would let the model be added.

Note (Elecraft): at connect sdroxide does the same — auto-information off, clarifier cleared, RIT, XIT and split off — and two things besides. It puts the rig into K20;K31;, because a K3 left in K2 command mode 1 or 3 by whatever ran before reports DATA and DATA-REV as LSB and USB, so it would look like a radio that never leaves SSB. And it asks the rig what it is (OM;), which is where the Drive slider’s scale comes from: 110 W with a KPA3 or a KXPA100 fitted, 12 W without one. Until that answer arrives the slider is the QRP scale, so the first moments after connect can only ask for less power than the radio has, never more.

A K3 whose CONFIG:CW WGHT is set to VFO OFS shifts its own dial by the CW pitch whenever the mode crosses into or out of CW, so that zero-beat stays zero-beat. That is useful at the radio and invisible over CAT, so sdroxide re-asserts the frequency behind every mode command it sends an Elecraft — otherwise an operator who asked for 14.050 would find themselves transmitting six hundred hertz away with nothing on screen to say so. Nothing on the wire reports how that menu entry is set, so the re-assert is unconditional; on a rig already on the right frequency it costs one frame and changes nothing.

Setting the mode sends DT0; after the mode itself, which pins DATA to DATA A — the sound-card path. It has to: MD6; on its own restores whichever of the four sub-modes that band was last left in, and on a rig used for RTTY that is the K3’s own FSK keyer, which has nothing to send. For the same reason sdroxide follows the rig into DATA only when it reports DATA A; left in AFSK A, FSK D or PSK D it reports no mode at all rather than one the two would then argue about.

Note (the filter width on a CAT rig): the width control in the receive panel is sent to the radio. It has to be: there is no demodulator on this side of a CAT rig — the audio arrives already filtered, and already levelled by an AGC that has ridden the interference down — so narrowing it here would only cut what the radio had let through, long after the damage was done.

What each family can express differs, and where sdroxide cannot say a passband exactly it leaves the radio’s filter alone rather than guess:

Where a width is not an exact entry in the rig’s table it is rounded up, so the radio’s filter is never quietly narrower than the one on screen — a filter that is too narrow presents as a signal that simply is not there.

Note (Yaesu): the S-meter and the transmit SWR come from the radio’s own meters (SM0 and RM6), because on a CAT rig there is nothing else to measure — the audio arriving at the sound card has already been through the radio’s filter and AGC. Both are read against the FT-991 calibration Hamlib uses for the whole current generation, so an FT-891, FT-991/991A, FTDX10, FTDX101D/MP, FTDX1200/3000/5000 all read alike.

On an FTDX3000 or FTDX5000 with the tuner in line the rig only answers the SWR read when its own meter is already set to SWR; there set the front-panel meter to SWR, or the reading stays at the bottom of the scale.

Note: on a Yaesu USB interface the Enhanced port is the CAT port configured above. The Standard port is the one whose RTS/DTR lines are wired to PTT and KEY; sdroxide does not use it, and PTT method DTR/RTS set on the Enhanced port will not key anything. Use CAT there.

Note (Icom over USB): if the dial and the waterfall follow the radio but PTT and TUNE do nothing, the link is fine and the keying is not. Check PTT method first: CAT keys with a CI-V command and always works on a rig that is answering, while DTR and RTS only key if the radio’s own USB SEND setting has been assigned to that line (an IC-7300 leaves it off, so those two do nothing at all out of the box), and VOX keys nothing until VOX is on at the radio. The Radio ID (hex) must also be the rig’s CI-V address — 94h on an IC-7300, B6h on an IC-7300MK2, 70h on a Xiegu X6100 — though a wrong one stops the frequency working too, so it is rarely the answer here. When the radio answers the key-down with a refusal, sdroxide says so in the log: the radio refused the transmit command.

Note (ELAD): this family is the FDM-DUO and FDM-DUOr. Set Baud to match menu 70 CAT BAUD on the radio, which ships at 38400 — the radio has only 9600, 38400, 57600 and 115200, and at any other rate the link is silent both ways rather than merely unreliable. The rig’s own S-meter and SWR are read (SM and WR) and its transmit power appears on the Drive slider as the nine fixed steps the radio has — 0.3, 0.5, 1, 1.2, 1.5, 2, 3, 4 and 5 W — rather than as a continuous control. Transmit input beside the family selects where the radio takes transmit audio from: leave it on USB audio unless you talk into the radio’s own microphone.

Antenna picks which of the radio’s two rear sockets the receiver listens on — its AN command, menu 31 ANTENNAS, the ANT 1 2 indicator on its display. RTX is one antenna doing both jobs; RX only moves receive to the second socket and leaves transmit on RTX, which is the arrangement for a receiving antenna with the beam still on the transmitter. It applies immediately and is remembered, and until you have picked one it shows the rig’s own setting, read when the port opens.

There is no DATA mode on an FDM-DUO, so digital modes go out as plain USB or LSB and which input the radio transmits is the Transmit input setting rather than anything the mode says. There is no text keyer either — SW plays one of the ten messages stored in the radio — so the CW panel cannot key it over CAT; use the radio’s own key or paddle, or menu 37 CW IN set to Key+DTR.

If your FDM-DUO’s receive USB cable is also plugged in, the ELAD FDM-DUO / FDM-S (USB) interface (6.2.16) drives the whole radio at once — a real wideband panadapter instead of an audio-band slice — and covers this CAT link itself. This family is for a DUO reached by its CAT cable alone. Neither has been verified against a radio.

Note (QRP Labs): this family is the QMX, the QMX+ and the QDX-series radios that share their command set. The Baud setting does not apply — the radio serves its own virtual COM ports over USB, so the rate means nothing at either end — but which port does: a QMX offers up to three, and only one of them is the CAT port you want. If nothing answers, try the next one.

⚠️ Never open a terminal program on the same port. A QMX takes a carriage return as an instruction to leave CAT and become a terminal, for the rest of the session. sdroxide never sends one; a terminal emulator will, on the first Enter you press.

The transmit power is set at the radio. There is no CAT command for it, so the Drive slider only reaches the level of the audio going into the sound card, and in Digi that does not change the power at all — the radio measures the frequency of what you send it and synthesises the carrier itself. What the radio does report while transmitting is the SWR and the forward power it has measured, in real watts, and both appear on the meter.

Modes. The radio’s DIGI-U and DIGI-L are what sdroxide’s digital modes go out on (MD6 and MD9); CW and CW-R are both CW; LSB, USB and AM are themselves. MD8 is not a mode — it is SWR Tune, a carrier into the radio’s own bridge — so sdroxide never asks for it, and a radio sitting in it is reported as being in no mode rather than in some sideband it is not on. A QMX has no FM position at all.

CW goes to the radio’s own keyer (KY), 24 characters at a time, at the speed the CW panel is set to (KS). Do not set that speed to zero: on a QMX zero words per minute is not a slow keyer, it is Straight Key mode, and sdroxide holds the bottom of the range at 5 for exactly that reason.

SWR protection. On firmware 1.04.004 and later sdroxide reads the radio’s protection latch (SR). If it has tripped, the radio will not transmit until it is reset at the radio — sdroxide says so in the log and deliberately does not reset it for you, because clearing a protection trip is a decision about an antenna.

What the profile leaves alone: the receive filter (the radio reports the width its mode implies — 3.2 kHz in Digi, 300 Hz in CW — and offers nothing to change it with), and the RF and audio gains, which live in the radio’s own menus. Written from QRP Labs’ published CAT and operating manuals; not yet verified against a radio.

Note (RS-HFIQ): HobbyPCB’s RS-HFIQ is an I/Q transceiver, and that is what makes this the shortest profile here (issue #383). A quadrature detector and a quadrature modulator sit either side of a synthesiser running at four times the dial, so what the sound card carries is complex baseband centred on the operating frequency, in both directions. Everything a CAT command does on another radio — the mode, the filter, the modulation, the demodulation — is sdroxide’s here, and the serial link is left with the two things that really are the radio’s: where to put the oscillator, and whether to transmit.

Selecting the family fills in three things that are facts rather than preferences, so leave them: Sound format goes to IQ (stereo), PTT method to CAT, and the port to 57600 8N1 — the firmware’s one rate, with no menu to change it, so sdroxide pins it when the port opens. The centre offset is set to zero, because the oscillator is on the dial. Set IQ rate to whatever your sound card is actually running at; that is what makes the panadapter as wide as it is.

The frequency command covers 3–30 MHz and nothing outside it. Ask for more and the radio answers Frq out of range. and stays where it is — the dial springs back within a poll, and the log says why.

What there is nothing to reach. No mode, power, filter, squelch, meter or keyer command exists, because the radio has none of them: transmit power is set at the radio, the S-meter is sdroxide’s own measurement of the I/Q, and CW goes out as a keyed tone through the transmit chain like any other audio. (The firmware has an internal CW generator on *X2; its own documentation says do not use it, and sdroxide never does.)

Written from HobbyPCB’s published Interface Commands page. Not verified against a radio, and one thing in particular is a guess: the page says what each query reports but not how the reply is framed, so sdroxide accepts a bare number, one with the command echoed in front of it, and either line ending. If the dial readout does not follow the radio, that is the thing to report.

Note: RIT, XIT and split are driven over the same serial link, by moving the radio’s dial — see 2.6. Set them in sdroxide rather than on the radio: sdroxide clears the rig’s own copies on connect so the two can’t stack up.

Which bands are offered. CAT carries no band table, so sdroxide cannot tell an HF-only FT-891 from an FT-991A on 70 cm or an IC-9700 on 23 cm. Rather than guess, it leaves every band live and lets the rig answer: ask a radio for a band it does not have and it simply declines over CAT, which sdroxide reports in the log. The real limits on transmit are your licence — the amateur-band gate, which follows your region (6.1) — and the rig itself. If you would rather sdroxide held the dial to the radio you actually own, state an RX range and TX range at the top of this tab.

6.2.3 HPSDR (network radios)

The Radio tab with the HPSDR (network) interface selected

With the HPSDR (network) interface, sdroxide reaches an OpenHPSDR (Hermes/Metis-family) Ethernet SDR over the LAN — no sound card or serial port involved:

Receive is wideband IQ, so the full panadapter and the skimmers work.

PureSignal needs the transmit sample to reach the receiver. The board is commanded in duplex, so its receiver keeps running through an over — that is the feedback path, and there is no second receiver involved. What is needed is a directional coupler on the amplifier’s output and an attenuator after it, feeding an input the T/R switch does not take away on transmit. On a Hermes Lite 2 that means the IO board’s PureSignal jack (J10), with IO board RX input set to “IO board J9, PureSignal on transmit” so the board switches it in for the length of every over. A coupler into the radio’s own antenna jack will not do: the T/R relay disconnects the receiver there for exactly the period being measured.

Set the attenuation so the feedback is strong but well clear of clipping — a Stockton bridge is about 36 dB down across HF, and the reference feedback unit adds another 25 dB. Two things hold whatever it is fed:

The S-meter says which it is. With PureSignal switched on, the meter face carries a small PS readout in its bottom-right corner, opposite the temperature: PS 4dB while the loop is locked and correcting (a * after it means Hold is on), and an amber PS -- while it is switched on but has not found the transmission in the feedback — which is the ordinary failure, and one that is otherwise invisible, since an unlocked loop transmits exactly as it would have with the feature off. Hover the meter for the match score behind it. Nothing is shown at all on a radio that is not running a loop. The reading is from the last over and stays put between them, which is when you want to read it.

The log says the same thing at more length: while transmitting you get either “PureSignal is correcting N dB of compression” or “PureSignal has not found the transmission in the receiver’s stream”, every few seconds. Table steps is how finely the curve is modelled (32 is a sensible start) and Adaptation how fast it follows the coupler; slow is right, because it is averaging a curve that does not move out of a path that has noise in it. Hold stops it adapting and keeps what it has learned.

⚠️ Not verified against hardware. No amplifier has been on the end of this on a Hermes Lite 2. The processor itself is exercised against a simulated compressing amplifier and converges; that says the arithmetic is right, not that a real feedback path is what it expects. The safe failure — nothing coupled in, so nothing learned and the transmitter left alone — is the one it is built around, but treat the first over as an experiment and watch the log.

The radio’s own PTT input keys sdroxide too: a foot switch or mic button on the board’s PTT connector (a Hermes Lite 2’s CN4 jack) transmits exactly as the on-screen PTT button does, safety rails and all. It belongs to the DDC1 radio — the one that owns the transmitter — so a second radio tab on another DDC never keys on it. Currently Protocol 1 only.

An N2ADR HL2IOBoard on the accessory bus is found and driven automatically: there is nothing to switch on. sdroxide asks the bus whether one is there when it connects, clears its registers (they are static, and survive whatever program drove the board last), and from then on keeps it told of both frequencies:

Updates are limited to one every half second, as the board’s documentation asks, so a spun dial cannot flood its I2C bus — and the receive code covers a whole band at a time, so ordinary tuning puts nothing on the bus at all. What the board’s outputs then do is decided by the firmware you program into its Pico: by design, sdroxide sends the frequencies and nothing else. Run with RUST_LOG=sdroxide_hpsdr=debug to watch the board being found and each update going out.

Help wanted — the HPSDR backend is not fully tested yet. If you own an HPSDR board, you can help by running with diagnostic logging and reporting what you see:

RUST_LOG=sdroxide_hpsdr=debug sdroxide

Use sdroxide_hpsdr=trace for per-packet detail. The log shows discovery replies (board, protocol, MAC, raw bytes), the protocol and sample rate chosen, the first RX datagram’s structure, and a periodic RX throughput line (datagrams/samples/ksps). A plausible ksps close to the selected sample rate means the receive decode is working; no … I/Q datagrams after 3 s or an implausible rate points at a firewall or a wrong offset. On transmit, a Hermes Lite also reports why nothing is going out: the log states whether the onboard PA was switched on at connect, and warns if the board says its transmitter is inhibited or its transmit FIFO under- or overran. Please attach that output to a bug report.

6.2.4 TCI (network): ExpertSDR3 and Thetis

The Radio tab with the TCI (network) interface selected

With the TCI (network) interface, sdroxide connects to a TCI server — such as Expert Electronics ExpertSDR3 or Thetis — over a WebSocket, receiving a wideband IQ stream and transmitting audio back:

Receive is wideband IQ (full panadapter and skimmers); transmit sends audio to the TCI server, which modulates it. Receive reaches 160 MHz and transmit covers HF, 6 m and 2 m, so a rig with a VHF section (a SunSDR2 PRO or DX, an MB1) keys up on 2 m without a stated TX range; the amateur-band gate keeps you inside your region’s allocation, and the rig declines anything it cannot do.

The SDR software has to be running. TCI is served by ExpertSDR3 or Thetis, not by the radio’s own firmware, so sdroxide connects to that program rather than to the transceiver. On a standalone set — an MB1, a Colibri, any SunSDR with a computer inside it — that program runs on the computer inside the radio, and it has to be started there with TCI switched on before anything can attach. This is not a limitation of sdroxide and no other TCI client avoids it: the same is true of the TS-480 CAT emulation those radios offer, which ExpertSDR3 also provides. A refused connection says as much in the message.

This is sdroxide acting as a TCI client. For the other direction — sdroxide acting as the rig so WSJT-X and friends can drive it — see § 5.8.2 Built-in TCI server.

6.2.5 RTL-SDR (USB dongles)

The Radio tab with the RTL-SDR interface selected

The RTL-SDR (USB) interface drives an RTL2832U dongle directly, using sdroxide’s own USB driver. There is no SoapySDR and no libusb involved, so this works in every build — including the standard Windows .msi and macOS .dmg — with nothing extra to install beyond access to the device itself (see the README’s RTL-SDR permissions).

Supported tuners are the R820T, R820T2 and R828D, which between them cover essentially every dongle still sold, including the RTL-SDR Blog V3 and V4. Older E4000 and FC001x sticks are not supported; sdroxide names the button it found and suggests the SoapySDR backend instead.

Receive only — there is no transmit path in this hardware.

The bias tee puts DC on the feedline. Never enable it with a transceiver, a DC-grounded antenna, or a preamplifier powered from somewhere else on the other end of the cable. sdroxide turns it off again on a clean shutdown, and shows a standing warning while it is on, because the setting is remembered across restarts and there is otherwise nothing to tell you.

If the dongle is unplugged, sdroxide notices within a few seconds and reconnects by itself when you plug it back in — no need to press Apply. A dongle left streaming by a program that was killed rather than closed is reset automatically on the next open, so it does not need physically replugging either.

6.2.6 SmartSDR (FlexRadio network radios)

The Radio tab with the SmartSDR interface selected

With the SmartSDR / FlexRadio (network) interface, sdroxide drives a FLEX-6000 or FLEX-8000 over the LAN. It connects as a GUI client on TCP 4992, creates a panadapter and a DAX IQ stream, and receives raw complex baseband from it — so the panadapter, the waterfall, the skimmers and every digital mode are sdroxide’s own, working from the radio’s samples rather than from a picture the radio already drew. Transmit sends audio over a DAX TX stream, which the radio modulates.

Tuning moves the radio’s own slice, so its front panel and any second client follow your dial rather than the other way round. TX power and TUNE power command the radio’s rfpower/tunepower, and SWR and forward power come back from the radio’s meters while you transmit.

Two clients, one identity. A FlexRadio identifies a GUI client by a UUID, and settles two clients arriving with the same one by disconnecting whoever had it first — reporting duplicate_client_id and handing the newcomer their slices. Because the default identity is derived from the station name, and the station name defaults to sdroxide, two sdroxide installations on one radio arrive holding the same UUID, as do two windows of one installation. Left alone that is not an eviction but a tug-of-war, each side reconnecting and throwing the other off every few seconds.

sdroxide asks the radio who is already connected before it registers, and takes a one-session identity instead of evicting anyone it finds holding its UUID. If the radio evicts it anyway, it remembers that and reconnects transiently rather than fighting back. The cost either way is the radio’s session restore — a transient identity is one the radio has never seen, so it has no slices filed under it. Set a GUI client ID of your own (any UUID will do) to keep the restore and still be distinct from every other sdroxide.

Panadapters are a fixed resource. A DAX I/Q stream is centred on a panadapter, so sdroxide needs one — and the radio has only so many: two on a FLEX-6400, four on a 6600 and up, shared with whatever SmartSDR has open. A radio also restores a GUI client’s panadapters when that client comes back under an id it has used before, so the one from your last sdroxide session is usually still waiting.

sdroxide takes that one up again rather than asking for another, and removes it on the way out. When every panadapter on the radio is in use anyway — SmartSDR with two open on a 6400, say — it borrows one instead of refusing to receive: that panadapter’s span and centre follow this receiver while sdroxide is connected, and it is left alone at shutdown because it belongs to somebody else. The log and the diagnostic report say when that has happened. Close a panadapter in SmartSDR if you would rather sdroxide had one of its own.

No spectrum. The control link is TCP and the spectrum is UDP, so a radio can answer everything you ask it and still send you nothing. If the panadapter stays empty while the frequency readout tracks the radio, suspect the UDP path. On a computer that has never run SmartSDR, its own firewall is the usual answer: SmartSDR’s installer adds a rule for itself and sdroxide arrives without one. A VPN comes next, then an MTU smaller than the Network MTU setting.

Unintelligible audio. Two faults sound the same and nothing on screen tells them apart: a receive chain running at the wrong sample rate, and a mirrored spectrum. The diagnostic report’s --- streams --- section settles the first — each DAX I/Q stream carries a line stating the rate it is measured to be delivering against the rate its packets claim, and flags them when they disagree. If those two agree, try Invert spectrum above for the second.

sdroxide says so on connect when nothing arrives, and the diagnostic report’s --- streams --- section is where to confirm it. It opens with a count of the datagrams that reached the machine at all, which separates the two silences: zero means the radio’s UDP never got here and the fault is outside sdroxide, while a non-zero count with no streams listed means it did arrive and sdroxide could not read it — a bug worth reporting.

One case sdroxide repairs by itself: some firmware ignores the UDP port a client asks for and streams to 4991, FlexLib’s own. When the radio refuses that request sdroxide listens on 4991 too and says so in the report. It takes that port only in that case, so SmartSDR can still be started alongside on the same machine.

Receive covers 30 kHz to 54 MHz, and to 165 MHz on the models with a VHF receiver (the 6600, the 6700 and the 8000 family). On those, transmit is offered on 2 m as well as HF and 6 m — a FLEX’s own PA stops at 6 m, but a transverter on the XVTR port transmits at the band the slice is showing, and sdroxide cannot see SmartSDR’s transverter table to tell the two apart. Without a transverter the radio simply declines the key-down.

Help wanted — this backend has not been verified against real hardware. It was written from the published wire format and tested against a simulator, which proves the bytes are self-consistent but not that a FLEX agrees with them.

Every session records a protocol trace — each control line in both directions, the first packet of each VITA-49 stream, and per-stream packet and loss counters. It is always recording, so there is no log level to set in advance and nothing to reproduce twice: press Copy diagnostic report and paste it into an issue. That report is what makes a fault diagnosable by somebody who does not own the radio.

If you do not have a FLEX either, you can still exercise the backend: a wire-level radio simulator ships in the source tree. Run cargo run -p sdroxide-smartsdr --example sim, then point this tab at 127.0.0.1:4992.

6.2.7 PlutoSDR (ADALM-Pluto)

The Radio tab with the PlutoSDR interface selected

An ADALM-Pluto — the AD9361/AD9363 learning radio — driven directly over IIOD, the protocol its on-board daemon speaks on TCP port 30431. sdroxide implements that protocol itself, so there is nothing to install: no SoapySDR, no libiio, no driver package. It is in every build, including the standard Windows and macOS packages.

Wideband IQ receive and transmit.

A Pluto is a network device, even on a USB cable. This surprises people, so it is worth stating plainly: plugging the Pluto in does not create a serial port — it creates a network adapter. The radio takes 192.168.2.1 on that link and your computer takes 192.168.2.10. That is why this tab asks for an address rather than for a serial number, and why a Pluto on your Ethernet LAN is configured in exactly the same way as one on your desk.

AD9363 or AD9364. A stock Pluto is an AD9363 and covers 325 MHz–3.8 GHz; a great many have had the well-known firmware change applied, which turns them into an AD9364 covering 70 MHz–6 GHz with a 56 MHz filter. sdroxide does not ask you which you have and does not guess — it reads the limits off the device every time it connects, so the band buttons and the transmit gate follow the radio you actually own. Press Test connection to see which it reported. (If a firmware publishes no limits at all, sdroxide says so rather than quoting the fallback figures as fact.)

70 MHz is not the floor any more. The two figures above are the ones Analog Devices’ own firmware publishes. The community firmware that most of the current AD936x work happens in — tezuka, by F5OEO — takes the same silicon down to 47.5 MHz, which is what puts 6 m and 4 m inside a Pluto’s range instead of just outside it. It also adds an 8-bit complex sample mode (about 14 MHz of span over USB, 45 MHz over gigabit Ethernet), RX1/RX2 and TX1/TX2 switching, and — the part worth having on its own — SD-card boot, so a firmware that does not suit you is undone by taking the card out rather than by unbricking a board. It builds for about ten boards: the original Pluto, PlutoPlus, ANTSDR E200/E310, Fishball/PlutoSky, SignalSDR Pro, LibreSDR/ZynqSDR, Pluto Nano and the PCIe and Mini OpenSDRLab boards.

As of today (10/2026), we recommend tezuka firmware v0.3.21: stable and tested. Versions v0.3.19 and v0.3.23 are not stable.

Power the Pluto from a supply that delivers at least 3 A, and give it an exact 5 V at the board. The Pluto needs a precise 5 V at its own input, and the supply cable loses some of it on the way there. We recommend a laboratory (bench) supply set to 5.15 V at its output, so that the board receives exactly 5 V. A supply that falls short shows up as EAGAIN errors on the stream, and running the board away from a precise 5 V exposes you to errors and crashes.

Nothing has to be configured in sdroxide to use it. The tuning range, the sample rate and the on-the-wire sample format are all read off the device as it connects rather than assumed, so a board running tezuka reports its own limits and its own format and sdroxide follows them. What that means in practice is that the band buttons open up as far as the firmware says and no further. This is read from what the firmware publishes rather than measured here — no tezuka board has been on this bench — so treat the 47.5 MHz figure as the firmware’s claim, and press Test connection to see what your own board actually answers.

The Fishball/PlutoSky build carries a DATV stack you are probably not using. That variant of tezuka ships, on top of the bare IIOD/AD9361 essentials, a whole amateur-television transmit stack: an MQTT broker (mosquitto) and several subscribers, a web server (maia-httpd), an NFS server, gpsd, and a handful of shell watchers that re-run themselves (api_controller.sh, bitrate_strategy.sh, mqtt_obs_ctrl.sh, watchconsoletx.sh, watchdatveasy.sh, watchconsolefreq.sh, pluto_mqtt_ctrl, pluto_stream). On the Zynq 7020’s two Cortex-A9 cores and 743 MB of RAM that costs real capacity even when no DATV transmission is running, and one station using the board purely as a wideband receiver for sdroxide reported it climbing to a load average above 12, a kernel RCU stall, and then an IIOD link that collapsed into a tight os error 11 / os error 32 loop until the board was unreachable. After shutting the stack down, the same board held about 607 MB free and a load of 1.1–1.3 through more than two hours of continuous streaming.

Its root filesystem lives in RAM, so editing /etc/init.d achieves nothing. This is the part that wastes people’s evenings: / on this firmware is a rootfs regenerated from the firmware image at every boot. Scripts you edit there — S95bgcript, S96plutostream — are correct when you check them and back to their original contents after a reboot. Only /mnt/jffs2 is real flash, and the stock S98autostart runs /mnt/jffs2/autorun.sh if it exists. That file is the one place a change survives:

cat > /mnt/jffs2/autorun.sh << 'EOF'
#!/bin/sh
sleep 5
# The DATV stack — nothing to do with receiving.
pkill -f watchconsoletx.sh
pkill -f watchdatveasy.sh
pkill -f watchconsolefreq.sh
pkill -f api_controller.sh
pkill -f mqtt_obs_ctrl.sh
pkill -f bitrate_strategy.sh
pkill -f pluto_mqtt_ctrl
pkill -f pluto_stream
pkill -f "inotifywait.*ensm_mode"
pkill -f "inotifywait.*RX_LO_frequency"
# MQTT, web, GPS and NFS — likewise.
pkill -f mosquitto_sub
pkill mosquitto
pkill -f maia-httpd
pkill gpsd
rpc.nfsd 0 2>/dev/null
pkill rpc.mountd
pkill rpc.statd
EOF
chmod +x /mnt/jffs2/autorun.sh
reboot

It leaves everything the board needs to stay reachable and to stream: iiod, dropbear for SSH, chronyd, avahi-daemon, the loggers, the watchdog, the network daemons and update.sh for firmware updates over USB. Do this only if you are certain you will not want the DATV side — the inotifywait watchers it kills are also what some tezuka builds use to follow the tuned frequency — and remember that it is your board. None of this has been run here: it is the recommendation of the operator who reported it (issue #379), on a Fishball board running tezuka-v0.3.21.

Full duplex — the checkbox above the port boxes, off by default. With it off, receive stops for the length of an over and the whole link goes to transmit, exactly as the HPSDR backend does. The reason is the link, not the part: the AD9361 genuinely does both at once (it has a synthesiser per direction), but a USB 2.0 Ethernet gadget will not carry a megasample-per-second stream in both directions and trying produces a transmission full of holes.

Turn it on for a board on real Ethernet — a LibreSDR, or a Pluto behind a gigabit adapter — and you keep hearing the receiver through your own transmission. That is what a QO-100 station wants: the downlink comes back through the transponder about a quarter of a second later, and listening to it while you talk is how you check your own audio, your drive and your frequency. It works for anything else split across two bands too — a crossband repeater watch, or simply hearing the frequency you are about to unkey onto.

Three things to know before you switch it on:

Keying an external amplifier, LNA or T/R switch (the GPO pins). A bare Pluto puts out a few milliwatts, so most of them end up in front of an amplifier — and an amplifier needs to know when you are transmitting. You can wire a serial PTT line for that, but the Pluto already has four output pins on the board (GPO0–GPO3, on test points; the Analog Devices note Controlling external devices has the locations), and the AD9361 can drive them from its own transmit and receive state with nothing in between. That is what the PTT pins setting does:

The settings are written as the AD9361 driver’s device-tree properties (adi,frequency-division-duplex-mode-enable, adi,gpo…-slave-rx-enable and adi,gpo…-slave-tx-enable) and committed with initialize, which is the same sequence the Analog Devices note gives for iio_attr. They persist in the radio until it is rebooted or something writes them again, so sdroxide both writes and unwrites them: it rewrites the whole set every time it connects with a pair selected — including on Apply / reconnect, which really does redial the board now rather than re-attaching to the connection that was already open, so a changed pair (or sample rate, or duplex) takes effect without restarting sdroxide — and setting PTT pins back to Off puts the radio back into FDD and un-slaves all four pins on the next connect. A radio that has never had these settings touched is left exactly as it booted, and so is one you have put in TDD yourself with no pin slaved to it — sdroxide undoes its own arrangement, not somebody else’s.

If the radio connects but hears nothing at all. The same state machine decides whether the receiver is on, and it can be left off with every other setting intact: the AD9361 driver parks it in alert while it calibrates, and does not always put it back. A Pluto in that state still streams, but what it streams is one value repeated — no signal and no noise, however the gain is set. sdroxide checks the state machine as the last step of every connect. On a board in FDD — every stock Pluto — it switches the receiver back on and logs that it did. It does not touch a board in TDD that you have not asked it to drive, or one whose state machine follows its enable pins, because both are somebody else’s arrangement; it says on connect that the radio is not receiving and why instead. Choosing TDD under Duplex has sdroxide drive a TDD board itself.

The sample rate is a transmit setting too. Every I/Q sample is four bytes in each direction, so 2.5 Msps is 10 MB/s the link has to carry — and on transmit it has to carry it on time, because the AD9361 plays out whatever is in its buffer and then stops. If the link cannot keep up, the result on the air is not a quiet signal but a chopped one: the envelope switches on and off at the buffer rate, which is buzzy and thin in SSB and completely unreadable in NFM, where every restart is a click in the receiver’s discriminator. Nothing on screen shows this — sdroxide’s own monitor sees the samples it sent, not the gaps between them — so run with RUST_LOG=sdroxide_pluto=debug if you suspect it and watch for the line that says the link is not carrying the full sample rate. The cure is to ask for less: 2.083 Msps, the lowest a stock Pluto accepts, is plenty for voice and leaves the most headroom. Reaching the radio over real Ethernet rather than the USB gadget helps too, and so does taking it off a USB hub.

When the receive stream stalls. Now and then the receive connection to a Pluto goes quiet part-way through a transfer while the board itself is fine — a fresh connection is answered in milliseconds. It has been reported over the USB gadget and over a dedicated gigabit link alike, on stock and Tezuka firmware; the bytes stop reaching this computer, and why is not yet understood. Once the receive connection has been silent for half a second, sdroxide asks the board, on a connection of its own, whether it is still answering. If it is, the stuck connection is replaced and the buffer reopened straight away — well under a second of audio — and the log says

PlutoSDR: the receive socket failed (… nothing on this socket for 0.5s while the board answered a fresh connection in 3 ms — the socket is stuck, not the radio) — replacing it

If the board does not answer either, it has paused — usually its own processor too busy to feed the network — and sdroxide waits for it, a few seconds at most, rather than redialling around it. Neither touches your dial, your gains or a transmission in progress: the control connection is a separate socket.

If it happens once in a while, ignore it. If the log keeps saying that the board stops answering, lighten its load: a lower sample rate, and on a Tezuka build the services described above. Halving Buffer size helps either way, because a smaller transfer is less likely to be caught part-way. Should the receive connection fail to come back at all, the radio is reported as disconnected and reconnected from scratch in the usual way. Copy diagnostic report records every stall and which of the two it was — that is the evidence that will find the cause, so it is worth attaching to a report.

Transmit, the first time. Set TX gain to its minimum, key into a dummy load, and check the signal is where the dial says before you raise it. The transmit path of an AD9361 can be fed either by a DMA buffer or by four on-chip tone generators, and the tone generators win by default; sdroxide silences them on every key-up, but a steady carrier where your modulation should be is the symptom to report if that ever fails.

Help wanted — this backend has not been verified against real hardware. The protocol is implemented from libiio’s own client and daemon sources, and tested against an in-process fake iiod, which proves the client is self-consistent but not that a Pluto agrees with it.

Every session records a protocol trace — each IIOD command and its reply, the device’s context description with the sample layouts the decoders were built from, and the first bytes of the sample stream verbatim. It is always recording, so there is no log level to set in advance and nothing to reproduce twice: press Copy diagnostic report and paste it into an issue.

The first-bytes line is the one that matters most. The way iiod frames a buffer — a length, then the channel mask, then the data — is the part of this that cannot be checked without a device on the other end, and that one line settles it.

From the source tree you can get the same information plus a live signal check:

RUST_LOG=sdroxide_pluto=debug cargo run -p sdroxide-pluto --example probe -- 192.168.2.1

It prints the limits the radio published, streams for two seconds, and reports the measured rate and signal level. A plausible rate with a level of zero means the link works and the sample layout does not; an implausible rate means the framing is wrong — unless every sample is the same value, which the probe points out, and which means the receiver was not running at all (see If the radio connects but hears nothing, above). The stream ends because the probe closes the radio after its two seconds, so a trace that stops there is expected, not a crash.

6.2.8 SDRplay RSP (USB)

The Radio tab with the SDRplay RSP interface selected

The SDRplay RSP (USB) interface drives any RSP — RSP1, RSP1A, RSP1B, RSP2, RSPduo, RSPdx, RSPdx R2 — natively, with no SoapySDR in the path. Receive only, 1 kHz–2 GHz, up to 10 Msps of complex IQ.

This SDR needs a vendor package. The SDRplay API is required. This is a userland library plus a background service that owns the hardware. Install it from sdrplay.com/api (v3.x) and make sure the service is running — on Linux sudo systemctl enable --now sdrplay; the Windows and macOS installers start automatically. SDR Oxide finds the library at runtime, so every build has this backend, and sdroxide --probe tells you which piece is missing when the device list stays empty: the library, the service, or the device.

On Linux, an RSP1 needs one more thing. The original RSP1 is a Mirics MSi2500 and enumerates as USB 1df7:2500, which is exactly what the kernel’s own in-tree msi2500 driver binds to — so on a stock Ubuntu (or Mint, or Debian) the kernel claims the receiver before the SDRplay service ever sees it, and the service reports no device however plainly the RSP is plugged in. The RSPs after it use other product ids and are not affected, which is why this is an RSP1 story, and why the same receiver works on a Mac and not here. SDR Oxide looks for this and names it in the error, and the fix is to keep those drivers out of the way — put

blacklist sdr_msi3101
blacklist msi001
blacklist msi2500

in /etc/modprobe.d/blacklist.conf, run sudo rmmod msi001 msi2500, then unplug the receiver and plug it back in.

The bias tee puts DC on the feedline. The same standing warning as the RTL-SDR applies: never enable it with a transceiver, a DC-grounded antenna, or a preamplifier powered from somewhere else on the other end of the cable.

If the service reports the ADC overloaded, sdroxide shows it on screen and in the log: raise the LNA state, lower the IF gain, or turn the AGC on. If the RSP is unplugged — or the service restarted under sdroxide — it notices within a few seconds and reconnects by itself when the device returns.

The RSPduo’s second tuner

Help wanted — this has not been verified against an RSPduo. Dual-tuner operation here is written from SDRplay’s API rather than measured on the hardware. If it misbehaves, the log is the place to look: it says which tuner is which, whether the two streams are being paired by the service’s sample numbers or by arrival order, and how deep a null the filter is reaching.

An RSPduo is two complete tuners on one board, clocked from one reference. Run both — Run both tuners on the Radio tab — and there are two things worth doing with the other one. Used for picks:

Either takes effect on Apply: which mode the board runs in is chosen when it is opened.

Diversity and QRM suppression

What to do with it picks between the two jobs:

The rest of the controls:

Everything except Run both tuners and Used for applies as you change it — finding a null is done by adjusting and listening. Those two reopen the device, because the API fixes the mode when the RSPduo is selected.

The three you use while listening are on the main window. With a filter running, the strip grows a DIV box (a DIV menu on a narrow window): the mode — CANCEL or COMBINE, click to swap — HOLD, RESTART, and the adaptation rail. That is the whole workflow with the waterfall in front of you: adaptation to the right, watch the noise drop away, HOLD. What stays in the settings dialog is what you set once — the filter length, and the second aerial’s own gains. The box appears only while a filter is actually running, so it is also the confirmation that one is.

What running both tuners costs. The API puts the ADC at a fixed 6 MHz and hands back 2 Msps from a low IF, so 2 Msps is the widest span with both running (1.536 MHz of it inside the analog filter), and the narrower rates are that decimated. The sample-rate and bandwidth lists shrink accordingly, and a wider rate left over from single-tuner operation is clamped rather than refused. Both tuners get the same span, the same filter and the same notches — two branches filtered differently are two branches the filter cannot line up — and both follow the dial together.

Nothing here can tell a wanted signal from an unwanted one. The filter only knows what the two aerials have in common, so pointing both at the same thing in Cancel will dutifully cancel the station. How deep a null it is achieving goes to the log every ten seconds — a converged canceller on a real noise source reads 15–30 dB, and one reading a fraction of a decibel is one whose second aerial cannot hear what it is being asked to subtract.

If the second tuner stops delivering, the first one carries on alone and the log says so: the receiver keeps working and the filter stops, rather than the other way round. Asking for both tuners on any other RSP — a setting left behind by an RSPduo — is reported on screen and ignored.

Both tuners as two radios

Set Used for to A second radio, on its own frequency and the pair is not combined at all: each tuner is a receiver of its own, tuned where you like. One RSPduo then serves two radio tabs — HF in one and VHF in the other — from one board and one connection to the API service.

Both radios have to be set up for it, because whichever one opens the board is what puts it into dual-tuner mode:

  1. On the first radio: pick the RSPduo, tick Run both tuners, set Used for to A second radio, and set This radio’s tuner to the one its aerial is on. Apply.
  2. Add a second radio (Settings → Radio → +, §2.17), give it the same receiver (the same serial), the other tuner, and the same two settings. Apply.

It does not matter whether the two radios name the board the same way — one picked from the list by serial and the other left on first found are the same receiver, and sdroxide resolves them to it before looking for a session to join (issue #392). A second radio that reports no SDRplay RSP found while the first one is happily receiving is the older behaviour, from before that; if you still see it, the message now says instead that the board is already open here and what to set.

Either order works, and either radio may be started first; the second one to open finds the board already running and takes the tuner that is free. Closing one leaves the other streaming, and the board is only handed back to the service when the last radio lets go.

What the two share, because the hardware does:

Neither radio transmits — no RSP does — and a tuner belongs to one radio at a time: a second radio pointed at a tuner that is already running, or at the second tuner of a board being used for diversity, is told so and does not open.

6.2.9 Airspy HF+ (USB)

Help wanted — this backend has not been verified against real hardware. It was written from Airspy’s own reference implementation rather than on a bench. If it misbehaves, the Radio tab has a Copy diagnostic report button; that report contains every command exchanged with the receiver, the sample-rate and calibration tables it reported, the whole tuning calculation, and the first bytes of the sample stream decoded as I/Q pairs. It is what makes a fix possible.

The Airspy HF+ (USB) interface drives an Airspy HF+ Dual, Discovery or Ranger directly, using sdroxide’s own USB driver. There is no SoapySDR, no libusb and no libairspyhf involved, so this works in every build — including the standard Windows .msi and macOS .dmg — with nothing to install beyond access to the device itself (see the README’s Airspy HF+ permissions).

Coverage is 0.5 kHz–31 MHz and 60–260 MHz on a Discovery or Ranger, from 9 kHz on a Dual, at up to 912 kSPS of complex baseband. Receive only — there is no transmit path in this hardware.

All three models share one USB id, so the device list cannot tell them apart; sdroxide asks the receiver which it is once the device is open, and the model appears in the interface label at the top of the window.

The bias tee puts DC on the feedline. The same standing warning as the RTL-SDR applies: never enable it with a transceiver, a DC-grounded antenna, or a preamplifier powered from somewhere else on the other end of the cable.

What the host does. The receiver’s firmware does the filtering; sdroxide does what the vendor library does, and for the same reasons:

Untick Host DSP to see raw hardware output. With it off, the mirror image appears on the zero-IF rates, DC is no longer removed, and the dial is accurate only to the nearest kilohertz. It is also the quickest way to tell a driver problem from a DSP one: if something looks wrong and turning this off changes it, the DSP is where to look.

If the receiver is unplugged, sdroxide notices within a few seconds and reconnects by itself when you plug it back in — no need to press Apply.

6.2.10 Icom LAN (network radios)

The Icom LAN (network) interface drives an Icom over the Ethernet or WiFi port on the radio itself, using the same IP-remote protocol Icom’s own RS-BA1 software speaks. No licence for RS-BA1 is needed, and no computer at the radio end: sdroxide talks to the transceiver directly.

It covers every Icom with a network port — the IC-7300MK2, IC-705, IC-7610, IC-7760, IC-7851/IC-7850, IC-9700, IC-905 and IC-R8600 — because the protocol is the same on all of them and the radio reports its own CI-V address when the session opens. There is nothing to choose from a model list. On the two-box IC-7760 it is the [LAN] port on the RF deck that speaks this protocol, not the one on the controller.

One connection carries three things:

On the radio, first

Three settings, all under MENU » SET:

  1. Network > Network Control — ON. Without it the radio never answers.
  2. Network > Network User1 (or User2) — set a network user name and password, and enter the same pair in sdroxide.
  3. Connectors > MOD Input > DATA OFF MOD and DATA MOD — LAN (on an IC-705, WLAN), or transmit audio is not heard. An IC-7610, IC-7760 or IC-7851 has three data slots rather than one, DATA1 MOD through DATA3 MOD, and all of them want LAN. sdroxide writes this for you on a model whose menu numbering it knows — every transceiver in the list above — and on any other it says so in the status line and leaves the menu alone. Not on a receiver: an IC-R8600 has no modulation input to set, so neither the write nor the warning appears.

    It is a loan, not a keep: sdroxide reads what these items hold before it writes anything, and puts them back the way it found them when the session ends — the radio switched off in sdroxide, its tab closed, the interface changed, or the program quit. A rig left on LAN is deaf to its own microphone and its own key the next time it is used on its own in the shack, with nothing on the radio saying why (issue #252). The same goes for the LAN AF/IF Output > Output Select item sdroxide sets for the 12 kHz IF. Two things it cannot put back: an item the radio never answered a read for, and a session that ends because the link died — a radio unplugged or a WiFi that went away keeps whatever it had at that moment.

    On an IC-7851/IC-7850 the first two live under SET » OTHERS rather than a Network submenu, and the third is CONNECTORS » DATA OFF MOD with LAN at the end of a nine-entry list. Same three settings, different signposting.

    The numbering is what sdroxide has to know, and it is not the menu path: it is a flat index the manufacturer renumbers between models, with the radio’s calibration marker a few places away from the modulation block. That is why an unrecognised model is asked to set the item by hand rather than guessed at. A radio whose CI-V address you have changed in Connectors > CI-V is still recognised: the name it reports is matched too, and either piece of evidence on its own is enough. Only when the two name different Icoms — a network radio name typed over the model’s — does sdroxide fall back to the address alone.

A receiver in the IC-R line gets no PTT, drive, tune or SWR controls at all, whatever its capability block says — at least one of them advertises a transmit stream over this protocol on a set with no transmitter in it.

Note the radio’s IP address from its Network screen — an Icom does not announce itself on the network, so there is no Discover button.

A tune over a network

A frequency sent over this link is a UDP datagram, and the radio never says it acted on one. So sdroxide watches for the radio to report the new frequency back, and if it has not within a fraction of a second it sends the tune again — up to a second, after which the radio has the last word. Over the same second the one frequency it will not accept from the radio is the one you just tuned away from: the answer to a question asked before the tune can arrive late, and out of order, and adopting it puts you back on the band you just left. That was a band change in FT8 taking three to five clicks (issues #285 and #297).

None of this overrules the radio. Turn its own dial and sdroxide follows at once, and a frequency the radio will not go to — outside its range, or a lock switch — wins after that second rather than being argued with.

How wide the waterfall gets

No Icom outputs I/Q over the network. One outputs it at all: the IC-7760’s RF deck has a USB 3.0 socket that streams 1.92 Msps I/Q, but only through a manufacturer-supplied FTDI driver on Windows, and nothing of it reaches the [LAN] port beside it. So over the network the ceiling is the same on every model, for sdroxide and RS-BA1 alike:

Because the scope is uncalibrated — Icom publishes a 0..160 amplitude scale (0..200 on an IC-7610 or IC-7760) with no dB per step — its levels are ranged automatically rather than from the FIT / floor-and-ceiling controls, which govern the audio-band panadapter and every other front end as before.

The strip appears on its own once the first sweep arrives, and the WIDE button appears with it. If neither ever shows up, the radio is not sending its scope: Copy diagnostic report and look at the scope sweeps counter — zero against a healthy CI-V frames in count means the 27 10/27 11 writes did not take.

A scope that stops in the middle of a session restarts itself. Nothing on this link reports that the sweeps have stopped, and several ordinary things stop them — an enable lost on the way (these are single UDP datagrams that nothing re-sends), the radio’s own scope screen being closed and reopened, or the CI-V stream reconnecting under a session that otherwise carries on. sdroxide notices the silence after about three seconds and sends the enables again, backing off while the scope stays quiet, so the strip comes back without a reconnect. The watchdog holds off while you transmit, since a radio that stops sweeping for the length of an over is behaving normally. The log and the wire trace record each stall and recovery.

The flip side is that switching the scope off on the radio will not stick while the strip is on — the watchdog reads it as a fault and turns it back on. Clear Show the radio’s spectrum scope in the connection settings instead.

If the strip is there but barely wider than the panadapter, the span is the reason: the radio sweeps whatever span was last chosen on its own screen, and that is often a few kHz. Scope span sets it from here.

The default is 200 kHz (±100k), about 400 Hz per bin — a whole HF sub-band at once. ±500k gives a megahertz at 2 kHz a bin. A radio that does not offer a particular span refuses it and keeps the one it had.

Receive from: AF or the 12 kHz IF

Receive from is the one setting worth thinking about. It selects what the radio puts in the audio stream (SET > Connectors > LAN AF/IF Output > Output Select), which decides who does the demodulating:

Transmit is unaffected by the choice: it is always audio the radio modulates.

IF spectrum: which way round the IF runs

Only on the 12 kHz IF, and only worth touching if something is wrong.

A 12 kHz IF is a real signal, so it carries the band you want and a mirror of it, and sdroxide has to pick one. Pick the wrong one and everything still sounds like a radio — it is just mirrored, which on SSB means the audio comes out on the opposite sideband to the one it was sent on. The giveaway is having to select USB on 40 m and LSB on 20 m to make anybody intelligible, with the radio’s own mode display agreeing with sdroxide the whole time.

Icom documents this nowhere — not in the CI-V reference guides, not in the IC-7760’s I/Q supplement — so the automatic answer is built from what radios have actually been reported to do, and the IC-7760’s comes from a single operator’s session. If your radio needs the opposite of what it is given, set it by hand and please say so, so the default can be corrected. The IC-7610 is the one to watch: it shares the IC-7760’s scope shape and may well share this too, but nobody has reported it, so it is left alone.

The dial and the mode belong to the radio

Both travel in both directions, on either receive path. Turn the radio’s dial or change its mode and sdroxide follows within a fifth of a second; change VFO or mode in sdroxide and the radio follows. On the 12 kHz IF the mode still matters even though sdroxide is the one demodulating — it is the mode the radio will transmit in, and the radio’s own display should not disagree with yours. What it will not fix is a mirrored IF: the sideband you hear on that path is sdroxide’s to choose, not the radio’s, which is why a swap there is the IF spectrum setting above and not this one.

What sdroxide will not do is impose the session’s dial or mode when the connection opens: it adopts whatever the transceiver is already sitting on. Starting a session by retuning somebody’s radio out of a config file is not what a transceiver operator expects — unlike an SDR dongle, this radio was somewhere deliberate before you connected.

If the radio refuses a mode it does not have, it keeps the one it was in and sdroxide follows it back after about a second.

The rest of the tab

6.2.11 RTL-SDR over rtl_tcp (network dongles)

The RTL-SDR over rtl_tcp (network) interface is the dongle from §6.2.5 on a different machine — typically a Raspberry Pi at the foot of the mast, so the coax run is a metre instead of thirty. The far end runs rtl_tcp, which owns the dongle and performs every register write on sdroxide’s behalf; this end sends five-byte commands and receives the same 8-bit I/Q the USB endpoint would have produced.

On the remote machine:

rtl_tcp -a 0.0.0.0

The -a 0.0.0.0 matters. With no -a, rtl_tcp binds to localhost and only accepts connections from the machine it is running on. Add -p if you want a port other than 1234, and -d to pick between several dongles. Any server that speaks the protocol works — osmocom’s rtl_tcp, the rtl-sdr-blog fork’s, or one of the several re-implementations.

The settings are deliberately the same ones as the USB tab, in the same order, because it is the same radio; only these differ:

Everything else — AGC, tuner gain, IQ correction — behaves as on the USB tab and applies as you change it, without reconnecting.

Two consequences of the protocol are worth knowing, because they look like bugs and are not:

A dropped connection is retried on its own: a server that is restarted, a Pi that reboots, or a client dropped for falling behind all come back without touching anything on the Radio tab.

SDRplay servers (rsp_tcp)

rsp_tcp publishes an SDRplay RSP over the same protocol, and sdroxide connects to one through this interface — not the SDRplay one, which drives an RSP on this machine through the vendor API.

There is a wrinkle worth knowing, because it is not what anyone expects. An rsp_tcp server greets exactly like a dongle: magic "RTL0", tuner type R820T. It poses as an RTL-SDR so that every existing rtl_tcp client keeps working. The "RSP0" marker that looks like it ought to be the greeting belongs instead to a 45-byte capability block that the server sends after the greeting, and only when it was started with -E.

So run the server with -E if you can. With it:

The SDRplay server group on this tab sends the RSP-specific commands — antenna input, LNA state, IF gain reduction, the RSP’s own AGC and set point, the notch filters, and the reference clock output. They are shown always rather than when a server is detected, because there is nothing to detect against a server without -E. An ordinary rtl_tcp server ignores them: this protocol has no replies and silently discards commands it does not recognise, which is the same reason a bias tee that does not come on is not necessarily this end’s fault.

The gain controls above the group are the dongle ones and do nothing on an RSP. Use LNA state and IF gain reduction instead — and note that IF gain reduction is a reduction, so a bigger number is less signal.

rtl_tcp has no authentication and no encryption. Anyone who can reach the port gets the dongle and can retune it — including turning its bias tee on. Keep it on a network you trust, or reach it through a VPN or an SSH tunnel (ssh -L 1234:localhost:1234 pi@host, then connect to 127.0.0.1:1234 here, leaving rtl_tcp bound to localhost on the far end).

6.2.12 HackRF One / Pro (USB)

A HackRF One or HackRF Pro — or a Jawbreaker or a rad1o — driven directly over USB by sdroxide’s own pure-Rust driver. No SoapySDR, no libusb and no libhackrf, so this interface is in every build variant on every platform. DC to 7.25 GHz, 2 to 20 Msps, wideband IQ in both directions; a Pro takes narrower rates, down to 250 ksps.

This is the only USB interface here that transmits, and the only one that is half duplex: receive stops for the length of every over, because the hardware has one signal path and switches it. Nothing you can configure changes that.

Permissions. Linux needs the packaged udev rule — see “HackRF permissions” in the README. Windows normally needs nothing: a HackRF carries the Microsoft OS descriptors that ask for WinUSB by itself. macOS needs nothing.

Radio. Rescan lists what is on the bus. The serial is matched on its suffix, which is why the list shows only the last eight digits: a HackRF serial is 32 hex characters of which the leading half is zeroes on every unit, and nobody types the whole thing. Leave it empty for “the first one found”.

A HackRF Pro appears in this list as “HackRF Pro” and is otherwise the same radio to drive: it carries the HackRF One’s USB id, answers the same vendor requests, and streams the same 8-bit I/Q. Three things about it are different and sdroxide reads all three off the board rather than assuming — see the notes on sample rate, tuning range and baseband filter below. Its half-precision (4-bit, 40 Msps) and extended-precision (16-bit) gateware modes are not driven here; if some other program has loaded one with hackrf_debug -P, the radio stays in it until you unplug it and sdroxide will show noise.

Sample rate. 2 Msps is the default and the gentlest on the host. Everything below 8 Msps is outside the MAX5864’s specified range — it is what everyone uses regardless, and it is the rate the LO-offset behaviour was measured at, so it is offered with a note rather than hidden. 20 Msps is 40 MB/s, which is what the High-Speed USB 2.0 link every HackRF has is rated for; there is no SuperSpeed HackRF to move it to, and sdroxide only says something about the link if the board has enumerated below high speed — a cable or hub problem, and one no sample rate will survive. Changing the rate reopens the radio.

A HackRF Pro is offered four extra rates below that — 250 and 500 ksps, 1 and 1.5 Msps — and only a Pro, because only a Pro can use them. On the other boards a low rate just runs the converter slowly while the narrowest analog filter is still 1.75 MHz wide, so most of what you get back is the rest of the band folded in. The Pro runs its front end fast and decimates in its FPGA, so its narrow rates are narrow all the way through — and at 500 ksps it is sending 1 MB/s over USB instead of 4, with the whole panadapter-and-decoder chain running on a fortieth of the samples.

Gains. The radio’s own model, three stages and a switch:

Control Range Note
LNA 0–40 dB, 8 dB steps Front end. The stage that changes sensitivity, and the stage that overloads first on a real antenna.
VGA 0–62 dB, 2 dB steps Baseband, after the mixer. Reach for this before the LNA on a weak signal.
TX VGA 0–47 dB, 1 dB steps Transmit driver. Only shown once transmit is enabled.
RF amp 14 dB, on/off One switch, offered as two settings — see below.

The hardware truncates rather than rounds: ask the LNA for 15 dB and you get

  1. The slider shows back what the radio really did, so it will move under your hand at the boundaries. That is the radio being honest, not the UI fighting you.

The RF amplifier is one switch with two settings. There is a single 14 dB amplifier in the signal path, and it sits in both directions. sdroxide gives you a receive setting and a transmit setting for it and applies whichever belongs to the direction the radio is entering — so you can run the preamp bypassed on receive, where a HackRF front end overloads easily on a real antenna, and in circuit on transmit for the extra output. This works because sdroxide reprograms the entire front end on every change of direction. Reaching the same radio through SoapySDR cannot express it at all: there the receive amp goes dead after the first over and the transmit amp never engages.

Baseband filter. Leave it on Automatic. The filter is coupled to something invisible: sdroxide parks the local oscillator a quarter of the span above your dial so the radio’s own DC spike lands clear of the signal, and it withdraws that offset when the filter is too narrow to reach where the signal was moved to. So a filter chosen by hand and set too low does not merely soften the band edges — it silently turns off the DC-spike avoidance, which looks exactly like the offset being broken. Automatic picks 0.75 × the sample rate, which always leaves room.

On a HackRF Pro this control is greyed out, because that board chooses the filter itself and discards what the host asks for. Its analog chain is nothing like a HackRF One’s — the narrowest setting its transceiver offers is around 10 MHz wide, and everything below that is a switched filter plus decimation that only the radio’s own firmware knows how to combine — so it derives the same 0.75 × sample rate itself and applies it across the whole chain. sdroxide does not send the request at all on that board rather than send one that would be accepted and ignored; if you have a filter pinned from another radio, the status line at open says so.

Tuning range. DC to 7.25 GHz, the same on every board, because that is what the firmware accepts — it clamps a tuning request into 0–7250 MHz and has no per-board table. libhackrf documents the same span and SoapySDR publishes it, which is why a HackRF driven through SoapySDR has always tuned wider here than one driven natively.

That is a wider span than any of these boards is specified for. A HackRF One is a 1 MHz – 6 GHz radio, a Pro is 100 kHz – 6 GHz, and outside those the receiver is heavily attenuated and the transmitter makes little or no power. But attenuated is not the same as absent: people listen to shortwave below 1 MHz on a HackRF, and 5 GHz Wi-Fi is visible above 6, so sdroxide lets the dial go there and lets you judge what you hear rather than deciding in advance that you cannot. Expect a deaf radio at the edges, and do not expect to transmit usefully there.

IQ correction. On by default. This is a zero-IF radio: its own oscillator leakage sits at the centre of the span, and the mixer’s quadrature error puts a mirror image across it. The correction removes both, adaptively. Turning it off shows raw hardware output, which is the quick way to tell a driver problem from a DSP one.

Bias tee. About 3 V at 50 mA on the antenna port, for an active antenna or a preamp. A HackRF One or Pro only — the Jawbreaker and the rad1o have no such circuit, and on those sdroxide does not send the command at all and says so rather than leaving a switch that quietly does nothing. A board that refuses the command anyway — the firmware answers it with a stall on anything that is not a One, an r9 or a Pro, and some boards do not identify themselves as any of those — is a radio with no antenna-port power, not a radio that will not open.

Transmit

Off by default, behind an Enable transmit switch, and the default is deliberate. A HackRF is a wideband transmitter with poor harmonic suppression: it wants an external low-pass filter for whatever band you are on, and it will happily radiate outside it. Somebody who plugged one in to listen should not be one PTT away from that. While the switch is off, sdroxide publishes no transmit channel at all, so nothing anywhere in the program can key the radio.

With it on:

Transmit has not yet been measured against hardware. Receive has. If anything about an over looks wrong, the Radio tab’s Copy diagnostic report button records every command exchanged with the radio in order, including the exact sequence around each key-down — which is the part a bug report needs and the part nobody can reconstruct from a spectrum.

6.2.13 Airspy R2 / Mini (USB)

An Airspy R2 or Airspy Mini, driven directly over USB by sdroxide’s own pure-Rust driver. No SoapySDR, no libusb and no libairspy, so this interface is in every build variant on every platform. 24 MHz to 1800 MHz, receive only.

This is not the Airspy HF+. Same vendor, different receiver: different silicon, a different USB id, a different protocol and a different tuning range. They have separate interfaces, separate drivers and separate udev rules, and neither substitutes for the other.

Permissions. Linux needs the packaged udev rule — see “Airspy R2 / Mini permissions” in the README, and note it is a different file from the HF+’s. Windows wants WinUSB via Zadig or Airspy’s own package. macOS needs nothing.

Receiver. Rescan lists what is on the bus. An R2 and a Mini share the USB id 1d50:60a1 and the same product string, so the list cannot say which is which — only the sample rates separate them, and those need the device open. The serial is matched on its suffix, so the last eight digits are enough.

Sample rate. The rate you pick is the rate you get: an R2 offers 10 and 2.5 Msps, a Mini 6 and 3. Once a receiver is connected the combo shows its rates; before that it shows both models’ and says which is which.

Underneath, the receiver runs at twice the rate shown. Its ADC is real rather than complex — it digitises a real signal at the full rate — and sdroxide makes complex baseband from it on the host with a quarter-rate translate and a half-band decimator. Two consequences are worth knowing:

Changing the rate reopens the receiver: the rate moves the tuner’s IF and the clock dividers together, so it cannot be changed under a running stream.

Gain is a step along a curve, not three sliders. The R820T2 has an LNA, a mixer and a VGA, and setting them independently is a good way to build a receiver that either overloads or hisses. Airspy publishes two curated curves through the three stages and sdroxide offers the same choice, because that is what the numbers were tuned for and what every other Airspy program does:

Curve Use
Linearity Least intermodulation for a given sensitivity. The right default on an antenna with broadcast stations nearby.
Sensitivity More gain for weak signals, less overload margin.

The Gain slider is a step from 0 (quiet) to 21 along whichever curve is selected. It is not a dB figure — how much a step is worth depends on the curve and the band.

Tuner AGC. The tuner has its own loops for the LNA and the mixer. They are off by default, and for a reason: with one running, the gain slider no longer sets the stage that loop owns — the loop overwrites it a moment later. Use one or the other, not both.

12-bit packing. On by default, and worth leaving on. The receiver can pack its 12-bit samples three-to-a-word instead of padding each to 16 bits, which is a third less USB traffic — and this is a USB 2.0 device carrying up to 30 MB/s packed against 40 unpacked. Firmware too old to have the request streams unpacked and sdroxide says so. Applies on reconnect, because it changes how every transfer is decoded.

Bias tee. DC on the antenna port for an active antenna or preamp. Off by default.

DC removal. On by default. Turn it off to see raw hardware output, which is the quick way to tell a driver problem from a DSP one — but see above for where the spur goes when you do.

Not yet verified against real hardware. If it misbehaves, the Radio tab’s Copy diagnostic report button records every command exchanged with the receiver, the sample-rate arithmetic (which is where a span that is half or double what it should be would show), and the first samples both as raw 12-bit values and decoded as I/Q pairs.

6.2.14 SpyServer (network receivers)

SpyServer is Airspy’s own network server. It works with Airspy R2/Mini, Airspy HF+, or RTL-SDR. Receive only.

There are two interfaces in the picker, and the choice between them is about the link rather than about the radio:

They are separate entries with separate settings, because an operator with both usually has two different servers — one at the mast and one far away — and because a decimation stage that suits a wideband stream is nowhere near one that suits a narrow one.

Everything below applies to both unless it says otherwise.

Server address — host or host:port. The port defaults to 5555, which is what spyserver listens on unless its config file says otherwise. A hostname, an IPv4 address or a bracketed IPv6 literal all work. Takes effect on Apply.

On the far end, check that spyserver.config binds an address other machines can reach. Bound to 127.0.0.1 it accepts connections only from the machine it is running on.

Two other keys in that file are worth knowing about before you start it:

Test connection connects, reads what the server says about itself, and disconnects again without starting a stream, so it is safe to press against a server somebody else is using. This is worth doing before Apply, because unlike rtl_tcp this protocol answers: the reply names the receiver on the far end, the range of rates it offers, and whether this end would be allowed to tune it.

I/Q bandwidth is a decimation stage, not a figure in hertz. Every receiver has a different ladder — its maximum rate halved stage by stage from whatever floor the server sets — and none of it is known until a connection is open, which may be from a machine on the other side of the world from this screen. Storing the stage means the same setting still means something sensible when it is pointed at a different server, and it is what the protocol carries.

Automatic is the default and is usually right. It aims at about 1 Msps on the wideband interface, and about 96 kHz on the VFO one — enough for every mode here including wide FM, at roughly 1.5 Mbit/s at 8 bits. Press Test connection to see what the stages come to on the server you are pointed at. Takes effect on Apply.

Measured against spyserver on an RTL-SDR at 2.048 Msps, the two interfaces came out at 8.4 Mbit/s and 1.3 Mbit/s for the same band coverage — the wideband one carrying 512 kHz of I/Q, the VFO one carrying 64 kHz of I/Q plus the whole 1.7 MHz as an FFT. On an Airspy at 10 Msps the gap is far wider.

Sample format decides what a rate costs on the link: 16-bit is twice 8-bit, and 32-bit float is four times it for no more information than the receiver’s ADC had. 8-bit is what makes a remote receiver work over a domestic uplink and is right for almost everything; 16-bit is worth it on an Airspy HF+ over a wired link, where there is real dynamic range to keep. A server configured to insist on one format overrides this and says so in the log. Takes effect on Apply.

Gain is the server’s gain stage, as an index — not a number of decibels. What each index is worth belongs to the receiver on the far end and changes with the band, and the protocol never says, so nothing here can turn it into dB without inventing a figure. The real range is the server’s; an index past it is clamped. Applies immediately.

Digital gain is how far the server scales its samples up before quantising them for the wire. Automatic computes it the way every other client does — from the receiver type, the gain index and the decimation stage — and is almost always right. It matters most at 8 bits: a signal sitting far below full scale loses its lower bits to the quantiser, and this is what puts them back. An Airspy HF+ behind an 8-bit server gets 32 dB of it before anything else, because its analog dynamic range leaves its I/Q a long way down the scale.

Full-band strip asks the server for a low-rate FFT of the whole band as well as the I/Q, and draws it in the strip above the panadapter (the WIDE button in the Display module shows and hides it). It costs almost nothing — a couple of kilobytes a frame, a dozen or so times a second — and it shows the whole receiver rather than the slice being demodulated. Clicking anywhere in it tunes there.

In the VFO interface this is the only band view there is, because the panadapter itself is only as wide as the I/Q being received. Switching it off leaves a receiver with no way to see anything it is not already tuned to.

The band view holds still while the dial roams inside it, and re-centres only when you reach its outer third. That is deliberate: a band picture that slid on every retune would be one nobody could steer by.

The dropdown beside it is how much of the receiver the strip covers. Whole band is the widest view there is; narrowing it puts the same number of bins across less spectrum, which is finer detail over a smaller stretch.

Note that “whole band” is the receiver’s analog bandwidth, which is not its sample rate and is often noticeably less: an RTL-SDR running at 2.048 Msps reports 1.7 MHz here. The strip is labelled with what actually arrives.

Strip dB window is the range the server quantises its FFT into before sending it, one byte a bin — so it decides how finely the strip is measured, not how it is drawn. The floor and ceiling the strip is displayed with are the engine’s own auto-levelling and are a separate thing. The default 150 dB is the whole protocol range and needs no attention.

I/Q correction removes the DC spike and the mirror image in DSP, on this side. Whether the receiver on the far end needs it depends on what it is — an Airspy HF+ does not, an RTL-SDR does — and the protocol does not say which it is talking to, so it is left to you, on by default.

When somebody else owns the receiver

A SpyServer can serve several clients, and only one of them owns the tuning. When another client has it:

Which of these applies is decided by the server and can change while you are connected.

What is not implemented

Two encodings in this protocol are documented nowhere and thus not implemented:

The protocol’s demodulated-audio streams are not used either: sdroxide demodulates its own.

Security. SpyServer has no authentication and no encryption. A server you run is reachable by anyone who can reach the port, and a public one sees your address. Keep a private server on a trusted network or behind an SSH tunnel.

6.2.15 Panadapter: borrowing another radio’s receiver

A great many stations have a transceiver with no wideband output — CAT on a serial port, demodulated audio on a USB sound card — and an SDR sitting on the desk beside it. On its own the transceiver can only show a slice of its audio band mapped to RF (6.2.2). Give it the SDR’s receiver and the same tab gets the real thing: a wideband panadapter and waterfall you can click to tune, a sub receiver, the digital modes, the CW skimmer and the band-plan and spot overlays — while the dial, the mode, the filter, the transmitter and the keyer all stay with the transceiver.

Both radios are configured exactly as they are on their own. Add the SDR as a radio (2.17), set its interface up until it works, and then, on the transceiver’s Radio page, pick it under Panadapter → Receiver. Press Apply / reconnect.

The receiver leaves the tab strip while it is lent. Its front end now belongs to the transceiver’s engine, so there is nothing left for a tab of its own to show — a station with one transceiver and one borrowed receiver reads as the one radio it is. It stays in the roster at the top of Settings → Radio, marked 🔗, which is where its own interface settings are and where you set Receiver back to None to have it as a radio again. It comes back by itself within a few seconds of being released; nothing needs restarting.

Switching the transceiver off (2.17) does the same thing: a radio that is off opens nothing, so it borrows nothing, and the receiver goes back to being a radio of its own for as long as the pairing’s owner is off. The lent receiver has no switch of its own while it is lent — whether its device is open is the borrower’s business.

How the receiver is connected — the choice under Connected to decides what the offset below it means:

The offset is in hertz and its sign follows the same rule as the converter’s above: the receiver is tuned to dial + offset. Nothing you type here is ever sent to either radio.

This is a third offset field, and the three do different things. The Converter offset above retunes the radio itself, for hardware in the antenna line (6.2). I/Q centre offset on the CAT tab says where a rig’s own sound-card output sits relative to its dial (6.2.2). This one says where a different radio is listening. Putting an I.F. in either of the other two puts the whole display out by that much instead of correcting it.

Per-mode offsets appear under an I.F. tap, because on many transceivers the carrier — and with it the I.F. — sits in a different place in each mode. Tick a mode to give it an offset of its own; leave it clear and it uses the plain offset above. The classes are the rig’s, not sdroxide’s: every digital and keyboard mode counts as DATA, because that is the one setting the rig is in for all of them.

These follow the mode the radio reports, not the mode named in sdroxide, so they stay right even when the two differ — which they routinely do, since Digimode mode (6.2.2) may leave the rig in plain USB for a digital mode. Changing mode retunes the receiver by the difference, so the band does not move on screen.

Invert spectrum mirrors the receiver’s span about its own centre, for a tap whose oscillator sits above the signal and hands the band over the wrong way round. The symptom is the one described in 6.2.2: a waterfall full of convincing signals that are all on the wrong side of the dial. Leave it off until you see that.

Follow the dial is what makes the two one radio, and it works both ways. Click a signal on the panadapter and the transceiver’s dial goes there; turn the transceiver’s own VFO knob and the marker follows within one poll. The waterfall itself only moves when the dial leaves what the receiver is covering — inside that span the picture stays still and the passband marker slides, which is the whole point of having it. Turn this off to park the receiver on one segment and let the radio go elsewhere.

Audio from — which of the two you actually listen to:

Mute on transmit and Blank on transmit, both on by default, are for the obvious hazard: a receiver on the same antenna — or on the transceiver’s own I.F. — hears your transmitter, loudly, and paints it across the whole span. Blanking stops the receiver being read for the length of the over, so the waterfall pauses and picks up on unkey. Turn both off only with the receiver on a separate antenna, where watching the band through an over is worth having; turn off blanking alone to watch your own signal while still not hearing it.

Mute on transmit also covers an over you key at the radio — the microphone’s own PTT, a foot switch, or MOX — as long as the CAT link reports the rig’s transmit state, which every dialect here does (including flrig and Hamlib’s rigctld). Blanking does not: nothing on this side is driving that over, so the receiver is read right through it, and the picture goes on showing the band — which is the panadapter doing what it was paired for while you talk. So an over from the microphone sounds like one keyed on screen and looks like one you asked to watch.

Things worth knowing.

6.2.16 ELAD FDM-DUO / FDM-S (USB)

An ELAD FDM-DUO, FDM-DUOr, FDM-S2 or FDM-S1, driven directly over USB by sdroxide’s own pure-Rust driver. No SoapySDR, no libusb and no gr-elad, so this interface is in every build variant on every platform.

All three are direct-sampling receivers: a 122.88 MHz ADC (61.44 MHz on the FDM-S1) behind a switchable low-pass bank and a 12 dB pad, with an FPGA down-converter delivering one wideband I/Q channel. The FDM-S2 covers 10 kHz–54 MHz and the FDM-S1 10 kHz–30 MHz, both receive only. The FDM-DUO is a 5 W transceiver wrapped around the same receiver.

One radio, three USB devices. An FDM-DUO’s rear panel has three USB sockets and they are three separate devices to the computer:

Socket What it is What sdroxide does with it
RX ELAD’s own vendor interface The wideband I/Q — the panadapter, the demodulators, the skimmers
CAT An FTDI serial bridge The dial, the mode, PTT, the S-meter, the SWR, the transmit power
USB Audio A USB sound card Transmit audio out of sdroxide and into the radio

This one interface drives all three, so there is nothing to pair up and no second radio tab. An FDM-S1 or FDM-S2 has only the first of them.

Permissions. Linux needs the packaged udev rule for the receive interface — see “ELAD permissions” in the README. The CAT port needs nothing installed; it is an ordinary /dev/ttyUSB*, so if that is what is refused the answer is the dialout group rather than the rule file. Windows needs the receive interface bound to WinUSB with Zadig, which stops ELAD’s own FDM-SW2 from seeing it until the driver is put back. macOS needs nothing.

Device. Rescan lists what is on the bus, by model and by where it is plugged in. There is no serial number in the list: ELAD keeps the serial in the device’s EEPROM rather than in its USB descriptor, so reading one would mean claiming every ELAD on the bus — including one that is streaming.

An FDM-S1 or FDM-S2 will not send a single sample until its FPGA is loaded. The two halves of a sampler come up very differently. The USB bridge runs from an EEPROM, so the moment you plug one in it enumerates, reports its serial and its hardware version, and acknowledges the start of the stream — everything looks perfect. The FPGA behind it is loaded from the host and comes up empty, so there is no down-converter in there to start and the spectrum sits on “waiting for spectrum…” for ever, with nothing wrong anywhere to point at.

ELAD ship the loader separately, and it has to run after every power-up. Download elad-firmware from ELAD’s Linux area (eladit.com → Download → SDR/Linux), copy it to /usr/local/bin/elad-firmware and make it executable:

sudo install -m 755 elad-firmware-2.0-intel /usr/local/bin/elad-firmware

⚠️ Take the “intel” build, not the newer “ubuntu-32” one. The 2019 ubuntu-32 file is a 32-bit binary; on a 64-bit machine it opens the receiver, sends it nothing and exits without an error, so it looks exactly like a successful load. The older 2016 “intel” file is the 64-bit build. A working run prints XYLINX programming correct and takes about six seconds — check that once by hand before blaming anything else.

sdroxide then runs it for you every time it opens the receiver, loading the image for the sample rate you picked. It takes about six seconds, once per session. If you keep the loader somewhere else, point SDROXIDE_ELAD_FIRMWARE at it. If sdroxide cannot find it at all, it says so on screen rather than retrying in silence.

Sample rate. The down-converter delivers 192, 384, 768, 1536, 3072 or 6144 kHz, and the six rates are six different FPGA images — which is why nothing in ELAD’s vendor protocol selects between them, and why their own GNU Radio module takes the rate as a parameter without ever sending it. On an FDM-S1 or FDM-S2 this setting therefore is a command: it chooses the image loaded above.

On an FDM-DUO it is not. The radio boots its own FPGA and has no front-panel menu for the rate, so it arrives at whatever it powered up in — 192 kHz on a fresh one — or whatever FDM-SW2 last left it in, and this setting says which one that is. Set it wrong and you still get samples: the panadapter is simply the wrong width, with every frequency inside it scaled to match. sdroxide measures the real throughput a couple of seconds after the stream starts and tells you on screen when the two disagree, naming the rate to pick. The one exception is 6144 kHz, where the samples themselves are half as wide — a wrong guess there is noise rather than a mis-scaled spectrum.

Attenuator and pre-selection filters. The pad is the same control as the main window’s Gain slider. The filters are the low-pass bank in front of the ADC: bypassing them gives the widest view and the worst behaviour near strong out-of-band signals, so leave them in unless you are deliberately listening outside the filtered range.

Antenna (FDM-DUO only). The radio has two M-type sockets on the back and this chooses which one the receiver listens on — the rig’s AN command, which is menu 31 ANTENNAS at the front panel and the ANT 1 2 indicator on its display:

Setting The radio’s menu What is where
RTX ANTENNAS = 1 One antenna doing both jobs, on the socket that also carries transmit
RX only ANTENNAS = 2 Receive on the second socket, transmit still out of RTX

“RX only” is the arrangement for a receiving antenna — a loop, a beverage, a low-band wire — with the beam left on the transmitter. It moves the whole receiver: the panadapter, the demodulators, the skimmers and the radio’s own audio all come from the socket selected here, because they are all fed from the one ADC behind it.

The choice applies immediately and is remembered, and every start re-asserts it on the radio — the antenna belongs to the station’s coax rather than to the radio’s memory. Until you have picked one, what is shown is the rig’s own setting, read when the control port opens: a socket chosen at the front panel with sdroxide not running is adopted rather than overridden. On an FDM-DUO reached through its receive cable alone the command still goes out, but nothing can be read back, so the setting shown is the one you last picked rather than one the radio confirmed.

The same control is on the CAT radios tab for an FDM-DUO driven over CAT alone (6.2.2) — it is a rig command, so it works wherever the rig is reached.

Rig control (FDM-DUO only). Set the serial port and the baud rate to match menu 70 CAT BAUD on the radio, which ships at 38400. With the port set you get everything a CAT radio gives: frequency and mode in both directions (see below), PTT, the radio’s own S-meter and SWR, and its transmit power on the Drive slider (nine fixed steps from 0.3 W to 5 W, which is what the radio has rather than a continuous control).

Check the baud rate first if nothing you do reaches the radio. The FDM-DUO’s CAT port has four rates and no others — 9600, 38400, 57600 and 115200, always 8N1 — and a port opened at any other one is silent in both directions: no command lands, no answer comes back, and what you see is a radio that ignores the dial and will not key, on every serial port you try. This setting is shared with the CAT / Audio interface (6.2.2), whose own default is 19200, so a configuration in which you have never touched Baud starts out at a rate the radio has no setting for. sdroxide falls back to 38400 in that case and says so on screen, but the honest fix is to set this to whatever menu 70 says.

Leave the port empty and an FDM-DUO is still usable on its receive cable alone: the driver tunes, changes mode and keys through the CAT gateway on the same USB interface, and the radio’s own dial is followed — the receive cable carries a read-back of the frequency the radio is tuned to, which sdroxide asks for four times a second, so turning the knob moves the panadapter with it. What you give up is the rest of what needs an answer: the S-meter, the SWR, the power readback, and any notice of a mode changed at the front panel. That is also the setting for an FDM-S1 or FDM-S2, which have no CAT port at all.

A and B are the radio’s own two VFOs on that cable. The FDM-DUO has the pair a transceiver has, and its receive window follows whichever is selected, so taking up sdroxide’s VFO B takes up the radio’s: its display, its knob and its A/B button are all on the dial you are working, and each VFO keeps its own mode at both ends. What it cannot see is that button being pressed at the radio — the read-back reports a frequency, not which VFO produced it, so sdroxide reads a press of A/B as the dial having moved and follows it onto the VFO it already thinks you are on. To put the two back in step, click sdroxide’s A or B for the VFO you want, even the one already lit: that selects it at the radio too. With a CAT serial port set instead, the radio is kept on its VFO A and sdroxide drives that one dial, because the dial is read there by asking FA;, which answers VFO A whichever VFO is selected.

Transmit input is the radio’s TI command, menu 32 TX IN at the front panel, asserted when the port opens. USB audio is what makes transmit work here — the radio sends what sdroxide puts into its sound card. A radio left on Microphone transmits the room instead, with nothing on screen to say so, which is why this is a visible setting rather than an assumption. Pick the radio’s own USB Audio device beside it, or under Settings → Radio → Radio audio.

The panadapter centre is the dial, because on this radio they are one knob. This front end hands over a whole down-converter window, but that window is centred on the transceiver’s own VFO: the receiver being streamed is the one the radio tunes for itself, so moving the VFO moves the window with it, hertz for hertz. There is no arrangement in which the radio’s display and sdroxide’s readout are different numbers and both are true — except in CW, where they are supposed to differ by your sidetone pitch, and the paragraph on CW below says why.

So with the CAT port set, the two agree in both directions. Tuning here — the digits, the mouse wheel, a click on the waterfall, a memory, a band button — moves the radio’s VFO, and the panadapter re-centres on the dial as it goes. Turning the front-panel knob moves the readout here. Nothing is commanded back at a frequency the radio itself reported, so your hand on the knob and sdroxide cannot fight over it.

With no CAT port — or one the radio does not answer on — there is no VFO to command, and sdroxide tunes inside the window the radio is already sending, the way it does on any other SDR. The frequency axis is then only as right as the number you have typed into it, so set the band on the radio and type its dial frequency here to line the two up. That is also how an FDM-S1 or FDM-S2 works, having no VFO at all.

CW is keyed by the radio’s own key or paddle. The FDM-DUO has no command that accepts text — its SW command plays one of the ten messages stored in the radio — so the CW panel cannot key it over CAT. Menu 37 CW IN set to Key+DTR is the other route, using the CAT cable’s DTR line as a straight key.

Which is why, in CW and only in CW, the radio’s VFO sits a sidetone pitch above sdroxide’s readout. The down-converter comes out on the VFO whatever mode the radio is in, so the station you are copying at 700 Hz is 700 Hz above the number in the big readout — and the VFO is what the radio keys its own transmitter on. sdroxide therefore leaves the VFO on the station and tunes its own receiver the 700 Hz down, so the radio’s display reads the frequency you are working (the same figure the CW panel shows beside the pitch, and the one to log) while sdroxide’s readout stays the zero-beat it has always been — unless QRG is on (2.14), which reads the worked frequency on this side too, so the two displays then agree. Nothing on the waterfall moves. Without it the paddle answered every station a whole sidetone low and nobody came back.

Mostly not verified against hardware. This backend — the USB protocol, the tuning arithmetic, the calibration map and the CAT dialect — is written from ELAD’s own gr-elad GNU Radio module and from the FDM-DUO manual’s CAT chapter. Receiving on an FDM-DUO over the USB interface alone has since been run on one (hardware 2.9, firmware 4.9, at 192 kHz): the I/Q order, the tuning word, following the radio’s own dial and its VFO A/B all checked out. Transmit, the serial CAT port on a bench, the higher sample rates and the FDM-S1/S2 have not been. If it misbehaves, Copy diagnostic report on the Radio tab puts every command exchanged with the device on the clipboard; cargo run -p sdroxide-elad --example probe does the same from a terminal and also settles what rate the device is really in.

One of the two things that wanted checking has now been answered on a real FDM-DUO, and the answer was no: the down-converter feeding this USB interface is not independent of the receiver the transceiver uses for its own audio — they are one receiver, and the paragraph on the panadapter centre above is what sdroxide now does about it. The other still stands: whether the stream survives a transmit cycle. It is assumed not to — receive stops for the length of an over — which is the safe way to be wrong.

6.2.17 LimeSDR family + LimeRFE (LimeSuite)

Drives a LimeSDR-USB, LimeSDR Mini (v1 or v2), LimeNET-Micro or LimeSDR-PCIe through LimeSuite, and the LimeRFE front end in front of it. Wideband I/Q both ways, and genuinely full duplex — the receiver keeps running through your own transmission, which is how a QO-100 station listens to its own downlink.

A LimeSDR has always been reachable through the SoapySDR interface, and SoapyLMS7 is itself a thin wrapper over this same library, so the I/Q path is not what this interface adds. The LimeRFE is: SoapySDR exposes none of it. So is the board’s second receive chain, which can carry a second aerial for diversity reception or for nulling a local noise source, or a directional coupler for linearising an amplifier — see The second chain below.

Why a library rather than a driver. Every other USB interface here speaks its radio’s wire protocol directly. This one does not, because driving the LMS7002M means its register map, its synthesisers, its signal-processing chain and — the part no amount of desk-checking settles — its DC-offset and IQ-imbalance calibration. LimeSuite is Apache-2.0 and already has all of it. The library is found with dlopen at runtime, so nothing is linked at build time: this interface is in every build variant and simply says what to install where the library is absent.

The board
The second chain: diversity, QRM suppression and PureSignal

On a board with two receive chains, the one you are not listening on can be put to work — and because both chains share one synthesiser and one sample clock, the two streams are coherent: the same span, at the same instant, with a relative phase set by the cabling rather than by chance. That is what makes it possible to combine them. Used for picks the job: a second aerial, or a sample of your own transmitter. Either takes effect on Apply, because the chain’s stream is bound to its channel when it is created.

Its socket and Its gain apply to both jobs; the rest of the controls depend on which one you picked.

There are two things worth doing with it, and What to do with it picks:

The rest of the controls:

Nothing here can tell a wanted signal from an unwanted one. The filter only knows what the two aerials have in common, so pointing both at the same thing in Cancel will dutifully cancel the station. How deep a null it is achieving goes to the log every ten seconds — a converged canceller on a real noise source reads 15–30 dB, and one reading a fraction of a decibel is one whose second aerial cannot hear what it is being asked to subtract.

PureSignal: linearising the amplifier

Set Used for to Transmit feedback and the second chain listens to a directional coupler on your amplifier’s output instead of to an aerial. The transmitter then compares what came back with what it meant to send, and sends the inverse of the difference — so what leaves the amplifier is straight. This is the technique openHPSDR calls PureSignal, and the payoff is the usual one: around twenty decibels less intermodulation, landing on other people’s QSOs either side of you, with the amplifier keeping its power instead of being backed off.

Every amplifier compresses near its ceiling, and compression on a multi-tone signal — which SSB and every digital mode are — is intermodulation. What is learned is a complex gain against drive level: how the gain sags as drive rises, and the phase shift that comes with it. It is applied to each outgoing sample before the converter sees it.

Two things hold whatever the feedback says, because a correction loop fed rubbish must not become an over-driven amplifier. The correction stays at unity until the feedback lines up with the transmission, so a coupler that is not connected, a chain that is deaf, or an alignment that never locks all leave the transmitter exactly as it would have been. And the table is normalised at the top and clamped, so it can never ask the converter for more than full scale — a compressing amplifier is linearised by pulling the small-signal gain down, not by asking for more peak.

The loop finds the delay between what was written to the transmit FIFO and what came back through the amplifier by correlating the two envelopes, once per over. It reports itself to the log every ten seconds while you are transmitting: how much compression it is correcting, and how well the feedback matched. A run of “has not found the transmission in the coupler’s chain” is the coupler, the cabling or that gain setting — not the correction.

Split and cross-band transmission are outside this. The feedback arrives at the receiver’s centre frequency, and the receiver is where your dial is. Transmit far enough away from it and the coupled signal falls outside the captured span, where there is nothing to hear; the log says so once and the over goes out uncorrected.

Not tried on an amplifier. The correction converges against a simulated compressing amplifier with a delay, an oscillator offset and noise in the feedback path — which says the arithmetic is right, not that a real coupler and a real PA behave the way this expects. It is safe to try: with the feedback disconnected, nothing changes.

Transmit is off until armed, and with it off the interface publishes no transmit channel at all — so nothing can key the radio, not merely the paths that remembered to check. A LimeSDR transmits from about 100 kHz to 3.8 GHz with no filtering of its own; use a low-pass filter, an appropriate LimeRFE channel, or a dummy load.

Transmit gain starts at 0 dB, the bottom of the board’s 0–73 dB range, and that is the same decision as the arming box: a transmitter that has just been armed should not be able to radiate anything anybody has to explain. It does mean the first over after arming produces microwatts — which downstream of an amplifier and a power meter is indistinguishable from a radio that does not transmit at all — so the panel says so under the slider while it is down there, and the log says so at every key-down. Raise it into a dummy load first and measure; the useful setting is a property of your board, your band and whatever is in front of it, not a number this program can pick.

Transmit port — BAND1, BAND2, or Automatic. The two are different matching networks on the board, not two jacks onto the same one: LimeSuite’s own table gives BAND1 (TX1_1) as 30 MHz–1.9 GHz and BAND2 (TX1_2) as 2–2.6 GHz. So every band below 23 cm goes out of BAND1, and keying one of them out of BAND2 puts the over into a 13 cm filter that passes almost none of it — the synthesiser is on frequency, the drive is at whatever you set, the stream runs, every setting reads correct, and the power meter reads zero. Leave this on Automatic, which follows the dial and moves the port when you cross into 13 cm. If you do pick one by hand and it does not cover the band you are on, the panel says so under the interface and the log says so at every key-down.

Every over prints one line naming what it went out through — the frequency, the socket, the drive and the analog filter — and prints it again whenever any of those changes; at unkey it prints what the transmitter was actually given, so a key-down that put nothing on the air says whether the modulator sent no samples, sent nothing but silence, or sent samples the board would not take. That line, and the LimeRFE’s own beside it, is what to read first when a transmission does not appear where it should.

The LimeRFE

Two cables decide whether any of this works, and only one of them is a setting. The LimeRFE’s receive output goes to one of the LimeSDR’s receive sockets — RX1_W, the wideband input LimeSuite calls LNAW, unless you have chosen otherwise — and its transmit input comes from TX1_1. Whichever socket you used is the one Receive port above has to be on: the radio listens to one input at a time, and a LimeSDR listening on LNAL with the front end on LNAW is deaf rather than merely quieter. Leaving it on Automatic does the right thing for the usual cabling.

Connected by is Not connected until you say otherwise. That default is deliberate: this board switches a power amplifier, and an accessory that could be wired to anything comes up inert and gets declared, the same rule the HPSDR open-collector outputs follow.

Two links, and the choice is worth making deliberately:

If you change band often, use the cable.

If the LimeRFE will not answer, there is a standalone check that talks to it directly and prints what happened at each step, without the rest of the program in the way:

cargo run -p sdroxide-limerfe --example rfe -- /dev/ttyUSB0

With no port named it lists the ports it can see. It only says hello and reads the board’s identity; add --configure to also set a receive-only wideband configuration, which is the gentlest thing the board can be asked to do. Nothing it does keys an amplifier.

Band — with Follow the dial on, the operating frequency picks the channel and the filters are switched before any RF appears. Tuning within one band puts nothing on the control link at all; changing band always does. The mapping is LimeSuite’s own, so a LimeRFE configured here and one configured in LimeSuiteGUI put the same filters in circuit.

Relays decides what the board is doing between overs. On Automatic — the default — it receives, is switched to transmit at key-down, and switched back at key-up. That is true on either cabling, and the reason is the hardware: the LimeRFE’s amateur channels have one filter with a transmit/receive switch either side of it, so a board asked for both directions at once puts that switch on the transmitter and stops passing anything to the receiver. It answers the command and goes deaf. LimeSuite’s own GUI and SDRangel both leave a receiving board in receive for the same reason, and reach for both at once only on the cellular bands, which have duplexers.

So an over costs one short transaction either side of it, and sdroxide waits for the relay before letting drive out. On the GPIO/I²C link that transaction is the better part of a second — another reason to use the LimeRFE’s own USB cable if you transmit.

The other three settings are pins rather than automation:

Relays What it does
Always receive Transmit is refused outright rather than driven into a closed relay. The panel says so, in yellow, as soon as it is selected.
Always transmit Bench use: the board stays keyed.
Always both For a cellular band, which has the duplexer for it. On an amateur channel it stops receive — the panel warns. Not reachable at all when one connector serves both directions; the board refuses that combination.

Which connector is which still matters, and for two separate reasons.

The first is simply which jack the antenna is in. Receive comes in on J3 and transmit goes out of J4 by default, which is the board doing what it is for — one aerial or amplifier chain per direction — and is wrong for the very common station with a single antenna: everything transmitted goes into an open connector while receive carries on perfectly. Nothing warns you in hardware, so the panel states the pair under the connector combos. With one antenna, put Transmit connector on the same jack it is in.

The second is what each connector can reach: J5 is one jack for both directions and the only path to the HF and 6 m amplifiers, so every HF contact shares a connector with a live amplifier. Above 30 MHz, transmitting from J4 keeps the receive path off it — which is why it is the default, and why it is worth a look before the first over.

If a band you use falls back to the unfiltered wideband path on your chosen connectors, the panel names it: J5 receives only up to 70 cm, and HF and 6 m transmit only through J5.

Receive attenuator is 0–14 dB in 2 dB steps. Notch and Fan are the board’s own; the fan is worth having on for any sustained transmitting.

Every control in this section — the connectors, the band, the relays, the attenuator, the notch and the fan — applies to the board immediately, with no Apply and no restart. Only Connected by and the serial port rebuild the session, because which cable the board is on is settled when it is opened. Each accepted transaction is logged in full (what the board was told, and that it agreed), which is what to look at first if the front end answers but nothing comes through.

Not verified against hardware. No LimeSDR has been attached to this code. The wire-level facts come from LimeSuite’s headers and source and from a measured struct-layout check against the installed library; what cannot be checked without a board is whether the streams behave as documented, how long a LimeRFE band change really takes, and whether the LimeRFE’s port rules match its datasheet in every case. Copy diagnostic report on this tab is the thing to send: it dumps every library call this session made — what was asked for and what LimeSuite said — with the LimeRFE’s own transactions beside it, on either of its cables. cargo run -p sdroxide-lime --example probe does the radio half from a terminal.

The console log is the other half, and it is where an over is described: start sdroxide from a terminal to see it. RUST_LOG=info sdroxide is enough for the transmit and LimeRFE lines; RUST_LOG=sdroxide_lime=debug,sdroxide_limerfe=debug,info adds every retune. On Windows, run sdroxide.exe from cmd or PowerShell rather than from Explorer, or the console goes nowhere.

See “LimeSDR and LimeRFE permissions” in the README for the Linux udev rule — the LimeSDR itself needs nothing from this project, because LimeSuite ships its own rules.

6.2.18 HydraSDR RFOne (USB)

A HydraSDR RFOne, driven directly over USB by sdroxide’s own pure-Rust driver. No SoapySDR, no libusb and no libhydrasdr, so this interface is in every build variant on every platform. 24 MHz to 1800 MHz, receive only.

A fork of the Airspy R2, not a relative of it. libhydrasdr still carries libairspy’s 2014 copyright header: vendor requests 0–26 line up number for number, the gain curves are byte-for-byte identical, and the receiver is built the same way — a real ADC whose wanted signal sits at a quarter of the sample rate, with the host doing the downconversion.

It has its own interface all the same, because the two drivers cannot drive each other’s hardware. The RFOne takes an eight-byte tuning command where the Airspy takes four, and a receiver programmed by the wrong one tunes somewhere nobody asked for without saying so. sdroxide checks: pick the wrong interface for either radio and you are told the name of the right one.

Permissions. Linux needs the packaged udev rule — see “HydraSDR RFOne permissions” in the README. Windows wants WinUSB via Zadig or HydraSDR’s own package. macOS needs nothing.

Receiver, and the shared USB id. Rescan lists what is on the bus. Production boards enumerate as 38af:0001; the prototypes came up on 1d50:60a1, which is the Airspy R2 and Mini’s own pair. sdroxide separates them twice — by the USB descriptors during the scan, which opens nothing, and by the firmware version string after opening, which is the check HydraSDR’s own library makes. A board on the legacy id is marked as such in the list. The serial is matched on its suffix, so the last eight digits are enough; the HYDRASDR SN: prefix the descriptor carries may be left on or taken off.

Sample rate, and the four the receiver will not admit to. Seven rates: 12, 10, 8, 6, 5, 4.096 and 2.5 Msps. The receiver reports three of them — 10, 5 and 2.5 — and says nothing about the other four, which live in a second table in its firmware and are reached by naming the ADC rate directly. The menu marks which is which. If a particular firmware turns out not to carry an alternate it answers with a refusal, and sdroxide falls back to the nearest listed rate and says so on the status line rather than leaving the span quietly wrong.

Underneath, the receiver runs at twice the rate shown, for the same reason as the Airspy R2 above: its ADC is real rather than complex, and sdroxide makes complex baseband from it on the host with a quarter-rate translate and a half-band decimator. The same two consequences follow — the receiver’s own DC offset lands at the edge of the span rather than its centre, and image rejection is full across the inner 80 % of the span and progressively less at the edges.

Changing the rate reopens the receiver: the rate moves the tuner’s IF and the clock dividers together, so it cannot be changed under a running stream.

RF input. The RFOne brings out three sockets, and this is where you pick between them:

Socket Notes
ANT The antenna SMA. The only one with a bias tee behind it.
CABLE1 A plain input.
CABLE2 A plain input.

The bias-tee switch is greyed out on the two cable ports, and moving to one turns it off. That is the hardware’s arrangement, not a caution: the DC is on the antenna port alone, so a switch that stayed on elsewhere would be claiming power that is not there.

Gain is a step along a curve, not three sliders. The R828D has an LNA, a mixer and a VGA, and setting them independently is a good way to build a receiver that either overloads or hisses. Two curated curves run all three together — the same two the Airspy R2 publishes, and the same numbers:

Curve Use
Linearity Least intermodulation for a given sensitivity. The right default on an antenna with broadcast stations nearby.
Sensitivity More gain for weak signals, less overload margin.

The Gain slider is a step from 0 (quiet) to 21 along whichever curve is selected. It is not a dB figure — how much a step is worth depends on the curve and the band.

Tuner AGC. The tuner has its own loops for the LNA and the mixer. They are off by default, and for a reason: with one running, the gain slider no longer sets the stage that loop owns — the loop overwrites it a moment later. Use one or the other, not both.

12-bit packing. On by default, and worth leaving on. The receiver can pack its 12-bit samples three-to-a-word instead of padding each to 16 bits, which is a third less USB traffic — and this is a USB 2.0 device carrying up to 36 MB/s packed against 48 unpacked at the top rate. Firmware too old to have the request streams unpacked and sdroxide says so. Applies on reconnect, because it changes how every transfer is decoded.

Bias tee. DC on the antenna port for an active antenna or preamp. Off by default, and only available on ANT.

DC removal. On by default. Turn it off to see raw hardware output, which is the quick way to tell a driver problem from a DSP one — but see above for where the spur goes when you do.

Not yet verified against real hardware. If it misbehaves, the Radio tab’s Copy diagnostic report button records every command exchanged with the receiver, which firmware and which board answered, the sample-rate arithmetic (which is where a span that is half or double what it should be would show, and which of the two rate tables a rate came from), and the first samples both as raw 12-bit values and decoded as I/Q pairs. cargo run -p sdroxide-hydrasdr --example probe does the same from a terminal.

6.2.19 KiwiSDR / Web-888 (network receivers)

A KiwiSDR, or the Web-888 board its listing calls a KiwiSDR 2 — the ~870 0–30 MHz receivers published on rx.kiwisdr.com, and any private one running the same firmware. Receive only.

Give it an address and press Apply / reconnect. The port defaults to 8073, but a receiver reached through the project’s own proxy — at a something.proxy.kiwisdr.com address, which is nearly half the public ones — answers on 80 instead, so give the port explicitly.

Test connection reads the receiver’s status page over HTTP — it does not open a session, so it takes none of the receiver’s channels — and says what it is, what it covers, how many channels are free, and whether its operator allows connections from apps other than a browser at all.

To find a receiver rather than type one in, use PUBLIC SDR in the System box: 15.21.

6.2.20 RigExpert Fobos SDR (USB)

A Fobos SDR, driven through RigExpert’s own libfobos. Receive only.

The library is found at runtime, not linked. libfobos is LGPL-2.1 and open source (github.com/rigexpert/libfobos), but sdroxide loads it the same way it loads the SDRplay API and LimeSuite — by name, when you open the interface. The reason is build portability rather than licensing: this interface is in every build variant on every platform, nobody needs libfobos installed to compile sdroxide, and a machine without it simply lists no receivers and says what to install. Build and install it from that repository, then press Rescan.

Receiver. Rescan lists what is on the bus; the list is built from fobos_rx_list_devices, which opens nothing, so it is safe to press while receiving. Receivers are named by serial, and leaving the picker on first one found is right for a one-radio shack.

Input: three genuinely different radios in one box. The RF port goes through the tuner — a mixer, an LNA and a VGA — and covers roughly 25 MHz–5.4 GHz. HF1 and HF2 bypass the tuner entirely for direct sampling. HF1 + HF2 runs both at once and combines them.

That split matters more than a socket choice usually does, because the HF ports have no local oscillator at all. The receiver hands back two independent real ADC channels — HF1 in one, HF2 in the other — and sdroxide makes complex baseband from them itself, with the same wideband channelizer the RX-888 uses for the identical problem. Two consequences follow:

Changing the input reopens the receiver: RF and the HF ports are different hardware paths, and the HF ports build their downconverter at open time.

Sample rate, and why it decides how low you can tune. On RF this is the ADC’s own I/Q rate, picked from the list the receiver reports. Below about 8 Msps the hardware snaps the request up to 8 Msps whatever you asked for; the rate it actually landed on is what sdroxide reports and works from, so the span on screen stays honest.

On the HF ports the figure is a target for the software downconverter, which lands on the nearest power-of-two bin count — so the achieved rate can differ from the one you picked, and again the achieved one is what is reported. The number matters for a second reason: the downconverter selects a band out of a real spectrum, so it can never centre closer to DC than half its own output rate. At 2.5 Msps that floor is 1.25 MHz, which puts the entire AM/mediumwave broadcast band out of reach. The default is 625 kHz for exactly that reason — a floor of 312.5 kHz, below every mediumwave channel.

Ask for a dial below the current floor and sdroxide does not quietly receive something else and label it with the frequency you asked for: the log says the request was below the floor, and the frequency the receiver really landed on is reported back so the panadapter’s own scale agrees with the spectrum under it. A wider view means a higher floor, so if you want both, change the rate rather than fighting the dial.

Changing the rate reopens the receiver, like the input.

HF1 + HF2: cancelling a noise source, or combining two aerials. Selecting this input runs both real channels and puts them through the same adaptive filter the RSPduo’s second tuner and the LimeSDR’s second receive chain use. Cancel is the DSP form of a noise-cancelling phaser: it finds the gain, phase and delay that make a local noise source line up on both aerials and subtracts it. Combine is diversity reception: it adds the two in the phase that reinforces and weights each by how well it hears, which fills in HF fades. The filter is multi-tap, so a null holds across the span rather than at one frequency.

Mode, adaptation rate and HOLD are on the main window’s DIV strip, where you can reach them while listening; Diversity taps is on this tab, with a note of what the length costs. RESTART zeroes the filter and lets it find the null again — it also releases HOLD, because a filter zeroed and left held is parked at zero and stops cancelling anything, which looks exactly like Combine mode and says nothing about why.

Both channels come off one ADC on one clock, so unlike two independent tuners the phase between them is reproducible across a restart.

Clock source. External reference switches the receiver to an external clock; it applies immediately, without a reopen.

What has been verified. All three inputs were checked against a real Fobos SDR by the contributor who wrote the backend, including 38.6 dB of measured cancellation on real aerials. Two ADC rates turned out to be unusable for streaming on that unit even though the receiver accepts them — 40 Msps never streams at all, and 50 Msps streams but distorts audibly — and the rate selection steers around both. The cost is a practical ceiling around 10 MHz for the widest HF views; wider targets need a faster ADC than the safe rates provide.

6.2.21 USB audio radio (sound card only)

For a radio sdroxide cannot control at all — a handheld, a walkie, a USB dongle rig — but can hear and talk through. Nothing is commanded: no frequency, no mode, no PTT. There are two sound cards and the radio’s own VOX.

Receive (radio → PC) is the card the radio’s headphone or speaker socket feeds, and Transmit (PC → radio mic) is the card whose output goes into the radio’s mic socket. Pick both by name; the lists are the cards on the machine the radio is plugged into and appear once that machine has answered. Left on the system default, either one is almost never the radio — it is the computer’s own headset or speakers — and the log says so when the radio opens. Apply / reconnect reopens the radio on the cards chosen, handing the old ones back first, so the same card can be picked again or moved to a CAT rig without a restart.

The dial is a label. The radio sits wherever its own knob is, and sdroxide has no way to read or move it. Type the frequency the radio is on into the dial anyway: it is what the log, the spots and the transmit lockout go by. Received audio is already demodulated by the radio, so the panadapter shows a few kilohertz of audio around the dial rather than a view of the band, and the digital modes decode from it as they do on a CAT rig’s demod audio.

Transmit is audio into the mic socket, and VOX does the keying. Turn VOX on at the radio, and set its mic gain so the audio arriving from the computer does not overdrive it. Speech, digital-mode tones and CW (sent as keyed audio tones, MCW) all go out the same way.

Leave the radio on a sideband — USB, the mode FT8 rides — and not in CW. Nothing is commanded on this interface: sdroxide cannot read or move the radio’s mode, so this one is set by hand and it is the setting that makes CW send do nothing while everything on screen says otherwise. MCW is audio, and a radio switched to CW does not modulate what arrives at its sound card — in CW it selects its own keyer instead. So with the radio in CW the tone still sounds locally, the send is still decoded straight back into text, and the transmitter is never touched: no power, no signal, nothing on the air, and no error anywhere. If CW sends and only you can hear it, this is why. Set the radio back to USB. (A CAT rig held on a sideband by sdroxide is the same requirement, 6.2.2.)

Two consequences of a radio that keys on whatever it hears:

There is no S-meter reading, SWR or power readback: the radio has nothing to report them on. If the capture card drops audio because the machine is not emptying it fast enough, the log says how much was lost.

6.3 UI: display preferences and voice announcements

The UI tab: frame rate, scroll/spectrum speed, palette, spectrum background, and the Simple UI / Start in SWL mode switches

The UI tab holds display preferences, stored in config.toml under [ui], and the spoken announcements below them under [speech]:

Under 3D view:

Undocked — modules in their own windows

Any of the big modules can be pulled out into its own OS window:

Set each under its row on this tab — Docked in this window (the default) or Undocked — its own window. Closing an undocked window docks it again, and its size and place are remembered for next time.

You can also do it from the window itself: the 🪟 WINDOWS chip at the right of the radio-tab strip — the row of radio names at the top of the main window — opens a list of the module windows (SP1 — the spectrum, SP2 (AUX) — a second spectrum, Operating panel, RX control, Band & mode), each with a DOCKED / IN ITS OWN WINDOW toggle, and DOCK ALL WINDOWS to bring them all back. The chip is lit while any of them is out of the main window. It acts on the radio you are looking at.

This is the same arrangement as the rows on this tab, from the face of the program — a window arrangement is something you change while watching the program, not while watching a settings page.

Undocking the Controls is the biggest change: the main window loses its top strip and becomes the spectrum and the decoders, while the strip lives in the control window — which is SDRuno’s RX control, and it carries the band keypad and the band/mode selector with it, so the controls and the bands are one window. The keypad is SDRuno’s too: Bands and MHz above, ten keys laid out like a calculator (7 8 9 / 4 5 6 / 1 2 3, with 0 centred underneath), Clear and Enter below. Each key names the band it goes to and the bands rise with the digits, so 1 is 160 m and 9 is 11 m; a press tunes there, staying in the mode you are in. Press MHz and the same keys type a frequency instead — in kilohertz, so 14074 is 14.074 MHz — and Enter tunes it and puts the keys back to bands. The full band list stays beside the keypad rather than behind it: the keypad carries the ten HF allocations, and everything else (60 m, the VHF and UHF bands, the CB channels, the broadcast services) is a chip in the list as it always was. A key for a band your radio cannot receive is greyed, and says which range the radio published. The main window keeps its radio-tab strip and, when nothing is left in it, shows a plain face rather than a black hole (the band selector is already in the control window). Undocking the other two is the same idea one module down. Undocking the Controls does not first flip it to a phone-shaped strip: the control window is a desktop console whatever its own height, because it opens wide and short and a compact strip there was the first thing to look wrong.

Undocking the band/mode selector is the widest surface of all: as a docked column it cannot be much more than 280 pt — the operating panels below it are built for about 680 pt, and a wider column squeezes them — so its window is where the mode sections lay out in five columns (SDRuno’s band panel). Open it from the ⇱ WINDOW chip in the band popup, from the docked column’s header, or from the 🪟 WINDOWS menu. While it is out the docked column is not drawn, so there is one selector on screen; closing the window docks it again.

When everything is undocked there is nothing left of the radio to draw in the main window’s centre, so the band/mode selector fills it rather than leaving an empty panel. A voice mode, which has no operating panel, opens no panel window at all; a notice says so once. The undocked panadapter window carries a large frequency readout with the mode and signal level beneath it, so the second monitor says what you would otherwise glance back at the main window for. A Dock all windows / UNDOCK ALL WINDOWS buttons appear under the rows: one brings every module home, the other puts every module in a window of its own (a module with nothing to show, like the operating panel in a voice mode, opens no window). Each is shown only while it would do something. The same pair is in the 🪟 WINDOWS menu on the radio-tab strip.

Workspaces save a whole arrangement and put it back: under the undocked rows, type a name and SAVE CURRENT to store which modules are in their own windows and where those windows are, then click a saved name to recall it. The × beside a name forgets it, and a name you save again replaces the earlier one. Up to ten — SDRuno’s limit. A workspace is the window arrangement only; what is on is the station’s, not the workspace’s. They live in workspaces.json beside the rest of the configuration.

The tool windows — the scanner, the schedule, the logbook, the spots list, the signal-id guide and the rest — can go to their own windows too. Each carries a small ⇱ WINDOW chip at its top-right: click it and the tool moves into its own OS window (where the chip reads ⇱ DOCK to bring it back). Closing an undocked tool closes it, as the ✕ does when it is docked. A tool window is session-only, like its position inside the main window — where it sat is not remembered across a restart. Their app-ids are sdroxide-tool-<name> (e.g. sdroxide-tool-scanner, sdroxide-tool-mail), so one rule can float them all.

Every menu tool window has one, and each remembers its own size: Settings, SCHEDULE, RECORDINGS, SPOTS, PUBLIC SDRS, the voice keyer, and the AIS / ADS-B / VDL2 / FSQ Contacts and per-mode setup panels. The WEFAX chart viewer is the one exception and stays docked — it belongs to the chart you picked rather than to the menu, so it opens and closes with that chart.

Settings is the one worth putting on a second monitor: it opens in the middle of the screen the first time and will not be dragged narrower than its tabs can use, so the whole box survives a move rather than becoming a column of clipped controls.

Tool window Application id
Settings sdroxide-tool-settings
Schedule sdroxide-tool-schedule
Recordings sdroxide-tool-recordings
Spots sdroxide-tool-spots
Public SDRs sdroxide-tool-public-sdrs
Voice keyer sdroxide-tool-voice-keyer
AIS setup sdroxide-tool-ais-setup
ADS-B setup sdroxide-tool-adsb-setup
VDL2 setup sdroxide-tool-vdl2-setup
FSQ contacts sdroxide-tool-fsq-contacts
Digital-mode setup sdroxide-tool-digi-setup

The app does not place the window on Wayland. A Wayland client is given no absolute position, so on niri, sway or GNOME the window opens where the compositor tiles it. To float it and pin it to a monitor, give it a window rule matching its application id:

Module Application id
Panadapter (SP1) sdroxide-panadapter
AUX SP (second spectrum) sdroxide-panadapter-aux
Operating panel sdroxide-panel
Controls sdroxide-controls
Band & mode selector sdroxide-bandmenu
Tool windows sdroxide-tool-<name>

For niri, in ~/.config/niri/config.kdl (use your own output names — niri msg outputs):

window-rule {
    match app-id="sdroxide-panadapter"
    open-floating true
    open-on-output "HDMI-A-1"
    default-column-width { fixed 1200; }
    default-window-height { fixed 720; }
}
window-rule {
    match app-id="sdroxide-controls"
    open-floating true
    open-on-output "HDMI-A-1"
    default-column-width { fixed 1400; }
    default-window-height { fixed 150; }
}
window-rule {
    match app-id="sdroxide-panel"
    open-floating true
    open-on-output "DP-1"
    default-column-width { fixed 560; }
}

On X11, Windows and macOS the position is honoured directly and no rule is needed.

Voice announcements

The last section of the UI tab reads the radio out loud, so it can be operated without seeing it. Tick Speak changes to the radio to switch it on; it is off until you ask for it.

The voice is a neural one that ships with sdroxide and runs on your own machine. Nothing is sent anywhere, no speech service has to be installed, and it works with no network at all.

What to announce, the collapsing section below, is a switch per category. The defaults are what most operators want: frequency, mode and band, VFO and split, AGC, the drive/tune/mic levels, transmit and receive, RIT and XIT, memories and scanning, band-edge warnings, and the engine’s own messages. Filters, squelch and noise reduction are off, because they move constantly while chasing a signal.

Some behaviour worth knowing, because it is deliberate:

Callsigns are read in phonetics — “kilo one alpha bravo charlie” — because a callsign is the one thing that must not be misheard. Frequencies are read the way an operator reads a dial, digit by digit after the decimal point, and always “zero”, never “oh”. Both can be changed under How things are read.

Keys for Speak status, Repeat last announcement, Stop speaking and Announcements on/off are on the Controls tab (6.4) under Speech. They have no defaults; bind the ones you want.

sdroxide also exposes its whole window to the platform screen reader — NVDA on Windows, Orca on Linux, VoiceOver on macOS — so the controls can be navigated and read as well as heard.

Audible alerts

The Alerts tab is the other half of the same idea, aimed the other way: the announcements read out what changed, the alerts ring when a decode matters. They listen to the FT8, FT4, FT2 and JS8 decodes, and they ring whether or not sdroxide’s window is in front — reaching you while you are looking at something else is what they are for. Tick Sound an alarm when a decode matters to switch them on; they are off until you do, and they need your callsign (6.1) to know which calls are for you.

What to sound has a switch, a sound — Ding, Two-tone, Triplet, Warble or Digital, all generated on the spot — and a reply for each of five events:

Event On by default Rings for
A station is calling me yes A decode addressed to your callsign, including a Fox’s RR73 to you in Hound mode
A CQ I could answer no A plain CQ, an activity CQ (CQ POTA, CQ TEST …), CQ DX from another entity, or a CQ aimed at your continent or your country — the same test the decode list uses. Off because a busy band is a hundred of these a minute
New DXCC entity yes A station from an entity your logbook has never had, on any band
New entity on this band yes An entity in the log, but not from this band
New grid square yes A grid square the log has never had

A decode that is several of these at once rings for the first in that list, in the order calling you, new entity, new on the band, new grid, CQ. One batch of decodes rings once, for the most important match in it wherever it sits in the list — a slot full of new stations says no more as sixteen alarms than as one. After it rings, that station stays quiet for that event for a while — a minute for a call, 45 seconds for a CQ, two minutes for a grid and five for an entity — so a new entity calling CQ all evening does not ring all evening.

Tone, voice or both. Each event’s reply is Tone (the alarm sound above, and the default), Voice, or Tone + voice. Voice reads the alert through the spoken-announcement voice (Settings → UI → Voice announcements) — “Juliett Alfa One, calling you”, “Juliett Alfa One, new DXCC, Japan”, “Juliett Alfa One, new one on 20 metres”, “Juliett Alfa One, new grid”. The callsign leads every phrase, so the one thing you act on is never the part that is clipped, and the spoken alert fires from the alarm path, so it too is heard whether or not sdroxide’s window is in front. With the voice switched off a Voice reply is silent — there is no tone to fall back on — so pick Tone + voice if you would rather hear something either way; the sound is greyed on a voice-only row because it is not used. A phrase is not spoken while you transmit, because it would go out through the microphone. And so you are choosing on more than a label: any event that speaks also shows the words it will say beneath it, and its SAY button reads them out through the announcement voice — so you can hear what you are switching on without waiting for the band to produce one. The button is greyed until the reply speaks and the voice is on, and it then says which of the two is missing.

The settings are stored in config.toml under [alerts] and belong to the screen in front of you, like the announcements. On a station with several radios there is one alarm for all of them: every radio tab shares the same settings and the same output. A browser client keeps the settings but has no sound for them yet.

6.4 Controls: keyboard, mouse and MIDI

Everything sdroxide can be told to do is an action — tune, PTT, change band, cycle noise reduction, open the logbook — and the Controls tab binds actions to whatever you would rather press or turn than click. The three sections of the tab (keyboard, mouse, MIDI) all draw on the same list of actions.

Actions come in two kinds, and the Step / mode column changes to match. A continuous action (tuning, volume, filter width) takes a step — the amount one keypress or one detent moves it — and a down tickbox to make that control move it the other way, which is how the left and right arrows share one action. An accel above zero makes a held key move further the longer you hold it. A momentary action (PTT, mute, split) is either Hold — asserted while the key is down — or Toggle, which flips on each press.

6.4.1 Keyboard

The Controls tab, Keyboard section: the shortcut table with its action, step and accel columns

The table lists every shortcut, one per row: the key Shortcut, what it Does, its Step / mode, its Accel, and an On tickbox to disable a binding without deleting it. Click the shortcut button to rebind it, then press the key combination you want (Esc cancels). + Add shortcut creates a row, ✕ removes one, and Restore defaults puts back the shipped set listed in 16. Shortcuts are ignored while you are typing in a text field or a control has keyboard focus.

Push-to-talk deserves a note. No PTT key ships bound, on purpose: a transmitter keyed by accident is the worst thing this feature could do to you. (The voice-keyer digits are bound out of the box — see 2.11 — because a key over an empty slot does nothing, and a new installation has ten of them.) Bind hold-to-talk to Space sets it up in one click. A held PTT is released when you let go, when the window loses focus, when a text field takes the keyboard, and after the Unkey a held PTT after timeout at the bottom of the section (300 s by default, 0 disables it) — so alt-tabbing mid-over drops you back to receive rather than transmitting your office.

6.4.2 Panadapter mouse and mouse buttons

The Controls tab, mouse section: wheel actions, tuning steps, and the mouse-button bindings

Panadapter mouse sets what the wheel does over the spectrum:

Mouse buttons binds the buttons themselves. The left and right buttons are reserved for tuning and panning; the middle and extra (side) buttons are free, so + Add mouse button picks a button, an action and Hold/Toggle — a side button held for PTT behaves like a footswitch.

F1 always opens this manual, even while you are typing, so it is not rebindable. While the manual is open, the arrow, Page and Home/End keys scroll it instead of running whatever you have bound them to, and Ctrl+F / F3 drive its search bar.

6.4.3 MIDI controller

The Controls tab, MIDI section: port selection, the live message readout, and the binding table

Any class-compliant MIDI surface works, and they are the cheapest real VFO knob there is: a DJ controller’s jog wheel tunes, its pads make PTT and band buttons, its faders make gain controls. MIDI needs the native app — the browser client has no MIDI access.

Each row of the binding table is one control: the Control button (click it, then move the control you want — LEARN captures it), what it Does, how it Reads as, its Step / mode, an LED tickbox, and On. + Add MIDI control adds a row and Clear all empties the table.

Endless “jog” encoders send a relative step rather than a position, in one of three encodings that are indistinguishable from small movements. LEARN guesses from the direction you turn; if the knob then tunes backwards, tick rev. A plain fader or knob that sends a position instead should be set to Absolute (fader).

Tick LED on a binding to send the current value back to the controller, so a PTT button lights while you transmit and a motor fader follows the volume. Not every surface likes being written to, which is why it is off by default.

A controller unplugged mid-QSO releases anything it was holding and reconnects by itself when you plug it back in.

Bindings live with the client. They are stored in input.json on the machine running the user interface, not the one running the radio — so a knob plugged into your laptop works just as well against a remote engine (--connect, 8). Keyboard and mouse bindings work in the browser client too; MIDI needs the native app.

6.5 Spots: spot feeds

The Spots tab: DX cluster login, the POTA / SOTA / PSK Reporter feeds, and the Report as (SWL) identity

The Spots tab turns on the feeds that put other stations on your panadapter and in the SPOTS window. What the spots then do — clicking one to work it, the filters, the world map — is §10.1.

FreeDV Reporter is a spot source too, but has its own tab — 6.6.

Where your reports say you heard it. Every network above that you upload to — PSK Reporter, WSPRnet, FreeDV Reporter, the WSJT-CB spot server — is told a locator, and that locator is your own only while the antenna is yours. A radio pointed at an online receiver reports from the receiver’s square instead, and one whose receiver publishes no position reports nothing at all. That is the Antenna is row on Settings → Radio (6.2); it is filled in for you when you take a receiver under PUBLIC SDR.

WSPRnet. Two independent halves, both using the callsign and grid from the General tab:

WSJT-CB spot server. One switch, off by default:

6.6 FreeDV: FreeDV Reporter

The FreeDV tab: FreeDV Reporter station, server and reporting settings

FreeDV Reporter is where FreeDV operators announce where they are listening and who they are hearing; sdroxide talks to it in both directions. What that gets you is §10.5; the tab itself is:

6.7 Uploads: callsign lookup and QSL services

The Uploads tab: callsign lookup, a tab per logging service, and LoTW confirmations

The Uploads tab holds every online account the logbook uses. All of it is stored in plaintext in net.json. How the features behave is §10.2 and §10.3; the fields are:

At the bottom of the tab, APPLY saves everything above, and SYNC CONFIRMATIONS pulls your LoTW/eQSL confirmations into the log.

Testing the credentials

Each upload service’s tab carries its own Test button — Test QRZ Logbook / Test eQSL / Test HamQTH / Test Club Log / Test World Radio League / Test LOG11DX — and there is a Test LoTW beside the confirmation login. It asks that service, there and then, whether the login you have typed works, and prints what came back — a green tick with the account the service recognised, or a red cross with its own words for the refusal.

Without it the first sign that a password is wrong is a QSO that failed to upload, hours after the contact, which is both too late and the wrong place to find out.

Everything the Winlink mailbox needs to identify itself and decide where to forward. What the feature does — the MAIL window, composing, the packet panel — is §11; this is the tab.

All of it is stored in plaintext in net.json, the account password included, exactly as the QRZ, HamQTH, Club Log and LoTW credentials on the Uploads tab are.

The Winlink tab: account, route, gateway list and automatic connection

An account is created the first time a callsign connects to the CMS, and its password arrives as a service message. Winlink validates amateur licences automatically for many countries.

How to connect

Route picks the lane the CONNECT button uses:

Choosing Radio (packet) reveals the gateway fields:

Both Speed and Frequency are applied when the session starts, not when you set them, so nothing moves the dial or the modem out from under you while you are still listening. When a connect does change either one it says so in the status line, and the session transcript names the speed it called at.

My gateways

Winlink publishes its gateway list through an API that refuses every request without an access key sdroxide does not have, so you keep your own list. That is what a packet operator does anyway — the two or three gateways reachable from one location are learned by trying, and they rarely change.

+ ADD GATEWAY saves whatever is in the Gateway, Via, Speed and Frequency fields. Each saved entry shows its digipeater path, frequency and speed; USE loads all four back into those fields, making it the one the next connect calls, and FORGET removes it. A typed callsign works exactly as well as a fetched one would, and if an API key ever arrives the fetched entries land in this same list.

Because each entry carries its own speed and channel, a list holding a 1200 gateway and a 9600 one needs no further setting-up: USE on either puts the modem and the dial where that gateway wants them.

Internet gateway

Client name, and why it is a field you may have to change. Winlink’s production servers accept only client names that have been registered with them, and answer anything else with *** Unknown client types are not allowed on production servers. sdroxide is not registered yet, so out of the box a connection to the production CMS is refused. Until that is resolved this field is how an operator gets in. It is deliberately visible here rather than quietly defaulted to another project’s name.

Automatic connection

Connect on a timer polls for mail on its own, Every n minutes (5 to 1440). Off by default: a forwarding session keys the transmitter when the route is Radio, and nothing here should start doing that unasked.

APPLY

APPLY persists the account and hands it to the mailbox. Like every other network tab, the fields above are edited in a scratch copy until it is pressed — so an account typed in and left unapplied will look saved and still fail with “set a Winlink callsign and password” when you press CONNECT.

6.9 Servers: letting other programs drive the radio

The Servers tab makes sdroxide the radio for other software. Three sections share the tab, one above the other, and all can run at the same time.

Which server should I use? rigctld carries control only and is understood by nearly everything. The built-in TCI server additionally carries receive audio, transmit audio and a wideband IQ stream, but only a handful of programs speak it. The WSJT-X UDP broadcast is not a control surface at all: it is how loggers and mapping tools learn what you are decoding and working.

Neither control protocol has any authentication, which is why both default to 127.0.0.1.

With more than one radio configured (§2.17), each radio has its own copy of this tab and its own servers — a client connects to a port and gets that radio, so two copies of WSJT-X on two ports can drive two radios at once. Additional radios start with the TCI server disabled, since its default port is already taken by the first radio’s: enable it and pick a free port here.

6.8.1 Hamlib rigctld server

The Servers tab, Hamlib rigctld section

Most amateur software reaches a radio through Hamlib, over the network protocol its rigctld daemon speaks. sdroxide serves that protocol directly, so WSJT-X, fldigi, JS8Call, N1MM, Log4OM, GPredict and CQRLOG can drive it with no extra daemon, no serial cable and no virtual COM port pair.

The status line shows whether the server is listening, on which address, and how many clients are connected. Press APPLY to save and (re)bind. If the bind fails on 4532, the usual cause is a real rigctld already running.

Supported: frequency, mode and passband, PTT, VFO A/B and split (including split frequency and mode), RIT and XIT, the RFPOWER / AF / MICGAIN / STRENGTH levels, the NB / NR / ANF / MUTE functions, the XCHG / CPY / TOGGLE / BAND_UP / BAND_DOWN / TUNE VFO operations, and the voice keyer (send_voice_mem 1…10, stop_voice_mem — see 2.11). The voice keyer obeys Allow clients to transmit like PTT does.

Setting up clients:

sdroxide reports every digital mode (FT8, FT4, FT2, PSK, RTTY’s neighbours, SSTV, RADE…) as Hamlib’s PKTUSB, because that is what they are on the air. Clients that read the mode and periodically write it back — WSJT-X does — therefore cannot knock a running FT8 session out of its mode: setting the mode already reported changes nothing.

6.8.2 Built-in TCI server

The Servers tab, built-in TCI server section

sdroxide also is a TCI server, so TCI-capable programs can use it as their radio: frequency and mode control, a wideband IQ stream, receive audio to decode, and transmit audio to put on the air. It is on by default.

The green status line shows whether the server is listening, on which address, and how many clients are connected right now. Press APPLY to save and (re)bind.

Setting up WSJT-X: under Settings → Radio, choose the TCI Client RX1 rig, put sdroxide’s address in TCI Server (e.g. 127.0.0.1:50002), set PTT to CAT, and tick TCI audio so both audio devices come over TCI. JTDX and MSHV are configured the same way. Verified against WSJT-X on this address.

If a client won’t connect, run sdroxide with RUST_LOG=sdroxide_tci=debug — the whole TCI conversation is logged in both directions, which is usually enough to see which command it gave up on. WSJT-X also records the reason in ~/.local/share/WSJT-X/wsjtx_syslog.log (handle_transceiver_failure: reason: …).

A few things worth knowing:

6.8.3 WSJT-X UDP broadcast

The logging ecosystem around FT8 — GridTracker, JTAlert, N1MM+ and Log4OM — learns what a station is doing from the datagrams WSJT-X sends on UDP port 2237. sdroxide sends the same ones, so those programs work with it unchanged: decodes as they arrive, station status (frequency, mode, who you are working, what you are about to transmit), and every completed QSO — as both the structured message and an ADIF record, so a logger can take whichever it prefers.

Every completed QSO, not only the digital ones: a contact typed into the logbook window goes out on the same two datagrams the FT8 sequencer’s own contacts do, so a logger that takes its log from this socket — MacLoggerDX, RUMlogNG, N1MM+ — sees the SSB and CW as well. An ADIF import is deliberately silent: a file of last year’s contacts is not a contact being made.

Changing band tells the clients to empty their decode windows, exactly as WSJT-X does on its own band change — otherwise a logger goes on showing the band you have left, which is the one list sdroxide’s own window has just been taken out of. Tuning about within a band sends nothing, and WSPR band hopping is exempt.

This one is output only: nothing is read from the socket, so no program on it can tune or key the radio. Programs that want to drive sdroxide use rigctld or the TCI server above.

N1MM+ contactinfo sits on the same page, with its own switch and its own port, because a logger that speaks one of these dialects is deaf to the other and a station may want both. It sends the same news in N1MM’s words: one XML contactinfo datagram per logged contact, hand-entered contacts included. There is no decode stream in that protocol, so contacts are all it carries.

The contest fields N1MM’s format carries — section, precedence, check, multipliers and points — go out empty, and deliberately. Each means whatever a particular contest’s rules say it means, and a number invented here would be a claim about a contest that was not being worked; the logger receiving the contact is the thing that knows the rules.

6.10 TLE: satellites and their frequencies

The TLE tab decides which satellites the tracker in the 3D view (7) follows, and what frequencies it shows for them.

Out of the box it follows the amateur radio group and the ISS. Both are ordinary subscriptions, so unlike earlier versions they can be switched off, filtered, given orbit rings or pointed somewhere else — and anything else worth tracking can be added beside them: a weather satellite, a cubesat too new to be in the amateur group, a fresher element set than the one that arrived, or a frequency the built-in table has wrong.

Everything on this tab is saved the moment you change it — there is no APPLY — into satellites.json. The 3D view picks changes up on its next frame.

The file lives with the radio engine, not with the screen: the subscribed listings are fetched and cached on that machine, which in server mode is also what feeds the browser’s 3D view. So this tab configures the same set of satellites from anywhere — the shack machine, a native remote client, or a browser tab — and UPDATE NOW asks the engine to do the fetching.

6.9.1 Subscriptions

The TLE subscriptions management

A two-line element set is only good for a few days: SGP4 accuracy decays quickly, and sdroxide refuses to propagate elements more than a fortnight past their epoch at all. So anything you mean to keep tracking wants a subscription — a URL serving an element-set listing, refetched on the same six-hourly cadence as the amateur set.

Each row has:

The status beside each row is what the last fetch actually did: how many satellites it yielded and how old the listing is, or why it failed.

The CelesTrak groups buttons below add the common listings in one click. A lit button means you are already subscribed:

button What it is
Amateur radio Every amateur satellite. On by default — this is what the tracker used to fetch unconditionally.
ISS The ISS on its own, from its own element set. On by default: fresher than the copy inside the amateur group, and it keeps working if you unsubscribe from that.
Weather The NOAA APT and Meteor LRPT birds on 137 MHz
CubeSats Everything cubesat-sized, including amateur payloads too new for the amateur group
Space stations The ISS, Tiangong and the vehicles docked with them
Last 30 days’ launches Where a brand-new amateur satellite turns up first
Geostationary The geostationary belt, QO-100 among it
GNSS GPS, Galileo, GLONASS and BeiDou

The two default ones are added the first time this version runs and then left alone: unsubscribing sticks, and if you have already customised one — renamed it, turned its orbit rings on — your version is kept rather than replaced.

Subscribing to a group does not put ninety orbit rings on the globe: both default subscriptions arrive on the Orbits setting that suits them, so the amateur group shows the curated few with rings and labels and everything else as dots behind ALL SATS — exactly as it behaved when it was built in.

Subscriptions refresh while the 3D view is open, which is the same rule the rest of that window’s network activity follows (7). UPDATE NOW fetches them all immediately without opening it. Fetched listings are cached on disk, so they survive a restart and keep working offline.

6.9.2 Pasted element sets

The manual TLE input area

For a one-off, paste the two- or three-line set straight into the box and press + Add pasted. Both forms are understood, several at once are fine, and pasting a set for a satellite already listed refreshes that entry rather than adding a second one.

Each row shows its catalogue number and how old the elements are — green while they are fresh, amber past three days, red once they are too stale to propagate. Press ✎ to see and correct the two lines (in a monospace font, because the format is column-addressed and a misaligned paste is otherwise invisible). A malformed entry says what is wrong with it instead of quietly never appearing in the sky.

Pasted satellites are always drawn with their orbit ring and label: typing a TLE in by hand is a clear enough statement of interest. They also override a subscribed element set for the same satellite, so this is how you put a fresher ISS TLE in front of the one CelesTrak served this morning.

6.9.3 Frequencies

The TLE frequency management

These are the rows the pass table shows underneath a pass (7). Give a catalogue number and press + Satellite: if the built-in table knows it, the entry starts as a copy of it, so correcting one frequency does not mean retyping the beacon and the transponder as well.

Each link is a row: what it is, the downlink, the uplink, the mode, and a note for anything you have to know before keying up. A frequency is either one number (145.800) or a transponder passband written 145.950-145.970. Leave a direction blank for a beacon.

An entry here replaces the built-in one for that catalogue number outright rather than merging with it — which is why a new one starts from a copy. Delete every link in an entry and it disappears, and the built-in table shows through again.


6.11 T/R switch: protecting the receiver on transmit

An SDR sharing an antenna system with a transmitter has to be disconnected before the transmit RF appears. A receiver that is fine on a microvolt does not survive a hundred watts of it.

The usual answer is a relay: a coax relay that disconnects the SDR and grounds its input, an outboard T/R switch, or the receive-antenna port on an amplifier. This tab drives one — and sequences an amplifier or a second relay with it — so the contacts always close before your transmitter comes up and open after it has stopped.

Read 6.11.5 before relying on this feature.

6.11.1 What it can drive

Hardware What it is
USB relay board (serial) The cheap boards sold everywhere: LCUS-1/2/4/8 (a CH340 in front of a microcontroller), KMtronic, and Numato Lab. They appear as a serial port; pick the port and the make.
Serial RTS/DTR line A contact closure on any USB-serial adapter, a DigiRig, or a home-made opto-isolator. What every outboard sequencer with a PTT input wants — W6PQL, DX Engineering, Array Solutions. Contact 1 is RTS, contact 2 is DTR.
USB relay board (HID) The “free-driver USB control switch” family, sold under MagiDeal and a dozen other names, 1 to 8 channels. No driver on any platform.
CM108/CM119 sound-card GPIO The pins on a cheap USB “rig interface” — DRA boards, the RB-USB RIM, the AIOC. Pin 3, the one every design brings out. The audio the card is carrying for your radio is on a different interface and is not disturbed.
Linux GPIO line A Raspberry Pi header, or any board with a /dev/gpiochip*.
External command Runs a program on key-down and another on key-up. For everything with a command-line tool and no protocol worth building in: Denkovi’s boards, microHAM, usbrelay, a script of your own.

On Linux the two USB kinds need permissions the distribution does not grant. Install the packaged rule and replug:

sudo cp packaging/linux/60-sdroxide-relay.rules /usr/lib/udev/rules.d/
sudo udevadm control --reload

Serial relay boards need nothing from that file — they are serial ports, so add yourself to dialout as you would for a CAT cable.

Every packaged rule — this one and every receiver’s — grants access two ways: an ACL for whoever is logged in at the seat (TAG+="uaccess"), and a group for everyone else. The ACL grants nothing where there is no seat to be logged in at — WSL2, a headless machine over ssh, a container, or sdroxide running as a systemd service — and the device stays root-owned with nothing on screen saying why. In that case join the group the rule names (plugdev for USB receivers and HID relay boards, gpio for GPIO lines, dialout for serial), then log out and back in:

sudo groupadd -f plugdev && sudo usermod -aG plugdev $USER

6.11.2 Contacts and the sequencer

Each row in the Contacts table is one switched contact:

The order is the timings. There is no ordering column because there does not need to be one: at key-down every contact closes at its own lead before the RF, so the longest lead goes first; at key-up every contact opens at its own hold after the RF, so the shortest hold goes first. Give the antenna relay the longer lead and the longer hold and the amplifier the shorter of each, and you have a sequencer:

  antenna relay   ────────█████████████████████████████──────
  amplifier key   ─────────────█████████████████──────────────
  RF              ──────────────████████████████─────────────
                        ↑     ↑                ↑     ↑
                   antenna  amp key         amp off  antenna
                   throws                            returns

The panel spells the resulting sequence out in one line under the table, so you can see what you have bought without working it out.

Choosing a Job fills both in with numbers that sequence correctly: 10 ms and 20 ms for the antenna, 5 ms and 0 for an amplifier. A small coax relay throws in 5 to 15 ms. Longer than it needs to be costs you something real: transmit waits for the longest lead, so a large value is an audible gap at the end of the receive audio and a delay between your thumb and your own transmitter. Anything over 250 ms is ignored. The hold is free by comparison — letting the antenna back a moment late costs nothing, and letting it back early costs a front end — so when in doubt, lengthen the hold rather than the lead.

If it will not answer decides what happens when the hardware stops responding. Refuse to transmit is the default, and it behaves like the SWR guard: the over is refused with a notice rather than sent into an unprotected receiver. Transmit anyway, warn is for a station running a few watts into a preamp bypass, where a loose USB cable ending a contest is the worse outcome.

6.11.3 The transmit sense input

When you key a transceiver at the radio — its own microphone button, a foot switch, VOX, or its keyer — sdroxide does not know until it next asks over CAT. That question rides the meter poll, so the answer arrives a few hundred milliseconds into the over, and the relay throws then.

The fix is a wire. Bring the rig’s SEND / PTT / accessory key line, through an opto-isolator, into a handshake input on the same serial port that drives the relay, and set Line to CTS, DSR or DCD. sdroxide watches it every five milliseconds, so the over is seen almost at once — and not only by the relay: the meter switches to transmit, and the interlock that stops sdroxide keying on top of you starts working, at the same speed.

Most opto-isolated interfaces pull the line down when the rig keys, so leave Transmitting is a high line off unless yours does the opposite. On a station with more than one radio, Belongs to radio says which tab the sensed transceiver is.

6.11.4 Wire it so that a dead relay is the safe one

This is the only fail-safe that survives sdroxide not running, the USB cable being pulled, or the computer being off — and no setting can substitute for it.

Choose TX closes so that the de-energised contact is the state you want when nothing is running:

With a real amplifier behind it, take the first.

6.11.5 What this cannot do

It cannot protect from transmissions initiated at the radio itself.

Keying from sdroxide is the arrangement this was designed for: the contacts lead the RF by construction, because the transmit path waits for them. Set your rig’s PTT method on the Radio tab and press PTT here rather than on the microphone, and the guarantee holds every time.

A transmission initiated at the radio is different. Without the sense input above, sdroxide learns of it a few hundred milliseconds late; with the sense input, in a few milliseconds — but even then the relay itself still has to throw, after the RF has started. No program on a computer can make that zero.

For a receiver genuinely worth protecting, use an RF-sensed hardware T/R switch as well. It costs a fraction of the SDR and it does not depend on a computer being awake. What this tab gives you is sequencing, an amplifier interlock, and protection on every over sdroxide keys — which on a digital-modes or remote station is all of them.

An HPSDR operator already has a hardware-timed version of the same thing in the J16 open-collector outputs; see 6.2.3.

6.11.6 If it does not click

6.11.7 Band decoder outputs

A contact’s Job can be Band decoder (filter / transverter) instead of grounding the antenna or keying an amplifier — for a station with per-band external hardware in front of the radio: a bank of band-pass filters on receive, low-pass filters on transmit, or a transverter selector, on a PlutoSDR, a LibreSDR, or anything else that has no band-aware output of its own (issue #442). The same idea as an HPSDR board’s open-collector band code (6.2.3), generalised to whatever this relay hardware actually is — a USB relay board (serial or HID), a GPIO header, or the two RTS/DTR lines. Not a CM108 pin or an external command: each of those is a single on/off for every contact, so a band’s RX word would key it for as long as you were receiving there, and the settings refuse the combination.

A retune moves a band-decoder contact the instant the band changes. Keying is different: going from a band’s RX word to its TX word is an on-air edge like any other, so a band-decoder contact has a Lead and a Hold of its own and is sequenced exactly like the antenna relay and the amplifier — a transmit-only low-pass filter is in circuit its lead before RF, and out only its hold after. Its lead counts toward how long transmit waits. That is true even of a contact whose RX and TX bits agree, because a split across bands changes every one of them at key-down. It shares the same board as any ordinary on-air-driven contact without disturbing them.

Once at least one contact has the role, a Band decoder outputs table appears below the sequencer. One row per band, two control words each — RX and TX — read the same way the HPSDR OC table is: bit 0 is contact 1, bit 1 contact 2, and so on up to contact 32. Give RX and TX the same value for a filter that does not care which way the RF is going; give them different ones for a receive-only preamp bypass or a transmit-only LPF bank that must not be in circuit on receive. A band left at 0x00 asserts nothing. The Outputs asserted column names the contacts a word actually closes, so you never have to work the bit pattern out by hand.

The RX word is the receive dial’s band, on the primary radio — the bank belongs to the station. The TX word is the transmit dial’s band of whichever radio keyed, so on a multi-radio station the filters follow the radio that is actually transmitting, and a split operator’s follow where the RF is going. Retuning the transmitter during an over does not move a filter that is carrying RF: the new band is taken after that over’s hold, or at the next key-down. Behind a transverter table that is the true dial, the same one the HPSDR OC decoder follows: the filters, relays and transverter this switches belong to the band on the air, not to the intermediate frequency underneath it.

6.12 Profiles: saved station setups

A profile is a named snapshot you take on purpose — contest, DX, nets, a band plan — of how the station is set up, and Apply puts all of it back in one click. Type a name on the Profiles tab and press Save; the list below has Apply and ✕ (delete) for each saved one. Saving under a name that already exists replaces it (names are matched without regard to case).

What a profile holds:

What it deliberately leaves out is the hardware: the interface, the sound devices and the converters are properties of a radio, not of a way of working it, so a profile follows you across the rig you always sit at rather than dragging yesterday’s sound card behind it. Applying one retunes rather than reopens anything.

Apply is refused while the station is on the air — by any route, including a rig keyed at its own microphone — since it moves the dial and the transmit setup under the over. The callsign, messages and band stacks are station-wide, so on a station with several radios applying a profile on one changes them for all of them, as editing them does.

Profiles are kept in profiles.json on the machine the radio engine runs on (§13), shared by every radio of the station, and a remote or browser client sees, saves and applies the same list.

6.13 Audio: your sound, the radio’s, and recordings

Sound used to be in four places under four names: your speakers and microphone on General, the rig’s sound card on Radio — and differently again on each interface — speech on UI and the alert tones on Alerts. None of that was wrong; it just could not be found as one thing. This page is one thing, and the organising idea is whose audio it is rather than which file it is saved in.

Your audio — the speakers you listen on and the microphone your voice goes out through:

These belong to this machine and to you, not to any radio, so they are the same whichever radio you are working. Both device rows default to System default and can be changed live. In config.toml they are audio_output, audio_routing and audio_input.

In a browser the page says so. A browser tab has no device list to offer — the page asks your browser for the speakers and the microphone, and the choices live in the browser’s own site settings. The radio’s sound card, further down this page, still applies.

This radio’s audio — the sound card between this radio and this computer:

A receive-only radio (the ATS Mini) is offered no transmit row, and an SDR is offered no sound card at all: neither has one, and a row that cannot do the thing is worse than no row.

These are per radio, and they always were. Two rigs running at once use two sound cards at once, so these rows edit the radio you opened Settings from — the one on the tab you opened it from. They moved off the General page in 1.6.9 for that reason (issue #474) and are here now because this page gathers sound in one place; radio.json never changed.

You can type a device name. Every picker is a list and a text field. The list is what the host’s audio API enumerates, and a sound server can hold devices it does not report — a PipeWire node is the case this fork knows about, and enumerating those is the open half of the Bluetooth microphone work. A picker that can only be pointed at leaves you with no way to name a device you can hear. Type the exact name the sound server uses; an empty field is the system default.

Recording — the folder the MP3 recordings, the scheduled recordings and the raw I/Q captures are written to, with CHOOSE… to pick another and DEFAULT to go back to the music folder (<Music>/sdroxide, or the config directory’s recordings where the system exposes no music folder). It is a path on the machine the radio is attached to, so it is shown only where the engine is in this process. In config.toml it is recordings_dir.

The rest of the recording controls are not here on purpose: Quick clip, Stop after and Auto-record answer a question about this session, so they live on the REC chip where you press them rather than becoming a setting you have to remember you changed.

7. Solar system 3D view

The ☀ 3D button in the Display module opens the solar system in three dimensions — the Sun, the Earth and the Moon, the other seven planets and eighteen of their moons — with live solar imagery, sunspot regions and coronal-mass-ejection trajectories. This enables operators to see if anything is on its way here, and when it will arrive.

In the native app this is a second window. In the web client it is a second browser tab, with the same controls, the same layers and the same QSO visualisation; there, the data below is fetched by the server and relayed to your browser rather than fetched by the browser itself. Several people may watch the map at once — it controls nothing, so it does not take the single control connection — but they share one feed, so changing the SDO channel changes it for everyone watching.

The window itself. There is one 3D window, and it belongs to the program rather than to a radio tab. Switching to another radio leaves it up; opening the 3D on another radio moves it there and closes the previous one, so a session cannot accumulate them. Where you leave it — its size, and its position where the platform reports one — is remembered in this screen’s settings and put back when it is opened again, fitted so it never comes up off the screen. On Wayland a client is not told where its windows are, so only the size is restored and the compositor chooses the place; on a tiling compositor the same applies, and the window keeps the tile you gave it precisely because a tab switch never closes and reopens it.

If the browser crashes. This view is the app’s heaviest graphics consumer — a depth buffer, multisampling and a few dozen draws a frame — and browser WebGPU implementations vary in how well they take it. Firefox on Linux has been seen to abort the whole browser process with this page open. Adding &gfx=webgl to the URL pins the page to WebGL2, which draws the same scene and only gives up multisampling and a little depth precision: http://<host>:4950/?view=solar&gfx=webgl. &gfx=webgpu forces the other way. Without either, the browser’s own preference is used.

The solar disk in AIA 171, with sunspot regions, a flare marker and the CME arrival banner

The Earth carries a higher-resolution version of the same Natural Earth data as the FT8 world map — coastlines, international borders and rivers — lit by the real Sun with a soft terminator. Your QTH is the green ring and the yellow dot is the point the Sun is directly overhead; both appear once you zoom in far enough for a point on the surface to mean anything.

On the night side the cities light up, from Natural Earth’s built-up urban areas: the Ruhr is a sprawl, the Nile is a thread through the desert and the Sahara around it is empty, which is what the photographs from orbit show. It is the one place on this globe where the map stops being a line drawing, and it can afford to be because it is not invented.

The coastlines and borders keep a faint glow of their own on the night side, fading in across the terminator the way city lights do. It is deliberately subtle — the terminator is still the most obvious thing on the globe — but it means the dark hemisphere stays a map rather than a slab, which matters because almost everything worth looking at happens there: the far end of a grey-line QSO, the auroral oval, a satellite footprint crossing at 3 a.m.

The Earth with the FT8 coastlines, the QTH ring and the sub-solar point

7.1 Navigating: the camera, targets and the auto tour

Mouse:

Action Effect
Drag Rotate around the focused body
Scroll Zoom in and out
Click a body or its label Make it the camera’s target

Any mouse input cancels AUTO.

Target — the ◎ button names what the camera pivots around and opens a picker with everything in the system: SUN, EARTH, MOON and E+M (the Earth–Moon midpoint), then a row per planet with its own moons beside it. Choosing a target pulls the camera in to frame it. You can also simply click a planet, a moon or its name in the view — hovering marks the body with a reticle first, so there is no guessing about what a click will grab. ▶ AUTO flies a continuous camera path through various framed viewpoints to make for an informative and visually pleasing display that you could have on a main monitor or projector.

While you are working a station, AUTO leaves the loop and flies down to the contact instead, holding it for as long as the QSO lasts — the readout calls it QSO PATH. The shot is centred on your QTH, the station you are working and the arc between them, from off to one side of the path and at a shallow angle, so the horizon curves across the frame and the arc’s rise off the surface is plain rather than flattened into a line by an overhead view. It frames itself to the path: a neighbouring country is a low pass over the horizon, an antipodal contact pulls back until both ends and the whole arc are in the picture. When the QSO ends the camera rejoins the tour at whichever viewpoint is nearest. Switching the QSO layer off leaves AUTO on its normal loop.

7.2 The layers

Layers — ORBITS (orbital paths, sampled from the real ephemeris, so they are the true eccentric orbits), CLOUDS, PLANETS, CME, SUN OBS, LABELS, SMALL BODIES, QSO, SATS, AURORA, PROP and AWARDS. All but PROP and AWARDS are on to begin with — those two each paint the whole planet (one with a marker on all three hundred-odd DXCC entities, the other with a wash of colour), so they wait until you ask for them. Switching either on stands the other down, because two full-globe washes at once is neither.

SUN OBS is solar observations on the Sun’s disk: the sunspot active regions and the flare source locations, which used to be two buttons and are one idea. The name also settles a collision — everywhere else in this manual, SPOTS means the DX cluster.

The star field and the heliographic graticule (the solar rotation axis, equator and parallels) have no buttons: they are the backdrop and the coordinate frame everything else is read against, and are always drawn.

7.3 The planets, moons and small bodies

The PLANETS layer adds the rest of the solar system: the seven other planets, eighteen major moons, and Saturn’s and Uranus’s rings. Names are shown for every planet however small it is on screen — from anywhere in the inner system Neptune is a fraction of a pixel, and the label is the only thing that makes it findable — and a body’s own name disappears once you have flown close enough to it that the name would be stamped across the picture. A planet’s moons are named once the planet itself is big enough on screen for the names not to pile up.

Where the numbers come from, and how good they are:

  Source Accuracy
Planet positions JPL’s Keplerian element set for 1800–2050 Measured against JPL Horizons over 2015–2045: better than 0.02° for the inner planets, 0.12° for Saturn
Orientations IAU/WGCCRE rotational elements Poles and rotation rates; the small periodic terms are dropped
Moon orbits Circular orbits fitted to JPL Horizons Under 1° of orbital phase for most, up to 4° for Titan and Iapetus, whose real orbits a circle cannot express

The Moon, Jupiter and Saturn are drawn from published spacecraft maps — LRO’s lunar albedo mosaic and Cassini’s global maps of the two giants. The other bodies are procedural: Mars gets its polar caps and dark albedo markings, Io its sulphur yellows, Iapetus its black leading hemisphere. Radii are exaggerated by the body scale like the Earth’s, but capped so that no planet ever outgrows the Sun; each planet’s moons are scaled by the same factor as the planet, so a moon at six planet radii is drawn at six planet radii.

The dwarf planets, asteroids and comets ride on the same PLANETS layer. Forty bodies: Pluto, Ceres, Eris, Haumea and Makemake; twenty asteroids; and fifteen periodic comets.

They are there because the next fifty years turn on them, and that is a query rather than an opinion. tools/fit_smallbodies.py asks JPL’s close-approach database for everything that passes inside 0.02 AU of the Earth between now and 2076 and is big enough to be worth naming — which is how Apophis, 2001 WN5 and 1999 AN10 got in — and adds the bodies anyone would expect to find: the dwarf planets, the large main-belt asteroids, the mission targets (Bennu, Ryugu, Itokawa, Didymos, Psyche, the two Lucy Trojans), and every periodic comet with a perihelion inside the window. Swift-Tuttle is absent for that last reason: the Perseids’ parent does not come back until 2126.

Point the camera at one and the info card gives its distance, its perihelion and aphelion, the length of its year, and one line on why it is in the table — the date and distance of the close approach, straight out of JPL’s database, or the spacecraft that went there.

Finding one is what the box under the clock is for. It searches the small bodies and the satellites together, on name, catalogue number or designation: apophis, 99942, 1P, 2024 YR4. A match is drawn with its orbit and its name whether or not it otherwise would be, and ↵ on a single match flies the camera to it. The asteroids have no layer button of their own on purpose — a button answers “show me all thirty-five of these”, which is not a question anyone has; the question people have is where is Apophis, and that is a search box. The SMALL BODIES button is a different thing: it governs their names, because thirty-five designations at once bury the planets. Whatever it is set to, the body the camera is on and anything the search has matched stay named.

Comets grow tails, and the tails are geometry rather than decoration:

All of it switches on and off with the comet’s distance from the Sun. Water ice stops sublimating past about 3 AU, so a comet spends most of its orbit as a bare dot and lights up for the months around perihelion; the tails grow as the inverse square of the distance and with the cube root of the nucleus radius. Phaethon is the exception that shows the model is doing something: it is a rock, not a comet, and gets a short dust tail and no ion tail at all, inside a fifth of an AU of the Sun where its own surface is being cooked apart.

Use the Time module’s ±1 mo steps to watch it happen — Encke returns every 3.3 years, Tempel-Tuttle in 2031, Halley in 2061.

Where the numbers come from, and how good they are:

  Source Accuracy
Small-body positions A chain of Keplerian arcs fitted to JPL Horizons across 2026–2076 Measured against Horizons: inside 0.16° for every body but Apophis, whose 2029 Earth encounter changes its orbit and leaves it at 0.66° worst case, 0.03° typical
Which bodies JPL’s close-approach database, plus the dwarf planets, large asteroids and mission targets The close-approach dates and distances quoted in the info card are JPL’s, not this model’s
Tail lengths A visual model, stated as one Scaled so Halley at its 2061 perihelion draws the tail Halley actually had; the directions are physics

Outside 2026–2076 the arcs simply run on, which is a two-body extrapolation of a perturbed orbit and decays quickly. Scrub the clock past either end and the info card says so rather than letting the body sit there looking authoritative.

7.4 Clouds

The CLOUDS layer puts the weather on the globe, live, from NOAA/NESDIS’s Global Mosaic of Geostationary Satellite Imagery — GOES-East and GOES-West, both Meteosats and Himawari, stitched into one picture of the planet every hour.

Like the aurora it is drawn as a depth of air rather than as a picture stuck on a sphere, and for the same reason: that is what it is. What makes that possible is the infrared channel. Brightness in the infrared is cloud-top temperature, and temperature is altitude — so the renderer is handed a height field taken from measurement, and a thunderhead stands fifteen kilometres tall over the stratus beside it because it really does. The Sun lights the tops and they shade their own undersides, which is what makes a deck read as three-dimensional rather than as fog, and the limb shows the deck standing off the surface because a grazing line of sight crosses a great deal more of it.

Two channels are fetched. Infrared is the backbone and works in the dark. Visible is a correction on the sunlit half only: low warm cloud is nearly invisible to infrared — the top of a marine stratus deck is within a few kelvin of the sea under it — and obvious in visible light, so where the Sun is up that channel fills in what the first cannot see.

What is real and what is not. The cloud field is measured. The lightning is simulated — and the readout along the bottom of the window says so, because a globe that flickers with plausible-looking strikes must not be read as showing strikes. What comes from the data is where the thunderstorms are, how large, how tall, and how often each should flash: cold-top area is the oldest satellite proxy there is for flash rate and a good one. What is invented is which millisecond a given stroke fires. No free worldwide feed of individual strikes exists to use instead. The flashes light the cloud from inside rather than being drawn as marks on it, so an anvil goes bright from below.

Four honest limits, all of them stated in the readout or visible in the picture:

The vertical scale is exaggerated about six times. Eighteen kilometres on a six-thousand-kilometre planet is a quarter of one per cent of the radius, and a hairline cannot be volumetric; six times over is enough for a storm to stand up out of the deck and shallow enough that nobody would mistake the result for a mountain range. Altitudes are fractions of the radius the globe is drawn at, so the deck stays glued to the surface at any setting of the body scale.

Cloud rendering on the UI settings tab (6.3) chooses how the deck is drawn. Layered stacks slices through the troposphere and is the cheap option. Volumetric walks a ray through it instead, so the Sun casts the cloud tops onto the deck below and a flash glows out through the storm making it rather than only brightening its outside — at several times the cost per pixel. Both draw the same weather.

7.5 The aurora

The AURORA layer puts the auroral oval on the globe, live, from NOAA’s OVATION model — a 1°×1° grid of the probability of seeing aurora, issued every few minutes and valid about forty minutes ahead.

It is drawn as a stack of glowing shells at the altitudes the atmosphere actually radiates at, not as a texture painted on the surface, and everything about how it looks falls out of that. The colour changes with height because the emission lines do: green oxygen at 557.7 nm around 110 km, the forbidden red line at 630 nm hundreds of kilometres above it, and a violet nitrogen fringe underneath when the precipitation is hard — which is why a quiet oval is green and a storm goes crimson at the top. The limb is far brighter than the disk, because a grazing line of sight crosses a great deal more of every shell, giving the thin bright ribbon on the horizon that is the most recognisable thing about aurora seen from orbit. The fine structure runs in arcs along the oval and in rays through the stack, because auroral precipitation is field-aligned. And because the emission is only drowned out by daylight rather than stopped by it, the sunlit half of the oval fades to a floor rather than to nothing — you can still see where it is.

The structure is shaping, not invention: it multiplies what the grid says and can never put aurora where NOAA has none. The green contour on the surface is the honest boundary — the equatorward edge of the 10 % line, straight off the grid, drawn to be compared against your own latitude. It bulges towards the equator on the night side and over the magnetic poles, which is where it really does; the southern oval reaches much lower geographic latitudes than the northern one for exactly that reason.

Aurora panel — under the propagation numbers on the right:

Row What it is
power N/S Gigawatts being deposited in each auroral zone. This is the number that says how big the event is.
activity The same figure as NOAA’s Hemispheric Power Index, 1–10, with a word for it. Yellow from HPI 6, pink from 8.
edge N/S How far towards the equator the 10 % contour reaches in each hemisphere, read off the grid.
your grid square The probability of visible aurora directly over your QTH. Green when there is anything at all, yellow past 10 %, pink past 25 %.
Kp peak 24 h The worst three-hour bin still ahead of you in NOAA’s planetary K forecast, and how far away it is.
viewline Roughly how far towards the equator that Kp puts the aurora, as a geomagnetic latitude. A rule of thumb — see below.

Under the rows is the planetary K trend: one bar per three-hour bin, the observed history behind you flowing into the forecast ahead, so the shape of the last day and the shape of the next are one picture and “it picks up after midnight” reads at a glance. The measured bars are solid and the predicted ones a wash, with the boundary between them marked, because a measurement and a prediction must never be read as the same thing; the foot of the chart says observed | forecast and the ends carry their UTC hour. Green is quiet, yellow worth watching, pink a storm. The footer says what the picture is valid for and how old the fetch is — never what time it is now, because the grid is a forecast for about forty minutes ahead and may itself be half an hour old.

The viewline row is the one number here that is not measured. It is a straight-line fit to SWPC’s published table (66.5° at Kp 0, falling about 2° per unit of Kp) and it says nothing about cloud, moonlight or how dark your sky is; geomagnetic latitude is also several degrees from geographic at most longitudes. The oval on the globe needs none of those caveats, so prefer it when the two seem to disagree.

7.6 Satellites

The SATS layer puts amateur-radio satellites in orbit around the globe, live, propagated with SGP4 from CelesTrak element sets. Ten popular ones are drawn by default with their orbit rings — QO-100, the ISS, AO-7, FO-29, SO-50, AO-73, JO-97, RS-44, XW-3 and IO-117. Geostationary orbits are green, low ones cyan. ALL SATS in the Sun module adds every satellite in the subscribed listings as a plain dot; the orbit rings stay on the curated few, because ninety rings at once is unreadable.

Which satellites arrive at all is set in the TLE settings tab (6.10) — the amateur group and the ISS are subscribed by default, and you can add the weather birds, the cubesats or your own element sets beside them. A set you paste in there is always drawn with its ring and label, and overrides a fetched one for the same satellite. Those fetches happen while this window is open, like every other fetch it makes.

With LABELS on, each of the curated satellites is named with its elevation from your QTH right now — a number means it is above your horizon and workable, ▼ means it is not.

Finding one by name. The search box under the clock takes a designator or a catalogue number — AO-73, o-7, 25544 — and matches are pulled out of the crowd in yellow, with their orbit ring and their name, whether or not they were being drawn a moment ago. That is the point of it: a satellite outside the curated set has no label at all until ALL SATS is on, and then there are ninety unlabelled dots. Matching is case-insensitive and on any part of the name, so a partial designator is enough. The line underneath says how many of the tracked satellites matched; Enter on a single match opens its pass table, and ✕ clears the box. The same box finds the dwarf planets, asteroids and comets — see the PLANETS layer above — and Enter on a single body flies the camera to it instead. It appears whenever either the SATS or the PLANETS layer is on, since those are the two populations it can find anything in.

Aurora and satellite visualization and pass table

Click a satellite’s label for its pass table:

Column Meaning
START / END Rise and set times, UTC
DUR How long the pass lasts
AOS / LOS Azimuth at the horizon on acquisition and loss — where to point, and where it ends up
MAX EL Highest elevation reached, with a word for how good that makes the pass

A pass already under way is shown in green, one starting within the hour in yellow. QO-100 is geostationary, so instead of a table it tells you the fixed azimuth and elevation to point at — it never sets. A satellite whose orbit never reaches your latitude says so rather than showing an empty table. Click the label again, or close the window, to dismiss it.

Predictions come from SGP4 on the current element set, and the window shows how old those elements are. A day-old TLE is good to a second or so on rise time; a week-old one is not, which is why the age is on display.

Below the pass table is the satellite’s frequency list — what to actually tune to once it comes over the horizon:

Column Meaning
LINK What the link is: a linear transponder, an FM repeater, a beacon, a telemetry or APRS downlink
DOWNLINK Where to listen, in MHz. A transponder shows its whole passband
UPLINK Where to transmit, in MHz. — for a beacon, which only transmits
MODE The emission: SSB/CW, FM, BPSK 1k2, DVB-S2, …

Anything you have to know before keying up — a CTCSS tone, an inverting transponder, a bird that only runs to a schedule — is spelled out under the table and repeated as a tooltip on the link name. Remember that these are the nominal frequencies: Doppler moves a LEO downlink by several kilohertz across a pass, upwards on the way in and downwards on the way out. The LOCK ON button above the table hands the satellite to satellite mode, which corrects for exactly that — the locked bird is highlighted on the globe with a line drawn from your QTH to it, and with AUTO the camera frames the two of you through the pass.

The built-in list covers the satellites drawn by default plus a few more, and it is reference data transcribed from the AMSAT list rather than anything derived from the element set — transponders do get switched and schedules do change. Add your own or correct a wrong one in the TLE settings tab (6.10), where your entries override the built-in table. They belong to the station, so the browser’s 3D view shows them too — it is fed by the same engine — and a correction made at the shack machine is on screen in every open tab.

7.7 Your QSOs on the globe

The QSO layer puts your FT8/FT4/FT2 traffic on the globe. Every station decoded in the last two minutes is a white dot that fades as it ages — the same set the flat map in the FT8 panel shows, so the two never disagree. Behind them, every decode of the last hour is an arc from your QTH to the station that sent it, cyan when it is fresh and cooling to violet as it ages out of the trail, with a spark running the newest ones in the direction the signal travelled. That is the band’s shape over the last hour, drawn: which paths were open, and when they opened.

The station you are working is joined to your QTH by a heavy green beam with a ring on each end and a pulse running the path — outwards to them while you transmit, back to you the rest of the time — so the QSO in progress is unmistakable among an hour of traffic. Green is the globe’s colour for your own station: it is what the QTH ring under one end of the arc already wears. A decode you have clicked but not yet answered gets a thin yellow arc. All of them are true great circles lifted off the surface, bowing further out the longer the path: an antipodal contact springs well clear of the planet, which is the only way both ends stay visible at once on a sphere.

The contact card rides the top of that arc. It types itself out a line every half second as the contact runs, and carries what the QSO is:

Row What it says
heading The station you are working.
MODE The mode and the band — FT8 · 20M.
PATH Great-circle distance and your initial bearing to them.
TIME How long the contact has been running.
SENT The report you sent them, which is their signal at you.
RCVD The report they sent you.
SIG Their signal at you in the most recent slot — the live number, which keeps moving after the reports are settled.
GRID Their grid square, once they have sent one.
DXCC The entity their callsign resolves to.

Rows appear only when there is something to put in them, so a contact that has not got as far as exchanging reports simply shows a shorter card. It is pinned to the arc’s highest point in three dimensions rather than to a place on the screen, so it rides the arc as you turn the globe, with a leader down to the point it belongs to. It sits over that point where there is room and flips under it where there is not, and it wears whichever Window style you have chosen (6.3), like every other window and popup. In JS8 the card follows the arc to whoever the composer is aimed at, exactly as the arc itself does.

Activity — the controls for that hour of traffic:

Control What it does
LIVE Follow the band as it happens (where it starts every session).
▶ REPLAY Sweep the replay head from an hour ago to now, over and over, at the chosen speed.
min ago Park the head anywhere in the last hour by hand. Dragging it stops a running replay.
trail How long a decode’s arc stays on the globe behind the head (default 10 minutes).
speed How many times real time the replay runs at (default 60×, so the hour takes a minute).

Wound back off LIVE, the white “decoded just now” dots go away: what is on the globe then is the hour being replayed, not the present, and the two are not mixed. The history is kept only while sdroxide runs, so a fresh start begins with an empty hour that fills as the decodes come in.

7.8 The propagation heat map

Propagation heatmap

The PROP layer paints where signals are actually getting through, band by band, from every mode this station runs. Everything this station hears is evidence about the ionosphere, and it is all pooled into one picture: WSPR both ways, FT8/FT4/FT2 and JS8 decodes, and the logbook. With the Reverse Beacon Network switched on, so is everything everyone else hears. The PROP button above the flat map in the FT8 and WSPR operating panels draws the same thing under the panel map.

What a bright patch means. Each reception is placed at the midpoint of its path — the patch of ionosphere that bent the signal — and not at the far station. That is the whole design: a map of remote stations would tell you where radio amateurs live, which you already know. This tells you where the sky is working. A path longer than about 3000 km came down and went up again, so it gets a control point per hop.

Two displays:

On the flat map the controls are the PROP button above it; on the globe they are the PROP button in the menu bar, which adds the source filter and the half-life. Both draw the same field.

Signal reports are made comparable before they are pooled. WSPR, FT8, FT4, FT2 and JS8 all quote SNR in a 2500 Hz bandwidth, but their decode floors are ten decibels apart — so what is stored is the margin above each mode’s own floor. Without that, the most sensitive mode on the band would paint as the worst propagation on it. WSPR also declares its transmit power, so a 200 mW beacon is credited for the power it did not use. A logged QSO contributes a path and no signal report at all: an RST is not an SNR, and it counts towards how busy a cell is without ever moving its average.

Memory. An observation’s contribution halves every 45 minutes by default (adjustable in the PROP menu). The ionosphere’s own memory is short, and an opening from two hours ago should not be arguing with one from two minutes ago.

What it cannot show. Without the Reverse Beacon Network, only paths this station has been one end of — so a band the radio is not listening to has no evidence at all, however open it is. Oceans light up because the midpoints of long paths fall there, which is the single biggest thing this adds to an ionosonde map — but Antarctica stays dark because nobody is transmitting from it. The legend gives the absolute path count the brightest cell stands for, so the colours are never relative without saying so.

The Reverse Beacon Network layer. RBN is on by default (under Settings → Spots, and it needs only the callsign from the General tab). It reads the network of CW and RTTY skimmers that listen to whole bands continuously, worldwide, and feeds every spot they publish into this same field. That is the one thing that fills in the bands this radio is not on: while you work 20 m, the map can still tell you 15 m is open to South America, because a few hundred other receivers just heard it.

The difference is not subtle. Monitoring 20 m FT8 alone, the propagation field knows about one band; with RBN running it knows about seven within a minute — including a 40 m that the published forecast calls “Poor” and the skimmers show as the busiest band on the air. Where the forecast and the measurement disagree, the measurement is the one that was actually observed.

It comes with a real limitation, and the map keeps it on its own switchable source for that reason. An RBN line carries two callsigns and no locators, and the network publishes no machine-readable list of where its skimmers are — so both ends of every RBN path are placed at their DXCC entity’s nominal centre. For San Marino that is within the blur the map already applies; for the United States or Russia it can be two thousand kilometres out. Turn the RBN button off in the globe’s PROP menu to see the field without it.

RBN spots never appear in the spot list. There are thousands a minute, they would bury every human spot in the window, and they are measurements rather than invitations to call anyone. Narrow the feed with a set/filter line in the RBN settings if you only care about one continent.

The HEARD ≥ row. The propagation panel gains a line under the ionosonde MUF: the highest frequency that has demonstrably got through near your QTH, normalised to a 3000 km path so short and long paths are comparable. It is a floor, not an estimate — the signal got through, so the ionosphere was at least this good; how much better is exactly what a reception report cannot say, because nobody transmits on the frequencies that would have failed. A cell needs two independent paths before it will claim anything, and paths under 300 km are excluded because they may never have touched the ionosphere at all.

The two numbers sit together because they fail in opposite directions: the sounder is a real measurement with dreadful spatial coverage, and this covers the oceans but only bounds. When the observation is above the sounder, the panel says so — the band is better than modelled is the most actionable thing either number can tell you.

The BANDS OPEN chart. The same field, read per band instead of per place, in a box under the propagation numbers on the globe: one bar for each band with anything in it, showing how much of the world that band is currently getting through to. It is the map’s answer to “which band should I be on” without having to turn the globe and compare patches by eye.

What the bar measures is reach — the share of the Earth’s surface with evidence on it, weighted by area so a polar cell does not count for more than an equatorial one. Deliberately not a count of contacts: forty decodes out of one corner of Europe are one direction open, and a count would call that the best band of the evening. The number beside each bar is that share, and the footer gives the top of the scale, which auto-ranges in steps (1 %, 3 %, 10 %, 30 %) rather than stretching the best band to a full bar — a chart normalised to its own leader would draw the same picture on a dead night as on a good one.

Bands stay in frequency order so the shape of the chart is the familiar spectrum, and each bar takes the hue the ALL BANDS view paints that band in. It inherits the heat map’s memory exactly, because it is read off the same decayed field: whatever the half-life is set to is how long a band lingers here after it shuts. The same caveat applies as to the map itself — a band nobody has listened to has no evidence and no bar, which the footer says out loud.

The BANDS table. Under the BANDS OPEN chart is the same table the main window’s BANDS window shows — the published CONDX verdict beside the measured WSPR, PSK, PATHS and REACH, one row per band with anything to say. It is there so conditions can be read from the globe without opening the BANDS window over the main view. The footer names the three sources and whether it is day or night at your QTH. It appears once any of the three feeds has landed, and only on a desktop or tablet layout — a phone puts the space weather behind the WEATHER chip, and this table with it.

The heat map is also relayed to the browser’s 3D tab, unlike the awards layer: it is live data about the station’s own conditions, which is what that relay is for.

7.9 The awards layer

The AWARDS layer paints your logbook’s DXCC coverage on the Earth as a map of what is missing. Every entity in the bundled country file gets a marker at its nominal centre: orange and slowly breathing where you have never worked it, amber where you have worked it but no QSL has come back, and a dim green dot once one has. The gaps are what stands out — an evening’s chase has somewhere to aim. A key in the bottom-right corner counts the three states.

It follows the band filter in the AWARDS window (§10.4), so setting that to 20m repaints the globe as “what am I still missing on twenty”. The layer needs the Earth to fill a fair part of the view before it draws — three hundred markers on a planet a few pixels across is noise, not information — and it is off by default. In the browser tab it is absent entirely: the logbook lives in the main window, and the relay carries live data rather than your records.

7.10 The Sun

Sun — which SDO product wraps the Sun:

Button Product
HMI HMI continuum — white light. This is the one that shows sunspots.
193 AIA 193 Å — corona and coronal holes
304 AIA 304 Å — chromosphere and filaments
171 AIA 171 Å — quiet corona and coronal loops
211 AIA 211 Å — active-region corona
MIX The 211/193/171 composite

↻ fetches everything again immediately. Next to the buttons is the age of the solar image — green when it is current, yellow when the last fetch failed and you are seeing a cached picture, pink when there is nothing at all. It always tells you what you are actually looking at; a cached image is never presented as a live one.

Sunspot markers are sized by each region’s real spot area and coloured by NOAA’s own next-24-hour flare probability — grey for quiet, yellow for likely, pink for a region worth watching. Regions on the far side of the Sun are hidden by the Sun itself, as they should be. CME cones grow from the Sun at the measured speed, so the picture is a direct read-out of where the plasma has got to; a cone drawn faint has its direction estimated from the source region rather than fitted, and cones are coloured cyan through pink with increasing speed.

CME trajectory cones seen from outside the Earth's orbit

7.11 Scale and time

Scale — the Earth is 23 000 times smaller than its distance from the Sun, so at true scale it is invisible whenever the Sun is in frame. body exaggerates Earth and Moon radius (default 20×) and moon orbit stretches the Earth–Moon distance. Positions are never exaggerated — only sizes — so the orbits and the CME geometry stay physically truthful. Body scale is capped against the moon-orbit scale, because past that point the enlarged Moon would render inside the Earth. Every body also has a glow with a minimum on-screen size, so nothing is ever invisible however you set these.

Eclipses — during a solar eclipse the Moon’s shadow falls across the globe: the penumbra as a broad dimming of the daylit side, the umbra as the small patch of night it really is, and the cloud deck darkens under both. The occlusion is computed at true scale — the real Moon, at its real distance, against the real Sun — and painted geographically, so the shadow follows the Earth’s own body scale and ignores the Moon’s exaggerations entirely: however swollen the rendered Moon, the shadow crosses the countries the real eclipse crosses, when it crosses them. The mirror case is drawn too: during a lunar eclipse the Earth’s shadow sweeps across the Moon, and inside the umbra the Moon turns the dim copper every photograph of a total lunar eclipse shows — sunlight bent through the ring of the Earth’s atmosphere, not blackness. There is no layer button for any of this, because when there is no eclipse there is no shadow — which is almost always. The total solar eclipse of 12 August 2026 (Greenland, Iceland, northern Spain, greatest at 17:46 UTC) is the nearest occasion for the one; the total lunar eclipse of 3 March 2026 (greatest at 11:33 UTC) was the most recent for the other.

Time — NOW, −24h, −6h, +6h, +24h scrub the whole scene, bodies and all, forwards and backwards.

Clock — a UTC time readout sits in the top-left corner. Scrubbing the time with the ±6h/±24h buttons turns it yellow and relabels it SIM, denoting
that the time displayed is not the current real time.

7.12 The propagation panel

Propagation panel — top right, the numbers worth checking before you call CQ:

Row What it is
MUF Maximum usable frequency for a 3000 km path near your QTH, interpolated from the ionosonde network. Green above 24 MHz, cyan above 14, yellow below.
HEARD ≥ The highest frequency that has demonstrably got through near your QTH, from what this station has actually decoded, normalised to a 3000 km path. A floor, not an estimate — see §7.8. Only appears once two independent paths agree.
Kp / A Planetary geomagnetic indices. Green when quiet, yellow from Kp 4, pink from Kp 5 (a storm — polar paths degrade and aurora becomes possible).
F10.7 10.7 cm solar radio flux in solar flux units, the standard proxy for ionisation. Under about 90 the high bands stay shut; over 150 they open up.
X-ray Current GOES soft X-ray class. Turns pink at M class and above, which is when the D layer starts absorbing HF on the daylit side.

Bands-open chart — under the propagation numbers: one bar per band, showing how much of the world each band is getting through to right now, read off the same propagation field and with the same memory. See §7.8 for what the bars measure and why it is not a contact count.

The line under the MUF says how far away the nearest contributing ionosonde is and how much to trust the number. MUF is interpolated, not measured at your location, and the ionosphere changes sharply across the day/night terminator — a value drawn from sounders 3000 km away on the other side of it is a guess, and the panel says so rather than hiding it. When no sounder is in range it reads no sounder.

7.13 Readouts and the CME arrival banner

Readouts — the card at the bottom left gives UTC, the sub-solar point, the solar disk’s B0 and L0 angles, the Sun’s elevation and azimuth from your QTH (and whether it is day or night there), and how many CMEs and sunspot groups are being shown. When an Earth-directed CME is in the data, a banner across the bottom names it with its speed and estimated arrival:

EARTH-DIRECTED CME  2026-07-10 09:48Z  ·  516 km/s  ·  ETA 2026-07-12 14:20Z (+38 h)

Arrival is a straight-line constant-speed estimate from the fitted cone. Proper forecasts model the CME’s drag against the solar wind and are typically good to about ±6 hours; treat this the same way.

7.14 Where the data comes from

Everything on this list is fetched only while this window is open — closing it stops the background fetcher entirely, and never opening it means no request is ever made. The one exception is the band conditions row: those colour the band menu in the main window, so they are fetched hourly for as long as the program is running, whether or not this window has ever been opened. The two share a cache, so it stays one request an hour either way. The hosts contacted:

Host Data Refresh
sdo.gsfc.nasa.gov Solar disk imagery (NASA SDO — AIA and HMI) 10 min
kauai.ccmc.gsfc.nasa.gov CMEs and solar flares (NASA CCMC DONKI) 20 min
services.swpc.noaa.gov Sunspot regions, planetary K/A, 10.7 cm flux, GOES X-ray level (NOAA SWPC) 5–60 min
services.swpc.noaa.gov The OVATION auroral oval grid, auroral hemispheric power, and the three-day planetary K forecast 15–60 min
nowcoast.noaa.gov Global infrared and visible cloud mosaics (NOAA/NESDIS GMGSI, served by nowCOAST) 10 min
prop.kc2g.com Ionosonde soundings for the MUF estimate (GIRO network, aggregated by KC2G) 15 min
www.hamqsl.com Calculated band conditions (N0NBH) — see §2.15. Fetched whether or not this window is open 1 h
db1.wspr.live Global WSPR activity per band (the wspr.live ClickHouse database) — see §2.15. Fetched whether or not this window is open 10 min
celestrak.org Orbital element sets: the listings you subscribe to (the amateur group and the ISS by default), plus QO-100 6 h

hamqsl.com is the one entry here that is a single operator’s server rather than an institution’s, and its published request is hourly polling at most. That is the interval used, and it is not adjustable.

Everything fetched is cached under solar/ in the config directory and is loaded before the first network request, so the window opens instantly with the last data it had and stays useful with no connection at all.

The OVATION grid is issued every five minutes but fetched every thirty: it is 900 kB, by far the largest thing here after the solar imagery, and the oval does not move far in half an hour. Nothing is hidden by that — the aurora panel says what the picture is valid for, so a half-hour-old forecast is labelled as one rather than presented as this instant’s sky.

Credits: solar imagery courtesy of NASA/SDO and the AIA and HMI science teams; CME and flare data from NASA CCMC’s DONKI; sunspot regions, geomagnetic indices, solar flux, X-ray data and the OVATION aurora model from NOAA SWPC; cloud imagery from NOAA/NESDIS’s Global Mosaic of Geostationary Satellite Imagery, served by NOAA nowCOAST; ionosonde soundings from the GIRO network via prop.kc2g.com; satellite element sets from CelesTrak, propagated with SGP4. Planetary positions from JPL’s approximate element set, moon orbits fitted to JPL Horizons, and body maps from NASA/GSFC’s LRO mosaic (Moon) and NASA/JPL-Caltech/SSI’s Cassini global maps (Jupiter, Saturn); coastlines, borders, rivers, urban areas and populated places from Natural Earth.


8. Remote operation

sdroxide can run as a headless server and be controlled from a second sdroxide instance (a native remote client) elsewhere on the network.

8.1 Start the server

sdroxide --server --port 4950

The server opens the configured radio, streams spectrum and audio, and accepts a WebSocket control connection. The default port is 4950 and the default bind address is all interfaces (0.0.0.0).

Set a username and password first — see § 7.3. Without one the server is open to anyone who can reach the port, and says so in its log at startup.

WARNING: the timed digital modes (FT8, FT4, FT2, WSPR, JS8 …) are decoded on the server, by the server’s clock. Make sure it is synchronised (timedatectl must say System clock synchronized: yes) — a server without a time service decodes nothing in those modes, and says nothing about why (3.2).

A station with more than one radio (2.17) serves all of them from the one port. Every radio in the roster is opened — each with its own engine, exactly as the GUI would — and each is reachable in its own right:

Address Reaches
/ws the first radio in the roster
/ws/<id> the radio with that roster id, the first one included
/radios the list, as JSON: [{"id":0,"name":"RTL-SDR","path":"/ws/0"}, …]

The id is the one in radios.json, not a position in the list, so deleting a radio never renumbers the others. The server logs which radio is on which address at startup, and curl http://HOST:4950/radios answers the same question from anywhere. A radio that is not plugged in right now still gets its address and keeps trying to attach, the same way it would in the GUI.

One connection operates one radio: the single-client rule is per radio, so two people can work two radios of the same station at once — and a native client makes one connection per radio by itself, so one operator gets the whole station in tabs (8.2). A radio id that the station does not have is refused with a 404 rather than quietly answered by a different radio.

The roster can be changed from a client. A headless station’s radios used to be fixed at start-up: adding one meant editing radios.json on that machine and restarting the server, which drops everyone on the air. A signed-in client can now add a radio to the station and close one again — the + and Close on station described in 2.17 — and the station acts on it at once: the new radio gets its own configuration scope, its own engine and its own address, and every client connected is told the roster changed. It arrives with no interface, so the next step is the same as it is in the shack: pick one on the Radio page and press Apply / reconnect. The station’s first radio cannot be closed this way; nothing else is protected, so treat the sign-in as what it is — the key to the station, not to one radio.

The interlock applies across the whole station: only one of its radios can transmit at a time, as in the shack. Note that each radio has its own rigctld.json and tciserver.json in its own scope — if you enable those built-in servers on more than one radio, give each a port of its own, or the second one to start finds the address taken.

8.2 Connect a native remote client

From the GUI, on any other machine running sdroxide: open Settings → General, enter the server’s Address and Port in the connect section at the bottom, and press CONNECT.

The station comes up as a radio tab of its own, beside whatever radios that sdroxide already has open — the tab strip at the top of the window switches between them, and ⊞ puts two side by side (2.17). Your own radio keeps running while you work the remote one. To hang up, close the tab from the roster at the top of Settings → Radio; nothing on the server is changed by that. Adding a radio on the server, and closing one there, are separate and clearly-marked actions in the same roster — see 2.17. If the server asks for a username and password, its sign-in screen appears in the new tab (8.3).

The address is remembered in config.toml on the machine you typed it on, so the next connection is one button. Address takes a host name, an IPv4 or IPv6 address, or a complete ws://… (or wss://) URL if the server sits behind a reverse proxy — a URL is used exactly as typed and ignores the port box. Port is server_port from the server’s own config.toml, 4950 unless it was given --port.

The same thing from the command line, which starts sdroxide as a client and nothing else:

sdroxide --connect HOST:4950

--connect accepts host, host:port, or a full ws://… URL. A client started this way has no radio of its own — and can still reach Settings → General to connect to a second station.

A station with several radios arrives with all of them. The connection you make is to one radio — the first, unless you named another — and the station says what else it has; the client opens the rest beside it, one tab each. So dialling a server that has an RTL-SDR and a Pluto gives you the same two tabs you would have standing in front of them, ⊞ included (2.17). The tab you dialled keeps the name you typed; the others are named as the station names them.

Each of those tabs is a connection of its own. You still sign in once: a station that asks for a password asks each connection separately, and the tabs behind the one you answered let themselves in with what you gave it, for as long as the program runs (8.3). Each tab does carry its own audio and spectrum, though, so on a thin link close the radios you are not using: a tab you close stays closed until you dial the station again.

To open just one radio of a station, name it in the address: sdroxide --connect HOST:4950/ws/1, or type the full ws://HOST:4950/ws/1 in the Address box. /radios on the server says which id is which (8.1).

Either way, a remote client is the full sdroxide GUI running against the server: control, state, memories, meters, spectrum, FT8 decodes and logging, and skimmer spots all work. Receive audio streams down (48 kHz mono), and your microphone is sent up to the server while you transmit. The remote client uses your local speakers and microphone for audio.

8.3 Sign-in: who may operate the station

The server can ask every remote client for a username and password. Set them on the machine the radio is attached to, either in Settings → General → Remote access (6.1) or by hand in config.toml:

[remote_access]
username = "oe1test"
password = "a long passphrase"

Leave username empty to be asked only for the password. Leave both empty — which is the default, and what every version before this one did — and the server is open to anyone who can reach it.

Nothing crosses before the sign-in is accepted, and — the part that matters most — an unauthenticated connection does not take the single-client slot. A stranger cannot lock you out of your own radio by opening a socket to it.

One sign-in per station, not per radio. A station serves each of its radios on a connection of its own and asks each one for the password. You answer the first one, and then you are not asked again: the station remembers the sign-in itself, for the time you chose, and every other connection of that station is let in on the strength of it — its other radios, the 3D solar view, and the browser after a reload or a restart. Another station is another door, and asks for itself, once.

In the browser there is one question: tick REMEMBER ME, or don’t. It starts ticked, because being asked again every twelve hours on a station with three radios was the complaint that produced the box. Ticked, the station — not the page — keeps the result for a month: a signed cookie the page itself cannot read. That is why there is no copy of your password in the browser’s storage any more, and why every other radio of the station opens without a field to fill. Unticked is a real answer and it is the tidier one on somebody else’s browser: the cookie then lasts only as long as the browser is open and is dropped when it closes, so nothing is left behind on a shared machine. How long a cookie is honoured is the station’s business, not a number you have to pick — and because the station signs the cookie with its own configured password, changing the password signs every browser out at once, and a station with no password configured has no cookie to give.

If you are on an older station that has no sign-in cookie to hand out, the card says nothing about that — the page falls back to keeping your password in local storage, and Settings → General → Signed-in station names every station that is being treated that way, so you are never quietly holding a station’s password.

SIGN OUT is on that same row, and it is the only thing that can end a remembered sign-in: the cookie is deliberately unreadable by the page, so ending it has to be something the station does. It forgets this device’s sign-in for that station; the connection you are already signed in on stays up until you close it.

The native client keeps the password instead. There is no cookie to hold — the program has no cookie store — so --connect and the desktop application do what they always have: Remember on this device writes the sign-in to remote_login.json beside your other settings, in plain text. SIGN OUT clears it.

A station compares one answer at a time, so its radios’ tabs take turns signing in and the card says CHECKING… while a tab waits for its own. That wait is not a verdict on the password and is never shown as one: only “username or password not accepted”, in red, means the station actually looked at what you typed and said no.

Sign-in is not encryption. It stops the wrong people operating the radio; it does not hide what you are doing from anyone watching the network, and the password itself crosses in the clear over plain ws://. On anything but a trusted LAN, run the server behind a VPN or an HTTPS reverse proxy — which is also what the browser client needs before it will give you audio (9.3).

8.4 What to know


9. Web operation

The same server serves a browser client, so you can operate from any device with a web browser.

Browsing the public SDRs (15.21) works here too, and works the same way: the lists are fetched by the station, not by the browser, and the station is what holds the connection to the receiver. So a browser tab can find a receiver on the other side of the world and add it to the station’s roster, where every other client sees it as one more radio.

The web client in a browser

9.1 Serve the web client

Builds that bundle the web UI (compiled with the embed-web feature, including the packaged binaries) serve it automatically:

sdroxide --server

Then open a browser at:

http://HOST:4950/

The page connects back to the server over a WebSocket at ws beside itself — the station’s first radio, at /ws when the page is served from the root and under the same prefix when it is not (9.4). To open one of its other radios, add the roster id to the page address:

http://HOST:4950/?radio=1

Two browser tabs on two different radios work the way two clients do; two tabs on the same radio do not, since one client operates a radio at a time. The station’s radios and their ids are listed at http://HOST:4950/radios.

If you are running a build without the embedded web UI, point the server at a trunk-built web directory:

sdroxide --server --web-root path/to/sdroxide-web/dist

9.2 What works in the browser

The web client mirrors the native UI: tuning, mode and band changes, the panadapter and waterfall, receive audio, FT8/FT4/FT2, the logbook, memories, and meters. Microphone transmit is supported where the browser grants microphone access — see audio needs a secure context below. Settings → Radio shows the server device’s own settings panel — its gains, its antenna ports, and everything else its interface has, read from and written back to the radio.json on the machine the radio is attached to (8.4) — so you can swap feedline, wind an LNA back or take a dongle’s AGC off from a phone. Which interface the server opens is reachable from here too: the Rescan and Discover buttons enumerate the server’s buses and network, so you can pick another radio out of that list and press Apply / reconnect. So is how many radios it has: the roster across the top of Settings → Radio has the same + as the desktop client — which here can only mean the station, so it names it and asks before making one — and the × on a radio’s button offers Close it on station to take one out again. A radio added this way opens as another browser tab of the same page within a second, exactly as the station’s other radios do. The solar system 3D view works too: ☀ 3D opens it in a new tab, which connects to a separate read-only endpoint and so does not consume the single control connection — though it is challenged for the same sign-in, since it is shown your QTH and everything the station is decoding. The same single-client and sign-in notes as remote operation apply, and nothing here is encrypted — put the server behind HTTPS if it is reachable from an untrusted network.

Files go through the browser: every export is a download, and the logbook’s IMPORT and the memory channels’ CHIRP IMPORT open the browser’s own file picker, reading a file in any encoding the native application reads. A channel import goes to the station, which keeps the memory list. An ADIF import goes into this browser’s logbook, which lives in the page’s local storage — not in the station’s log — and browsers cap that storage at around 5 MB per site: a logbook of a few thousand contacts, depending on how much each one carries. Past that the import still reports what it added, but the browser declines to keep it, and after a reload the log is back to what it was. Keep a large log in the native application. Exporting and importing the settings is native only.

9.3 Audio needs a secure context

Browsers only hand out the two APIs the web client’s audio is built on — AudioWorklet for playback and getUserMedia for the microphone — to pages in a secure context. Over plain http:// that means localhost only, so:

How you open the page Receive audio and microphone
http://localhost:4950 / http://127.0.0.1:4950 work
https://… (reverse proxy, tunnel) work
http://<lan-or-wan-address>:4950 silent — the browser withholds both

Everything else — the panadapter and waterfall, tuning, decodes, the logbook — works either way; it is only audio that the browser gates. A page opened on a non-secure origin says so in a banner across the top.

This is a browser rule, not a server setting: sdroxide cannot opt out of it. To get audio from another machine, put the server behind an HTTPS reverse proxy (a VPN or tunnel with TLS), or forward the port to your own machine so the browser sees localhost:

ssh -N -L 4950:localhost:4950 user@radio-host
# then open http://localhost:4950

The native remote client (sdroxide --connect) has no such restriction — it uses your local sound devices directly and carries audio over the same WebSocket.

The first touch starts the sound. Even on a secure page, a browser will not play audio until you have interacted with it. So a fresh session, or one reloaded with F5, is silent at first, and a large yellow message sits in the middle of the screen:

🔇 Tap, click or press a key anywhere to start the sound

This message does not mean the session has failed. The connection is up, the waterfall runs and the radio is working; only the sound is waiting for you. Click, tap or press a key — anywhere on the page, with a mouse, a laptop touchpad, a finger or the keyboard — and the sound starts and the message goes away. You do not need to touch the volume. That first gesture does nothing else, wherever it lands: it does not tune, press a button, move the waterfall or run a keyboard shortcut, so a receiver you are coming back to keeps its frequency. From the next gesture on, the page works as usual.

While the message is up, moving the mouse, scrolling or pinching on a touchpad does nothing at all, and does not start the sound either: the browser does not count those as a gesture. Click, tap or press a key.

This is the browser’s autoplay rule, not a fault, and an installed web app follows it too. The message is shown only when the page opens — a new session, or a reload with F5 — and never again during the session, whatever happens to the sound later (a network drop, a stutter, a cut).

Once you know what to do, untick Settings → UI → Sound welcome: the message goes at once and does not come back at the next opening. The sound still waits for your first touch, and that touch then works as usual. The setting is kept with your profile on the server, so it follows you to another device; that device shows the message once more at its very first opening, until it has heard your answer from the server.

9.4 Behind a reverse proxy on a subpath

The web client works from any path, not only the root. Behind a reverse proxy that gives it a prefix — https://shack.example/sdroxide/ — everything hangs off the page’s own address rather than the top of the host: the WebSocket, the radio listing, the wasm bundle and the scripts beside it. So the two ways a proxy can be configured both work, and neither needs anything from you:

A Caddyfile for the second, which is the shorter one to write:

shack.example {
    reverse_proxy /sdroxide/* localhost:4950
}

The address works with or without the trailing slash. Sockets have to be allowed through — most proxies do that by default, and Caddy needs nothing said; anything that filters Upgrade and Connection headers has to pass them or the page will load and then fail to connect.

Serving through HTTPS this way is also what gets the browser to hand over audio and the microphone (9.3).

9.5 Removing an installation completely

Asked for on fork discussion #17, and here it is so nobody has to ask again.

The Debian package (sdroxide, or sdroxide-soapysdr) owns exactly this, and every line of it goes with the package:

Path What
/usr/bin/sdroxide the binary — client and server are the same program
/usr/share/applications/sdroxide.desktop the desktop menu entry
/usr/lib/udev/rules.d/60-sdroxide-*.rules nine dongle rules, so no root is needed
/usr/share/icons/hicolor/*/apps/sdroxide-brown.{png,svg} the icon, in nine sizes
/usr/share/sdroxide/voices/ the speech voice, for spoken announcements
/usr/share/doc/sdroxide/ README, copyright, and four licence notices
sudo apt purge sdroxide-soapysdr      # or sdroxide — removes every path above
rm -rf ~/.config/sdroxide-brown      # every setting, logbook and recording it wrote

Three things worth stating plainly, because “is anything left behind?” is the real question:

Not ours to remove: your reverse proxy, your own scripts and backups, and any other program using libsoapysdr0.8. The RX-888 firmware is inside the binary rather than in a file of its own, so there is nothing to delete for it either.

A fresh installation has no radio in it. No radios.json, no radio.json, no per-radio folder — so there is nothing listening and nothing can decode until one is added at Settings → General → Radio (6.2). That is the first thing to check after any clean install.

9.6 Phones and tablets

The control strip is eight boxes of a fixed width. On a desktop they sit in a row; on a narrow screen they cannot shrink, only wrap, so the strip would eat the screen and the widest boxes would still run off the side of it. Below about 1100 points wide the strip is replaced by menus, and below about 600 — or on anything shorter than 440 points, which is a phone held sideways — by a compact strip. Settings → UI → Layout (6.3) forces a particular one; Auto is the default and picks from the window.

The same rule applies to the native app, so dragging a desktop window narrow gets the same treatment.

On a tablet, the frequency readout and the S-meter stay as they are — the digits shrink a little in portrait so both fit one row — and the rest becomes a row of menu buttons:

Button What it holds
PTT Keys the transmitter. Hold it down to talk, or click it with a mouse to latch it on.
RX Volume, front-end gain, AGC, squelch, the filter width and edges, NB, ANC, NR, BIN
VFO A↔B, A→B, SPLIT, SUB, and the RIT/XIT offsets
SUB The second receiver’s frequency, mode, filter and level (only while it is running)
TX TUNE, the voice keyer, and the drive, tune and mic levels
DISP ☀ 3D, WIDE, FIT, CTR, the panadapter boxes (the spectrum and waterfall switches, peak hold, their speeds and the detail), the skimmers, and the VIEW options (waterfall floor/ceiling, FFT size and scroll direction)
SYS LOG, SPOTS, AWARDS, BANDS, SAT, ISM, PUBLIC SDR, MAIL, MEM, SCAN, SETTINGS, HELP

A menu stays open until you tap outside it or tap its button again — the top-bar popups do not fade away on a touch screen the way they do under a mouse, because there is no hovering pointer to hold them open.

Tuning buttons. Under the menu row is a full-width row of three: −, the step, and +. Each press moves the dial by the step shown, and tapping the step itself takes the next one — 10 Hz, 100 Hz, 500 Hz, 1, 2.5, 5, 9, 10 and 25 kHz, then round again. It is remembered between sessions.

Settings → UI → First press snaps to the step (off by default) tidies a dial left anywhere: a press goes to the next multiple of the step in the direction pressed — from 7 074 300 at a 1 kHz step, + goes to 7 075 000 and − to 7 074 000 — and every press after that moves by exactly the step. At a 9 kHz step that is the medium-wave channel raster; at 1 kHz, the zeroes on a printed channel list (issue #422).

This is the one thing a touched screen had no way to do (issue #380). A desktop tunes three ways and a phone has none of them: there is no wheel, so scrolling a digit on the readout is unreachable; tapping the panadapter lands where you tapped, which is a gesture nobody makes twice when the next station is 3 kHz away; and typing the whole frequency in to move one channel is data entry rather than tuning. Stepping in round amounts is what working down a band actually is.

The row costs one button’s height of waterfall, so it can be switched off: Settings → UI → Tuning buttons. It is never drawn on a desktop, which has the wheel and the readout’s own per-digit scrolling.

On a phone the readout shrinks too, and the A/B selector and the other VFO’s frequency move into the VFO menu; a small A or B before the digits says which one you are tuning.

PTT is press-and-hold on both, and a finger never latches it: a latching control an inch from a waterfall you pan with your thumb is one mis-tap away from a transmitter left on. Lifting your finger always drops it, including when the browser takes the touch away because you switched tabs.

A mouse gets the latch back, because a mouse is not the thing that rule guards against — and these layouts are not only touch screens, since Auto picks the tablet strip for any window under 1400 points wide and you can force either one outright. Press and hold to talk, exactly as a finger does, or click the button to leave it keyed; the next press lets go. Dragging off the button before releasing cancels the latch, so an accidental press ends the over rather than leaving it on the air.

The digital-mode panels

Every operating panel (3) is two columns side by side — an activity list and a working area, or a picture and a gallery. A tablet keeps them that way. A phone cannot: the two want 180 and 220 points before either has drawn anything, which is more than the screen, so it shows one at a time with a row of buttons above them.

The panes, by mode:

Mode Buttons
FT8, FT4, FT2 DECODES · QSO · WFALL
JS8 HEARD · CHAT · WFALL
FSQ HEARD · TRAFFIC · WFALL
SSTV, SSTV-FM, RIFP RECEIVE · SEND · WFALL
Weather fax CHART · SAVED · WFALL
RF Paint TEXT · IMAGE · WFALL
PSK, RTTY, Olivia, THOR, Contestia, Hell, RADE PANEL · WFALL

WFALL is the waterfall, zoomed to the mode’s sub-band and filling the screen. It is a view of its own rather than a strip above the panel because a third of a phone’s height is not enough to work a mode and watch a band — split that way, both were too small to use.

In FT8 and FT4 the count of stations decoded in the last slot sits at the right of the button row, so it reads from all three views, and answering somebody from the decode list switches to QSO by itself — you started an exchange, so the panel shows you the exchange. In SSTV the live picture and the received gallery stack one above the other instead of sharing the width.

The FT8/FT4/FT2 world map is gone on both compact layouts. It is the largest thing in that column and the only part of it that is neither the state of the contact nor a control that changes it, and on a tablet it was taking the room the transmit buttons needed. The same stations are still on the panadapter and in the 3D view.

Touch gestures on the waterfall:

Gesture What it does
Drag Pans the view and takes the dial with it, with the same flywheel coast as a mouse
Two-finger pinch Zooms the span about the point between your fingers — there is no scroll wheel to do it with
Tap Tunes to that frequency
Drag a passband edge Sets the filter. The grab zone is wider than under a mouse, but never more than a third of the passband, so tapping inside a narrow CW filter still tunes. There is no Ctrl to hold on a touch screen, so the AM and FM modes always pair their edges here

Buttons, sliders and entry fields are all drawn larger on a touched layout, so a row of controls is a row of finger-sized targets rather than 22-point ones.

Remember that audio needs a secure context (9.3): a phone opening the server over plain HTTP on the LAN gets the waterfall and the controls but no sound at all.

Installing it to the home screen

In a browser tab, a third of a tablet’s screen is address bar and toolbars, and they never go away: the page deliberately does not scroll — a drag pans the waterfall instead — so the browser never hides its own chrome the way it does on an ordinary site.

Install it instead, and it launches with none of that:

Browser How
Samsung Internet, Chrome, Edge (Android) menu → Add page to Home screen
Safari (iOS, iPadOS) Share → Add to Home Screen

Then launch it from the new icon, not from the browser — opening the same address in a tab still shows the tab. On Android it is installed as a web app and runs genuinely full screen, with no address bar and no status bar; on Samsung DeX it behaves as an ordinary desktop window.

A private or incognito window cannot install it, and that is the browser, not the program. Chrome and Firefox both refuse to install an app from a private window — the option is simply not there in the menu — and no setting on the station changes that. It is worth saying plainly because it looks like something misconfigured: everything else in a private window works, and works normally. The one thing a private window does not keep is what the browser holds — your screen and your key bindings — so in one you sign in and the station supplies them instead of the device remembering them. That is the same path a profile on any other machine takes, and on this build the profile is held on the station, so a private window is in no way second class. It is only the installed icon that is unavailable.

This needs the same secure context as audio (9.3). Over plain HTTP on the LAN a browser will offer a plain bookmark at best, so the two reasons to put the server behind HTTPS — or to reach it over a tunnel, a VPN or Tailscale — are the same reason.

The screen can stay awake while the client is in front: tick Settings → UI → Wake lock (off by default, because it costs battery; kept with your profile on the server). A receiver is watched rather than read, and a tablet left alone blanks after half a minute; installed full screen that takes the whole application away and puts a lock screen in front of it. The client asks the browser to hold the screen on, gives that up whenever you switch away — a client in the background has no business keeping your screen lit — and asks again when you come back. The line beside the box says when the browser does not have it, or refused it.

The padlock locks the screen against stray fingers. It sits on the phone and tablet strips, just after the MEM chip; the desktop layout has none.

The home-screen icon is sdroxide’s own, the same artwork the desktop application and the packaged builds use.


10. Spotting, awards, and QSL upload

SDR Oxide features spots you can click to work, automatic callsign lookup, one-click QSO upload, and award tracking. This chapter is about what they do; the settings behind them are on the Spots (§6.5), FreeDV (§6.6) and Uploads (§6.7) tabs of the Settings window, and they are surfaced by the SPOTS and AWARDS buttons in the System module. Your callsign and grid come from the General tab and are used by all of them.

All of this runs on the machine with the radio (the server, in remote/web mode), so a browser or remote client uses it too. Credentials are stored in plaintext in net.json (see §13).

10.1 Spot feeds (DX cluster, POTA, SOTA, PSK Reporter)

FreeDV Reporter is configured separately, on its own Settings tab — see §10.5.

Live spots as clickable markers on the panadapter, and the SPOTS window

Enable the feeds you want — DX cluster, POTA, SOTA, PSK Reporter — on the Spots tab of Settings (§6.5) and press APPLY. Spots then appear two ways:

Switching a category off hides it everywhere at once — the list, the panadapter labels and the world-map dots — and the six category buttons are remembered between sessions, so a category you have no use for stays off. (IN VIEW is not: it is a way to read a crowded band for a moment, not a standing preference.)

Search — the ⌕ box below the buttons does a fuzzy search over everything in the list: callsigns, station and transmitter names, comments, park and summit references, and the frequency written either way, so 9420, 9.420 and avlis all find the same station. Letters need only appear in order, so bbcws finds “BBC World Service”; several words are all required, so bbc asc narrows to the BBC transmissions from Ascension. Matching rows are ranked best-first while you type, and a counter under the box says how many of the total matched. The search narrows the list only — the panadapter labels stay where the frequencies are.

Click a spot — on the panadapter or in the SPOTS list — to tune your VFO onto it, switch to its mode, and open a pre-filled New Entry in the logbook (call, frequency, mode, and any grid/reference from the spot). If auto-lookup is on (below), the name/QTH/grid are filled in too. CW spots are tuned a sidetone pitch low so the signal lands in the CW passband. Broadcast stations only tune — they have no callsign to log or look up.

Band openings

The OPENINGS chip at the top of the SPOTS window opens a live detector that answers a different question from the spot list: not “who is being heard” but “which paths have just come alive”. It watches the spot feeds the window already has — and, on 11 m, this station’s own WSJT-CB decodes — and flags a band and continent-pair whose recent activity has surged past its own baseline over the last three hours. A path that was quiet and suddenly carries a burst of new stations is an opening; a band that is simply busy is not.

Each detection names the band, the direction (which continent-pair), how far past its baseline it is running, and how long ago it opened; a path that goes quiet again is retired on its own. The section has its own draggable divider, so a listener watching a big surge can give the detections more room and the spot rows less. It is a surge detector over the spot traffic, not a propagation forecast: it says what the feeds are showing now.

10.2 Callsign lookup

Auto-fill operator details from an online callsign database — QRZ.com (needs an active XML-data subscription) or HamQTH (free). Pick the Provider and enter its credentials on the Uploads tab of Settings (§6.7).

Tick Auto-fill name/QTH/grid on spot click & QSO to look a call up automatically when you click a spot, start an FT8 QSO, or finish typing a call in the entry form. Either way, the LOOKUP button in the New/Edit Entry form does it on demand. Lookups only fill fields you’ve left blank, so they never overwrite what you typed; results also enrich the matching logged QSO (name, grid, DXCC, zones).

10.3 Uploading QSOs (eQSL, QRZ, HamQTH, Club Log, LoTW)

Enter your QRZ Logbook, eQSL, HamQTH and Club Log accounts on the Uploads tab (§6.7) — one tab per service, each with a Test button that checks the login against that service before a QSO depends on it, worth doing once, since otherwise the first sign of a wrong password is an upload that failed hours after the contact. Then either tick Auto-upload each new QSO and, on each service’s tab, the service itself, to push every QSO as it is logged; or upload individual QSOs from the logbook with the per-row UP button. Each upload sets that QSO’s status flag (the ↑ in the logbook), and failures are reported in the SPOTS window’s status line.

HamQTH needs no separate account from the callsign lookup — the same username and password do both, and if you already look calls up on HamQTH there is nothing more to enter. Its logbook wants a date, time, callsign, mode, band and both signal reports on every contact; a QSO missing one is refused before it is sent, naming the field, rather than coming back as HamQTH’s unexplained QSO Rejected (which is also what it says for a duplicate). Upload one contact at a time, as sdroxide does — HamQTH asks specifically that this route not be used to push a whole log, and offers a file upload on the website for that.

LoTW upload is deliberately not automated — LoTW requires a signed upload via ARRL’s TQSL. Export your log to ADIF from the logbook and sign/upload it with TQSL as usual.

Confirmations — enter your LoTW login (and/or use your eQSL credentials) and press SYNC CONFIRMATIONS. sdroxide downloads your LoTW/eQSL confirmations and matches them against the log to set the ✓ (confirmed) status, which drives worked-vs-confirmed in the awards view. (LoTW upload stays manual; only the confirmation download is automated.)

10.4 Award tracking

The AWARDS window: DXCC / WAS / WAZ / grids, worked vs confirmed

The AWARDS button opens a live tally computed from your log:

DXCC entity and CQ/ITU zone are resolved from the callsign using a bundled country file (cty.dat), so awards work even for QSOs you never looked up — though a lookup adds exact zones and state. A QSO counts as confirmed once any of LoTW, eQSL or a paper card is received for it. The same entity resolution flags new DXCC entities in the SPOTS list, so you can spot an all-time-new one at a glance.

Nothing here is ever reset, and there is no control to reset it: the tally is recomputed from the logbook every time it is shown, so it is only ever a statement about the log as it stands. Delete a QSO and the entity it brought in goes with it; import an ADIF and its entities appear. There is no per-year or per-season rollover either — DXCC, WAS, WAZ and grids are all-time awards. The band filter is the only thing that narrows what is counted, and it is a view, not a state.

On the globe — the 3D view’s AWARDS layer (§7) paints the same tally on the Earth as a “what am I still missing” heat map: every DXCC entity in the country file gets a marker at its nominal centre, orange and breathing where you have never worked it, amber where you have but it is unconfirmed, and a dim green dot once a QSL has come back. A key in the bottom-right corner gives the counts. It follows the same band filter as this window, so switching to 20m here repaints the globe as “what is missing on twenty”.

The grid tracker — the GRID button (System box) opens the log’s worked squares on their own map: each 4-character Maidenhead square is filled on the flat world map, amber where worked and green where a QSL has come back, with your own locator marked on top. Drag to pan and wheel to zoom; the square under the pointer is named. The HEARD layer shades, in cyan, the squares on the live decode list rather than the log — what is on the air right now — which is what makes the window useful to a shortwave listener with no log of their own. A square that is both heard and worked reads as worked.

An 11 m exchange carries no locator, so a CB log has no squares to draw. The tracker has a COUNTRY mode for that: each worked DXCC entity is marked at its nominal centre instead, resolved from the callsign exactly as the awards tally does (the leading digits of a CB call are its country). GRID and COUNTRY toggle between the two, and the window opens on whichever the log actually holds — a CB log opens on countries rather than on an empty grid map. The heard layer follows the mode.

10.5 FreeDV Reporter (qso.freedv.org)

FreeDV Reporter is where FreeDV operators announce where they are listening and who they are hearing. SDRoxide talks to it in both directions: your station appears on the site, and everyone else’s appears in SDRoxide as spots.

Turn it on and point it at a server on the FreeDV tab of Settings (§6.6). You are only shown to others while the radio is in RADE mode; in any other mode the connection stays up but your station is hidden, so the site never lists you as working FreeDV when you are actually on CW.

While the feature is on, SDRoxide reports your transmit frequency as you tune and your transmit/receive state as you key up, and reports your software as SDRoxide <version>.

With more than one radio the entry is still the station’s, not the tab’s: the session belongs to the first radio in the roster, but whichever radio is in RADE is the one whose frequency and transmit state go out, and the station is hidden only when none of them is. The settings on the FreeDV tab are likewise the station’s, so applying them from any radio’s window changes the one session rather than opening a second under the same callsign.

Callsign exchange. RADE carries a callsign in the frame at the end of each over. SDRoxide transmits the callsign from your digital-mode configuration there, so other FreeDV stations can identify you, and decodes the far end’s, showing it as the DX call and reporting it. This uses the same over-the-air format as FreeDV GUI, so the two interoperate.

Checking it works without going on air: sdroxide --freedv-reporter-probe 20 connects read-only for twenty seconds and prints the stations and events it saw. It uses the server’s view role, so it needs no radio and never makes you visible to anyone.

10.6 Broadcast stations on longwave and shortwave

SDRoxide labels longwave and shortwave broadcast stations on the waterfall in orange, alongside the network spots — so a carrier on 225 kHz comes up as Polskie Radio Program 1, Solec Kujawski rather than as an unexplained signal. Click one to tune it in AM; unlike a cluster spot it opens no log entry and looks up no callsign.

Only stations on the air now are labelled, which is what makes a schedule of this size usable: the three schedules below hold around 8,000 transmissions between them, of which some hundreds are on the air at any moment. Each carries a UTC window and, where the broadcast does not run daily, a day mask; the list is re-filtered against the clock every minute. Entries with no window — the longwave transmitters, the standard-time stations, the round-the-clock private shortwave stations — are always shown. Turn the whole category off with the BC button in the SPOTS window.

A band is still busy at prime time (the 31 m band carries 50–95 transmissions at midday UTC), so zoom in or use IN VIEW when the labels crowd each other — only five rows of labels are drawn, and the rest are dropped.

Because every entry names a real transmitter site with its coordinates, the stations also appear as dots on the FT8 world map, and tuning one draws its path on the 3D globe: a great-circle arc from your grid square to the transmitter, labelled with the station and site, exactly as a QSO or a weather-fax chart is. That turns “a signal on 15400” into “this came 8,000 km from Ascension Island”. It needs your grid set on the General tab, and the QSO layer on.

Only the station you are actually tuned to is named. A crowded band carries dozens of schedules at once, and labelling all of them buries the one under the dial. So the waterfall names the station on your frequency and nothing else; the rest — country, city, transmitter coordinates — is in the SCHEDULE window. If two broadcasters genuinely share a carrier, both are named, because those are two facts about what is on air and hiding one would be a lie.

The path to a station is drawn with its own twilight: each dot along it is lit or dim according to whether that point is in daylight, so you can see which half of a path is dark rather than being told a percentage. It fades through twilight rather than switching at the terminator, and a night dot keeps a faint outline — a path that vanished would read as “no path”.

The schedule downloads itself

Shortwave schedules are reissued twice a year, so SDRoxide keeps its own copies current instead of shipping a snapshot that goes stale. Three sources are fetched, each on its own terms, and all of them go into one store:

Source What it is Notes
EiBi The long-standing schedule, from eibispace.de. Plain HTTP, because its certificate is expired — see below.
Aoki A second schedule, read from the season’s own package. The same station often appears in both.
HFCC The HFCC operational schedule. Carries transmitter sites and positions.

How each is fetched:

The Spots settings tab lists every source whether or not it has been fetched, showing how many transmissions each holds and giving it its own Download button beside Download all now. A source that has never been fetched reads not downloaded rather than simply being absent — a row that only appeared once it had worked makes “did it download?” unanswerable.

Downloads run on a worker thread, so they never delay startup, and a file is written to the cache only after it parses into a plausible schedule: a captive portal’s login page cannot replace your station list. Aoki arrives as a zip holding a Shift-JIS text file, so it is unpacked and decoded as its own format rather than as CSV; HFCC arrives as one package holding the schedule and its reference tables, so the names cannot go stale against the schedule they belong to. Each source’s own week numbering is converted to this program’s as it is parsed — Aoki and HFCC both count the week from Sunday, this one from Monday — because doing it in two places is how every station ends up a day out.

The EiBi download is plain HTTP for the expired certificate. Nothing is trusted on the strength of the transport: the file is parsed into typed rows and rejected unless it looks like a season’s worth of transmissions.

Your own stations

broadcast_stations.json in the config directory is yours alone. SDRoxide never writes it, and merges it over the downloaded schedule each time it loads:

The file does not exist until you create it, and holds only your entries rather than a copy of everything, so it stays small and never goes stale. Reload on the Spots tab re-reads it after an edit.

Import my station list…, beside it, reads a list you already keep somewhere else and merges it in. It accepts this JSON, a CSV, or a plain text list, because a listener’s list comes from wherever they kept it and being asked to convert it first is what stops them:

BBC World Service 15400 kHz
5010,Radio Prague

The unit is decided by the number. Shortwave here runs from 3 kHz to 130 MHz, so a bare number at or above 1000 is kHz and anything below it is MHz — 15400, 15400 kHz and 15.4 all land on the same row without being told. Rows merge by name and frequency rather than being added twice, and a line with no frequency in it is skipped rather than half-read. Your own list is a schedule — what you expect to hear — and is not the reception log, which records what you did hear.

This is a schedule, not the log. The SWL LOG records what you heard; this records what is expected to be on air, which is what the waterfall labels against. Mixing them would put a station in the picture that was never transmitted. (Upgrading from an earlier SDRoxide that seeded a full copy here: that copy is moved aside to broadcast_stations.json.bak on first start, because laying a stale season back over a fresh one would duplicate hundreds of transmissions. Nothing you wrote yourself is touched.)

Each entry needs only a name and a frequency in kHz:

{ "name": "BBC", "freq_khz": 15400, "site": "Ascension Island",
  "country": "Ascension Island", "lat": -7.9, "lon": -14.3833,
  "lang": "English", "target": "West Africa",
  "start_utc": 1800, "end_utc": 1900, "days": "12345" }
Field Meaning
name, freq_khz Required. Frequency in kHz, as broadcast schedules print it.
site, country Transmitter site — the country is where the transmitter stands, not where the broadcaster is from.
lat, lon Transmitter position in degrees. Both or neither; without them there is no map dot and no globe arc.
power_kw, lang, target Shown in the spot row.
mode Only if it is not plain AM — SAM, USB, …
start_utc, end_utc UTC HHMM. Leave both out for a round-the-clock station. end_utc below start_utc wraps past midnight, so 2200–0200 works.
days Digits 1 (Monday) to 7 (Sunday), e.g. "12345" for weekdays. Empty means daily.
season "A" (last Sunday in March to last Sunday in October) or "B". Absent means both.

The SCHEDULE window

In SWL mode the strip’s ham chips give way to SCHEDULE and SWL LOG (§6.3), and the SCHEDULE window is where the listener browses the table: it turns the same EiBi schedule the waterfall labels into the list a listener works from.

At the top are the filters — a UTC time (or now), free text over name, site, country, language and target, language, target, and a metre band. On the chip row below them are ★ FAVS, which shows only the stations you have starred, and Source, which narrows the list to one schedule or shows all of them.

Source reads all of them by default, and that is deliberate. The store holds every downloaded schedule, so one broadcaster listed by two of them appears twice — and the repetition is the point here: this window is where the detail belongs, and the repetition is accepted in exchange for never querying several databases to answer one question. It is the panadapter that collapses it, by naming each station once. The label says all of them rather than any source’s name, because a box reading “EiBi” while three schedules are loaded would be a control that cannot be misread. A row can be TUNEd (the same tune as clicking its label on the waterfall) or LOGged straight into the reception log with the station, language and site already filled in.

SOLAR TIME puts each row’s local time at the transmitter beside its site, from the coordinates EiBi carries. It is mean solar time — the Sun’s clock, four minutes a degree from the site’s longitude — and deliberately not a civil time zone, because that would need a country-polygon dataset a fork should not carry for this. It is labelled solar rather than local for that reason: it knows nothing of daylight saving or of a country’s zone borders. Hover the column for the site and longitude it was read from. A listener planning in the broadcaster’s evening is the thing it is for.

Where the data comes from

The shortwave entries are EiBi’s seasonal schedule, parsed by SDRoxide itself — the same code path for a downloaded file and for the compiled-in one, so they cannot behave differently. Transmitter coordinates and the language, country and target-area names come from EiBi’s README, which changes very rarely and is therefore compiled in rather than fetched; tools/gen_broadcast_codes.py refreshes those tables and the offline fallback schedule:

tools/gen_broadcast_codes.py --season b26

Longwave and the HF standard-time stations are not in EiBi’s file — it starts at 2300 kHz and skips time signals — and are maintained by hand in crates/sdroxide-types/src/broadcast_seed.json.

The LISTEN window

Where the SCHEDULE window is a table to browse, LISTEN is the band to listen on. It opens beside SCHEDULE and answers two questions at once: what is on around this frequency, and where is it coming from.

Its own geometry: HISTORY (off by default) keeps the span you were on rather than following the dial.

The SWL LOG window

Where the SCHEDULE window is the table a listener works from, the SWL LOG window is the record of what was heard: a reception log, and the tools to work it — the antenna in use, the reception report, and the log’s CSV and ADIF exports. It is the listener’s counterpart to the LOGBOOK.

+ NEW logs the station the receiver is on right now, with the frequency, the mode and the S-meter reading taken from the live radio, and — when the dial sits on a station the schedule knows — its name, language, transmitter site and report contact, the same prefill LOG on a SCHEDULE row gives, so a catch is a judgement and a send. Where the schedule has nothing on the frequency, a station name you have logged on it before is offered instead. The entry form holds the rest of a reception: the station name, the frequency and mode, a language, the SINPO or SIO figures, and your own notes.

Each row in the log carries an rcl button: it tunes back to that reception’s frequency and mode in one click, so a listener can check whether the station has returned on the same channel at the same time another evening. It sets the mode through the listener’s route, so a recalled catch always comes back as it was logged rather than being refused by the band rule that governs what may be transmitted.

The form and the row keep the receiving station’s locator — where the reception was made — pre-filled from your own grid on the General tab and editable per entry. It is the comparison that matters when the same station is heard from two places, or from two aerials. On the row it takes the place the notes used to occupy; the notes are a hover over the station name, so a long one no longer pushes the row about.

The transmitter site is deliberately not a field: a listener almost never knows it, and the one source that does is the schedule, which fills it in when a row is LOGged or when + NEW lands on a scheduled frequency. It rides on the saved entry and shows on the row’s hover when it is there, beside the notes.

The entry form carries a Pirate tick for an unlicensed — “pirate” — broadcast, the kind of catch shortwave listeners go looking for. It is the listener’s judgement and nothing infers it. A reception so marked wears a small Jolly Roger in the log list, and the tick survives editing the entry later.

The Antenna box at the top of the window is the aerial in use, in your own words — “Longwire 20 m”, “MLA-30 loop”, a mini-whip. It is session state, set once when you start listening, because an aerial is swapped far more often than a settings page is opened; and it is not a property of the radio, so it stays on this screen rather than in Settings. Each reception captures it when it is logged. REPORT writes that reception out as a text report to save and send — the numbers, the received-at locator and the aerial, signed with your report identity — and names the program there as sdroxide_SWL, so a broadcaster can tell it apart from the amateur build.

MAIL REPORT… in the entry form is the same report, written and opened in your mail client instead of saved as a file. It is available when the form carries an email address — which is what a known station means here: one the schedule holds a report contact for, filled in by + NEW or by LOG on a SCHEDULE row. Where the schedule has no address, the chip is greyed and says so, because a reception report with nowhere to go is not a reception report. The report itself is built from the form as it stands, so a SINPO you have improved and then mailed without pressing SAVE still goes out as you typed it, and it is generated from exactly the same conversion SAVE uses, so the two cannot disagree. Every field you left blank is left out entirely rather than blanked or dashed: a report reading Grid: — is a line the station has to interpret, and one reading Grid: with nothing after it looks like an empty string rather than an unknown. An unjudged reception states no figures at all, rather than five defaulted ones nobody heard. The subject names the station and the date and nothing else — it goes to a broadcast engineer filing it by date, not to a contest logger. A transmission you marked Pirate is reported plainly, as a fact the station can act on. It sends nothing. The picture you configured in Settings is written out and named in the body, and the message opens with the report ready; attaching it — and a soundclip, if you cut one with REC’s 30-second quick clip — is your own click in your mail program. A program cannot put a file in a message without being a mail client, with an account and a password and a server, which is a different program with its own security to consider. This does everything up to that point and nothing beyond it. Two settings under Settings → UI, in the SWL section, decide what a report carries: Report picture (a path on this computer — your own card, a photograph, whatever you want the station to see; one image, used for every report) and Report note (your standing note — who you are, what you listen on, anything a station asks once rather than per letter). Both are optional and genuinely so: a plain-text report is a perfectly good report, so leaving them empty breaks nothing. The picture row is absent in a browser tab, because the setting names a file on this computer and there is no such thing there — it is left out rather than shown dead.

A reception is not finished when it is heard: an SWL’s loop is hear → report → await QSL, and the log records the whole of it. report sent stamps the day the report went out — REPORT sets it too, since writing the report is that step — and QSL received stamps the reply or card when it arrives. Each is a date rather than a plain tick, so the log keeps when as well as whether; unticking one clears it. The row carries a small sent or QSL mark after the locator, so the catches still owed a report, or still awaiting a card, are the ones with no mark. The two steps ride on the saved entry with everything else, so they survive a restart and travel with the log.

The row of controls above the log is how you read a log that has grown past a few dozen catches. Show is a find box over station, language, transmitter site and notes; beside it a band and a day menu — each listing only the bands and days the log actually holds — and a Pirates only switch for the unlicensed catches. CLEAR drops every filter at once, and while any is on the header says how many of the log are showing. The filters are how you are reading the log now: they never change or hide what was recorded, and they are not saved. The window’s own header counts the whole log at a glance — how many heard, and how many of those reported, QSL’d and pirates — so the filters above it never change what those totals say.

CSV and ADIF at the end of that row save the whole log in one file, filtered or not — CSV for a spreadsheet, one row per reception, and ADIF as reception records (SWL=Y, the station in CALL, and the report-sent and QSL-received dates in the fields ADIF keeps for them). The single-entry REPORT is the one to send to a broadcaster; these are the log’s own backup and export.

The window’s other controls are the listening tools in their own right: JOBS for scheduled recordings, REPLAY for the last two minutes of audio, SIG ID (see §10.7) for what is on the dial, and the Tone row for bass, mid and treble shelves on the demodulated audio.

LOUDNESS, at the end of that row and in the RX strip’s EQ popup, lifts the bass (up to +12 dB, around 120 Hz) and a little treble (up to +6 dB, around 6 kHz) as the volume goes down, because the ear loses the ends of the spectrum first at low level. It follows the volume knob as you turn it, works with the tone shelves on or off, is flat at full volume, and is never more than the volume it compensates — so it cannot make the speaker play louder than full volume would, nor clip it. Narrow modes (SSB, CW) carry little treble, so there it is mostly a bass lift.

Both the Tone shelves and LOUDNESS are off by default — nothing changes until you tick the box — and both are per-mode settings (Per-mode settings): what you set is remembered for the mode you are in, every other mode keeps its own (off until you set it there too), and the value comes back with the mode and after a restart. The circular-arrow reset chip and Settings → General → RESET EVERY MODE switch them back off. They shape the main receiver’s speaker audio only.

10.7 Signal identification

SIG ID, beside JOBS in the SWL LOG window, opens a guide to what is on the dial. It reads the dial frequency, the mode and the receiver’s passband, ranks a built-in catalogue against them, and lists the candidates — what the signal is, what it is modulated with, how wide it is, and a one-line description. The sigidwiki link on a row opens the matching sigidwiki page for a waterfall and a recording.

The ranking puts an exact mode match first, then the frequencies and bands the signal is known on, then how close the passband is to the signal’s own width. So tuning to 14.074 in FT8 names FT8, tuning to 27.185 in AM names the channel, and tuning to 518 kHz in NAVTEX names NAVTEX. It is a guide rather than a verdict, and the entries under the top name are the ones it weighed against the dial.

The Find box searches the whole catalogue instead of the dial — “weather”, “aircraft”, “meteor” — which is the way to reach a signal with no frequency to type, and reads as a map of what is out there rather than a description of what is playing.

The catalogue is built into SDRoxide and describes signals, not stations: around sixty entries covering the amateur, broadcast, marine, aviation, utility, time and satellite services the receiver knows. It carries no waterfall images or audio samples and nothing copied from another identification database — the sigidwiki link opens that content in your browser rather than redistributing it here.

10.8 Contest logging

CONTEST, beside TXT, ADIF and IMPORT in the LOGBOOK window, opens the contest logger. It is mode-agnostic: you type the exchange by hand for CW, SSB, RTTY or anything else, and on FT8 the exchange fills itself in where the contest has a message layout. Nothing about it is a separate log — what it records goes into the ordinary logbook, so TXT, ADIF, the QSL loop and every other tool work on it unchanged.

Starting a session. Pick a contest and enter your own exchange, then START. The contests that ship are:

Contest You send They send
CQ World Wide RST + CQ zone RST + CQ zone
CQ WPX RST + serial RST + serial
ARRL DX RST + state (or their power) RST + state (or power)
EU VHF RST + serial + 6-character locator RST + serial + 6-character locator
CB / 11 m activity RST + free text RST + free text
Serial (generic) RST + serial RST + serial

The entry form. Type the call, then the two reports and one box per part of their exchange. SENT is the report you give — 599 on CW, 59 otherwise, from the mode in force, and editable if you sent something else — and RCVD is what they gave you; they are separate fields, so one is never echoed as the other. The exchange boxes come from the contest, so EU VHF asks for their serial and their locator instead of a single box that keeps only whichever you typed last. Press LOG, and the row is written with your serial and your own exchange on the same line.

Serials and dupes. Your serial rises with each contact logged, and a new session for a contest you have worked before starts one past the highest serial already in the log for that contest — stopping for lunch, or restarting the program, does not send 001 again. A call already worked in this session lights DUPE on the same band; the check is deliberately over the session’s own contacts rather than the whole logbook, so a station you worked last month does not read as a dupe before the contest has started.

CABRILLO writes the session out as a Cabrillo v3 file (sdroxide.cab), which is what contests want back. The CONTEST: line and CATEGORY-MODE are chosen from the modes actually logged — an all-CW session exports as CW, not MIXED — and CREATED-BY names the program and its version. A contact logged with no frequency cannot be placed on a band and is left out of the QSO: lines; the export counts them in a comment at the end, so nothing disappears without a word.

Score and rate. The strip across the top counts QSOs, points, multipliers and the score, with the number of contacts in the last ten minutes and the hourly rate beside them. The score is an estimate and says so: points are one per QSO, because the sponsors’ own band and continent weighting is theirs to adjudicate and a wrong guess is worse than an honest baseline. The multiplier count is real. The sponsor’s adjudication is the one that counts.

On FT8 it logs itself. For the contests with an FT8 message layout — EU VHF, CQ WPX and the generic serial one — START also sets the digital-mode contest exchange, and every FT8 QSO that completes is written into the session with its sent serial, its received exchange and both calls, without you touching the entry form. A CQ WPX or EU VHF run over FT8 therefore needs no typing at all. The other contests (CQ WW’s zone, the CB activity) have no FT8 layout and are typed by hand, as are all CW and SSB contacts.

11 m is the exception, deliberately. None of those layouts is used on the citizens’ band — the band’s own format is the CB activity, typed by hand — so a contest started on 11 m leaves the digital-mode exchange exactly as it was and your CQ stays a plain CQ <call>. This matters for a reason worth knowing: the serial layout’s calling message is CQ RU <call>, and a Type-4 CB callsign is capped at eleven characters for the whole identifier, so CQ RU followed by even a short 11 m call will not resolve. The engine refuses the amateur layouts on 11 m even if one is left set from a session on another band, so it cannot reach the air either way.

Stopping. STOP ends the session; the contacts stay in the logbook, tagged with the contest, and are what the next session’s serial is seeded from. The digital-mode contest exchange the session set is put back to whatever it was before the session started, so the CQ returns to normal and the digi panel shows your setting, not the contest’s. Only the session’s own state — which contest, the serial, your exchange — is forgotten.


MAIL in the system button area opens the mailbox. Winlink is the amateur store-and-forward email network: messages are held by a Common Message Server (CMS) and collected when you connect, either over the internet or — eventually, see below — over the air.

sdroxide speaks the Winlink client protocol natively: B2F/FBB forwarding, LZHUF compression, and the secure-login challenge. There is no external program to install and nothing to configure beyond the account.

Setting up

An account is created the first time a callsign connects to the CMS, and its password arrives as a service message; Winlink validates amateur licences automatically for many countries.

Everything sdroxide needs is on Settings → Winlink, field by field in §6.8: the account callsign and password, the route (internet or radio), the gateway to call over the air, and the timer. Two of them catch people out — the password is case-sensitive, and the tab has its own APPLY button that has to be pressed before the account reaches the mailbox.

A connection refused before it starts. Winlink’s production servers accept only client names registered with them. sdroxide is not registered yet, so the Client name field on that tab is what gets an operator in for now; see §6.8.

Using it

The window has a folder row — INBOX, OUTBOX, SENT, ARCHIVE — with the message count beside each, and three buttons:

Addresses are callsigns, or SMTP:someone@example.org to reach ordinary internet email. Separate several with commas.

The mailbox lives on the machine with the radio, under ~/.config/sdroxide-brown/winlink/, one file per message. A remote or browser client reads it a page at a time over the wire rather than holding a copy, so a mailbox with attachments in it does not have to cross a phone link on connect.

Over the air

Two routes now: the CMS over the internet, and AX.25 packet on the radio, reaching the RMS Packet gateways. Pick one under Settings → Winlink → How to connect. ARDOP on HF is still to come; VARA deliberately is not, being a closed Windows binary whose licence forbids reverse engineering and for which no open implementation of the waveform exists.

To forward over the air:

  1. Put the radio in PACKET (VHF/UHF, FM) or PACKET-HF (HF, sideband).
  2. Set your station call in the packet setup dialog — with an SSID, e.g. OE3JJS-10. Nothing transmits until this is set: an unidentified transmission is illegal everywhere.
  3. Set the route to Radio (packet) and name the gateway, along with the speed and frequency it runs. Both are properties of that gateway rather than of the band, so they live with its callsign and are applied when the session starts. Leave the frequency at zero to keep the dial where it is and tune manually.
  4. Press CONNECT in the MAIL window as usual.

While a session is running, CONNECT becomes ABORT. Stopping is cooperative rather than a hard kill: the link is torn down properly and whatever mail already arrived is still filed, so aborting a session that was halfway through does not lose what it had. A call to a gateway that is not answering takes two minutes to give up on its own, and ABORT takes effect in well under a second.

Choosing a gateway

Winlink publishes its gateway list through api.winlink.org, which refuses every request that does not carry an access key. sdroxide does not have one, so you keep your own list — which is what a packet operator does anyway: the two or three gateways reachable from one location are learned by trying, and they rarely change.

Under Settings → Winlink, with the route set to Radio, type a gateway callsign and press + ADD GATEWAY to remember it. Each saved entry carries a digipeater path, a frequency and a speed, and USE loads all of them, making that gateway the one the next connect calls. Nothing is hidden behind the missing API key: a typed callsign works exactly as well as a fetched one, and if a key ever arrives the fetched entries land in the same list.

Digipeaters go in Via, in order, separated by spaces — usually empty, since a gateway you can hear directly is one you should call directly.

Keeping the speed with the gateway is what makes a mixed list work. There is no rule that derives speed from frequency — a 2 m RMS may be 1200 or 9600 — so the only reliable source is what the gateway’s owner publishes. Get it wrong in the 1200 direction and you hear the gateway answer a call it cannot understand; get it wrong in the 9600 direction and you hear nothing at all, which is why the session transcript records the speed each call went out at.

Packet length and window

Packet length is the most a single frame carries, and window is how many frames go out before waiting for an acknowledgement. Shorter frames survive a marginal path — only the frame that was hit has to be sent again — and cost more overhead per byte; a bigger window fills a good path and is more to resend on a bad one. 128 and 4 are reasonable everywhere; 64 on an HF path that is fading, 256 where the path is solid.

Both apply to Winlink over the radio as well as to the terminal: they are the link’s settings, not the panel’s.

Speeds

  Where Notes
300 baud HF, sideband 200 Hz shift AFSK. PACKET-HF runs at this speed and no other.
1200 baud VHF/UHF, FM Bell 202. The workhorse, and what most RMS Packet gateways answer on.
9600 baud VHF/UHF, FM G3RUH. Needs the radio’s data port — a microphone and speaker path destroys it at both ends. That is the radio, not sdroxide.

The modem is validated against Direwolf at all three speeds, in both directions: sdroxide decodes audio gen_packets produced, and atest decodes what sdroxide transmits.

The packet panel

MONITOR lists every frame heard on the channel — sender, destination, digipeater path, frame type and any text — with your own transmissions in a different colour. BUSY means another station is transmitting and the modem will not key over them. A rising bad count against a steady frame count is what a marginal path looks like: frames are arriving and failing their check sequence. CLEAR RX empties the monitor and resets the bad-frame count with it — the count is that page’s own tally, and one left over from a cleared page describes traffic that is no longer on it. A connected station stays connected.

Clicking the callsigns on a monitor line puts that station in the terminal’s connect bar, path and all. That is how you find out who is reachable: by watching the channel, not by typing callsigns from memory.

SETUP opens the packet settings — the station callsign above all, plus the speed, the TX delay, the packet length and window, the default digipeater path, the connect text, the beacon and the KISS server. It is the only route to them, and until a station callsign is set there CONNECT stays greyed out and nothing transmits: an unidentified signal is illegal everywhere.

TERMINAL is the connected session — see below.

Connecting to a node or a BBS

Type a callsign in the terminal’s connect bar and press CONNECT. What comes back appears in the pane above the input line; what you type goes out a line at a time. A node or a BBS answers with its own command prompt, and from there you are talking to its software, not to sdroxide — H for help and B to leave are a good guess almost everywhere.

Via is the digipeater path, nearest hop first, separated by commas: OE3XLR-1,OE3XMS-1. Leave it empty for a station you can hear directly. Most BBSes are a hop or two away through a node, so this is usually the difference between a call that works and one that never gets an answer — and a call through the wrong path fails exactly like a station that is not there. Setting a Default via in the packet settings fills the box in for you, because the path to your local node is the same every time and retyping it is how a hop gets left off.

The status row is the session in five numbers. CALLING means the connect is out and unanswered; CONNECTED means the link is up. n unacked is frames sent that the far end has not confirmed, and retry n is how many times we have asked again — a retry count climbing while the unacknowledged count stays put is what a fading path looks like from this side, and it is the warning before the link gives up. When it does give up, the transcript says so in those words, which is deliberately different from what it says when the far end hangs up: “the link gave up” and “disconnected” send you looking in completely different places.

Up and Down on the input line walk back through what you have already sent. At 300 baud, retyping is where the typos come from.

Lines end with a carriage return, which is what every BBS and node command line expects. Text that is not Unicode is read as Windows-1252 and sent as it — most of this network predates UTF-8, and a two-byte sequence arrives at a BBS as two characters of nonsense where one byte would have been the right letter.

Extended (mod-128) asks for a window bigger than seven frames. It is off, and worth leaving off unless you know the far end wants it: many nodes refuse the request with a DM, which looks exactly like a station that would not talk to you.

Answering calls

Switch on Answer calls and a station that connects to you arrives in the same terminal pane; Connect text is what they are greeted with. You are then in a conversation with whoever called — there is no mailbox here, so say so in the connect text if nobody is watching the screen.

A station whose link is already busy refuses calls with a DM rather than accepting them, which tells the caller to try later. That is the same rule as everything else in this section: there is one radio, one channel and one link.

The MAIL window and this pane are two ways to use one radio. Whichever asks first gets it, and the other is told so — a Winlink session started while you are connected is refused with the reason, and a CONNECT pressed during a Winlink session gets a line in the transcript saying the MAIL window has the link.

Disconnect before changing mode. A mode change ends the session immediately, and the DISC cannot get out: the modem needs seconds of audio that the mode change takes away. The far end is left waiting out its own timers.

When a call is not answered

At 300 baud a full frame takes seconds to reach the other end, so the link’s timers are worked out from the speed, the packet length and the number of hops rather than being fixed. If a call to a station you can plainly hear is never answered, the usual causes are, in order: the wrong digipeater path; the station not answering calls at all; a Packet length the far end will not accept — drop it to 128, or 64 on a marginal path; and Extended switched on against a node that refuses it.

Serving the modem to other software

Switch on KISS server in the packet setup dialog and sdroxide offers its modem as a KISS TNC on a socket (8001 by default), the same way it already serves TCI and rigctld. Pat, an APRS client, or the Linux AX.25 stack can then use the radio without knowing sdroxide exists.

The KISS server and the terminal are two hosts on one radio and neither knows about the other: a KISS client can put frames on the air under your callsign while you are in a session, and nothing will stop it. Use one at a time.

A host’s TXDELAY and persistence commands are logged and ignored — those are your settings, and a client overriding them invisibly would be a mystery to debug. The server runs only while the radio is in a packet mode: offering this modem while the radio is on FT8 would be a socket that accepts frames and never sends them.


12. Command-line reference

Option Description
--device <ARGS> SoapySDR device args, e.g. driver=hackrf (default: config, then first device).
--probe List devices and their probed capabilities, then exit.
--console Terminal (text) waterfall instead of the GUI.
--siggen Use the built-in signal generator instead of hardware.
--file <PATH> Play a raw interleaved CF32 IQ file instead of hardware.
--freq <HZ> Center frequency in Hz (default: where the last session was left, or 14,200,000 on a first run).
--rate <HZ> Sample rate in Hz (default: from config).
--gain <DB> Overall RX gain in dB (default: hardware AGC or a moderate value).
--mode <MODE> Initial mode, matched without regard to case: LSB, USB, CW, AM, SAM, NFM, WFM, DRM, HD RADIO, ADS-B, VDL2, AIS, DIGU, DIGL, DSB, ISB, SPEC, FT8, FT4, FT2, JS8, WSPR, PSK, RTTY, RTTY-FM, PACKET, PACKET-HF, APRS, SSTV, SSTV-FM, RIFP, WEFAX, NAVTEX, ACARS, OLIVIA, THOR, FSQ, ATCHAT, HELL, RFPAINT, RADE, HFDL. HD RADIO is the one name with a space in it, so it needs quoting on the command line: --mode "HD RADIO". Default: the mode the last session was left in.
--antenna <NAME> RX antenna port, as the device names it (LNAH, TX/RX — --probe lists them). Default: the port the last session was left on, and failing that whatever the driver selects.
--tx-antenna <NAME> TX antenna port, likewise (BAND1, BAND2).
--server Run as a server (web client + WebSocket streaming backend).
--connect <HOST[:PORT]> Connect as a native remote client to a running server.
--port <PORT> Server port (default: from config, 4950).
--web-root <DIR> Directory with the built web client (default: embedded assets).
--fft <SIZE> Spectrum FFT size (default 4096).
--fps <N> Console waterfall lines per second (default 15).
--db-floor <DBFS> Display floor in dBFS (default −110).
--db-ceil <DBFS> Display ceiling in dBFS (default −10).
--width <CHARS> Console spectrum width in characters (default 100).
--freedv-reporter-probe <SECS> Connect to FreeDV Reporter read-only for SECS seconds and print what arrives. Uses the server’s view role, so nothing is reported and you do not appear on the site. Needs no radio.
--freedv-reporter-host <HOST[:PORT]> FreeDV Reporter host for the probe (default qso.freedv.org).
--record-iq <PATH> Write every raw IQ sample the receiver delivers to PATH, in the same interleaved CF32 format --file reads back. For capturing a band to work on offline — see 5.6. Large: 8 bytes a sample, so about 16 MB a second at 2 Msps, and it runs until you quit. Radio 0 only.
--swl Start in SWL mode (Short Wave Listener): hide every transmit control for this run. The same as ticking Start in SWL mode in Settings → UI, without changing the stored preference.
--oob-tx Allow transmit on any frequency the hardware supports, not just the amateur bands. See below.

Testing without a radio: --siggen (built-in signal generator), --file (replay an IQ recording), --probe (list SoapySDR devices), and --console (a text-mode waterfall) are handy for trying things out. --record-iq is the other half of --file: capture a band once and replay it as often as a decoder needs.

Transmitting outside the amateur bands: --oob-tx

sdroxide refuses to key up outside the amateur allocations. That lockout is the last thing standing between a mistyped frequency and an out-of-band transmission, so it is on by default and there is no button in the interface to turn it off.

--oob-tx lifts it for that run only. It overrides tx_ham_only in config.toml and cannot be saved, so lifting the lockout is a deliberate act every single time sdroxide starts:

sdroxide --oob-tx

A warning appears in the middle of the window on startup and stays there until you dismiss it by hand. I UNDERSTAND dismisses it for that run, and it comes back on the next launch, because the flag has to be passed again on the next launch. Tick Don’t show again beside that button instead and the acknowledgement is remembered on that screen: the lockout is still off while the engine runs with --oob-tx, but the page is not shown again.

The flag can only ever loosen the lockout, never tighten it: without it, sdroxide behaves exactly as it always has.

This is for licensed out-of-band use — MARS/CAP, a commercial or experimental licence, a service-monitor or dummy-load bench — where you are authorised to use the frequencies you are about to key on. Transmitting outside your licence is an offence in every country that issues one, and the penalty for interfering with aeronautical, maritime or emergency traffic is not a fine.

Running --server --oob-tx lifts the lockout for every client that connects, local or remote, and each of them gets the warning: the licence at risk belongs to whoever is at the controls, who need not be whoever started the engine.


13. Configuration files

sdroxide stores its settings under the per-user config directory:

Platform Location
Linux ~/.config/sdroxide-brown/
macOS ~/Library/Application Support/org.sdroxide.sdroxide-brown/
Windows %APPDATA%\sdroxide\sdroxide\config-brown\

This build keeps its own directory. SDR Oxide Brown uses a …-brown directory beside upstream sdroxide’s, so the two builds never read or write each other’s settings — run both and nothing is disturbed, and settings the two do not share (the 11 m and listening ones) cannot be dropped by the other build rewriting a file. Your existing settings are moved across automatically the first time this build starts after the change: their contents are copied into the …-brown directory, the original is left exactly where it was, and the old build keeps working. You should not have to do anything.

Moving settings to another installation

You do not have to know any of that to copy a station’s setup somewhere else. Settings → General → Settings file has EXPORT…, which writes every settings file below — the root ones and each radio’s — into a single sdroxide-settings.json, and IMPORT…, which puts one back. Between two machines, two user accounts on one machine, or a laptop being rebuilt, that is the whole job.

The files travel exactly as they are on the disk, so a bundle written by a newer sdroxide does not lose settings this one has never heard of. An import replaces what is here file for file and leaves anything the bundle does not mention alone — so a bundle from a one-radio station will not remove a second radio’s configuration here — and it takes effect the next time sdroxide starts, because the settings already in memory would otherwise be written straight back over it.

Two things are deliberately not in the file, and both because they are not settings:

Both buttons are on the machine the radio is attached to: a remote or browser client says so instead, because the settings it could reach are its own screen’s and not the station’s.

File Format Contents
config.toml TOML General settings: device_args, sample_rate, cal_offset_db, spectrum_fft, spectrum_fps, server_bind, server_port, tx_ham_only, swr_guard and swr_limit (the SWR guard, §6.1), audio_output, audio_input, region ("R1" / "R2" / "R3" — the IARU region every band plan follows, §6.1), cb_plan ("World" / "Cept" / "Germany80" / "Uk27_81" / "Us" / "Australia" — the CB channel plan, §6.1), cb_tx_allowed (true only after the 11 m transmit opt-in is confirmed, §6.1), plus the [ui] display preferences (including theme, button_style and window_style), the [speech] announcement settings (§6.3), the [remote_access] sign-in that server mode demands (§8.3, stored in plaintext) and the [remote_server] address the General tab dials (§8.2). Belongs to the machine the engine runs on — except [ui], [speech] and [remote_server], which belong to the screen in front of you.
radio.json JSON Which radio interface is selected and everything that configures it — the CAT/HPSDR/TCI/SmartSDR/RTL-SDR/rtl_tcp/SpyServer/RX-888/Airspy HF+/SDRplay/PlutoSDR sections, the converter offset and stated tuning ranges, and the radio’s sound-card device names.
digi.json JSON Digital-mode operator settings: your callsign and grid, FT8/FT4/FT2 TX period, auto-sequence and message templates, the transmit-frequency hold (hold_tx_freq) and the per-band transmit offsets it pins (tx_audio_hz), the per-mode transmit-audio levels (tx_audio_levels, with tx_audio_level_fm / tx_audio_level_ssb as the level a mode with no entry of its own inherits), and the WSPR beacon’s duty cycle, power and band-hop list.
memories.json JSON Saved memory channels.
bandstacks.json JSON Per-band memory of your last frequency/mode/filter (up to three per band).
profiles.json JSON The saved station setups from Settings → Profiles (6.12): each one’s name, the remembered radio state (the same fields as session.json), the digital-mode settings and the band stacks. Shared by every radio of the station.
bandplan.json JSON The band plan itself, per IARU region: band edges, the CW/data/phone/beacon/all-modes sub-segments, and the PSK and RTTY skimmer windows — all in MHz. Written from the built-in IARU tables on first start and meant to be edited; narrow a band here and the transmit lockout narrows with it. Which region applies is region in config.toml. RELOAD BAND PLAN on the General tab applies an edit without a restart, and deleting the file restores the defaults. See §6.1.
digi_presets.json JSON The frequencies you have added to the digital modes’ own lists yourself, as mode / dial_hz / note — written by the + Save button in the ⇵ picker (§3.1) and readable and editable by hand, which is where a note comes from. Belongs to the station, so every radio and every remote client offers the same list. Absent until you save one.
session.json JSON Where you left the radio: both VFO dials and which of the two was selected, the mode, the RX/TX antenna ports, the AF volume, RX gain, AGC mode, squelch and noise reduction, the TX drive/tune drive/mic gain, and the front end’s own gain stages (the sliders on the Radio tab’s device panel), restored the next time you start. Written by the engine as you tune, so --freq, --mode, --antenna and --tx-antenna override it for a run without changing it. Gain stages are remembered by name: one your current front end does not have is kept, not thrown away, so switching back to the radio it belongs to brings it back, and a figure past what this device offers is clamped to its range.
qso_log.json JSON The logbook (digital and manual QSOs, with contest/QSL fields).
net.json JSON Network cockpit: DX cluster / POTA / SOTA / PSK / FreeDV Reporter / WSPRnet feed settings, and callsign-lookup / eQSL / QRZ / HamQTH / Club Log / LoTW credentials (stored in plaintext).
winlink/ directory The Winlink mailbox: inbox/, outbox/, sent/ and archive/, one .b2f file per message holding it exactly as it rides the wire (§11). The account settings live in net.json, password included, in plaintext.
tciserver.json JSON Built-in TCI server: enabled, bind address, port, advertised device name, whether clients may transmit, and the client limit.
rigctld.json JSON Built-in Hamlib rigctld server: enabled, bind address, port, reported rig name, whether clients may transmit, and the client limit.
wsjtx.json JSON WSJT-X UDP broadcast: enabled, destination host and port, and the name clients see.
scanner.json JSON The scanner: memories or a range, the range and channel step, the level that counts as busy, the dwell, how it resumes, and which memories to skip.
renderer-fallback.txt text Written only when a panic came from the graphics driver: the next start renders through OpenGL and says so. Delete it to go back to the default renderer (14).
skimmer.json JSON Skimmers: which of CW / PSK / RTTY run, and each one’s spot squelch in dB. Restored at startup; a narrowband (audio-mode) radio still forces them off without disturbing what you picked.
adsb.json JSON ADS-B decoder (§3.13): the two timeouts, how many history dots to keep, how far ahead the speed vectors reach, and the ceiling on the aircraft table. Restored at startup, and — like ism.json — a receiver that cannot feed the decoder forces it off without disturbing what you picked.
vdl2.json JSON VDL2 decoder (§3.15): which of the fourteen channels to listen on, the burst threshold in dB, how much log and how many stations to keep, and how long a silent station stays on the list. Restored at startup, and — like adsb.json — a receiver that cannot feed the decoder forces it off without disturbing what you picked.
ais.json JSON AIS decoder (§3.16): which of the two channels to listen on, the slot threshold in dB, the two timeouts, how many minutes of trail to keep, how far ahead the vectors reach, and the ceiling on the vessel table. Restored at startup, and — like adsb.json — a receiver that cannot feed the decoder forces it off without disturbing what you picked.
dab.json JSON DAB receiver: the channels a SCAN found, the stations heard on each, your ★ presets, the channel and station chosen, and the volume. Written whenever the panel changes it and restored at startup, so a scan is not lost to a restart. Delete it to start the list from nothing.
ism.json JSON ISM decoder: whether it runs, which device families it listens for, the burst threshold in dB, and whether the rtl_433 decoders are on, which band they watch and how wide a window they get. Restored at startup, and — like skimmer.json — a narrowband (audio-mode) radio forces it off without disturbing what you picked.
rtl433_flex.conf text Your own ISM decoders, in rtl_433’s “flex” syntax (§5.5). Written with a commented example the first time the ISM decoder runs, and never rewritten afterwards — like bandplan.json, it is yours to edit. A specification that does not pass its check is listed in the ISM window and skipped; the rest still load. RELOAD DECODERS in the ISM window applies an edit without a restart.
input.json JSON Control inputs: keyboard bindings, panadapter mouse behaviour, mouse-button bindings, and the MIDI controller mapping. Belongs to the machine running the user interface, not the engine.
remote_login.json JSON A sign-in to somebody else’s server that you asked this client to remember (§8.3). Written only when the Remember on this device box is ticked, holds the password in plaintext, and deleted when you untick it or the server refuses it. Belongs to the user interface, like input.json; the browser client keeps the same thing in local storage instead.
satellites.json JSON Satellite additions for the 3D tracker: subscribed element-set listings, element sets pasted in by hand, and frequency entries that override the built-in table. Belongs to the engine, like net.json: the listings are fetched and cached where the radio is, so remote and browser clients track the same satellites.
relay.json JSON The station’s external transmit/receive switch (§6.11): which relay board or contact closure, the contact table, the sequencer’s lead and hold times, what to do if it stops answering, and the transmit sense input. Belongs to the engine — the relay is bolted to the antenna — so remote and browser clients set up the real one.
broadcast_stations.json JSON Your own broadcast stations and corrections, merged over the downloaded schedule (§10.6). Never written by sdroxide, and absent until you create it.
broadcast/ CSV The broadcasting season’s schedule as downloaded from eibispace.de, one file per season. Managed by sdroxide: refetched when the season changes, and safe to delete.
sstv_messages.json JSON The overlay message stored for each of the five SSTV transmit slots.
voice_names.json JSON The label given to each of the ten voice-keyer slots.
voice/ dir The voice-keyer recordings (slot1.wav…slot10.wav), 48 kHz mono. Drop your own WAV in to replace a message.
speech_voices/ dir Extra voices for the spoken announcements: a Piper .onnx model and its .onnx.json config, side by side. Absent until you create it — the shipped voice lives with the program, not here. Note this is not voice/, which is the voice keyer.
sstv_tx/ dir The five SSTV transmit-image slots (slot0.png…slot4.png).
sstv_rx/ dir Received SSTV and RIFP pictures, kept for the gallery.
wefax_rx/ dir Weather-fax charts received by an earlier version. Charts now go to ~/Pictures/sdroxide/wefax/, but this is still read so an existing collection stays in the gallery.
solar/ dir Cached solar imagery, space-weather JSON and subscribed element-set listings for the 3D view, with an index of HTTP validators so refreshes stay cheap. Safe to delete; it is re-fetched on demand.
radios.json JSON The roster of configured radios (§2.17): each radio’s id, the name you gave it (empty = named after its interface) and whether it is switched on (enabled, absent = on). Absent until you add a second radio. Written by the GUI, and — on a machine running --server — by a signed-in remote client adding or closing a radio (§8.1).
radio-<N>/ dir An additional radio’s own copies of the files that describe a radio: radio.json, session.json, scanner.json, tciserver.json, rigctld.json and wsjtx.json. The first radio keeps those files at the root, exactly where a single-radio installation has always had them, so adding and removing other radios never touches it. Kept on disk when the radio is closed.

Every file has sensible defaults, so a missing or partial file always loads. You normally edit these through the GUI rather than by hand.

12.1 Choosing the radio interface without a GUI

Settings → Radio is the normal way to configure an interface, and a remote or browser client can use all of it — including which interface to open, because the device lists it is chosen from are enumerated on the machine the radio is plugged into and sent to the client (8.4). What follows is for the times there is no client either: a first boot with nothing configured, a container image, a machine being provisioned. Picking the interface by hand means writing radio.json, so here is what it contains.

Only the keys you want to change need to be present. Everything else falls back to its default, and a partial file is normal rather than a special case.

{
  "backend": "Pluto",          // which interface to open — see the list below
  "converter_offset_hz": 0.0,  // external up/down-converter in the antenna line
  "freq_ranges_rx": [],        // tuning ranges you state yourself, in Hz
  "freq_ranges_tx": [],        //   e.g. [[144000000.0, 146000000.0]]
  "radio_audio_in": null,      // sound-card names, for the CAT interface only
  "radio_audio_out": null,
  "rx_audio_gain_db": 0.0,     // fixed trim on this radio's receive audio, dB
  "pluto": { "address": "192.168.2.1", "sample_rate_hz": 2500000.0 }
}

backend is one of:

Value Interface Its settings live in
"Soapy" SoapySDR device device_args in config.toml
"Cat" CAT control + sound card "cat"
"Hpsdr" OpenHPSDR network radio "hpsdr"
"Tci" TCI over WebSocket "tci"
"IcomNet" Icom over its LAN/WiFi port "icomnet"
"SmartSdr" FlexRadio SmartSDR "smartsdr"
"Pluto" ADALM-Pluto over IIOD "pluto"
"RtlSdr" RTL-SDR dongle "rtlsdr"
"RtlTcp" RTL-SDR published by rtl_tcp "rtltcp"
"SpyServer" A receiver published by a SpyServer "spyserver"
"SpyServerVfo" The same, narrow I/Q + the server’s FFT "spyserver_vfo"
"Rx888" RX-888 Mk1 / Mk2 "rx888"
"AirspyHf" Airspy HF+ "airspyhf"
"Airspy" Airspy R2 / Mini "airspy"
"HackRf" HackRF One / Pro / Jawbreaker / rad1o "hackrf"
"SdrPlay" SDRplay RSP "sdrplay"
"Elad" ELAD FDM-DUO / FDM-S1 / FDM-S2 "elad"
"Lime" LimeSDR family + LimeRFE, via LimeSuite "lime"
"HydraSdr" HydraSDR RFOne "hydrasdr"

The per-interface object is only read when backend names it, so leaving the others out — or leaving them configured for a radio you have unplugged — changes nothing. The keys of each are the settings on that interface’s tab in §6.2, and the defaults are what the tab shows before you touch it. "pluto", for example, takes address, sample_rate_hz, rf_bandwidth_hz, rx_gain_db, agc ("Manual", "SlowAttack", "FastAttack" or "Hybrid"), tx_gain_db, rx_port, tx_port, ppm, buffer_samples and rx (which receive chain, for a 2R2T board — like "tci"’s rx and "hpsdr"’s ddc, it counts from 0 where the dialog counts from 1).

To see the whole file with every default filled in, start sdroxide once and read what it wrote: it saves a complete radio.json on exit, and that file is the authoritative list of keys for the version you are running.

A worked example — a Pluto on a headless server, reached over its USB gadget link:

{
  "backend": "Pluto",
  "pluto": {
    "address": "192.168.2.1",
    "sample_rate_hz": 2500000.0,
    "agc": "SlowAttack",
    "rx_gain_db": 40.0
  }
}
# /etc/systemd/system/sdroxide.service
[Service]
ExecStart=/opt/sdroxide/sdroxide --server --port 4950

No --device, --freq or --rate is needed once the file is in place; --device configures SoapySDR only, and --rate reaches the SoapySDR and PlutoSDR interfaces but not the rest — where it does not apply, sdroxide says so in the log rather than ignoring it silently.

One trap worth knowing if you clone a working install: session.json remembers the dial frequency, and a frequency that was valid on the previous radio may be outside the new one’s range. The engine says so on connect rather than sitting there silently — but if a freshly cloned server comes up receiving nothing, the remembered frequency is the first thing to check.

Two things are kept outside the config directory, because they are things you will want to open in an ordinary file manager rather than program state: audio recordings go to <Music>/sdroxide/ (2.21), and received weather-fax charts to <Pictures>/sdroxide/wefax/. Where the platform exposes no such folder, both fall back to the config directory. The recordings folder can be pointed anywhere else from Settings → General → Recordings (2.21).


14. Troubleshooting

“Waiting for spectrum” and no receive audio (CAT radio). The radio’s capture device could not be opened. Common causes:

FT8/FT4 decode nothing, yet the waterfall and the audio are fine. Check the clock of the machine running the decoder — on a remote station, the server. A clock a couple of seconds out puts every fifteen-second period in the wrong place, and nothing decodes while everything else looks healthy: the signals are on the waterfall, you can hear them, a phone app held to the speaker decodes them, and the log shows no warning. Run timedatectl on that machine; it must say System clock synchronized: yes. If it says no, or NTP service: n/a (a minimal server install often has no time service), run apt install systemd-timesyncd, then timedatectl set-ntp true, and restart sdroxide. A system health script that checks the station should check this too: it is the one fault that leaves every other line green.

“A buffer underrun or overrun occurred”, and FT8/FT4 will not decode. The audio device is losing samples. The line in the diagnostics reads

WARN sdroxide_audio: radio audio input: the audio stream from "…" glitched — the
host says samples were lost between two callbacks …

Read the stream’s name first. Only two of them can cost a decode: radio audio input (a transceiver’s demodulated audio) and radio IQ input (an SDR’s I/Q on a sound card). The mic input stream is the microphone, and nothing reads it at all unless you are transmitting by voice — while receiving, its samples are drained and thrown away on every tick. Both streams glitch together on a machine that is momentarily busy, which is why the microphone’s line is INFO and says so in as many words: it is not why a digital mode is failing to decode, and it sent one reporter looking for what a USB microphone had to do with FT8 (issue #367).

and after the first one they are counted and summarised rather than repeated, so a stream that does this every few seconds no longer buries the rest of the log. The host is telling sdroxide that the captured audio is not continuous: what arrives is spliced end to end, with a hole taken out of the middle.

For listening, that is a click. For the timed modes it is fatal, and silently so — every tone after the gap arrives earlier than it was sent, so the whole fifteen-second period misaligns and decodes nothing while the waterfall looks perfectly healthy. When that happens the FT8 panel says so directly:

WARN sdroxide_digi: FT8: the last receive period arrived 0.4 s short of the
15.0 s it should be — the audio device is losing samples …

The period you selected the mode in is exempt, however short it is: a mode chosen four seconds before the next boundary has legitimately only heard four seconds, and reporting that as a fault at every start had two people looking for a broken sound card that was never broken (issues #363, #367). So is the period the audio itself started in, which is not always the same one — the device may still be opening when the slot clock begins. Counting starts with the first period sdroxide has heard all of.

A period that arrives completely empty is a different message, because it is a different fault — no audio is arriving at all, rather than audio arriving with a hole in it:

WARN sdroxide_digi: FT8: no receive audio is reaching the decoder — a whole
15.0 s period arrived empty, so nothing can decode …

That is what a radio switched off, or an audio device that is not the one the radio is feeding, looks like from here. It is said once and not again until audio comes back, rather than every fifteen seconds for as long as it lasts — which is what filled one reporter’s log with a thousand sample-loss warnings about a sound card that was never losing anything (issue #393).

A virtual audio cable — VB-Audio, VAC, Flex DAX — is the usual source, and it is not a fault in the cable so much as a consequence of what one is: there is no crystal at either end, so the program feeding it and sdroxide reading it drift apart until the driver drops or repeats a buffer to catch up. Things that help, roughly in order:

A real sound card reporting the same thing means this machine is not keeping up with it, which is the capture frames dropped warning’s territory rather than this one — see §6.2.

“No radio” at startup, or the radio disappears mid-session. sdroxide shows the reason it could not open the interface and keeps trying it in the background — every second at first, then more slowly — so a rig that is merely late (ExpertSDR3 not up yet, an SDR still booting) attaches on its own within a few seconds of appearing. The same applies when a network rig hangs up: it reconnects once the radio is back. You only need Apply / reconnect to switch to a different interface, or to apply a settings change.

The dial jumps back, with a banner saying the frequency is out of range. The receiver cannot tune there. sdroxide checks the range the front end reports before it asks the hardware for anything, and returns the dial to the last frequency that worked, because a driver asked for the impossible does not always fail cleanly — a LimeSDR asked for a frequency below its range stops receiving altogether until it is set up again. If it happens anyway (the driver accepted the request and then failed), the front end is restarted on the last good frequency by itself, and reopened from scratch if that is not enough. Nothing needs restarting by hand; Dismiss clears the banner.

IQ shows no spectrum, or a warning that the device is mono. IQ requires a two-channel (stereo) capture device. A mono USB adapter cannot carry I and Q. Use a stereo line-input interface for IQ, or switch Sound format to Demod audio.

The log warns about dropped samples and a lower sample rate, but only while I am transmitting. It is not a fault, and is no longer reported as one. Most front ends are read only while they are receiving, so for the length of an over the receiver is streaming into a buffer nobody is emptying; it fills, and everything after that is discarded until the backlog is dropped at key-up. That is the ordinary cost of transmitting, at exactly the sample rate, for as long as you hold the key — nothing to do with the computer keeping up, and lowering the sample rate does not change it. It is now counted separately and said in the same breath as “discarded while keyed”, at debug level rather than as a warning. A drop count that appears while you are receiving is the real thing, and the advice there still stands.

This is most visible with a panadapter pairing (§6.2.15), where the lent receiver is a different radio from the one being keyed and knows nothing about the over; Blank on transmit, on by default, is what stops it being read. Turn that off and the receiver keeps being read through the over, in which case anything dropped really was dropped.

The T/R switch relay does not click. On Linux, the USB HID relay boards and the CM108 sound cards need a udev rule that no distribution ships. Install it and replug the device — see 6.11.1. If the device does not appear in the picker at all, cargo run -p sdroxide-relay --example relay -- --list --all prints every HID device the machine can see, which tells “not permitted” apart from “not recognised”. Several CM108 clones carry a genuine C-Media id and ignore the GPIO report entirely; nothing but listening for the click separates those.

Every transmit is refused, saying the T/R switch is not answering. That is the switch’s fail-safe doing its job: the relay that protects the receiver has stopped responding, so the over is refused rather than sent into an unprotected front end. Check the cable and press APPLY on the T/R switch tab to try again. If you would rather transmit anyway, set If it will not answer to Transmit anyway, warn — but read 6.11.4 first.

The SDR still gets blasted when I key the rig at the microphone. Expected, and the one thing this cannot fix from software: sdroxide learns of an over you start at the radio by asking over CAT, a few hundred milliseconds in. Wire the rig’s SEND line into the transmit sense input (6.11.3) to cut that to milliseconds, key from sdroxide instead of the microphone where you can, and use an RF-sensed hardware T/R switch for a front end genuinely worth protecting. See 6.11.5.

Transmit was cut off, and now every key-up is refused. The SWR guard has tripped (§2.10): the radio reported an SWR at or above the limit, so the over was stopped and transmit is latched out until you say you have seen it. The banner names the figure; Acknowledge on it re-enables transmit, and the trip is also shown on Settings → General. Check the antenna first — if the fault is still there the next transmission stops too. Turning the guard off clears a standing trip as well, which is the answer while you are tuning a manual ATU.

The CAT radio does not change mode. On the Radio tab, set Mode control to CAT. For the modes sdroxide modulates through the rig’s sound card — FT8, FT4, PSK, RTTY, SSTV and the rest — set Digimode mode to USB or DIGI as your rig expects; that setting governs them instead of Mode control. Check the serial port, baud, and (for Icom/Xiegu) the Radio ID. Check CAT family as well: Kenwood, Yaesu, Elecraft and QRP Labs look alike on the wire and none of them obeys the others’ commands.

The rig goes to USB rather than USB-D, so nothing comes out of the USB audio. Set Digimode mode to DIGI. On an Icom, also check Radio model: USB and USB-D are the same mode byte over CI-V and what separates them is a second command, whose sub-command number differs by model — an Other Icom is not sent it at all, because the wrong number writes somewhere else entirely. With both set, the rig goes to USB-D (LSB-D where SSTV or RADE rides the lower sideband) and takes the over from its data input. A rig with no DATA position wants USB here instead, plus its SSB modulation source set to the USB input at the radio — MENU → SET → Connectors → MOD Input on an IC-7300.

The CAT radio follows my dial but ignores frequency changes from sdroxide. Take the radio out of memory mode: most rigs answer a frequency read from a memory channel but refuse to be tuned into one, so the app follows the radio while the radio ignores the app. (On Yaesu this used to also happen because the frequency field is eight digits wide on the FTDX1200/3000/5000 generation and nine on the FT-891/991A and FTDX10/101 — sdroxide now reads the width off the rig’s own reply, so both work without a setting.) On a Kenwood, check that CAT family is Kenwood and not Yaesu: the frequency field is eleven digits here, and a Yaesu-width one is a syntax error the rig answers with ?; while carrying on reporting where it already was.

The Kenwood keys up and will not stop transmitting. CAT family is set to Yaesu. Yaesu unkeys with TX0;, and on a Kenwood that is a transmit command — the rig is being told to key, twice. Set the family to Kenwood, which unkeys with RX;. Pull the CAT cable or switch the rig off to stop it in the meantime.

The Kenwood keys but no audio goes out. On a TS-590S/SG, TS-890 or TS-990, set Send command to TS-590 style (TX1;). The plain send selects the microphone input and mutes the ACC2/USB audio sdroxide transmits.

The Kenwood transmits on the wrong band. On a TS-2000, set Send command back to TS-2000 style (TX;). TX1; is DATA SEND on a TS-590 but transmit on the sub-band on a TS-2000.

The QMX stopped answering, and now nothing on its CAT port works. Something sent it a carriage return, which a QMX takes as an instruction to leave CAT and become a terminal for the rest of the session — a terminal emulator left open on the same port does it on the first Enter. Close whatever else is on the port, then power the radio off and on. sdroxide never sends one.

The QMX answers nothing at all. Try its other ports. A QMX offers up to three virtual COM ports over USB and only one of them is the CAT port; Baud has no bearing on it either way, since the port is not a real UART.

The QMX’s Drive slider does not change the power. It cannot: there is no CAT command that sets a QMX’s output power, so the slider only reaches the level of the audio going into the sound card — and in Digi even that changes nothing, because the radio measures the frequency of what you send it and synthesises the carrier itself. Set the power at the radio.

The QMX will not transmit, and the log says its SWR protection has tripped. It has latched, and only the radio can clear it — sdroxide deliberately does not, because clearing a protection trip is a decision about an antenna. Check the antenna, then reset it at the radio.

The QMX’s panadapter is 12 kHz off, or it is nothing but noise. Two different faults. Everything sitting 12 kHz from where it belongs is the I/Q centre offset: it should be -12000, which sdroxide fills in when you pick the QRP Labs family with Sound format on IQ — a config carried over from before that will still have 0. (In CW, expect a further ~700 Hz: the radio moves its I.F. by the pitch, and one figure cannot follow that.) A panadapter that is noise from edge to edge with the format on Demod audio is the other way round — the radio is still in its own I/Q mode from something else, and sdroxide switches it back off at connect, so reconnect.

The radio transmits at a power the Drive slider does not show — often much less — and moving the slider changes nothing. Every one of these radios stores its output power per mode, and sdroxide commands the mode at key-down. So the level you set while the rig sat in one mode was stored in that mode’s register, and the over went out on another one’s. sdroxide now writes the Drive level behind every mode command, which puts it in the register the over transmits on; if you are on a build older than that, set the power at the radio in the mode it actually transmits in. The tell is a tune: the operating level is restored at unkey, so the rig’s own power display jumps to what the slider says the moment a TUNE ends.

The Elecraft goes into plain SSB for FT8 instead of DATA. CAT family is set to Kenwood. DATA is a flag beside the mode there (DA) but a mode of its own here (MD6), so the Kenwood profile leaves a K3 in USB and then earns a rejection for the flag — with nothing to show that anything was refused. Set the family to Elecraft.

The Elecraft is in DATA but nothing decodes, and sdroxide shows no mode. The rig is in the wrong DATA sub-mode. MD6 restores whichever of DATA A, AFSK A, FSK D and PSK D that band was last left in, and only DATA A is the sound-card path; the other three hand the over to the K3’s own modems. Set Mode control to CAT and pick the mode in sdroxide, which sends DT0; behind the mode and pins it — or press DATA MD at the radio until it reads DATA A.

The Elecraft’s Drive slider only reaches a fraction of the rig’s power. The OM; query at connect found no power amplifier, so the slider spans 12 W rather than 110. On a K3 that means the KPA3 was not detected; on a KX3 or KX2, that the KXPA100 is not attached over its control cable. Check the log line Elecraft CAT: rig identified for what the radio said it was.

The rigctld link will not open. Check that a daemon is actually listening — rigctl -m 2 -r localhost:4532 f asks the one on this machine for its frequency — and that the address matches. The log line CAT open failed: Connection refused means nothing is listening there; CAT link open means the socket came up and any remaining fault is between the daemon and the radio, not between sdroxide and the daemon. Note also that PTT method DTR and RTS key nothing over a socket: a network link has no control lines. Use CAT, which asks the daemon to key the radio.

The Elecraft answers nothing at all. Check Baud: a K3, K3S, KX3 or KX2 goes no faster than 38400 (CONFIG:RS232 at the radio), so choosing 57600 or 115200 here leaves the link mute in both directions. Only a K4 runs above that.

CW transmits nothing. Check CW keying on the Radio tab — see 6.2.2. A rig in CW ignores audio sent to its sound card, so it can only be keyed from text: with Rig keyer (CAT), on Yaesu check that CW memory 1 is free to be overwritten; on a Yaesu FTX-1, sdroxide plays that memory with KY01, the form its CAT manual gives; through Hamlib rigctld, the text goes to Hamlib’s send_morse, so it is Hamlib’s backend for your rig that keys it (issue #412); on Kenwood, that break-in is on (sdroxide only asserts it when the rig has reported CW, because the same command is the VOX switch in every other mode); on Icom, that the radio takes 16 47 — sdroxide turns semi break-in on with every message, and a model old enough to answer NG to that needs break-in set at the radio, or [TRANSMIT] held on, instead; on Elecraft, that the rig is not sitting in a limited-access state such as BSET or VFO REV, where it answers ?; and does nothing; on any rig, that the radio is actually in CW (Mode control = CAT) and that the Drive slider — which is the rig’s output power on a CAT rig, in CW as in every other mode — is not down at the bottom. On a radio whose keyer sdroxide cannot drive at all — a Xiegu G90 keys up with no power out, and the ELAD has no text keying — choose Sound card (MCW) instead: the keyed tone goes out as audio and the rig is kept on the Digimode mode sideband rather than switched to CW (on the G90, Radio controlled with the rig parked in U-D, as for FT8).

Two identical USB sound cards are hard to tell apart. Device names include the manufacturer, model, ALSA card id, and USB id in brackets (e.g. … [Device_1 · 0d8c:0014]), which disambiguates identical adapters. Where the system reports both under one name — Windows and macOS do, and two Icoms are two of the same USB codec — the second carries a tag of its own (… [#a3f1]). Re-select the intended device in the General tab if the names changed after an update. Which card each radio actually opened is in the log, on the audio output running and radio IQ input running lines.

Two radios share one sound card. Each radio has its own Radio audio devices, in its own settings — select the radio’s tab first, then pick its cards. If both radios were configured before their two cards could be told apart, both may be holding the same name: re-pick each one from the list and press Apply / reconnect.

A setting did not take effect. Backend, serial, sound-format, and radio-audio-device changes apply when you press Apply / reconnect (Radio tab, or under the CAT radio-audio settings). Audio output/input device changes apply immediately. If a change still seems stuck, press Apply / reconnect again.

The display flickers, or sdroxide uses more CPU on a Raspberry Pi than it should. Both are the same setting seen from either side. Mesa’s Vulkan driver for the Pi’s V3D GPU (V3DV, on the Pi 4, 5, 400 and 500) makes the picture flicker — unusably so on some compositors, and not only under sdroxide; other wgpu and Vulkan applications flicker on the same driver. sdroxide looks for that adapter at startup and renders through OpenGL ES instead, saying so in the log:

sdroxide: the Raspberry Pi's V3D through Mesa's Vulkan driver (V3DV) flickers,
so this window renders through OpenGL ES instead.

The GLES path is steady but costs roughly one core of the four — 237% CPU against 140% on an RTL-SDR at 2.4 Msps, so on a Pi 5 that is a quarter of the machine. If your desktop turns out not to flicker under Vulkan, take it back with

WGPU_BACKEND=vulkan sdroxide

WGPU_BACKEND (vulkan, gl, metal, dx12) pins the renderer on any machine, and pinning it also turns the check above off — and the Windows one below with it — so WGPU_BACKEND=gl is how to force the steady path on a GPU sdroxide does not know about.

On Windows, sdroxide closes the moment it starts, and Event Viewer names igvk64.dll with exception code 0xc0000005. That module is Intel’s Vulkan driver, and the exception is an access violation inside it — a crash in the graphics driver, before sdroxide has drawn anything. Nothing on this side can catch it. From 1.6.2 sdroxide does not load Vulkan on Windows at all: the window opens on Direct3D 12, with OpenGL behind it, which between them cover every Windows machine going back further than Vulkan does and are what a Windows driver is written against first. If your Vulkan driver is sound and you would rather use it, say

WGPU_BACKEND=vulkan

before starting sdroxide — in PowerShell, $Env:WGPU_BACKEND = "vulkan".

TUNE makes full power and FT8 makes full power, but speaking into the microphone makes milliwatts. The transmitter is doing exactly what it is told: it was handed silence. TUNE is a carrier and FT8 is a synthesised burst, so neither goes anywhere near the microphone — a voice mode is the only thing that does, and if the microphone is not the card you are speaking into there is nothing to modulate. The drive slider, the power register and the meters all read correctly throughout, which is what makes it look like a power bug.

An over that goes out with nothing on the microphone now says so when you unkey — “That over went out with no audio”. Pick the input under Settings → General; on a headset this is usually a separate device from the speaker, and “System Default” is whatever the desktop’s sound settings point at rather than whatever is plugged in.

sdroxide died with Failed to create staging buffer for index data, or another panic naming wgpu, after running for a while. The graphics driver refused an allocation and the renderer has no way to carry on without one. It is the driver’s failure rather than sdroxide’s — reported on an Intel HD Graphics 530 under Mesa, an hour into a session, with a wgpu validation error a moment before it — and nothing in the program can prevent it. What it can do is not walk into it twice: a panic that came from the graphics driver leaves a note in renderer-fallback.txt in the configuration directory (13), and the next start renders through OpenGL instead and says so:

sdroxide: the last session ended inside the graphics driver, so this window
renders through OpenGL instead.

The note stays until you delete it — a driver that has crashed once will crash again, and re-learning that costs another lost session. Delete the file to go back to the default renderer, or set WGPU_BACKEND to pick one yourself, which turns the check off in both directions. A panic anywhere else in sdroxide leaves no note and changes no renderer.

A blank window appears for a moment, sdroxide exits, and the console says Failed to wait for GPU to come idle before reconfiguring the Surface. An old graphics card taking too long over its first frame, on a machine with neither a Vulkan nor a Direct3D 12 driver — so OpenGL is all that is left. The first frame is where every shader is compiled and every texture allocated, and on such a card that can take several seconds; the window’s real size, arriving while that is still going, used to make sdroxide wait for the card to catch up. OpenGL gives that kind of wait 2.147 seconds and not a moment more, after which the window counted as broken and the process died — twice over, the second time inside its own cleanup, which is where the backtrace came from.

sdroxide no longer asks to be kept waiting by an OpenGL driver, so a slow card is now merely slow. The wait bought nothing here in any case — nothing in sdroxide reads back from the GPU; every pass ends on the screen. To hand the timing back to the driver, for a bug report say:

WGPU_GL_FENCE_BEHAVIOR=normal sdroxide

If no window appears at all on such a machine, WGPU_BACKEND=dx12 on Windows falls back to the software renderer Windows always has (Microsoft Basic Render Driver). It is slow, and the log says Software rasterizer detected, but it draws.


15. Radio-specific notes

Everything in this chapter is said somewhere else in the manual, in the section it belongs to. It is collected here a second time, radio by radio, so that the owner of one particular model can read their page and nothing else: the settings that model needs, the radio-side menus involved, and the traps with that model’s name on them. Each entry links to the section that carries the full detail.

15.1 Xiegu G90

15.2 Xiegu X6100

15.3 Icom over USB (IC-7300 and family)

All in §6.2.2:

15.4 Icom over LAN (IC-705, IC-7300MK2, IC-7610, IC-7760, IC-7851, IC-9700, IC-905)

All in §6.2.10:

15.5 Icom IC-R8600

15.6 Kenwood (TS-480, TS-590, TS-890, TS-990, TS-2000)

All in §6.2.2 and §14:

15.7 Yaesu (FT-891, FT-991A, FT-710, FTDX10, FTDX101, FTDX1200/3000/5000)

All in §6.2.2:

15.8 Elecraft (K3, K3S, KX2, KX3, K4)

All in §6.2.2 and §14:

15.9 ELAD FDM-DUO / FDM-S1 / FDM-S2

All in §6.2.16:

15.10 QRP Labs QMX / QMX+ / QDX

All in §6.2.2:

15.11 SunSDR / ExpertSDR3 / Thetis (TCI)

All in §6.2.4:

15.12 Hermes Lite 2 (and other HPSDR)

All in §6.2.3:

15.13 FlexRadio (FLEX-6000 / FLEX-8000, SmartSDR)

All in §6.2.6:

15.14 RTL-SDR dongles (Blog V3 / V4 and generic)

§6.2.5 and, remotely, §6.2.11:

15.15 SDRplay RSP (RSP1/1A/1B/2, RSPduo, RSPdx)

All in §6.2.8:

15.16 Airspy HF+, Airspy R2 / Mini and HydraSDR RFOne

Two different receivers, plus a fork of the second: different silicon, USB ids, protocols, and udev rules — §6.2.9, §6.2.13 and §6.2.18 respectively; no interface here substitutes for another.

15.17 HackRF One / Pro

All in §6.2.12:

15.18 PlutoSDR (ADALM-Pluto, Pluto+, LibreSDR)

All in §6.2.7:

15.19 LimeSDR + LimeRFE

All in §6.2.17:

15.20 RX-888 Mk1 / RX-888 Mk2

15.21 Public SDRs on the internet (KiwiSDR / Web-888, SpyServer)

About eleven hundred receivers are published for anyone to listen on, and sdroxide can open one as an ordinary radio — same panadapter, same demodulators, same digital modes, same logbook. Two networks are covered, and a third is listed but not yet reachable.

KiwiSDR and Web-888 (the board its own listing calls “KiwiSDR 2”) are the 0–30 MHz receivers, about 870 of them online. SpyServer is Airspy’s own server and the several that speak its protocol, about 230 online, mostly VHF/UHF dongles.

sdr-list.xyz is the directory of the newer RX-888-class web receivers — PhantomSDR-Plus, UberSDR, NovaSDR, VertexSDR — about seventy of them. They are listed here so you can see what is on the air and where, but none of them can be opened yet, and every row says why in its own words. PhantomSDR-Plus comes closest: recent builds answer the KiwiSDR protocol alongside their own, they do retune, and what they send back is demodulated audio rather than the I/Q that sdroxide’s KiwiSDR interface decodes — so the interface that looks like it should fit does not. The others each speak a protocol of their own. Turn the sdr-list.xyz button off at the top of the list if you would rather not see them.

Everything here is receive only, and not because of a missing feature. These are other people’s antennas.

Two networks you may be looking for are deliberately absent, which is why the chip says PUBLIC SDR rather than “WebSDR”. PA3FWM’s WebSDR — the receivers listed at websdr.org — sends audio in a proprietary codec whose author asks third-party clients to stay away, and OpenWebRX delivers demodulated audio only, over a protocol that has diverged between its forks and has no machine-readable directory to read in the first place. Neither is a “not yet”; use their web pages.

Browsing

PUBLIC SDR in the System box opens the list. The buttons across the top filter it by network, by whether a receiver can actually be used right now, and by whether it covers the frequency you are on; the search box matches on the name, the place, the antenna and the band, so 40m denmark or 7000 both work. Hovering a row shows its address, its hardware and its antenna.

Each row offers two things. USE points the radio you are on at that receiver, keeping everything else about it — converter offset, audio devices, the lot. + TAB opens it as another radio in a tab of its own, leaving the one you were on alone.

USE replaces a radio, so on a tab that already has an interface it asks first, across the top of the list: which radio is about to become which receiver, and REPLACE / + TAB INSTEAD / CANCEL. Going ahead also renames the tab after the receiver — a tab still calling itself “IC-9700” while it is really a dongle in another country, refusing your 2 m calling frequency as out of range, is a puzzle nobody should have to solve.

Nothing is lost by taking a receiver in a tab you had set up. Every interface keeps its own settings, and the tuning ranges you stated go with the interface they were stated for (6.2), so switching Radio interface back in Settings → Radio brings the transceiver back as it was — its address, its sound cards and its ranges. What it does not bring back is the tab’s name; type it again in the Name box on that page.

The lists are fetched by the machine the radio is attached to, not by the screen you are sitting at — so this works the same in the browser client, and a receiver is judged reachable from where it will actually be connected to. They are cached for a quarter of an hour; ⟳ REFRESH goes to the network.

Being a guest

Every one of these receivers has a hard limit on how many people can listen at once, and somebody pays for its antenna, its power and its uplink.

What a KiwiSDR actually gives you

A KiwiSDR has no wideband I/Q and never has. It has eight (or four) user channels, each about 12 kHz wide, which it normally demodulates for you — and one of its modes hands the channel over as complex baseband instead. That is what sdroxide opens.

So the panadapter is about 12 kHz, and honest about it. Alongside it, on a second connection, the receiver sends the waterfall its own web page draws: 1024 finished bins across the whole 0–30 MHz, in the strip above the panadapter. Tuning across that strip retunes the receiver. It is the same shape as the SpyServer VFO+FFT interface, and for the same reason — it is what a receiver at the far end of a network link can actually deliver.

That is enough for everything sdroxide decodes: SSB, AM and the synchronous detectors, CW, RTTY, NAVTEX, WSPR, FT8 and FT4, and the rest. It is not enough for anything wider than the window, and there is no way to ask for more.

The link costs about 64 kB/s: 44 for the I/Q and 20 for the waterfall. Turn the band view off, or slow it down, in Settings → Radio if that matters.

The main panadapter is not stuck at those 12 kHz, though: keep zooming out and it widens past them and goes on to cover the whole 0–30 MHz, drawn from the same waterfall bins the strip uses (§2.8). It coarsens where it crosses over — those bins are all there is out there — and zooming back in returns the I/Q’s own resolution.

Gain and the S-meter

Unusually for a receiver here, the AGC is left on at the far end by default. It sits ahead of the I/Q, so it acts before anything sdroxide does — but the alternative measured worse: on a live receiver the manual gain was not monotonic across its range and its top end clipped the I/Q at full scale, while the AGC held about −24 dBFS with 7 dB of headroom.

The consequence is that the sample amplitude is not a signal level, so the S-meter is read from the figure the receiver puts in every audio frame instead. That reading is already in dBm on its own operator’s calibration — which is worth rather more than sdroxide’s own uncalibrated scale, and comes with one caveat: it is for the receiver’s ±6 kHz channel, not for whatever filter you have in front of the demodulator. A narrow CW filter here still reads the wideband level.

SpyServer, and which shape to take

A SpyServer will send either a wideband stream — an ordinary SDR, as much of the band as its ladder offers — or a narrow window that follows the dial plus its own band view. The browse window’s LOW BW button picks the second, which is the one for a link that cannot carry megabits. It makes no difference to a KiwiSDR, which has only the one shape.

A server whose receiver another client already owns still works; tuning is then limited to the slice that client is receiving, and the gain is theirs. That is the usual reason a SpyServer’s band view looks stuck on a stretch of spectrum you did not choose — the notice at the top of the window names the range you are held to. Nothing this end can do will move it until that client does; pick another server, or come back later.

Its width is your choice, though: the band view is one stage of the server’s own decimation ladder, and I/Q bandwidth’s neighbour in Settings → Radio picks which. Stage 0 is the widest the server offers, and is the default. As with a KiwiSDR, the main panadapter can be zoomed out to cover the whole of it (§2.8).

Where your reports come from

Everything you hear through one of these receivers was heard at its antenna, not at yours. So taking one also moves the locator sdroxide reports from: PSK Reporter, WSPRnet and FreeDV Reporter are all told the receiver’s square, and the ADS-B lane places aircraft against it too. Without that, an online receiver in Australia opened from a European shack turns every local 2 m signal it hears into an intercontinental opening in somebody else’s database.

The directories publish a position for most receivers — a KiwiSDR states a locator outright, a SpyServer states latitude and longitude — and sdroxide takes it from there when you pick one. The confirmation says which square it will report from.

Some publish none. Then nothing that receiver hears is reported at all, which is the only honest answer available; the note under Settings → Radio says so. Fill the locator in there if you know where the receiver is.

Settings → Radio → Antenna is is where all this lives, per radio: At the station (the default — your own locator describes your own antenna) or Somewhere else with a locator beside it. It is not only for public receivers: set it for your own receiver on a hilltop, or any radio whose antenna is not where you are. Switching the Radio interface puts it back to At the station, because where the antenna was belonged to the receiver you just left.

Adding one by hand

A receiver that is not listed — your own, or one behind a name you were given — goes in under Settings → Radio, interface KiwiSDR / Web-888 (network) or SpyServer (network), as an address. Test connection reads the receiver’s status page without taking one of its channels and says what it is, what it covers, how many channels are free and whether non-browser apps are allowed at all.

One trap worth knowing: nearly half the public KiwiSDRs are reached through the project’s own reverse proxy, at a something.proxy.kiwisdr.com address, and those answer on port 80 rather than on a Kiwi’s usual 8073. Give the port explicitly. Picking a receiver from the browse window always gets this right.

15.22 USB audio radio (sound card)

A radio with no control port at all — a handheld, a walkie, a toy, a USB dongle rig. It reaches sdroxide through the computer’s ordinary sound cards, so it is the one radio that needs a cable to the PC even though nothing on it says why: receive comes into a sound card’s line or mic input (the radio’s headphone socket), transmit leaves through another into the radio’s mic socket, and the radio keys itself off VOX — the moment audio arrives at its mic line it broadcasts it. There is no CAT, no TCI, no serial anywhere, which is exactly the point.

The Radio tab with the USB audio radio interface selected

In Settings → Radio, interface USB audio radio (sound card), pick the two devices:

That is the whole tab. Every other radio control is absent because the hardware has none: the dial becomes a label rather than a command (the radio tunes itself with its own knobs), and there is no PTT to command — transmit is audio into the radio’s microphone, keyed by VOX. Apply / reconnect reopens the radio with the chosen cards without a restart.

Two things follow from the way it works. The band plan and transmit lockout still apply — sdroxide knows where the dial is because you tuned it here, even though nothing told the radio — so the usual ham-band / 11 m / broadcast rules hold (6.1). And because the only “measurements” come from the audio stream itself, an audio radio has no SWR bridge, no forward-power telemetry and no rig-reported S-meter — the level figures that still work are audio levels, which describe the radio’s own audio rather than what its antenna hears, and the radio’s front panel is where signal strength really lives. It is otherwise a perfectly ordinary radio: every mode, the logbook, the panadapter (a demodulated-audio spectrum), spots and awards all work as they do on any other backend.

15.23 Luiton LT-310SDR — DIY isolated digimode & audio interface (EXPERIMENTAL, at your own risk.)

The Luiton LT-310SDR has no CAT port, so it is driven the way 15.22 describes — through the sound cards — with one difference: the PTT is commanded over a USB-to-serial line, not left to the radio’s VOX. That needs a small, galvanically isolated interface between the PC and the radio.

This is experimental. sdroxide drives it through the T/R switch’s Serial RTS/DTR line rather than a dedicated PTT field; the “keeps receiving if the program dies” behaviour is whatever the serial driver does with RTS when the port closes; and it has not been tested against real hardware here. Build it and use it at your own risk.

The interface

The interface provides galvanic isolation for both audio and PTT control between a PC (running sdroxide, JS8Call, WSJT-X, …) and the Luiton LT-310SDR transceiver.

Components

1. PTT control. Connect the FTDI RTS line through the 1 kΩ resistor to PC817 pin 1 (anode), and FTDI GND to PC817 pin 2 (cathode). Connect PC817 pin 4 (collector) to the PTT pin on the RJ12, and pin 3 (emitter) to the GND pin on the RJ12. Driving RTS HIGH lights the optocoupler’s LED and grounds the radio’s PTT line — no electrical contact between PC and radio.

2. TX audio (PC soundcard out → radio mic in). Connect PC line-out (tip & sleeve) across the primary of the first 1:1 transformer. One secondary pin goes to GND on the RJ12; the other goes through the 10 kΩ potentiometer to the MIC pin on the RJ12. Isolated, and the trimpot stops the PC output overdriving the sensitive mic input.

3. RX audio (radio speaker out → PC soundcard in). Connect the Luiton EXT SPKR 3.5 mm jack (tip & sleeve) across the primary of the second transformer; its secondary goes straight across PC line-in / mic-in (tip & sleeve). Isolated reception for the decoders, and ground-loop mains hum is stripped.

Configuring sdroxide

  1. Settings → Radio → USB audio radio (sound card) (15.22). Set Receive to the card the radio’s EXT SPKR arrives on, and Transmit to the card feeding the radio’s mic through the trimpot.
  2. Settings → T/R switch (6.11): link Serial RTS/DTR line, the FTDI’s port (/dev/ttyUSB0, COMx), and contact 1 → RTS. Give that contact a role that is not “Ground the SDR antenna” — this is a PTT closure, not an antenna relay; Aux fits, or leave the other contacts at Not used. Key-down asserts RTS and key-up drops it, which is exactly the PTT the interface wants.
  3. Tune on the radio’s own dial. On this backend sdroxide’s dial is a label, so the band plan and the transmit lockout follow what you type here, not the radio (15.22).

The PTT being the T/R switch’s serial line leaves the switch’s other channels free for an antenna relay or an amplifier key line, since each link can carry more than one contact.

Failsafe caveat. sdroxide drops RTS on key-up and closes the port when it exits. Whether the radio returns to receive if the program crashes depends on the serial driver lowering RTS when the port closes — many FTDI drivers do, some do not. If a stuck transmitter must be impossible, wire the optocoupler so a floating RTS is the receive state, and test it.


16. Appendix

Keyboard shortcuts

Key Action
Left / Right arrow Tune ±100 Hz (with Shift, ±10 Hz).
Up / Down arrow Tune ±1 kHz.
Page Up / Page Down Tune ±10 kHz.
M Toggle mute.
N Toggle noise blanker.
F Fit the view to the full receiver span.
V Flip the waterfall (scroll upwards).
1 – 9, 0 (numpad) Transmit voice-keyer slots 1–10 (nothing if the slot is empty).
− (numpad) Stop a voice-keyer message.
Space (CW, with KEY on) The straight key: carrier while held, and re-bindable as CW straight key in Settings → Controls (2.14).
Ctrl+W Open Settings on the UI page, where saved window arrangements (Workspaces) are listed (6.4).
F1 Open this manual (works even while typing).

Shortcuts are ignored while typing in a text field.

While this manual is open it takes the scrolling keys for itself, so reading it never tunes the radio at the same time: Up / Down scroll a few lines, Page Up / Page Down scroll a screen, Home / End jump to the ends, and Left / Right step to the previous / next section in the CONTENTS outline. Esc or F1 closes it and the keys go back to tuning.

It opens filling the window, and you can move and resize it from there like any other panel.

Finding something. The bar across the top searches the whole manual as you type. Every occurrence is highlighted where it stands, the one you are on in yellow and the rest in cyan, and the view follows it:

Key / button What it does
Ctrl+F Puts the caret in the find field.
▶ or Enter or F3 Next match (wraps round at the end).
◀ or Shift+Enter or Shift+F3 Previous match.
✕ or Esc Clears the search. A second Esc closes the manual.

The tally beside the buttons reads 3 / 17 — which match you are on, out of how many there are. In the CONTENTS outline every chapter and subsection holding the term turns yellow with a count beside it, so a term that only appears in one chapter out of eleven is visible before you scroll anywhere: search for WSPR and the outline tells you where it is discussed and how much is said about it. The search is case-insensitive, so wspr and WSPR find the same things.

These are the defaults. Every one of them can be rebound — and PTT, band changes, filter width and much else bound to keys, mouse buttons or a MIDI controller — on the Controls tab; see 6.4. F1 is the exception: it always opens the manual, so it is not rebindable.

The spoken-announcement actions (6.3) ship with no default keys, since any choice would take a key somebody is already using. Bind them under Speech on the Controls tab:

Action What it does
Speak status Reads the whole radio out: band, frequency, mode, VFO, split, and the SWR while keyed.
Repeat last announcement Says the last one again — for the word that a burst of noise landed on.
Stop speaking Stops mid-sentence and drops whatever is queued.
Announcements on/off The master switch, confirmed out loud when switching on.

Modes

Mode Description
LSB / USB Lower / upper sideband voice.
CW Morse (continuous wave). Decoded on a waterfall cursor, with type-ahead keyboard sending — see 2.14.
AM Amplitude modulation.
SAM Synchronous AM. Its ECSS-U/ECSS-L filter presets keep one sideband and reject the other — the medium-wave DX trick for ducking an adjacent channel.
C-QUAM C-QUAM, Motorola’s AM stereo for the medium wave: AM carrying the sum and the stereo difference as carrier phase, with a 25 Hz pilot for the stereo lamp and the mono blend. Receive only. See cquam-design.md.
NFM / WFM Narrow / wide FM. WFM decodes broadcast stereo and RDS/RBDS automatically.
DIGU / DIGL Data over USB / LSB (general digital).
DSB Double sideband.
ISB Independent sideband: two different signals on one carrier, one on each sideband — a broadcaster’s two language services, or voice on one side and a teleprinter on the other. The lower sideband goes to your left ear and the upper to your right, so both can be listened to at once (or one recorded while the other is read). Receive only.
DRM Digital Radio Mondiale — digital shortwave broadcasting. Receive only; decodes the programme audio, the station label and its scrolling text. See 2.19.
SPEC Spectrum only (no demodulation).
FT8 / FT4 Automatic digital modes with decoding, QSO sequencing, and logging.
JS8 JS8 — conversational messaging on FT8’s waveform. Four speeds (Normal 15 s / Fast 10 s / Turbo 6 s / Slow 30 s); directed queries, heartbeats and multi-frame free text.
WSPR Weak Signal Propagation Reporter — a two-minute beacon carrying a callsign, grid and power. Not a QSO mode: it measures paths, uploads them to WSPRnet, and feeds the propagation heat map. See 3.11.
PI4 “Next Generation Beacon” — a one-minute four-tone FSK beacon carrying a callsign. Receive only. Not a QSO mode: it measures paths, and carries no grid to feed the propagation heat map with. See 3.20.
PSK PSK31 keyboard mode (BPSK31 / varicode).
RTTY RTTY keyboard mode (Baudot; selectable shift and baud), on a sideband.
RTTY-FM The same modem on an FM carrier, the way a club bulletin is still sent on VHF.
NAVTEX The maritime safety broadcast on 518, 490 and 4209.5 kHz: navigational and meteorological warnings, search-and-rescue bulletins and ice reports, framed into messages. Receive only.
DSC Digital Selective Calling — the marine distress and calling system on VHF channel 70 and the MF/HF distress channels: 1200-baud FFSK carrying distress alerts (MMSI, nature, position, time) and routine calls. Receive only. See 3.21.
JT65 / JT9 The classic WSJT weak-signal modes — 65-FSK (JT65) and 9-FSK (JT9), both in a 60-second slot, carrying <to> <from> <grid\|report>. Receive only in this build (no QSO sequencer). See 3.22.
FST4 The slow weak-signal mode for EME, troposcatter and LF/MF: 160-symbol GFSK in a 15/30/60/120/300-second T/R period, carrying the same 77-bit message as FT8/JT65. Receive only in this build. See 3.23.
MSK144 Meteor scatter on 6 m and 2 m: continuous-phase binary MSK at 2000 baud in a 15-second period, carrying the same 77-bit message as FT8. The decoder hunts the period for meteor-trail bursts. Receive only in this build. See 3.24.
Q65 The modern WSJT weak-signal mode for EME, ionoscatter, rainscatter and troposcatter: 65-tone FSK in a 15/30/60/120/300-second T/R period, with a tone-spacing letter A–E for Doppler spread. Carries the same 77-bit message as FT8. Receive only in this build. See 3.25.
UVPACKET A packet protocol for private amateur VHF/UHF groups: a short π/4-DQPSK burst carrying an application byte pipe (app type, sequence, 1–32 payload blocks) rather than a WSJT message. The sub-mode is detected from the preamble. Receive only in this build. See 3.26.
JTTY Experimental. The WSJT-X 3.2 asynchronous RTTY-like text mode: no T/R slots, ~1.888-second frames of 4-GFSK about 125 Hz wide carrying free text or typed contest atoms behind a tail-biting convolutional code. Sends a message once. See 3.28.
FSK441 The original meteor-scatter mode on 6 m and 2 m: 4-FSK at 441 baud carrying free text and the R26/R27/RRR/73 single-tone shorthand, in a 15/30-second period. The decoder hunts the period for meteor-trail pings; transmit repeats the message for the length of the over. See 3.27.
OLIVIA Robust MFSK keyboard mode (selectable tones/bandwidth).
THOR DominoEX-family IFK keyboard mode with FEC (THOR4…THOR32).
FSQ Fast Simple QSO — 33-tone IFK with directed (FSQCALL) messaging and images.
HELL Hellschreiber — facsimile “dot” mode read by eye, not decoded (Feld Hell, Slow, X5, X9, FSK Hell 245/105, Hell 80).
SSTV Slow-scan TV image mode (Scottie, Martin, Robot), on a sideband — LSB on 160/80/40 m, USB above.
SSTV-FM The same picture on an FM carrier, the way slow-scan is sent on VHF and UHF.
RIFP Radio Image Framing Protocol (draft-dulaunoy-rifp-00): packetised images over continuous-phase FSK. Centred on the dial, ~25 kHz wide — 70 cm, 2 m/6 m all-modes, or 10 m FM.
RFPAINT RF Paint — transmit-only spectrum painting of text and images onto the waterfall.
RADE FreeDV RADE V1 — digital voice: a neural codec (Radio Autoencoder) over an OFDM waveform about 900 Hz wide, decoded speech in place of what the receiver hears. On a sideband, and which one follows the band the way phone does — LSB on 160, 80 and 40 m, USB on 60 m, 30 m and above.
PACKET / PACKET-HF AX.25 packet radio: 1200 baud Bell 202 or 9600 baud G3RUH on VHF/UHF FM, 300 baud AFSK on HF sideband. Carries Winlink sessions and offers the modem as a KISS TNC. See 11.
APRS Automatic Packet Reporting System — 1200 baud AX.25 on the region’s shared channel, with a live map of every station heard, its own symbol per station, and messages you can send and answer. See 3.12.
ADS-B Aircraft surveillance on 1090 MHz: a target list and a radar picture with history dots, speed vectors and data blocks. Receive only, and needs a receiver streaming at least 2 Msps. See 3.13.
VDL2 The VHF datalink aircraft exchange ACARS over, on fourteen channels between 136.650 and 136.975 MHz at once: a message log and the stations sending them. Receive only. See 3.15.
AIS Ship reporting on the two channels either side of 162.000 MHz at once: a vessel list and a marine chart with hulls drawn to their heading, time-based trails and speed vectors. Receive only. See 3.16.
ACARS Airline datalink on VHF airband, decoded off the AM carrier: aircraft registrations, labels and message text, every message block-checked. Receive only. See 3.18.
HFDL The shortwave aircraft datalink (ARINC 635): ground stations across 2.8–22 MHz talking to aircraft over the ocean, with a decode log and an aircraft map drawn from the positions the aircraft downlink. Receive only, on an HF receiver. See 3.19.
ATCHAT AtCHAT NET — a 2.7 kHz COFDM multi-station keyboard and file mode: dynamic master election, a shared roster, common and directed chat, and block-CRC-ARQ file/image transfer. See 3.17.

Bands

160M, 80M, 60M, 40M, 30M, 20M, 17M, 15M, 12M, 10M, 6M, 4M (Region 1 only), 2M, 1.25M (Region 2 only), 70CM, 33CM (Region 2 only), 23CM, 13CM, 9CM, 6CM — read as 5CM outside Region 1 — and ALL (general coverage, formerly GEN). Bands your device cannot receive are disabled in the selector; bands your region does not have are not offered.

Waterfall colour schemes

Classic (PowerSDR-style), Viridis, Gray, Icom (Icom-style palette, peaking at red with no white blow-out), Neon, Synthwave, Matrix, Tron, Amber (one warm phosphor family, to wear with the Amber Phosphor UI theme), Rainbow (the full spectrum in order, to wear with the Rainbow UI theme) and Blue — the traditional blue waterfall SDR# has used since the beginning and SDR++ inherited: a navy floor rather than a black one, so the noise keeps its texture, and a top half that runs white, yellow, orange and two shades of red where the other ramps have already saturated. Chosen on the UI tab of the Settings window (6.3).


17. Addendum: a headless station on a Raspberry Pi Zero 2 W

A small, cheap board with a USB dongle makes a good network listening node: the receiver and the decoding run on the board, and your laptop, tablet or phone drives it through a browser. This is the “Pi at the antenna” arrangement §8 and §9 describe, sized for a Raspberry Pi Zero 2 W.

The board is 64-bit (armv8), so it runs the linux-aarch64-compat build made for Raspberry Pi OS Bookworm — no compiling. Run it as a server and use a browser for the drawing: that split is what makes a four-core, 512 MB board useful, because the graphical interface is the part it cannot carry.

Three things decide whether it is pleasant or painful:

The full walkthrough — imaging the card, installing the aarch64-compat build, the udev rules, the first-run setup, the systemd service and the troubleshooting in one place — is the Pi Zero 2 W setup guide, in the same four languages as the quick-starts:

For a graphical sdroxide on the Pi itself, or for the wideband decoders, step up to a Pi 4 (2 GB+) or Pi 5 — see the README’s Raspberry Pi note about Mesa’s V3DV Vulkan driver and the OpenGL fallback.