Skip to main content

VisaDriver

VisaDriver is the VISA transport that Nominal’s built-in SCPI instrument drivers sit on top of. It is available as a public part of the library so customers can build their own drivers for VISA-attached instruments without having to wrap pyvisa themselves. It is intentionally narrow: it opens, closes, and locks a VISA resource and exposes text and raw byte I/O. The caller chooses the command strings.
VISA (Virtual Instrument Software Architecture) is the IVI Foundation standard for talking to instruments over GPIB, USB-TMC, TCP/IP (SOCKET, VXI-11, HiSLIP), and RS-232/RS-485. VisaDriver uses pyvisa under the hood.

When to Reach For It

VisaDriver is the right starting point when any of the following are true: If you’re working with a non-VISA protocol (Modbus, raw TCP without VISA framing, a vendor REST API), use the appropriate protocol module (e.g. ModbusDevice) or a plain client library instead.

Quickstart

The most common use of VisaDriver is as a transport inside an instrument driver. Here it is on its own, talking to a VISA instrument directly:
A VisaDriver is configured with either a plain VISA resource string (defaults applied) or a full VisaConfig when you need to override the backend, terminators, timeouts, or serial settings.

Key Concepts

Lifecycle

The typical lifecycle is the same as any pyvisa session: open() and close() are both safe to call more than once. A best-effort close() also runs on garbage collection, but you should not rely on this. Close explicitly in a try/finally, or wrap the driver in the open()/close() of a higher-level instrument driver.

Thread Safety

VisaDriver is thread-safe at the I/O level. Each write, query, read, write_raw, read_raw, and query_raw call takes an internal reentrant lock for the duration of the call, so concurrent operations against the same driver are serialized rather than interleaved on the bus. When several VISA operations need to execute atomically (for example a write followed by an error-queue check, or a configuration sequence that must not be interrupted by another thread), use lock() as a context manager:
The lock is reentrant, so calling write/query/read from inside the with block does not deadlock the calling thread. Other threads still wait until the outer with exits.

Terminators

VISA instruments are line-terminated. VisaDriver applies a configurable read terminator (stripped from incoming text) and write terminator (appended to outgoing text) when the resource is opened. The defaults are read="\n" and write="\r\n", which works for most SCPI instruments. Override them through TerminatorConfig when an instrument’s programming manual specifies otherwise, as with USB-TMC devices that use "\n" for both directions, or older instruments that expect bare "\r".
If your first query to a new instrument hangs until the timeout fires, the most likely cause is a terminator mismatch. Check the device’s programming manual for the expected read/write terminators and pass them through VisaConfig(terminator=TerminatorConfig(read=..., write=...)).

Timeouts

The recv timeout in TimeoutConfig is specified in seconds and is forwarded to pyvisa as the session timeout (converted to milliseconds internally). It controls how long a read or query waits for the instrument to respond before raising. The default is 15 seconds. The connect and send fields are accepted by VisaConfig for forward compatibility but are not yet wired into per-operation overrides. Leave them at the defaults unless you have a reason to set them.

Serial Settings

When the VISA resource is an ASRL (RS-232 / RS-485) interface, VisaDriver applies SerialConfig (baud rate, data bits, stop bits, parity, and flow control) on open(). For any other interface type (USB-TMC, GPIB, TCPIP, …) the serial config is silently ignored, so you can leave it at the defaults.

Text vs. Raw I/O

VisaDriver exposes both a text path and a raw byte path: query_raw is a convenience: it writes a text command (so the write terminator is still applied) and then reads the response as raw bytes. This matches the common SCPI pattern of asking for binary data with a text command like :WAV:DATA?.

Backends

VisaConfig.visa_backend selects which pyvisa backend handles the resource. Most callers should leave it unset. When unset (None), instro uses the system IVI VISA implementation ("@ivi", e.g. NI-VISA or Keysight IO Libraries) and automatically falls back to the pure-Python "@py" backend when no IVI implementation is installed. Setting visa_backend to any explicit value (such as "@ivi", "@py", or "@sim") uses that backend as-is, with no fallback.

Raw TCP Sockets and Nagle’s Algorithm

For raw TCPIP...::SOCKET resources, VisaDriver disables Nagle’s algorithm (TCP_NODELAY) on open(). IVI backends already do this by default, but the pure-Python "@py" backend does not, so on "@py" it would otherwise leave Nagle enabled. With Nagle on, several small back-to-back SCPI writes can be coalesced into one TCP segment, and some instruments’ lightweight LAN firmware resets the connection when that happens. Disabling it makes the "@py" SOCKET path behave like IVI. Set VisaConfig(tcp_nodelay=False) to opt out; it has no effect on non-socket transports.

Building a Custom Driver

The intended use of VisaDriver is as an internal transport inside a vendor-specific instrument driver. instro’s shipped SCPI drivers all follow the same shape: take a str | VisaConfig in the constructor, store a VisaDriver, and delegate open() / close() and all I/O to it. Here is a minimal InstroPSU-compatible driver for a hypothetical SCPI power supply. The same shape applies to any instrument type whose driver base class exposes open(), close(), and a small set of category methods.
The driver is then plugged into the instrument type the same way as any built-in driver:
Two patterns from this example are worth calling out because they recur in every instro SCPI driver:
SYST:ERR? is a SCPI convention, not a VisaDriver feature. VisaDriver does not poll the instrument’s error queue for you. Whether and how to do so is a per-instrument decision. Most SCPI instruments implement SYST:ERR? and respond with 0,"No error" when nothing is wrong, but some use SYSTEM:ERROR? (TDK Lambda) or a different status mechanism entirely. Consult the programming manual.

Configuration

For terminators, timeouts, or serial settings, pass a VisaConfig instead of a plain resource string:

VisaConfig

Top-level connection parameters.

TerminatorConfig

TimeoutConfig

Operation timeouts in seconds.

SerialConfig

Serial-line settings, applied when the VISA resource is an ASRL (RS-232/RS-485) interface. Ignored for all other interface types.

VISA Resource Strings

VisaDriver does not invent its own addressing scheme. The visa_resource string is passed straight through to pyvisa’s ResourceManager.open_resource(). Some commonly used forms:
To discover what’s attached, you can use pyvisa’s resource manager directly:

Method Reference

Error Handling

VisaDriver deliberately does not retry, reconnect, or wrap pyvisa errors. Higher-level recovery (retry policies, reconnection on transient failures, escalation to operators) belongs in the instrument driver or application code on top.