Skip to main content
Glama
apiwat59
by apiwat59
README.md
# pxe200-sa-mcp

MCP server for the **Harogic PXE200** spectrum analyzer. It drives SAStudio4 on the PXE through an
SCPI bridge plugin (`libScpiBridge.so`, TCP **5025**) that runs inside SAStudio4.

> **Default PXE IP: `10.0.0.223`** (then `10.0.0.211` as a fallback), port 5025.
> If your PXE has a different address, set `PXE_HOST`, e.g. `PXE_HOST=192.168.1.50`
> (several addresses can be given, comma separated).

## Requirements

- Python 3.10+ and [uv](https://docs.astral.sh/uv/) (for `uvx`) on the computer running the AI harness
- The PXE200 on the same LAN, with the bridge plugin installed in SAStudio4 (see [Bridge plugin](#bridge-plugin))

## Install

Claude Code:

```bash
claude mcp add --scope user pxe200-sa -e PXE_HOST=10.0.0.223 -- uvx --from git+https://github.com/apiwat59/pxe200-sa-mcp pxe200-sa-mcp
```

Any other MCP harness (Claude Desktop, Cursor, Windsurf, VS Code, Cline, ...) — add to its MCP config JSON:

```json
{
  "mcpServers": {
    "pxe200-sa": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/apiwat59/pxe200-sa-mcp", "pxe200-sa-mcp"],
      "env": { "PXE_HOST": "10.0.0.223" }
    }
  }
}
```

Codex CLI (`~/.codex/config.toml`):

```toml
[mcp_servers.pxe200-sa]
command = "uvx"
args = ["--from", "git+https://github.com/apiwat59/pxe200-sa-mcp", "pxe200-sa-mcp"]
env = { PXE_HOST = "10.0.0.223" }
```

Without uv: `pip install git+https://github.com/apiwat59/pxe200-sa-mcp`, then use `pxe200-sa-mcp` as the command.

### Environment

| Variable | Default | Meaning |
|---|---|---|
| `PXE_HOST` | `10.0.0.223,10.0.0.211` | Bridge address(es), comma separated, tried in order |
| `PXE_REPORT_DIR` | `~/pxe200-sa-reports` | Where reports, screenshots and CSV go |

### ภาษาไทย (สั้น ๆ)

- IP เริ่มต้นของ PXE คือ **10.0.0.223** (ถ้าไม่ได้จะลอง 10.0.0.211) พอร์ต 5025 — ถ้าเครื่องของคุณใช้ IP อื่น ให้ตั้ง `PXE_HOST`
- ต้องติดตั้ง uv ก่อน แล้วใช้คำสั่ง `claude mcp add ...` ด้านบน หรือคัดลอก JSON ไปใส่ในไฟล์ตั้งค่า MCP ของโปรแกรมที่ใช้
- ต้องติดตั้ง bridge plugin ใน SAStudio4 บนเครื่อง PXE ก่อน (หัวข้อ Bridge plugin)

## Bridge plugin

`bridge/src/bridge_plugin.cpp` is a SAStudio4 plugin that opens an SCPI server on TCP 5025 and drives the
running GUI. Build it **on the PXE** (Qt 5 dev headers, `pkg-config`, `g++`):

```bash
sh bridge/build.sh          # -> bridge/libScpiBridge.so ; set SA4=<SAStudio4 folder> if not the default
```

Copy `libScpiBridge.so` into `<SAStudio4>/plugin/` and restart SAStudio4. `bridge/deploy.sh` does the
rebuild + restart on our unit (it expects the sources in `~/sa4dev/scpi`; adjust paths for yours).
Tested with SAStudio4 4.3.55.35. `iplugin.h` / `propertysystem.h` are minimal declarations reconstructed
from SAStudio4's exported libraries; no vendor code is included.

Quick check from a PC: `python scpi_client.py 10.0.0.223 "*IDN?"`

## Tools

- **Generic, any control**: `sa_controls` (catalog search), `sa_menu` (open a menu, live values),
  `sa_get`, `sa_set`, `sa_press`, `sa_dialog`, `sa_app` (File/Mode/System menus), `sa_file` (file dialogs),
  `sa_read` (labels, tables, plots, windows, device, widget tree), `sa_gui` / `sa_scpi` (raw).
- **Measurement**: `sa_configure` (mode-aware), `sa_trace`, `sa_sweep`, `sa_trace_data` (any graph; DET in
  seconds), `sa_peak`, `sa_channel_power`, `sa_channel_table`, `sa_measure` (CP/OBW/ACPR), `sa_results`
  (all results of the current mode), `sa_marker`, `sa_peak_table`, `sa_view` (dock views).
- **Files and state**: `sa_files` (list/download exports, images, states), `sa_state` (save/list/recall),
  `sa_info` (versions, temperature, USB, battery, menu states), `sa_screenshot`.
- **Digital Demod** (needs a working `lib/libDigitalSigDemod.so` in SAStudio4, not part of this repo):
  `dd_configure` opens the mode and sets modulation, symbol rate, center, filter alpha, averaging and
  reference level, then waits until two reads agree. `dd_results` gives the results as numbers
  (EVM / phase / magnitude / frequency error / SNR for PSK and QAM, FSK error / deviation / offset for
  FSK2, FSK4 and GMSK); `repeat=n` adds mean, median, min and max. `dd_constellation` saves the
  constellation, the ideal points and the eye as CSV plus a PNG. All three can add items to the report.
- **Report**: `report_start`, `report_add_note`, `report_edit_item`, `report_set_info`, `report_status`,
  `report_list`, `report_open`, `report_export`.

## Safety

- DANGER (refused unless `confirm=true` after the user agreed): signal-generator RF output and sweep
  (AUXS page, hidden on this unit), RxPort, reference clock source, calibration / antenna-factor table
  Apply/Clear/Delete/Import, Screen Lock, Date/Time, Power On State, Setting Mode, Fan/Display/Device.
- Blocked: File/Exit (would kill SAStudio4 and the bridge).
- Mode-switch prompts ("Switch to phase noise mode?") are answered Cancel automatically and reported.
- `MMEM:*` reads only below `/media/rpdzkj/userdata`.
- The bridge port has no authentication: keep the PXE on a trusted LAN.

## Values

Numbers are entered on SAStudio4's own keypad with the unit given (`'30kHz'`, `'250ms'`, `'-3dB'`,
`'2GB'`); Hz and seconds are scaled to whatever unit buttons the keypad has. Choices take the option
text (`sa_controls` lists them), toggles take On/Off.

## Absolute power: the rule (learned the hard way)

A jammer test once reported 184 W for a 25 W module: PosPeak + Max Hold read noise-like signals (jammers, OFDM,
multi-tone) ~10 dB too high. Now enforced by the tools:

- `sa_total_power` measures RMS + Average, cross-checks against the peak detector (>3 dB apart = noise-like) and
  restores the detector/trace. Use it for every watt / dBm-total figure.
- `sa_channel_power`, `sa_channel_table`, `sa_trace_data` attach `power_basis` (detector, trace type) and a
  `warnings` list (peak detector / Max Hold, ADC overflow, mismatch with rating). A report item with warnings is
  marked FAIL. Max Hold is for edges, flatness and hopping occupancy.
- `report_start(rated_power_w=...)`: every power result is compared with the DUT rating (+-3 dB).
- `sa_configure(ref_level_dbm=...)` is the level AT THE INPUT; the tool adds the offset for the screen value.
  (Before, ref 20 with offset 40 put the input range at -20 dBm: silent ADC overflow, power read 40 dB low.)

## Digital Demod notes

- The symbol rate must match the signal. A wrong rate or modulation still gives steady numbers (FSK4
  read 7.5 % at 60 ksym/s instead of 55.56, QPSK on a QAM16 signal read 45 % EVM). `dd_results` warns
  above 15 %.
- Right after a change the screen can show results from the old setting for a second or two.
  `dd_configure` waits for that; take figures with `dd_results(repeat=10)` and quote the median.
- FilterType is greyed out in SAStudio4 4.3.55.35 and stays RRC; FilterAlpha can be set.
- SAStudio4 lists QAM32 as "QAM34"; the tools accept QAM32. PSK8 also accepts 8PSK.
- The bridge reports this mode as `INST? UNKNOWN`; the tools detect it by the constellation graph.
- Reading eye traces costs about 0.1 s each. `dd_constellation` reads 100 by default, the screen holds
  up to about 400.

TDQS

B3.1/5.0

Scored across 42 tools

Disambiguation3/5

Several generic-access tools overlap substantially: sa_scpi (raw SCPI), sa_gui (control by name), and the sa_get/sa_set/sa_press trio (generic control access) all offer ways to read/write arbitrary settings, and sa_configure overlaps with sa_set. The power-measurement cluster (sa_measure, sa_channel_power, sa_total_power, sa_channel_table) and the read cluster (sa_trace_data, sa_read, sa_results) also require careful reading to distinguish. The detailed descriptions do help, but the boundaries are genuinely blurry in places.

Naming Consistency4/5

Overwhelmingly consistent snake_case with clear namespaced prefixes (sa_, dd_, report_) that group tools logically by domain. Verbs are used predictably (sa_get/sa_set/sa_press, report_start/open/list). A few noun-style names (sa_status, sa_controls, sa_files, sa_info) are minor deviations but still readable.

Tool Count3/5

42 tools is heavy and lands in the '25+' range that the rubric flags as potentially too many. However the server covers a genuinely broad instrument surface (multiple SA modes, Digital Demod, GUI control, files, state, and a full reporting subsystem), so many tools earn their place. It is on the excessive side but not arbitrary padding.

Completeness5/5

The surface is remarkably complete for an instrument-control server: connect/status, configuration, measurement, results parsing, markers, traces, GUI control, dialogs, file/state management, Digital Demod, and a full report lifecycle (start/open/list/status/add/edit/export). Generic sa_get/sa_set/sa_press/sa_scpi cover the long tail, leaving no obvious dead ends beyond a trivial missing explicit disconnect.

Maintenance

ActivityMaintained
ResponsivenessNo issues