rsba1server — a standalone RS-BA1 network radio server¶
rsba1server is an open-source, from-scratch clone of the server side of
Icom's RS-BA1 "Remote Utility". It attaches to a radio (or an SDR) and serves
it over the network using Icom's RS-BA1 UDP protocol, so any RS-BA1 client
can control it remotely:
- Icom's own RS-BA1 software,
- wfview,
- the Rafe web app in this repo.
It exists so a radio that only has USB (like the IC-7300) — or a bare SDR — can be operated over the network exactly the way a networked IC-705 is. It's pure Python 3, no GUI, and runs happily on a Raspberry Pi.
What it speaks¶
Three UDP streams:
| Port | Stream | Purpose |
|---|---|---|
| 50001 | control | login/passcode handshake, token/auth, capabilities + connection-info exchange, pkt7 keepalives, retransmit |
| 50002 | CI-V | transparent CI-V serial bridge between client and radio |
| 50003 | audio | RX audio radio→client and TX audio client→radio |
The protocol was implemented from this repo's own RS-BA1 client
(app/radio/) plus wfview's server as a reference, and is verified end-to-end
against that client (test_rsba1.py): login, CI-V request/reply, and RX+TX
audio. Audio is uncompressed 16-bit LPCM (what the IC-705 path uses); the
Opus/µ-law codec options some clients offer are not implemented — request LPCM
on the client if asked.
One authenticated control client per source IP.
Backends¶
rsba1server can serve three kinds of source:
- usb —
UsbRadio: a real USB Icom radio. CI-V overpyserial, audio via ALSAarecord/aplay(resampled to/from the device rate). - soapy —
SoapyRadio: any SoapySDR receiver (RTL-SDR, LimeSDR Mini, HackRF, Airspy…). CI-V frequency/mode retunes the SDR and switches the demodulator (FM / AM / USB / LSB / CW); demodulated audio is streamed to the client. RX only.--backend rtlsdr/--backend limeare shortcuts. - fake —
FakeRadio: answers common CI-V polls and emits a test tone; no hardware. Used bytest_rsba1.pyand for trying a client.
Running it independently¶
The server is a self-contained package — copy rsba1server/ to the machine
next to the radio and run it with the system Python.
A USB radio (e.g. IC-7300)¶
python3 -m rsba1server --backend usb \
--serial /dev/ttyUSB0 --civ-address 0x94 --device IC-7300 \
--audio-in plughw:1,0 --audio-out plughw:1,0 \
--user patrick --password secret
Find the serial port with ls /dev/serial/by-id/ and the USB-audio ALSA
device with arecord -l / aplay -l (then plughw:<card>,0).
CI-V addresses: IC-7300 0x94, IC-705 0xA4, IC-9700 0xA2, IC-7610 0x98,
IC-7100 0x88, IC-7851 0x8E, IC-905 0xAC.
An SDR (RTL-SDR / LimeSDR Mini)¶
# RTL-SDR
python3 -m rsba1server --backend rtlsdr --device "RTL-SDR" \
--civ-address 0x94 --user patrick --password secret
# LimeSDR Mini
python3 -m rsba1server --backend lime --device "LimeSDR Mini" ...
# any SoapySDR device by driver key
python3 -m rsba1server --backend soapy --driver hackrf --samp-rate 2000000 ...
Options: --driver (SoapySDR key), --samp-rate (IQ rate, default 240000),
--sdr-gain (dB; omit for AGC), --ppm (frequency correction).
A simulator (no hardware)¶
Then point a client at the host's IP, port 50001, with those credentials.
From a config file¶
See rsba1server/rsba1-server.example.json. As a systemd service, use
deploy/rsba1-server.service (it runs from /opt, SupplementaryGroups=dialout
audio for serial + USB-audio access).
Multiple remote SDRs¶
There are two independent ways to add remote receivers, and you can mix them.
1. Several SDRs each served as a radio (switch between them)¶
Run one rsba1server instance per SDR — on the same host (different ports)
or on separate Raspberry Pis around the site — and add each as a radio in the
web app's radio switcher (⚙ dialog). Each becomes a selectable "radio":
# Pi in the loft, wideband discone -> RTL-SDR
python3 -m rsba1server --backend rtlsdr --device "Loft RTL" \
--user patrick --password secret # (host: 192.168.1.20)
# Pi in the shack, LimeSDR on a beam
python3 -m rsba1server --backend lime --device "Beam Lime" \
--user patrick --password secret # (host: 192.168.1.21)
In the app, add two radios pointing at 192.168.1.20 and 192.168.1.21; the
switcher flips the whole panadapter/audio/CI-V head between them. To run more
than one instance on a single host, give each its own bind/ports via the config
file.
2. Remote data collectors (feed decoders, not a radio head)¶
For data rather than a tunable head — AIS ship positions today — a Pi with a cheap RTL-SDR runs in collector mode and forwards decoded traffic to the central Rafe server, where every collector's output is merged onto one map:
--collect aisruns AIS-catcher on the local dongle and forwards AIVDM NMEA over UDP to--feed HOST:PORT(the server's AIS ingest port, default 10110).--serialselects the dongle;--sdr-gainsets the tuner gain;--driverselects a SoapySDR device instead (e.g. a LimeSDR on the Pi).- It supervises the decoder and restarts it if it dies.
Point as many collectors at the server's port as you like — no per-collector setup on the server. The server also has its own local SDR path (see the AIS and satellite-decode sections of the install guide); the local SDR and a satellite decode are mutually exclusive because they share one SDR, but remote collectors are independent and always on.
Status / limitations¶
- Verified against this repo's RS-BA1 client (control + CI-V + audio, both directions). Testing against Icom's own client / wfview is recommended before relying on it on the air.
- The SoapySDR demodulator is verified against synthetic IQ; on-air reception
against a physical dongle may need gain/sample-rate and per-mode audio-gain
tuning in
demodulate(). - SDR backends are receive-only; TX is not implemented for SDR.