C4FM-VB

No description available.

C4FM-VB

C4FM-VB is a C++ project for experimenting with wide C4FM-style file transfer. It is intentionally structured like the working 4GFSK project, but the modem layer is refocused around 4-level FM / C4FM dibits instead of the earlier 4GFSK interpretation.

This first pass provides:

  • packetization, CRC protection, and file reassembly
  • a self-contained C4FM-style dibit modulator and FM discriminator decoder
  • simulation with AWGN, timing offset, and frequency offset
  • optional SoapySDR over-the-air testing
  • full-duplex self-loopback transport
  • a first-pass half-duplex runtime option

It is meant as a clean sandbox for building a wideband C4FM transmitter/decoder without depending on dsd-neo.

Design notes

This project is wide C4FM-style, not a strict P25 implementation.

  • The symbol mapping follows the usual C4FM-style 4-level dibit idea.
  • The framing, file transfer, and OTA workflow are custom and project-local.
  • SiteSim was used as a reference for C4FM transmit conventions, but this project keeps its own decoder and does not reuse the dsd-neo receive engine.

Build

Requirements:

  • CMake 3.20+
  • a C++20 compiler
  • pkg-config
  • SoapySDR development files for OTA mode

Build:

cmake -S . -B build
cmake --build build

Run tests:

ctest --test-dir build --output-on-failure

If SoapySDR is available, OTA support is compiled in automatically. Otherwise, the simulation path still builds and runs.

Command line usage

Show help:

./build/c4fm_vb --help

Important options:

  • --mode <simulate|ota> selects simulation or OTA
  • --input <path> uses a real file as payload
  • --generate-bytes <n> generates a synthetic test payload
  • --payload-bytes <n> controls file chunk size
  • --symrate <Hz> sets symbol rate
  • --sps <count> sets samples per symbol
  • --deviation-step <Hz> sets the C4FM deviation step for the +/-1 and +/-3 levels
  • --duplex <full|half> selects OTA duplex mode
  • --stream-mode <continuous|burst> selects continuous whole-file streaming or per-packet bursts
  • --packet-repetitions <n> retransmits each OTA packet payload n times

Default waveform behavior

General waveform defaults:

  • --symrate 480000
  • --sps 4
  • --deviation-step 60000

That corresponds to:

  • sample rate: 1.92 Msps
  • maximum symbol deviation: 180 kHz

OTA defaults are intentionally more conservative when you do not explicitly override them:

  • --symrate 120000
  • --sps 4
  • --deviation-step 15000

That gives a safer 480 ksps OTA sample path for bring-up and experimentation on hardware such as a B210.

The default OTA center frequency is set to 433.5 MHz as a reasonable 70cm amateur-band default. Override it with --freq whenever you want a different channel.

The default OTA stream mode is continuous, which keeps the signal on-air across the whole file transfer rather than keying separate packet bursts.

Simulation examples

Default simulation:

./build/c4fm_vb --mode simulate

Larger multi-packet simulation:

./build/c4fm_vb --mode simulate --generate-bytes 4096

Simulation with channel impairments:

./build/c4fm_vb --mode simulate \
  --generate-bytes 4096 \
  --snr-db 30 \
  --freq-offset 1200 \
  --timing-offset 3

OTA examples

Full-duplex continuous self-test at the default 70cm frequency (433.5 MHz):

./build/c4fm_vb --mode ota \
  --duplex full \
  --stream-mode continuous \
  --device driver=uhd \
  --tx-gain 35 \
  --rx-gain 35 \
  --packet-repetitions 2 \
  --generate-bytes 4096

Half-duplex runtime example:

./build/c4fm_vb --mode ota \
  --duplex half \
  --stream-mode burst \
  --device driver=uhd \
  --tx-gain 35 \
  --rx-gain 35 \
  --generate-bytes 4096 \
  --turnaround-delay-ms 10

Use --input yourfile.bin instead of --generate-bytes when you want to transfer a real file.

Full duplex vs half duplex

Full duplex is the current validation path for same-radio self-test, because transmit and receive happen at the same time and the receive window is aligned to each burst.

Half duplex is exposed so the transport architecture is not locked to one operating style. It is better suited to future remote or turn-taking workflows than same-radio self-loopback.

Limitations

  • This is a wide C4FM-style modem, not a standards-accurate P25 physical layer.
  • The decoder currently uses a straightforward FM discriminator plus symbol slicing.
  • Burst acquisition is still simple and can miss packets under real RF conditions.
  • Continuous OTA mode keeps RF data flowing across the whole file, but receive-side packet recovery still works by finding packet prefixes and validating CRCs inside the decoded symbol stream.
  • B210 over USB 2 can still be throughput-limited.
  • This is an experimental transfer tool, not a hardened production modem.

Repository layout

  • include/c4fmvb/ public headers
  • src/ modem, framing, simulation, OTA, and CLI implementation
  • tests/ regression tests