# Configuration

This document lists all currently supported configuration options for `trx-server` and `trx-client`.

## File Locations

### `trx-server`
Configuration lookup order:
1. `--config <FILE>`
2. `./trx-server.toml`
3. `~/.trx-server.toml`
4. `~/.config/trx-rs/server.toml`
5. `/etc/trx-rs/server.toml`

### `trx-client`
Configuration lookup order:
1. `--config <FILE>`
2. `./trx-client.toml`
3. `~/.config/trx-rs/client.toml`
4. `/etc/trx-rs/client.toml`

CLI options override file values.

## Environment Variables

- `TRX_PLUGIN_DIRS`: additional plugin directories (path-separated), used by both server and client.

## `trx-server` Options

### `[general]`
- `callsign` (`string`, default: `"N0CALL"`)
- `log_level` (`string`, optional): one of `trace|debug|info|warn|error`
- `latitude` (`float`, optional): `-90..=90`
- `longitude` (`float`, optional): `-180..=180`

Notes:
- `latitude` and `longitude` must be set together or both omitted.

### `[rig]`
- `model` (`string`, required effectively unless provided by CLI `--rig`)
- `initial_freq_hz` (`u64`, default: `144300000`, must be `> 0`)
- `initial_mode` (`string`, default: `"USB"`): one of `LSB|USB|CW|CWR|AM|WFM|FM|DIG|PKT`

### `[rig.access]`
- `type` (`string`, default behavior: `serial` if omitted): `serial|tcp|sdr`
- Serial mode:
  - `port` (`string`)
  - `baud` (`u32`)
- TCP mode:
  - `host` (`string`)
  - `tcp_port` (`u16`)
- SDR mode:
  - `args` (`string`, required when `type = "sdr"`): SoapySDR device args string (e.g. `"driver=rtlsdr"` or `"driver=airspy,serial=00000001"`). Passed verbatim to `SoapySDR::Device::new()`.

Notes:
- For `serial`, both `port` and `baud` are required.
- For `tcp`, both `host` and `tcp_port` are required.
- For `sdr`, `args` must be non-empty. The `port`, `baud`, `host`, and `tcp_port` fields are ignored.

### `[behavior]`
- `poll_interval_ms` (`u64`, default: `500`, must be `> 0`)
- `poll_interval_tx_ms` (`u64`, default: `100`, must be `> 0`)
- `max_retries` (`u32`, default: `3`, must be `> 0`)
- `retry_base_delay_ms` (`u64`, default: `100`, must be `> 0`)

### `[listen]`
- `enabled` (`bool`, default: `true`)
- `listen` (`ip`, default: `127.0.0.1`)
- `port` (`u16`, default: `4530`, must be `> 0` when enabled)

### `[listen.auth]`
- `tokens` (`string[]`, default: `[]`)

Notes:
- Empty token strings are invalid.
- Empty list means no auth required.

### `[audio]`
- `enabled` (`bool`, default: `true`)
- `listen` (`ip`, default: `127.0.0.1`)
- `port` (`u16`, default: `4531`, must be `> 0` when enabled)
- `rx_enabled` (`bool`, default: `true`)
- `tx_enabled` (`bool`, default: `true`)
- `device` (`string`, optional)
- `sample_rate` (`u32`, default: `48000`, valid: `8000..=192000`)
- `channels` (`u8`, default: `1`, valid: `1|2`)
- `frame_duration_ms` (`u16`, default: `20`, valid: `3|5|10|20|40|60`)
- `bitrate_bps` (`u32`, default: `24000`, must be `> 0`)

Notes:
- When `[audio].enabled = true`, at least one of `rx_enabled` or `tx_enabled` must be true.

### `[pskreporter]`
- `enabled` (`bool`, default: `false`)
- `host` (`string`, default: `"report.pskreporter.info"`, must not be empty when enabled)
- `port` (`u16`, default: `4739`, must be `> 0` when enabled)
- `receiver_locator` (`string`, optional)

