Skip to content

Native protocols

Rafe reimplements its radio protocols natively (clean-room, from published standards and functional facts) instead of shelling out to external decoders. External binaries (fldigi, WSJT-X, dsd-fme, SatDump, AIS-catcher, …) are kept only as optional fallbacks/oracles for the edges the native code doesn't cover. See NOTICE.md for the clean-room provenance of each.

Supported (native)

Weak-signal / WSJT-X family

Protocol Module Notes
FT8, FT4 radio/ftx/ 8-/4-FSK, LDPC(174,91), CRC-14, Costas sync
JT65, JT9, JT4 radio/jtx/ classic weak-signal MFSK/RS
Q65 radio/jtx/q65.py 65-tone, tolerant of Doppler/scatter
FST4, FST4W radio/jtx/fst4.py LF/MF weak-signal + WSPR-style beacon
WSPR radio/wsprx/ K=32 conv + beacon message

HF keyboard / chat digital

Protocol Module Notes
RTTY (Baudot) radio/rtty.py 45.45 baud, 170 Hz shift
PSK31 / PSK63 / PSK125 radio/psk.py, pskvaricode.py BPSK/QPSK + varicode
Olivia radio/olivia.py MFSK, Walsh/FEC
DominoEX radio/domino.py incremental-frequency MFSK
THOR radio/thor.py MFSK + FEC (robust)
Throb / ThrobX radio/throb.py tone-pair MFSK
MFSK16 / MFSK32 radio/mfsk.py MFSK + conv FEC
Feld Hell radio/feld.py on/off Hellschreiber raster
JS8 (normal/fast/turbo/slow) radio/js8/, js8_mode.py FT8-derived PHY + JS8 message layer
MT63 radio/mt63.py 64-tone Walsh-spread DBPSK OFDM + interleave
Protocol Module Notes
ARDOP (modem + ARQ + TNC) radio/ardop_native.py, ardop_arq.py, ardop_tnc.py 4FSK/PSK/QAM, RS FEC, ardopcf host interface
Mercury radio/mercury/ OFDM + LDPC + our own ARQ data-link

Digital voice

Protocol Module Notes
M17 radio/m17.py, m17_voice.py 4-FSK, Golay/conv/interleave, Codec2 voice
P25 Phase 1 (C4FM) radio/p25/, radio/imbe.py, radio/mbe.py framing + IMBE FEC + native IMBE/MBE vocoder (no mbelib)
DMR (Tier I/II) radio/dmr.py, radio/ambe.py 4FSK bursts, BPTC(196,96), LC/CSBK, voice superframe + native AMBE+2
D-STAR (DV) radio/dstar.py, radio/ambe.py GMSK 4800, coded radio header, voice + slow data, native full-rate AMBE
YSF (System Fusion) radio/ysf.py, radio/ambe.py C4FM, FICH, DN-mode DCH/VCH frames + native AMBE+2
NXDN radio/nxdn.py, radio/ambe.py 2400/4800-sym 4FSK, LICH/SACCH/FACCH1, VCALL + native AMBE+2
FreeDV radio/freedv_native.py, freedv_voice.py via libcodec2 (LGPL)
Codec2 radio/codec2_native.py via libcodec2 (LGPL)
RVQ-voice radio/rvqvoice*.py original low-bitrate source-filter + RVQ vocoder

Paging / packet / maritime

Protocol Module Notes
POCSAG radio/pocsag.py 512/1200/2400 bps FSK pager
APRS / AX.25 (RX + TX) radio/aprs.py, aprstx.py 1200 bps AFSK, HDLC
NAVTEX / SITOR-B (CCIR 476) radio/navtex.py FEC-B time-diversity
Marine DSC (ITU-R M.493) radio/dsc.py 10-bit symbols + B-count check, DX/RX time diversity, MMSI/format/EOS/ECC, FSK + AFSK
CW / Morse radio/cwdecoder.py decode + encode

Images / fax

Protocol Module Notes
WEFAX / radiofax radio/wefax.py HF weather-fax IOC576
HamDRM / digital SSTV radio/hamdrm/ amateur DRM (EasyPal-compatible)
SSTV (sstv library) Scottie/Martin/Robot — via a Python lib, not clean-room

