Connecting Instruments
galois-edge discovers instruments on every supported bus at startup and at a configurable cadence afterward (RESCAN_INTERVAL_SEC). Each instrument is queried with *IDN?, matched against the 130+ bundled YAML profiles by regex, and registered with all of its profile-defined commands. Instruments without a profile still work — they accept raw SCPI through SendCommand.
How discovery works
Section titled “How discovery works”When the daemon starts, the Python engine walks each enabled bus:
- GPIB —
linux-gpibbus scan, primary addresses 1–30. - USB — PyVISA’s
list_resources()covers USBTMC. The raw-USB transport (USB_RAW_ENABLED) walks vendor IDs known not to use USBTMC (e.g. Signal Recovery lock-in amplifiers). - LAN — mDNS/Zeroconf browses
_lxi._tcp.local.for LXI-compliant instruments, plus any explicit addresses inLAN_INSTRUMENTS. - Serial — VID/PID-tagged USB-serial adapters surfaced through PyVISA’s serial backend.
Each candidate is opened, queried with *IDN?, and matched against identity.patterns in the loaded YAML profiles. The first matching profile wins. Matched instruments expose:
- All
commands:from the profile, with typed parameters and units - All
sequences:(multi-step measurements like IV sweeps) - The instrument’s settings block (timeout, terminator, OPC behavior)
- Any SDK binding (
sdk:) for non-SCPI vendor libraries
Listing connected instruments
Section titled “Listing connected instruments”galois-edge statusDaemon status: RUNNING Python gRPC: 127.0.0.1:50052 Instruments: 3 found - Keithley 2400 (GPIB0::24::INSTR) [connected] - Keysight 34461A (USB0::0x2A8D::0x0101::MY54505555::INSTR) [connected] - Tektronix MSO64 (TCPIP::192.168.1.42::INSTR) [connected]You can also call galois-edge configure list to see active bus toggles and galois-edge doctor to verify drivers are installed and udev permissions are correct.
GPIB is enabled by default on Linux (GPIB_ENABLED=auto). Install linux-gpib, load its kernel module, and configure your board.
-
Install the kernel driver and userspace tools (Debian/Ubuntu example):
Terminal window sudo apt install linux-gpib-dev linux-gpib-bin -
Edit
/etc/gpib.conffor your board. For a typical Agilent 82357B:interface {minor = 0board_type = "agilent_82357a"pad = 0master = yes} -
Load the driver:
Terminal window sudo gpib_configVerify with
ibtestoribterm. Ifgpib_configis missing,galois-edge doctorwill flag it as a fail. -
Restart the daemon:
Terminal window sudo systemctl restart galois-edge
To use a different board index, set GPIB_BOARD=1. To skip the slow startup scan and only scan on demand, set GPIB_SCAN_ON_INIT=false.
USB (USBTMC)
Section titled “USB (USBTMC)”USBTMC instruments work out of the box on Linux — the installer drops udev rules at /etc/udev/rules.d/99-galois-edge.rules granting the plugdev group access to common vendors:
| Vendor | USB VID |
|---|---|
| Keysight / Agilent | 0x0957 |
| Tektronix | 0x0699 |
| Rohde & Schwarz | 0x0aad |
| National Instruments | 0x3923 |
| Rigol | 0x1ab1 |
| Siglent | 0xf4ec |
For other vendors, you can either add a rule yourself or run the daemon as root. After the rules are installed:
sudo usermod -aG plugdev $USER # add yourself if needednewgrp plugdev # pick it up without re-loginsudo udevadm control --reload-rulessudo udevadm triggerVerify USB permissions with:
galois-edge doctor# look for: [PASS] usb_permissions: User <name> is in plugdev groupRaw USB (non-USBTMC)
Section titled “Raw USB (non-USBTMC)”Set USB_RAW_ENABLED=true (the default) to enable the raw-USB transport for vendor-specific devices that don’t speak USBTMC. The engine ships a small set of vendor matchers — Signal Recovery (0x0A2D) lock-in amplifiers are the headline use case — and uses pyusb under the hood. Other vendors (Digilent, Keithley pico-ammeters, etc.) are typically supported through their own SDK rather than raw USB; see the SDK proxy section.
LAN — VXI-11, HiSLIP, raw sockets
Section titled “LAN — VXI-11, HiSLIP, raw sockets”galois-edge finds LAN instruments two ways:
mDNS / Zeroconf (LAN_MDNS_ENABLED=true, default). The discovery layer browses for _lxi._tcp.local. — every LXI-compliant instrument advertises that service type. Anything responding gets queried automatically.
Static list (LAN_INSTRUMENTS). For instruments behind a router that drops mDNS, or for raw-socket devices that don’t advertise:
LAN_INSTRUMENTS=TCPIP::192.168.1.42::INSTR,TCPIP::scope.lab.example.com::5025::SOCKETUse VISA resource syntax:
| Form | Meaning |
|---|---|
TCPIP::host::INSTR | VXI-11 (port 111 → dynamic) — the default for LXI gear |
TCPIP::host::hislip0::INSTR | HiSLIP — preferred for high-throughput Keysight/R&S |
TCPIP::host::5025::SOCKET | Raw TCP socket on port 5025 (typical SCPI-Raw port) |
Apply changes with galois-edge configure set LAN_INSTRUMENTS … followed by systemctl restart galois-edge, or edit config.env directly.
Serial
Section titled “Serial”USB-serial adapters (FTDI 0403, Prolific 067b, CH340 1a86, CP210x 10c4) are auto-recognised. Linux users need to be in the dialout group:
sudo usermod -aG dialout $USERProfiles for serial instruments declare interfaces: with type: serial and the expected baud rate, parity, data bits, and stop bits — discovery reads those fields rather than guessing.
Profile matching in detail
Section titled “Profile matching in detail”Take a Keithley 2400 sourcemeter. Its *IDN? response looks like:
KEITHLEY INSTRUMENTS INC.,MODEL 2400,1234567,C30The bundled profile keithley_2400.yaml contains:
identity: query: "*IDN?" pattern: "KEITHLEY INSTRUMENTS INC.,MODEL 24[0-4][0-9]"(pattern: is a single regex; patterns: is the multi-regex form. Either works.)
The first profile whose pattern (or any patterns) matches case-insensitively wins. Once matched, the instrument exposes named commands like set_voltage, measure_current, sequences like iv_sweep, and any vendor SDK binding declared in the profile’s sdk: block.
To inspect what matched and what’s available:
grpcurl -plaintext localhost:50051 \ galois.edge.v1.EdgeDaemonService/ListInstruments
grpcurl -plaintext -d '{"instrument_id": "GPIB0::24::INSTR"}' \ localhost:50051 \ galois.edge.v1.EdgeDaemonService/GetCapabilitiesInstruments without a matching profile still appear in ListInstruments and accept raw SCPI through SendCommand — they just have no commands or sequences to advertise.
Adding support for a new instrument
Section titled “Adding support for a new instrument”If you have an instrument with no bundled profile, you have three options:
- Use it as raw SCPI. No setup required — just open a session and send commands.
- Write a YAML profile. Drop it in your
PROFILE_DIR(or contribute it upstream). See Instrument Profiles for the schema. - Bind a vendor SDK. For non-SCPI instruments (Quantum Design PPMS, Zurich Instruments MFLI, etc.), write a profile with an
sdk:block that points at a Python package. The daemonimportlib-loads it on demand.
Forcing a rescan
Section titled “Forcing a rescan”Periodic rescans run every RESCAN_INTERVAL_SEC seconds (default 60). To force one immediately, call the gRPC method:
grpcurl -plaintext localhost:50051 \ galois.edge.v1.EdgeDaemonService/ScanInstrumentsNewly discovered instruments appear in subsequent ListInstruments calls and are pushed in the next heartbeat.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Fix |
|---|---|---|
[FAIL] python_health: Cannot reach Python gRPC | Python engine crashed | journalctl -u galois-edge -n 100 for tracebacks |
| Instrument missing on USB | Permissions | Verify plugdev group, run sudo udevadm trigger |
Instrument shows but *IDN? is empty | Wrong terminator | Some serial instruments use \r\n — set in profile settings.terminator |
| GPIB scan times out | Bus contention or wrong board | ibtest to confirm; set GPIB_SCAN_ON_INIT=false and trigger ScanInstruments manually |
LAN instrument visible to ping but not discovered | mDNS blocked or non-LXI | Add to LAN_INSTRUMENTS explicitly |