Notes:
- If `receiver_locator` is omitted, server tries deriving it from `[general].latitude`/`longitude`.
- PSK Reporter software ID is hardcoded to: `trx-server v<version> by SP2SJG`.

### `[aprsfi]`
- `enabled` (`bool`, default: `false`)
- `host` (`string`, default: `"rotate.aprs.net"`, must not be empty when enabled)
- `port` (`u16`, default: `14580`, must be `> 0` when enabled)
- `passcode` (`i32`, default: `-1`)

Notes:
- When `passcode = -1` (the default), the passcode is auto-computed from `[general].callsign` using the standard APRS-IS hash algorithm.
- `[general].callsign` must be non-empty when `[aprsfi].enabled = true`; otherwise the IGate is silently disabled at startup.
- Only APRS packets with valid CRC are forwarded; packets from other decoders (FT8, WSPR, CW) are ignored.
- The IGate reconnects automatically with exponential backoff (1 s → 2 s → … → 60 s) on TCP errors.
- Requires `[audio].enabled = true` (APRS packets are decoded from audio).

### `[sdr]`
- `sample_rate` (`u32`, default: `1920000`, must be `> 0`): IQ capture rate in Hz. Must be supported by the device.
- `bandwidth` (`u32`, default: `1500000`): Hardware IF filter bandwidth in Hz.
- `center_offset_hz` (`i64`, default: `100000`): The SDR tunes this many Hz below the dial frequency to keep the signal off the DC spur. Negative values tune above.

### `[sdr.gain]`
- `mode` (`string`, default: `"auto"`): `"auto"` enables hardware AGC (falls back to `"manual"` with a warning if the device does not support it); `"manual"` uses the fixed `value`.
- `value` (`f64`, default: `30.0`): Gain in dB. Used only when `mode = "manual"`.

### `[[sdr.channels]]`

Defines one virtual receiver channel within the wideband IQ stream. At least one channel is required when using the `soapysdr` backend. The **first** channel in the list is the *primary* channel: `set_freq` and `set_mode` from rig control apply to it, and `get_status` reads from it.

- `id` (`string`, default: `""`): Human-readable label used in logs.
- `offset_hz` (`i64`, default: `0`): Frequency offset from the dial frequency in Hz. Primary channel should be `0`.
- `mode` (`string`, default: `"auto"`): Demodulation mode. `"auto"` follows the RigCat `set_mode` command; or a fixed mode string: `LSB`, `USB`, `CW`, `CWR`, `AM`, `WFM`, `FM`, `DIG`, `PKT`.
- `audio_bandwidth_hz` (`u32`, default: `3000`): One-sided bandwidth of the post-demodulation audio BPF in Hz.
- `fir_taps` (`usize`, default: `64`): FIR filter tap count. Higher values give sharper roll-off at the cost of latency.
- `cw_center_hz` (`u32`, default: `700`): CW tone centre frequency in the audio domain (Hz).
- `wfm_bandwidth_hz` (`u32`, default: `75000`): Pre-demodulation filter bandwidth for WFM only (Hz).
- `decoders` (`string[]`, default: `[]`): Decoder IDs that receive this channel's PCM audio. Valid values: `"ft8"`, `"wspr"`, `"aprs"`, `"cw"`. Each decoder ID may appear in at most one channel.
- `stream_opus` (`bool`, default: `false`): Encode this channel's audio as Opus and stream to clients over the TCP audio port. At most one channel may set this to `true`.

Notes:
- Requires `libSoapySDR` installed (`brew install soapysdr` on macOS; `libsoapysdr-dev` on Debian/Ubuntu).
- The SDR backend is RX-only. `[audio] tx_enabled` must be `false`.
- Channel IF constraint: `|center_offset_hz + offset_hz| < sample_rate / 2` for every channel; violated channels cause a startup error.
- `[audio] sample_rate` must match the output audio rate of the SDR pipeline (48000 Hz recommended).
- Use `trx-server --print-config` to see all defaults. SDR fields appear only if the binary was built with `--features soapysdr`.

