Events & SRQ
How to use PyVISA events and Service Request (SRQ) to get instrument notifications without polling. Includes callback and queue-based patterns.
PyVISA supports hardware events so your script can react to instrument signals instead of polling in a loop. The most useful event is Service Request (SRQ), where the instrument tells you it's done.
Why SRQ Beats Polling
The polling approach sends *OPC? repeatedly until the instrument replies. This ties up the bus and wastes CPU time.
import pyvisa
rm = pyvisa.ResourceManager()
inst = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
try:
inst.write("MEAS:VOLT:DC?")
# Blocks until measurement completes
result = inst.read()
print(f"Voltage: {result.strip()} V")
finally:
inst.close()With SRQ, the instrument asserts a hardware line when the operation completes. Your script sleeps until the event fires.
Wait for SRQ with wait_on_event
Enable the SRQ event, trigger a long measurement, and wait for the instrument to signal completion.
import pyvisa
from pyvisa import constants
rm = pyvisa.ResourceManager()
inst = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
inst.timeout = 30000
try:
inst.write("*RST")
inst.write("*CLS")
# Enable SRQ on operation complete (bit 5 of SRE)
inst.write("*ESE 1") # OPC sets ESR bit 0
inst.write("*SRE 32") # ESR summary enables SRQ
# Enable SRQ event handling
inst.enable_event(
constants.EventType.service_request,
constants.EventMechanism.queue,
)
# Start a slow measurement
inst.write("CONF:VOLT:DC 10, 0.0001")
inst.write("SAMP:COUN 100")
inst.write("INIT")
inst.write("*OPC") # Set OPC when measurement finishes
# Block until the instrument fires SRQ (up to timeout)
response = inst.wait_on_event(
constants.EventType.service_request, timeout=25000
)
print(f"SRQ received, event type: {response.event.event_type}")
# Read the status byte to confirm
stb = inst.read_stb()
print(f"Status byte: {stb:#04x}")
# Fetch the results
data = inst.query("FETC?")
values = [float(v) for v in data.strip().split(",")]
print(f"Got {len(values)} readings, mean: {sum(values)/len(values):.6f} V")
inst.disable_event(
constants.EventType.service_request,
constants.EventMechanism.queue,
)
finally:
inst.close()
rm.close()Log measurements automatically
TofuPilot records test results from your PyVISA scripts, tracks pass/fail rates, and generates compliance reports. Free to start.
Install an Event Handler (Callback)
For continuous monitoring, install a callback that fires every time the instrument asserts SRQ. This is useful in long-running test sequences where multiple operations complete at different times.
import pyvisa
from pyvisa import constants
import threading
done = threading.Event()
def handle_srq(resource, event, user_handle):
stb = resource.read_stb()
print(f"SRQ fired, status byte: {stb:#04x}")
done.set()
return constants.StatusCode.success
rm = pyvisa.ResourceManager()
inst = rm.open_resource("TCPIP0::192.168.1.50::inst0::INSTR")
try:
inst.write("*RST")
inst.write("*CLS")
inst.write("*ESE 1")
inst.write("*SRE 32")
wrapped = inst.install_handler(
constants.EventType.service_request, handle_srq
)
inst.enable_event(
constants.EventType.service_request,
constants.EventMechanism.handler,
)
inst.write("CONF:VOLT:DC")
inst.write("INIT")
inst.write("*OPC")
done.wait(timeout=20)
if done.is_set():
result = inst.query("FETC?")
print(f"Voltage: {float(result.strip()):.6f} V")
else:
print("Timed out waiting for SRQ")
inst.disable_event(
constants.EventType.service_request,
constants.EventMechanism.handler,
)
inst.uninstall_handler(
constants.EventType.service_request, wrapped, handle_srq
)
finally:
inst.close()
rm.close()Handler thread safety
The callback runs in a separate thread. Don't call inst.write() or inst.query() from inside the handler. Use a threading event or queue to communicate back to the main thread.
Event Types
| Event type | Constant | Use case |
|---|---|---|
| Service Request | EventType.service_request | Instrument signals operation complete, error, or data ready |
| GPIB Talk | EventType.gpib_talk | Controller addressed this device to talk |
| GPIB Listen | EventType.gpib_listen | Controller addressed this device to listen |
| VXI Signal | EventType.vxi_signal_interrupt | VXI backplane interrupt |
| PXI Interrupt | EventType.pxi_interrupt | PXI hardware interrupt |
Useful Status Commands
| Command | What it does |
|---|---|
inst.read_stb() | Read the status byte without clearing it |
inst.write("*SRE 32") | Enable SRQ when ESR summary bit is set |
inst.write("*ESE 1") | Enable OPC bit in the Event Status Register |
inst.write("*CLS") | Clear all event registers and queues |
inst.write("*OPC") | Set OPC bit when all pending operations complete |
inst.assert_trigger() | Send a hardware trigger (Group Execute Trigger) |
Status Byte Bits
| Bit | Weight | Meaning |
|---|---|---|
| 0-1 | 1, 2 | Instrument-specific |
| 2 | 4 | Error/event queue not empty |
| 3 | 8 | Questionable data summary |
| 4 | 16 | Message available (MAV) |
| 5 | 32 | Event Status Byte summary (ESB) |
| 6 | 64 | Request Service (RQS) / Master Summary |
| 7 | 128 | Instrument-specific |