Broadcast / wideband

Protocol Module Notes
RDS radio/rds.py FM broadcast data, 57 kHz subcarrier
DAB / DAB+ radio/dab/ Mode I OFDM, RS, MP2/HE-AACv2 (linked codecs)
DVB-S / DVB-S2 (DATV) radio/datv/ ETSI EN 300 421 / 302 307-1, LDPC

Satellite / space (CCSDS)

Protocol Module Notes
CCSDS TM core radio/sat/ccsds.py r=1/2 K=7 Viterbi, RS(255,223) dual basis, PN, CADU
NOAA APT radio/sat/apt.py 2400 Hz AM subcarrier → image (FM audio)
Meteor-M LRPT radio/sat/lrpt.py QPSK → CCSDS → Meteor JPEG image
LRIT / HRIT (xRIT) radio/sat/xrit.py GOES/Meteosat file layer, JPEG via Pillow
NOAA HRPT radio/sat/hrpt.py Manchester, 10-bit AVHRR de-interleave
MetOp / FengYun AHRPT radio/sat/ahrpt.py AVHRR over the CCSDS core
Inmarsat-C STD-C / EGC radio/inmarsat.py BPSK 1200, r=1/2 K=7 Viterbi, interleave/descramble, unique-word sync, SafetyNET/MSI EGC parse
Inmarsat AERO / ACARS radio/acars.py ACARS message layer (ARINC-618) + AERO framing over the Inmarsat-C FEC
VHF ACARS radio/acars.py 2400 bps AM-MSK PHY (1200/2400 Hz), char odd-parity, SYN SYN SOH sync

Tracking / sensing / trunking

Protocol Module Notes
AIS (marine) radio/aisdecode.py GMSK, NRZI, AX.25-like
ADS-B Mode S radio/adsb.py DF17, CRC-24, CPR position
VDL Mode 2 radio/vdl2.py, radio/acars.py D8PSK 10500, RS(255,249), LFSR scramble, AVLC + ACARS
ISM / rtl_433 devices radio/rtl433/ config-driven OOK/FSK sensor decode
LoRa (CSS) radio/loracss.py, lorasdr/ chirp spread spectrum + Semtech PHY
TETRA (downlink signalling) radio/tetra/ π/4-DQPSK, RCPC/Viterbi, clear signalling only

Radio control / transport

Protocol Module Notes
RS-BA1 (Icom network) radio/civ.py, control.py, passcode.py UDP transport, CI-V, credential scrambling

Remaining candidates (not yet native)

Protocol Currently Feasibility
dPMR (digital voice) dsd-fme/mbelib Feasible — shares NXDN's 2400-sym 4FSK PHY (now parameterised) and the native AMBE+2 codec; only its ETSI TS 102 658 framing remains. The last standing candidate.

On the AMBE/IMBE vocoder

The digital-voice modes were previously flagged "voice gated" by the AMBE patent. That is not a technical barrier (mbelib is a clean-room software MBE decoder) and in this project's context it is not a practical legal one either: IMBE (P25 Phase 1) patents have expired, the UK/EU do not grant patents on "programs as such", and the project is non-commercial. A native MBE vocoder (radio/mbe.py) therefore replaces the mbelib IMBE->PCM step, making P25 and the DMR/D-STAR/YSF/NXDN family fully native. AMBE+2 (some in-force patents) is the only lingering edge.

Out of scope (not wire protocols)

  • whisper.cpp — speech-recognition model (transcription), not a protocol
  • Pat — Winlink email/BBS client app (ARDOP itself is native)
  • ffmpeg (DATV video codec), Leaflet / OSM tiles (maps) — libraries

Implementation log

