# Operation Modes

The active radar backend is selected manually in JSON by `radar.model`.
The GUI does not expose a model selector.

Available models:

```text
librevna
librevna_multi
compact_m_k209
kamil_adc
```

Example configs in the repository root:

```text
run_config_librevna.example.json
run_config_librevna_multi.example.json
run_config_compact_m_k209.example.json
run_config_compact_m_k209_local_mock_switches.example.json
run_config_kamil_adc.example.json
run_config_simulator.example.json
```

## Common Commands

Build native binaries:

```bash
cd /path/to/radar_system
make
```

Run the GUI:

```bash
.venv/bin/python -m python_app.gui.main
```

Run a single acquisition producer manually:

```bash
build/bin/sweep_orchestrator --config run_config.json
```

The GUI process supervisor starts the correct producer automatically:

- `librevna` -> `build/bin/sweep_orchestrator`
- `compact_m_k209` -> `build/bin/sweep_orchestrator`
- `librevna_multi` -> `python_app.scripts.multi_device_raw_producer`
- `kamil_adc` -> `python_app.scripts.kamil_adc_raw_producer`

## Pure Simulator

Use `run_config_simulator.example.json` to run the full GUI pipeline without
radar hardware or GPIO. It uses the single-LibreVNA mock producer, mock
switches, and the synthetic `smoke_cal` / `smoke_ref` preprocessing sets stored
under `python_app/data`.

Typical local check:

```bash
cd /path/to/radar_system
make
.venv/bin/python -m python_app.gui.main
```

Then load `run_config_simulator.example.json` in the GUI and press Start.

## Single LibreVNA

Use this mode when one LibreVNA is connected directly over USB to the machine
running the project.

Config:

```json
"radar": {
  "model": "librevna",
  "serial": "",
  "driver_mode": "native"
}
```

Notes:

- Empty `serial` means use the first compatible LibreVNA found.
- Set `serial` when multiple LibreVNAs are connected.
- `driver_mode: "native"` uses the direct USB LibreVNA driver.
- `driver_mode: "mock"` generates synthetic radar data for UI/development.
- Switch GPIO is controlled by the same machine unless switch `driver_mode` is
  set to `mock`.

Typical local check without GPIO:

```bash
cp run_config_librevna.example.json /tmp/librevna_mock_switches.json
# edit both switches to driver_mode="mock" if needed
build/bin/sweep_orchestrator --config /tmp/librevna_mock_switches.json
```

## LibreVNA Multi-Device

Use this mode for one master LibreVNA and two slave LibreVNAs. This mode does
not use physical RF switch GPIO in the acquisition producer. It exposes a fixed
virtual matrix:

```text
inputs:  0..3
outputs: 0..1
combos:  8
```

Config:

```json
"radar": {
  "model": "librevna_multi",
  "serial": "MASTER_SERIAL",
  "driver_mode": "native",
  "multi_device": {
    "slave_serials": [
      "SLAVE_SERIAL_1",
      "SLAVE_SERIAL_2"
    ],
    "force_external_reference": true,
    "recovery_attempts": 3
  }
}
```

Notes:

- Exactly two slave serials are required.
- `force_external_reference` configures the synchronized reference workflow.
- `recovery_attempts` controls reopen/retry attempts after native acquisition
  errors.
- The Python producer is selected automatically by the GUI. Manual raw-producer
  run:

```bash
.venv/bin/python -m python_app.scripts.multi_device_raw_producer \
  --config run_config_librevna_multi.example.json
```

## Compact-M K209 On The Same Computer

Use this for local development on the x86_64 computer that runs S2VNA and has
the K209 connected over USB-C. GPIO can be disabled with mock switches.

1. Start S2VNA and enable HiSLIP on port `4880`.

2. Start the local project K209 server:

```bash
.venv/bin/python -m python_app.scripts.k209_remote_server \
  --host 127.0.0.1 \
  --port 50209
```

