From bd3ddb86cde19b10ab6370ae8ae60da3a6bea9c6 Mon Sep 17 00:00:00 2001 From: Jan Svabenik Date: Sun, 5 Apr 2026 11:16:16 +0200 Subject: [PATCH] docs: refresh README for current runtime and control surface --- README.md | 316 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 259 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 7cdf68d..d2df8ad 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,290 @@ # fm-rds-tx -Go-based FM stereo transmitter with RDS. Supports ADALM-Pluto (PlutoSDR) and any SoapySDR-compatible TX device. +Go-based FM stereo transmitter with RDS. Supports ADALM-Pluto (PlutoSDR) and SoapySDR-compatible TX devices. -## Status: v0.7.0-pre — hardware bring-up milestone +## Status -### What works -- Complete DSP chain: pre-emphasis → stereo encoding → RDS (IEC 62106) → MPX → limiter → FM modulation -- Real hardware TX via SoapySDR CGO binding (PlutoSDR tested) -- Continuous TX engine with Start/Stop/Stats -- IQ resampling (composite rate → device rate) -- HTTP control plane with /tx/start, /tx/stop, /runtime -- 82 passing tests including spectral verification +**Current status:** `v0.7.0-pre` — hardware bring-up milestone -### Signal path -``` -Audio Source → PreEmphasis(50µs) → StereoEncoder(19k+38k) → RDS(57k) -→ MPX Combiner → Limiter → FM Modulator(±75kHz) -→ IQ Resample(228k→528k) → SoapySDR → PlutoSDR RF +What is already in place: +- complete DSP chain: audio -> pre-emphasis -> stereo encoding -> RDS -> MPX -> limiter -> FM modulation +- real hardware TX paths for PlutoSDR / SoapySDR backends +- continuous TX engine with runtime telemetry +- dry-run, offline generation, and simulated TX modes +- HTTP control plane with live config patching and runtime/status endpoints +- browser UI on `/` +- live audio ingestion via stdin or HTTP stream input + +## Signal path + +```text +Audio Source -> PreEmphasis(50us/75us/off) -> StereoEncoder(19k + 38k DSB-SC) +-> RDS(57k BPSK) -> MPX Combiner -> Limiter -> FM Modulator(+/-75kHz) +-> optional split-rate FM upsampling -> SDR backend -> RF output ``` +For deeper DSP details, see: +- `docs/DSP-CHAIN.md` + +## Prerequisites + +### Go +- Go version from `go.mod` (currently Go 1.22) + +### Native SDR dependencies +Depending on backend, native libraries are required: + +- **SoapySDR backend** + - build with `-tags soapy` + - requires SoapySDR native library (`SoapySDR.dll` / `libSoapySDR.so` / `libSoapySDR.dylib`) + - on Windows, PothosSDR is the expected setup + +- **Pluto backend** + - uses native `libiio` + - Windows expects `libiio.dll` + - Linux build/runtime expects `pkg-config` + `libiio` + +### Hardware / legal +- validate RF output, deviation, filtering, and power with proper measurement equipment +- use only within applicable legal and regulatory constraints + +## Quick start + ## Build ```powershell -# Without hardware (simulation/offline only): +# Build CLI tools without hardware-specific build tags: go build ./cmd/fmrtx go build ./cmd/offline -# With SoapySDR hardware support (requires PothosSDR installed): +# Build fmrtx with SoapySDR support: go build -tags soapy ./cmd/fmrtx ``` -## Usage +## Quick verification + +```powershell +# Print effective config +go run ./cmd/fmrtx -print-config + +# Run tests +go test ./... + +# Basic dry-run summary +go run ./cmd/fmrtx --dry-run --dry-output build/dryrun/frame.json +``` + +For additional build/test commands, see: +- `docs/README.md` + +## Common usage flows + +### 1) List available SDR devices -### List available SDR devices ```powershell .\fmrtx.exe --list-devices ``` -### Offline IQ file generation +### 2) Dry-run / config verification + ```powershell .\fmrtx.exe --dry-run --dry-output build/dryrun/frame.json + +# Write dry-run JSON to stdout +.\fmrtx.exe --dry-run --dry-output - +``` + +### 3) Offline IQ/composite generation + +```powershell go run ./cmd/offline -duration 2s -output build/offline/composite.iqf32 + +# Optional output rate override +go run ./cmd/offline -duration 500ms -output build/offline/composite.iqf32 -output-rate 228000 +``` + +### 4) Simulated transmit path + +```powershell +go run ./cmd/fmrtx --simulate-tx --simulate-output build/sim/simulated-soapy.iqf32 --simulate-duration 250ms ``` -### Real TX (PlutoSDR) +### 5) Real TX with config file + ```powershell -# Start with manual TX control via HTTP: +# Start TX service with manual start over HTTP .\fmrtx.exe --tx --config docs/config.plutosdr.json -# Start with auto-TX on launch: +# Start and begin transmitting immediately .\fmrtx.exe --tx --tx-auto-start --config docs/config.plutosdr.json ``` -### HTTP control +### 6) Live audio via stdin + +```powershell +ffmpeg -i "http://svabi.ch:8443/stream" -f s16le -ar 44100 -ac 2 - | .\fmrtx.exe --tx --tx-auto-start --audio-stdin --config docs/config.plutosdr.json +``` + +### 7) Custom audio input rate + +```powershell +ffmpeg -i source.wav -f s16le -ar 48000 -ac 2 - | .\fmrtx.exe --tx --tx-auto-start --audio-stdin --audio-rate 48000 --config docs/config.plutosdr.json +``` + +## CLI overview + +## `fmrtx` +Important runtime modes and flags include: +- `--tx` +- `--tx-auto-start` +- `--dry-run` +- `--dry-output ` +- `--simulate-tx` +- `--simulate-output ` +- `--simulate-duration ` +- `--config ` +- `--print-config` +- `--list-devices` +- `--audio-stdin` +- `--audio-rate ` + +## `offline` +Useful flags include: +- `-duration ` +- `-output ` +- `-output-rate ` + +If the README is too high-level for the exact CLI surface, check: +- `cmd/fmrtx/main.go` +- `cmd/offline/main.go` + +## HTTP control plane + +Base URL: `http://{listenAddress}` (default typically `127.0.0.1:8088`) + +### Main endpoints + +```text +GET / browser UI +GET /healthz health check +GET /status current config/status snapshot +GET /runtime live engine/driver/audio telemetry +GET /config full config +POST /config patch config / live updates +GET /dry-run synthetic frame summary +POST /tx/start start transmission +POST /tx/stop stop transmission +POST /audio/stream push raw S16LE stereo PCM into live stream buffer ``` -POST http://localhost:8088/tx/start → start transmission -POST http://localhost:8088/tx/stop → stop transmission -GET http://localhost:8088/runtime → engine + driver telemetry -GET http://localhost:8088/status → config status -GET http://localhost:8088/config → full config -POST http://localhost:8088/config → patch config (freq, RDS, etc.) -GET http://localhost:8088/dry-run → dry-run summary -GET http://localhost:8088/healthz → health check + +### What the control plane covers +- TX start / stop +- runtime status and driver telemetry +- config inspection +- live patching of selected parameters +- dry-run inspection +- browser-accessible control UI +- optional HTTP audio ingest + +### Live config notes +`POST /config` supports live updates for selected fields such as: +- frequency +- stereo enable/disable +- pilot / RDS injection levels +- RDS enable/disable +- limiter settings +- PS / RadioText + +Some parameters are saved but not live-applied and require restart. + +For the full API contract, examples, live-patch semantics, and `/audio/stream` details, see: +- `docs/API.md` + +## Configuration + +Sample configs: +- `docs/config.sample.json` +- `docs/config.plutosdr.json` +- `docs/config.orangepi-pluto-soapy.json` + +Important config areas include: +- `fm.*` +- `rds.*` +- `audio.*` +- `backend.*` +- `control.*` + +Examples of relevant fields you may want to inspect: +- `fm.outputDrive` +- `fm.mpxGain` +- `fm.bs412Enabled` +- `fm.bs412ThresholdDBr` +- `fm.fmModulationEnabled` +- `backend.kind` +- `backend.driver` +- `backend.deviceArgs` +- `backend.uri` +- `backend.deviceSampleRateHz` +- `backend.outputPath` +- `control.listenAddress` + +For deeper config/API behavior, refer to: +- `internal/config/config.go` +- `docs/API.md` +- `docs/config.sample.json` + +## Development and testing + +Useful commands: + +```powershell +go test ./... +go run ./cmd/fmrtx -print-config +go run ./cmd/fmrtx -config docs/config.sample.json +go run ./cmd/fmrtx --dry-run --dry-output build/dryrun/frame.json +go run ./cmd/fmrtx --simulate-tx --simulate-output build/sim/simulated-soapy.iqf32 --simulate-duration 250ms +go run ./cmd/offline -duration 500ms -output build/offline/composite.iqf32 ``` -## PlutoSDR notes +See also: +- `docs/README.md` -- Device rate: 528 kHz (PlutoSDR minimum ~521 kHz) -- IQ format: CF32 (float32 interleaved I/Q) -- Gain range: 0–89 dB (`outputDrive` 0..1 maps to 0..89 dB) -- SoapySDR driver name: `plutosdr` -- Requires: PothosSDR or SoapySDR + SoapyPlutoSDR plugin installed +## PlutoSDR / backend notes + +- PlutoSDR commonly runs with a device-side sample rate above composite rate, so split-rate mode may be used automatically +- SoapySDR backend is suitable for Soapy-compatible TX hardware +- backend/device settings are selected through config rather than hardcoded paths +- runtime telemetry should be used to inspect effective TX state during operation ## Repository layout ```text cmd/ - fmrtx/ main CLI (--tx, --dry-run, --simulate-tx, --list-devices) - offline/ offline IQ file generator + fmrtx/ main CLI + offline/ offline generator internal/ - app/ TX engine (continuous chunk loop) + simulated transmit - audio/ sample types, WAV loader, resampler, tone generator - config/ config schema, validation, PI parsing - control/ HTTP control plane (/tx/start, /tx/stop, /runtime) - dryrun/ JSON dry-run summaries - dsp/ oscillator, pre-emphasis, FM modulator, limiter, Goertzel, IQ resampler - mpx/ MPX combiner - offline/ offline composite generation (full DSP chain) - output/ backend abstractions (file, dummy) - platform/ SoapyDriver interface, SoapyBackend, SimulatedDriver - platform/soapysdr/ CGO SoapySDR native binding (build tag: soapy) - rds/ RDS encoder (IEC 62106, CRC, differential, group scheduler) - stereo/ stereo encoder (19 kHz pilot, 38 kHz DSB-SC) + app/ TX engine + runtime state + audio/ audio input, resampling, tone generation, stream buffering + config/ config schema and validation + control/ HTTP control plane + browser UI + dryrun/ dry-run JSON summaries + dsp/ DSP primitives + mpx/ MPX combiner + offline/ full offline composite generation + output/ output/backend abstractions + platform/ backend abstractions and device/runtime stats + platform/soapysdr/ CGO SoapySDR binding + platform/plutosdr/ Pluto/libiio backend code + rds/ RDS encoder + stereo/ stereo encoder docs/ - config.sample.json default config - config.plutosdr.json PlutoSDR-specific config - pro-runtime-hardening-workboard.md living workboard for pro runtime hardening + API.md + DSP-CHAIN.md + README.md + config.sample.json + config.plutosdr.json + config.orangepi-pluto-soapy.json + pro-runtime-hardening-workboard.md scripts/ examples/ ``` @@ -103,10 +292,23 @@ examples/ ## Planning / workboard For the current pro-runtime-hardening track, see: - - `docs/pro-runtime-hardening-workboard.md` -This document is the detailed working board for status tracking, confirmed findings, open decisions, verification notes, and implementation progress. +This is the living workboard for: +- status tracking +- confirmed findings +- open technical decisions +- verification notes +- implementation progress + +## Release / project docs + +Additional project docs: +- `CHANGELOG.md` +- `RELEASE.md` +- `docs/README.md` +- `docs/API.md` +- `docs/DSP-CHAIN.md` ## Legal note