W5TSU

Making Amateur Radio Connections

Seven Months, One Little Radio

In February 2026 I bought a Hermes-Lite 2 from MakerFabs, along with Jim Ahlstrom’s N2ADR filter board and IO board. I wrote a blog post about it and said the community support was thin. I hoped my notes would help someone, maybe even me.

I didn’t expect those notes to turn into seven months of writing software.

Spring: taking ownership

It started small. In April I forked MI0BOT’s Hermes-Lite 2 build of Thetis and spent a day making GitHub Actions build it. The installer had to come out of CI rather than off somebody’s desk. Getting there took four commits, each fixing whatever the last one broke: a WiX version pin, a toolset mismatch (v145 vs v143), and an installer project the runner didn’t know how to build.

After that I kept pace with upstream. Merge MI0BOT, bump the version, ship.

By July I wanted to understand the code, not just rebuild it. Thetis is big and old, with layer on layer of PowerSDR history. So I generated documentation for the whole thing: every file and function with its callers, plus deep dives on RNNoise, the network protocols, hardware selection and the settings database. Then I wrote down how to regenerate the docs and how to merge upstream, so the next person (or the next AI session) wouldn’t have to rediscover it.

My first real feature was humble: hold the spacebar to transmit, release it to receive. It immediately had a bug, too. If another window stole keyboard focus, the radio dropped out of transmit. I fixed that, released 2.10.3.19, and changed the build name to “HL2 (MI0BOT/W5TSU).” It felt like signing my name on the chassis.

Summer: the month of “no sync”

On July 15 I decided Thetis should decode FreeDV natively. That meant no separate app and no virtual audio cables patched between programs. I built codec2 for Windows (MinGW, then an MSVC import library, then static libgcc because nothing is ever easy). I added a FreeDV decode block to WDSP and wired it into the console.

It didn’t work. The status said no sync.

The next three weeks were a detective story. My test-signal generator had the sideband backwards because WDSP’s spectrum runs the other way, so I conjugated the I/Q. Still no sync. I dumped raw demodulator audio for spectral analysis. I suspected the AGC, seeded it differently, then froze its gain entirely. That was a negative result, so I reverted it. I logged the OFDM demodulator’s own sync metric, frequency offset and timing, and ruled out a carrier-offset dead zone. Each dead end went into the project plan so I wouldn’t walk down it twice.

On August 8 two things came out almost together.

First, Quick-Play, the feature I was using to feed test audio into the receiver, had been silently doing nothing the whole session. I’d been debugging a decoder that wasn’t getting any signal.

Second, once real audio reached it, the modem loop was stopping when codec2 asked for zero samples. That nin=0 is codec2’s way of saying “drain me,” not “I’m done.” The fix was a few lines. After it I got three clean runs and 36 of 36 polls synced.

Along the way I’d built a second tool almost by accident. thetisctl controls a running Thetis over CAT and TCI, and I wrapped it as a skill so an AI agent could operate the radio. That meant taking transmit seriously. TUNE is hard-capped at five seconds, and every TX-capable command is gated, including Quick-Play once I realized it could key the rig. The same tool scanned FreeDV calling frequencies and watched FreeDV Reporter for live spots.

August: RADE, and a HackRF pretending to be the world

FreeDV’s newer mode, RADE V1, uses a neural-network decoder. SV1EIA had already done a Thetis RADE port, so I brought it into a test branch. Then came a day of vendoring the dependencies: opus with its DNN pieces, rnnoise with its model weights, libebur128, WebRTC AGC, r8brain, and the LDPC code from codec2. Each one needed its own fix before the build went green.

Once it built, I sat through the off-air checks against the live station with no sync again.

This time I didn’t wait for the band. On August 15 I turned a HackRF into a transmitter running a GNU Radio flowgraph, so I had a known-good signal over real RF. It had its own bugs. A quantization problem garbled the signal, and it transmitted on LSB when it should have been USB. Once those were fixed, 700E synced. Then RADE V1 decoded over real RF, first for 14.85 seconds and then continuously for 126. That same night I found that the decoded audio had never reached the local speaker. Of course it hadn’t.

On August 26, 2026, I made my first over-the-air QSO using RADE V1 through my own build of Thetis on the Hermes-Lite 2.

The work didn’t stop there. That week I added a single Digital Voice mode selector with CAT commands, digital voice on RX2, a sync/SNR overlay on the panadapter, and FreeDV Reporter spots drawn right on the band with click-to-tune. Thetis could also report its own decodes back to FreeDV Reporter, and the tab was renamed from “Digital Voice” to what everyone calls it: FreeDV.

I also taught the station to talk. talk is an AI voice operator. It listens to the band, recognizes when it’s being called, answers from a Claude “brain,” and transmits only when armed, inside clocks and budgets designed so it can’t run away with the transmitter.

September: a second home, and down to the gateware

Thetis is Windows. I wanted the HL2 everywhere, so on August 31 I forked AetherSDR, a Qt6/C++20 client written for FlexRadio. That day I promoted the Hermes-Lite 2 from experimental to supported. The work behind it was an ADR, a certification run, real RTTY and DFM modes, spectrum averaging, a peak-hold detector, and moving the span-change rebuild off the GUI thread so the display stopped freezing.

Releases 26.9.2 through 26.9.9 followed. They brought Windows code signing (Authenticode, then Azure Trusted Signing), sanitizer-clean tests, and HL2 AGC/ALC. They also added RQST/ACK, a wideband bandscope, ADC diagnostics and a JS8Call spot feed. That HackRF, promoted from test gear, now has its own backend.

Finally I went below the software. In my Hermes-Lite 2 repository I documented every major subsystem and wrote the project’s history. I found that ethernet.v is dead code. I also put the Quartus toolchain in a Docker container so the Radioberry gateware builds reproducibly, then fixed two bogus timing-closure reports that were making clean builds look broken.

What it adds up to

In February I wrote that the radio’s community support was poor. It still isn’t a big crowd. But there’s now a signed, CI-built Thetis with native FreeDV and RADE, a cross-platform client that treats the HL2 as a first-class radio, and gateware you can build in a container. There’s also a pile of plans and dead ends written down, so the next ham doesn’t have to lose three weeks to a Quick-Play checkbox.

The radio still sits on the shelf, streaming IQ over a network cable. It just has a lot more to say now.

W5TSU