### `[decode_logs]`
- `enabled` (`bool`, default: `false`)
- `dir` (`string`, default: `"$XDG_DATA_HOME/trx-rs/decoders"`; fallback: `"logs/decoders"`, must not be empty when enabled)
- `aprs_file` (`string`, default: `"TRXRS-APRS-%YYYY%-%MM%-%DD%.log"`, must not be empty when enabled)
- `cw_file` (`string`, default: `"TRXRS-CW-%YYYY%-%MM%-%DD%.log"`, must not be empty when enabled)
- `ft8_file` (`string`, default: `"TRXRS-FT8-%YYYY%-%MM%-%DD%.log"`, must not be empty when enabled)
- `wspr_file` (`string`, default: `"TRXRS-WSPR-%YYYY%-%MM%-%DD%.log"`, must not be empty when enabled)

Notes:
- Decoder logs are server-side and split by decoder name (APRS/CW/FT8/WSPR).
- Files are appended in JSON Lines format (one JSON object per line).
- Supported filename date tokens: `%YYYY%`, `%MM%`, `%DD%` (UTC date).

## `trx-client` Options

### `[general]`
- `callsign` (`string`, default: `"N0CALL"`)
- `log_level` (`string`, optional): one of `trace|debug|info|warn|error`

### `[remote]`
- `url` (`string`, optional in file but required at runtime unless provided by CLI `--url`)
- `poll_interval_ms` (`u64`, default: `750`, must be `> 0`)

### `[remote.auth]`
- `token` (`string`, optional)

Notes:
- If provided, token must not be empty/whitespace.

### `[frontends.http]`
- `enabled` (`bool`, default: `true`)
- `listen` (`ip`, default: `127.0.0.1`)
- `port` (`u16`, default: `8080`, must be `> 0` when enabled)

### `[frontends.rigctl]`
- `enabled` (`bool`, default: `false`)
- `listen` (`ip`, default: `127.0.0.1`)
- `port` (`u16`, default: `4532`, must be `> 0` when enabled)

### `[frontends.http_json]`
- `enabled` (`bool`, default: `true`)
- `listen` (`ip`, default: `127.0.0.1`)
- `port` (`u16`, default: `0`)
- `auth.tokens` (`string[]`, default: `[]`)

Notes:
- `port = 0` means ephemeral bind (allowed).
- Empty token strings are invalid.

### `[frontends.audio]`
- `enabled` (`bool`, default: `true`)
- `server_port` (`u16`, default: `4531`, must be `> 0` when enabled)
- `bridge.enabled` (`bool`, default: `false`): enables local `cpal` audio bridge
- `bridge.rx_output_device` (`string`, optional): exact local playback device name
- `bridge.tx_input_device` (`string`, optional): exact local capture device name
- `bridge.rx_gain` (`float`, default: `1.0`, must be finite and `>= 0`)
- `bridge.tx_gain` (`float`, default: `1.0`, must be finite and `>= 0`)

Notes:
- The bridge is intended for local WSJT-X integration via virtual audio devices.
- Linux: typically use ALSA loopback (`snd-aloop`).
- macOS: install a virtual CoreAudio device (e.g. BlackHole), then set device names above.

## CLI Override Summary

### `trx-server`
- `--config`, `--print-config`
- `--rig`, `--access`, positional `RIG_ADDR`
- `--callsign`
- `--listen`, `--port` (JSON listener)
- SDR backend: all SDR options are file-only (`[sdr]` and `[[sdr.channels]]`).

### `trx-client`
- `--config`, `--print-config`
- `--url`, `--token`, `--poll-interval`
- `--frontend` (comma-separated)
- `--http-listen`, `--http-port`
- `--rigctl-listen`, `--rigctl-port`
- `--http-json-listen`, `--http-json-port`
- `--callsign`
