Metadata-Version: 2.4
Name: hamlib-sidecar
Version: 0.2.0
Summary: Generic sidecars that bridge Hamlib rigctld's IQ/audio sidechannel to PulseAudio (Linux) and to GNU Radio ZMQ + SoapySDR (any OS), with a built-in software-defined radio receiver/transmitter.
Author-email: Jeff Francis <gjfrancis@protonmail.com>
License: MIT
Project-URL: Homepage, https://github.com/jfrancis42/hamlib-audio-sidecar
Keywords: hamradio,ham,radio,sdr,hamlib,rigctld,gnuradio,soapysdr,tci,kiwisdr,rtl-sdr,js8call,fldigi,wsjtx
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Telecommunications Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Communications :: Ham Radio
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.20
Requires-Dist: scipy>=1.7
Provides-Extra: gnuradio
Requires-Dist: pyzmq>=24; extra == "gnuradio"
Provides-Extra: soapysdr
Requires-Dist: pyzmq>=24; extra == "soapysdr"
Dynamic: license-file

# hamlib-sidecar

Generic, modern Hamlib sidecars: bridge any Hamlib backend's IQ /
audio sidechannel to whatever your software wants to consume.

Two sidecars, one shared library, plus a small CLI:

| Component | Role |
|-----------|------|
| `hamlib_sidecar_linux.py` | Linux: virtual PulseAudio audio devices (and virtual stereo IQ devices) for ham/SDR software. |
| `hamlib_sidecar_portable.py` | Linux / macOS / Windows: GNU Radio ZMQ in/out and SoapySDR direct hardware. |
| `hamlib_sidecar_common.py` | Shared library: wire protocol, demods, modulators, DSP, `SmartSidecar`. |
| `hamlib.sh` | Lifecycle script: `start`, `stop`, `restart`, `status` for the rigctld + sidecar + audio-routing pipeline. |
| `hamctl` | Runtime control CLI: tune, mode, AGC, S-meter, audio routing, favorites, band plan. |

Both sidecars include a built-in software-defined-radio receiver and
transmitter (SSB / AM / FM mono+stereo / CW), so they can demodulate
IQ → audio (RX) and modulate audio → IQ (TX) for whichever radio
backend you point them at.

> ## Status
>
> - **RX is well exercised.** Hundreds of hours on JS8Call via TCI 2.0,
>   plus verified against KiwiSDR (HF AM/SSB/CW + IQ mode) and RTL-SDR
>   (98.5 MHz WFM stereo, 124.3 MHz airband AM, 162.45 MHz NBFM) with
>   live signals.
> - **TX is implemented but UNTESTED on real RF.** Test into a dummy
>   load + spectrum analyzer before transmitting on an antenna. If you
>   verify TX against a real radio, please report back.

## Documentation

| Document | For whom |
|----------|----------|
| [`USERS.md`](USERS.md) | Ham operators using JS8Call / WSJT-X / fldigi / gqrx — start here. |
| [`DEVELOPERS.md`](DEVELOPERS.md) | Writing a new sidecar in any language, or extending the Python code. |
| [`PROTOCOL.md`](PROTOCOL.md) | Wire-protocol specification. Language-agnostic. |
| [`linux.md`](linux.md) | Internals of the Linux PulseAudio virtual-device backend. |

## 30-second quick start (Linux)

Bring up the whole pipeline — rigctld, sidecar, virtual audio, and an
optional loopback to a real device — with one command:

```bash
# RTL-SDR USB dongle, WFM stereo on 98.5 MHz, routed to a USB headset.
# "C-Media" is any unambiguous substring of a PulseAudio sink name.
./hamlib.sh start --radio rtlsdr \
                  --sink C-Media \
                  --freq 98500 --mode WFM 200000

# KiwiSDR over the network, IQ mode (best audio quality)
./hamlib.sh start --radio kiwisdr --host 10.1.0.18 --stream iq \
                  --sink USB --freq 10000 --mode AM 6000

# ExpertSDR3 / SunSDR over TCI 2.0
./hamlib.sh start --radio tci --host 127.0.0.1 --port 50001 --stream audio
```

Once it's running, drive the radio with `hamctl`:

```bash
./hamctl tune 124300       # tune to 124.3 MHz; auto-applies AM / 6 kHz /
                           # fast AGC because that's in the air band

./hamctl smeter live       # realtime S-meter bargraph (press q to quit)
./hamctl show              # full radio + DSP + audio routing status
./hamctl save morning_nws  # save the current state as a favorite
./hamctl load morning_nws  # re-apply it later
./hamctl bands             # list the band plan
```

`hamctl --help` lists every verb. `./hamlib.sh stop` tears everything
back down.

For non-Linux, for the portable (GNU Radio / SoapySDR) sidecar, and
for direct integration with JS8Call / WSJT-X / fldigi / gqrx, see
[`USERS.md`](USERS.md).

## Install

```bash
pip install -r requirements.txt
sudo apt install pulseaudio-utils       # needed for the linux sidecar
```

Optional, depending on which user-side backends you want to use:

```bash
pip install pyzmq                                           # gnuradio backend
sudo apt install python3-soapysdr soapysdr-module-rtlsdr   # soapysdr backend
```

For development, just run the scripts directly out of the source
tree — no install needed.

## Files

| File | What it is |
|------|-----------|
| `hamlib_sidecar_common.py` | Shared library: protocol parser, demods, mods, DSP, `SmartSidecar`. |
| `hamlib_sidecar_linux.py` | Linux sidecar: PulseAudio + IQ-stereo PulseAudio backends. |
| `hamlib_sidecar_portable.py` | Portable sidecar: GNU Radio ZMQ + SoapySDR. |
| `hamlib.sh` | Lifecycle script: `start` / `stop` / `restart` / `status` for rigctld + sidecar + audio. |
| `hamctl` | Runtime control CLI (frequency, mode, DSP, S-meter, audio routing, favorites, band plan). |
| `pyproject.toml`, `requirements.txt`, `MANIFEST.in` | Packaging. |

`hamctl` writes its favorites and band plan to
`$XDG_CONFIG_HOME/hamctl/` (typically `~/.config/hamctl/`). The band
plan is auto-seeded on first use with sensible defaults for HF
amateur, SW broadcast, FM broadcast, airband AM, NOAA weather, marine
VHF, 2 m / 70 cm, GMRS, and others; edit `bands.json` to suit.

## License

MIT. See [`LICENSE`](LICENSE).