3. In another terminal, smoke-test the server:

```bash
.venv/bin/python -m python_app.scripts.k209_remote_smoke_test \
  --host 127.0.0.1 \
  --port 50209
```

4. Run one acquisition with mock switches:

```bash
build/bin/sweep_orchestrator \
  --config run_config_compact_m_k209_local_mock_switches.example.json
```

This mode is useful on a laptop because it avoids GPIO dependencies.

## Compact-M K209 With Raspberry Pi GPIO

Use this for the real K209 + Raspberry Pi setup:

```text
K209 --USB-C--> x86_64 computer running S2VNA
x86_64 computer --Ethernet--> Raspberry Pi 5
Raspberry Pi 5 --GPIO--> RF switches
```

On the x86_64 computer:

```bash
cd /path/to/radar_system
.venv/bin/python -m python_app.scripts.k209_remote_server \
  --host 0.0.0.0 \
  --port 50209
```

On the Raspberry Pi, set `radar.remote_host` to the Ethernet IP address of the
x86_64 computer:

```json
"radar": {
  "model": "compact_m_k209",
  "remote_host": "192.168.1.10",
  "remote_port": 50209,
  "driver_mode": "native"
}
```

Then run the GUI or producer on the Raspberry Pi:

```bash
.venv/bin/python -m python_app.gui.main
```

For a command-line connection check from the Raspberry Pi:

```bash
.venv/bin/python -m python_app.scripts.k209_remote_smoke_test \
  --host 192.168.1.10 \
  --port 50209
```

The Raspberry Pi does not need S2VNA or NI-VISA in this remote mode.

## Kamil ADC With Laser Control

Use this mode for the ADC collector from `/home/europa/Documents/kamil_adc`
and the laser board configured through `laser_control`. The external
`kamil_adc` project is not modified by `radar_system`; the producer launches
the configured executable and reads its TTY stream.

Config:

```json
"radar": {
  "model": "kamil_adc",
  "serial": "kamil_adc",
  "driver_mode": "native",
  "kamil_adc": {
    "project_dir": "/home/europa/Documents/kamil_adc",
    "executable_path": "/home/europa/Documents/kamil_adc/kamil_adc_capture",
    "tty_path": "/tmp/ttyADC_data",
    "args": [
      "profile:phase",
      "clock:internal",
      "internal_ref_hz:2000000",
      "mode:diff",
      "channels:2",
      "ch1:2",
      "ch2:3",
      "do1_toggle_per_frame",
      "do1_pair_subtract_avg"
    ]
  },
  "laser_control": {
    "enabled": true,
    "port": "/dev/ttyUSB0",
    "mode": "variation"
  }
}
```

Notes:

- `executable_path` is mandatory and must name the real Raspberry Pi binary.
- The producer appends `tty:<tty_path>` automatically; do not put `tty:` in
  `radar.kamil_adc.args`.
- The producer derives the sweep point count from the Kamil ADC TTY stream.
  `radar.sweep.start_hz` and `stop_hz` define the synthetic frequency axis;
  `radar.sweep.points` is not a Kamil ADC setting.
- The laser-control driver is vendored under `python_app.hardware_full.laser_control`.
- `laser_control` and `kamil_adc` are treated as one hardware configuration.
  Changing either section requires restarting acquisition so the lasers are
  configured before the ADC collector starts.
- The TTY frame `0x000A step data1 data2` is imported as `S21 = data1 + j*data2`.
  `S11` is filled with explicit zeros.

Manual raw-producer run:

```bash
.venv/bin/python -m python_app.scripts.kamil_adc_raw_producer \
  --config run_config_kamil_adc.example.json
```

## K209 Remote Performance

The remote K209 path keeps one persistent TCP connection open. Configuration
sends sweep settings once and receives the frequency axis once. Each sweep then
sends one command byte and receives only binary `S11` and `S21` `float32`
arrays.

Use wired Ethernet. Wi-Fi works for tests but adds jitter.