Remaining candidates are implemented one at a time, each on its own worktree; as each lands it moves from the candidates table to Supported.

  • VDL Mode 2radio/vdl2.py, test_vdl2 (8). ICAO Annex 10 Vol III: a Gray-coded differential 8-PSK modem at 10500 sym/s (RRC shared with tetra, widened to 8 phases; a one-step slip is a single-bit error), RS(255,249) over GF(0x11D) (6 parity, corrects 3 byte errors -- BM/Chien/Forney ported from sat/rs.py), a 15-bit LFSR scrambler, a Golay(24,12)-protected length header, and the AVLC data-link (HDLC bit-stuffing + CRC-16/X.25 reused from aisdecode, 24-bit ICAO addresses). ACARS rides in an AVLC information field and is handed to the existing acars.parse. A full burst -- ACARS message -> AVLC -> RS/scramble -> D8PSK IQ and back -- round-trips clean and through 30 dB complex noise. Training symbols, scrambler seed, header bit layout and RS symbol ordering are the on-air interop checks. dPMR is now the only remaining candidate.
  • VHF ACARS PHYradio/acars.py, test_acars (+5). The 2400 bps AM-MSK front end for the existing ARINC-618 message layer: phase-continuous 1200/2400 Hz tone modem, per-character odd parity, and the pre-key + '+' '*' SYN SYN SOH air frame, with the 16-bit BCS sent raw (not parity-bearing) and DEL terminating. A message round-trips through the modem clean and recovers through 30 dB noise + an arbitrary sample offset; the BCS surfaces a mid-message corruption. Only VDL2's D8PSK + AVLC now remains in the candidates table. Exact pre-key/bit-sync values and mark/space polarity are the on-air interop checks.
  • NXDNradio/nxdn.py, test_nxdn (7). The NXDN common air interface over the p25 4FSK modem with its symbol rate parameterised (2400 sym/s for the 6.25 kHz 4800 bps channel, 4800 for 9600; both tested). The 384-bit frame: 20-bit FSW + LICH (7+parity bits sent twice) + SACCH (26 info + CRC-6, K=5 conv punctured 72->60 -- the shared ysf Viterbi gained erasure support) + either 4 x 72-bit AMBE+2 channel frames or duplicated 144-bit FACCH1 (80 info + CRC-12, punctured 192->144) carrying VCALL/TX_RELEASE with 16-bit unit IDs. A call round-trips clean at both rates and at 30 dB SNR. FSW value, puncture patterns and LICH functional-type encodings are the on-air interop checks. dPMR now needs only its ETSI framing on this PHY.
  • YSFradio/ysf.py, test_ysf (6). Yaesu System Fusion over the shared 4800-sym C4FM modem: the 960-bit / 100 ms frame (40-bit sync 0xD471C9634D + 200-bit FICH + 720-bit payload), the published FICH chain (32 info bits + CRC-16 -> 4x Golay(24,12) -> rate-1/2 K=5 trellis-terminated conv -> 20x10 interleave), and DN mode (V/D type 2): five DCH/VCH pairs per frame with the 20-char CSD (dest+source callsigns, CRC-16 + K=5 conv + 20x18 interleave + PN whitening) and 5 x 72-bit AMBE+2 channel frames. A header/comm/terminator call round-trips clean and at 30 dB SNR. Interleave orderings, whitening seed, K=5 polynomials and YSF's exact V/D2 voice protection are the on-air interop refinements.
  • D-STARradio/dstar.py, test_dstar (7). JARL DV mode: a GMSK-4800 modem on FM-discriminator audio (Gaussian pulse shared with aisdecode), the 660-bit radio header (39 bytes of flags + RPT2/RPT1/UR/MY callsigns, CRC, rate-1/2 K=3 (7,5) conv + 12x55 interleave + x^7+x^4+1 scramble), and the 96-bit voice frame stream: 72-bit full-rate AMBE (radio/ambe.py) + 24-bit slow data with the 0x55 2D 16 sync every 21st frame and the 20-char TX message in 0x70 4F 93-scrambled type-0x4x blocks. Header survives 8 bit errors (Viterbi + CRC), full stream round-trips clean and at 30 dB SNR. Interleave geometry, LFSR seed, sync/termination patterns and the in-frame AMBE bit interleave are the on-air interop checks.
  • DMRradio/dmr.py, test_dmr (8). ETSI TS 102 361 Tier I/II: the 264-bit burst geometry + the four 48-bit sync words over the shared 4800-sym C4FM modem (p25/demod reused unchanged), BPTC(196,96) (Hamming(15,11) rows x new Hamming(13,9) columns in p25/fec, 181-step interleave), Golay(20,8) slot type, full LC with RS(12,9) parity under the 0x969696/0x999999 masks, CSBK with the 0xA5A5 CRC mask, and the A-F voice superframe: 3 x 72-bit AMBE+2 channel frames per burst with the 72-bit LC embedded across B-E under EMB. A full call (header
  • superframe + terminator) round-trips through C4FM audio clean and at 30 dB SNR. The EMB (16,7) generator, embedded-LC/CACH interleaves and RS(12,9) generator constants are the on-air interop checks.
  • AMBE parameter codecsradio/ambe.py, test_ambe (7). The DV-family voice frames onto the native MBE vocoder, as imbe.py did for P25: the half-rate AMBE+2 49-bit parameter frame (DMR/NXDN/YSF-DN) and the D-STAR full-rate 48-bit frame, each carried as a 72-bit channel frame -- Golay(24,12) over the most-sensitive bits + a PN-scrambled Golay(23,12) (hr) / Golay(24,12) (fr) + unprotected tail. Parameters round-trip (f0 <5%, amp corr >0.7, V/UV

    0.8) and the channel frames correct 3+3 injected errors. DVSI's exact VQ tables, PN seed and inter-frame prediction remain for bit-exact on-air audio.

  • Marine DSCradio/dsc.py, test_dsc (8). ITU-R M.493 10-bit symbol codec

  • B-count check, DX/RX time-diversity error correction, message build/parse (format/MMSI/category/self-ID/EOS/ECC), FSK + AFSK modem. Round-trips through an AFSK audio channel clean and under noise; time diversity recovers fully-corrupt DX copies. On-air interop (exact M.493 bit ordering / phasing) is the next check.
  • ACARS + Inmarsat AEROradio/acars.py, test_acars (6). The ARINC-618 ACARS message layer (mode/registration/label/block-id/sequence/flight/text + the CRC block-check) shared across VHF/VDL/satellite, plus AERO framing that reuses the Inmarsat-C r=1/2 Viterbi + interleave/descramble. Messages round-trip and recover through 3%% bit errors; BCS rejects tampering. The VHF-ACARS MSK PHY and the AERO burst timing are the interop steps.
  • IMBE parameter codec -> native P25 voiceradio/imbe.py, test_imbe (5). The 88-bit IMBE frame <-> (f0, per-band V/UV, harmonic amplitudes): the fundamental/harmonic-count relation (w0=4pi/(b0+39.5), L via the 0.9254 band limit) is spec-accurate; amplitudes are gain + differential-log quantised, bit-allocated by L. Wired through p25.voice's Golay/Hamming/PN FEC and the MBE vocoder, an 88-bit frame -> PCM runs fully native (p25 Vocoder.decode, no mbelib). f0 within 5%, amplitude corr 0.7-0.98 (finer at low L), V/UV ~95%, surviving 8 channel bit errors. The exact IMBE amplitude tables + inter-frame DCT prediction remain for bit-exact on-air audio.
  • Native MBE vocoderradio/mbe.py, test_mbe (7). The Multi-Band Excitation analysis + synthesis (pitch f0, per-harmonic voiced/unvoiced, harmonic amplitudes; sinusoid + shaped-noise synthesis) -- the IMBE/AMBE step formerly on mbelib. f0 within 5%, amplitude corr >0.95, V/UV recovered incl. mixed, envelope corr >0.97. Unblocks fully-native P25 voice (its 88-bit IMBE frame maps to these params) and the DMR/D-STAR/YSF/NXDN family; the per-codec quantisation mapping is the wiring step.
  • MT63radio/mt63.py, test_mt63 (6). 64-carrier DBPSK OFDM with Walsh(64) symbol spreading + block interleave; text round-trips clean and through noise up to 0.6x signal power. Exact fldigi interop (bandwidth/tone spacing, interleave geometry, the secondary channel) is the refinement.
  • Inmarsat-C STD-C / EGCradio/inmarsat.py, test_inmarsat (7). BPSK-1200 chain reusing the sat r=1/2 K=7 Viterbi + BPSK receiver; descrambler, block interleaver, unique-word frame sync, and the EGC (SafetyNET/MSI) message layer. Recovers the message clean, through noise+offset, and from raw BPSK IQ (180-deg ambiguity resolved via the unique word). AERO/ACARS remains. Scrambler/ interleaver/UW constants need on-air validation.