Pure Python implementation of a VISA library for instrument communication.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
General Purpose Interface Bus (GPIB/IEEE 488) communication for controlling GPIB instruments with support for bus management, device addressing, and control operations. PyVISA-py provides comprehensive GPIB support through linux-gpib and gpib-ctypes backends with automatic device discovery and proper bus control.
Main dispatcher for GPIB instrument communication that automatically creates the appropriate session implementation (native GPIB or Prologix adapter) based on the GPIB board configuration.
class GPIBSessionDispatch:
"""Dispatcher that creates native GPIB or Prologix sessions based on board configuration."""
def __new__(cls, resource_manager_session, resource_name, parsed, open_timeout):
"""
Create appropriate GPIB session based on board configuration.
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): GPIB resource name
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
Returns:
GPIBSession or PrologixInstrSession: Implementation-specific session
"""Native GPIB instrument communication using linux-gpib or gpib-ctypes drivers with full IEEE 488.2 protocol support.
class GPIBSession:
"""Session for native GPIB instrument communication."""
def __init__(self, resource_manager_session, resource_name, parsed, open_timeout):
"""
Initialize GPIB instrument session.
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): GPIB resource name (e.g., "GPIB0::10::INSTR")
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
"""
def read(self, count):
"""
Read data from GPIB instrument.
Args:
count (int): Maximum number of bytes to read
Returns:
Tuple[bytes, StatusCode]: Data read and operation status
"""
def write(self, data):
"""
Write data to GPIB instrument.
Args:
data (bytes): Data to transmit
Returns:
Tuple[int, StatusCode]: Number of bytes written and status
"""
def gpib_command(self, command_byte):
"""
Send GPIB command bytes (ATN asserted).
Args:
command_byte (bytes): GPIB command bytes to send
Returns:
Tuple[int, StatusCode]: Bytes written and status
"""
def read_stb(self):
"""
Read status byte from GPIB device.
Returns:
Tuple[int, StatusCode]: Status byte value and operation status
"""
def clear(self):
"""
Clear GPIB device (send Device Clear command).
Returns:
StatusCode: Operation result
"""
def close(self):
"""
Close GPIB session and release device.
Returns:
StatusCode: Operation result
"""
@staticmethod
def list_resources():
"""
List available GPIB instruments.
Returns:
List[str]: List of GPIB instrument resource strings
"""Provides GPIB bus controller operations for managing the GPIB bus and controlling multiple devices.
class GPIBInterface:
"""Session for GPIB interface/controller operations."""
def __init__(self, resource_manager_session, resource_name, parsed, open_timeout):
"""
Initialize GPIB interface session.
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): GPIB interface resource name (e.g., "GPIB0::INTFC")
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
"""
def gpib_send_ifc(self):
"""
Pulse Interface Clear (IFC) line for at least 100 microseconds.
Returns:
StatusCode: Operation result
"""
def gpib_control_ren(self, mode):
"""
Control state of Remote Enable (REN) interface line.
Args:
mode (constants.RENLineOperation): REN line operation
Returns:
StatusCode: Operation result
"""
def gpib_control_atn(self, mode):
"""
Control state of Attention (ATN) line.
Args:
mode (constants.ATNLineOperation): ATN line operation
Returns:
StatusCode: Operation result
"""
def gpib_pass_control(self, primary_address, secondary_address):
"""
Pass controller in charge (CIC) to another device.
Args:
primary_address (int): Primary address of new controller
secondary_address (int): Secondary address (or VI_NO_SEC_ADDR)
Returns:
StatusCode: Operation result
"""Operations for managing GPIB bus state, addressing, and device control.
# GPIB addressing constants
VI_NO_SEC_ADDR = 0xFFFF # No secondary address
# REN line operations
VI_GPIB_REN_DEASSERT = 0 # Deassert REN line
VI_GPIB_REN_ASSERT = 1 # Assert REN line
VI_GPIB_REN_DEASSERT_GTL = 2 # Deassert REN and send GTL
VI_GPIB_REN_ASSERT_ADDRESS = 3 # Assert REN and address device
VI_GPIB_REN_ASSERT_LLO = 4 # Assert REN and send LLO
# ATN line operations
VI_GPIB_ATN_DEASSERT = 0 # Deassert ATN line
VI_GPIB_ATN_ASSERT = 1 # Assert ATN line
VI_GPIB_ATN_DEASSERT_HANDSHAKE = 2 # Deassert ATN with handshake
VI_GPIB_ATN_ASSERT_IMMEDIATE = 3 # Assert ATN immediatelyimport pyvisa
# Use PyVISA-py backend
rm = pyvisa.ResourceManager('@py')
# List GPIB instruments
gpib_resources = rm.list_resources('GPIB?*::INSTR')
print("GPIB instruments:", gpib_resources)
# Resource string format: GPIB[board]::primary_address[::secondary_address]::INSTR
# Examples: "GPIB0::10::INSTR", "GPIB0::5::2::INSTR" (with secondary address)
if gpib_resources:
try:
# Open GPIB instrument at primary address 10
inst = rm.open_resource("GPIB0::10::INSTR")
# Configure timeout
inst.timeout = 5000 # 5 seconds
# Standard IEEE 488.2 communication
idn = inst.query("*IDN?")
print("Instrument ID:", idn.strip())
# Reset and clear instrument
inst.write("*RST")
inst.write("*CLS")
# Check operation complete
inst.write("*OPC?")
opc = inst.read()
print("Operation complete:", opc.strip())
# Read measurement
inst.write("READ?")
measurement = float(inst.read())
print(f"Measurement: {measurement}")
except pyvisa.VisaIOError as e:
print(f"GPIB communication error: {e}")
finally:
inst.close()
rm.close()# Open GPIB interface for bus control operations
try:
gpib_intfc = rm.open_resource("GPIB0::INTFC")
# Send Interface Clear to reset bus
gpib_intfc.send_ifc()
print("Interface Clear sent")
# Assert Remote Enable for all devices
gpib_intfc.control_ren(pyvisa.constants.VI_GPIB_REN_ASSERT)
print("REN asserted")
# Address device at primary address 5
gpib_intfc.control_ren(pyvisa.constants.VI_GPIB_REN_ASSERT_ADDRESS)
# Send Group Execute Trigger to all devices
gpib_intfc.assert_trigger(pyvisa.constants.VI_TRIG_PROT_ON)
# Return devices to local control
gpib_intfc.control_ren(pyvisa.constants.VI_GPIB_REN_DEASSERT_GTL)
print("Devices returned to local control")
except pyvisa.VisaIOError as e:
print(f"GPIB interface error: {e}")
finally:
gpib_intfc.close()# Communicate with multiple GPIB devices
devices = {
"DMM": "GPIB0::3::INSTR", # Digital multimeter
"PSU": "GPIB0::5::INSTR", # Power supply
"GEN": "GPIB0::10::INSTR", # Function generator
}
instruments = {}
try:
# Open all devices
for name, resource in devices.items():
inst = rm.open_resource(resource)
inst.timeout = 3000
instruments[name] = inst
# Verify communication
idn = inst.query("*IDN?")
print(f"{name}: {idn.strip()}")
# Configure instruments
instruments["PSU"].write("VOLT 5.0") # Set 5V output
instruments["PSU"].write("CURR 1.0") # Set 1A limit
instruments["PSU"].write("OUTP ON") # Enable output
instruments["GEN"].write("FREQ 1000") # Set 1kHz frequency
instruments["GEN"].write("VOLT 1.0") # Set 1V amplitude
instruments["GEN"].write("OUTP ON") # Enable output
# Make measurement
instruments["DMM"].write("MEAS:VOLT:DC?")
voltage = float(instruments["DMM"].read())
print(f"Measured voltage: {voltage} V")
# Turn off outputs
instruments["PSU"].write("OUTP OFF")
instruments["GEN"].write("OUTP OFF")
except pyvisa.VisaIOError as e:
print(f"Multi-device error: {e}")
finally:
# Close all instruments
for inst in instruments.values():
inst.close()# Check GPIB device status and handle errors
inst = rm.open_resource("GPIB0::10::INSTR")
try:
# Clear status registers
inst.write("*CLS")
# Send command that might cause error
inst.write("INVALID:COMMAND")
# Check for errors using status byte
stb = inst.read_stb()
print(f"Status byte: 0x{stb:02X}")
# Check error queue if error bit set
if stb & 0x04: # Error queue not empty
error = inst.query("SYST:ERR?")
print(f"Device error: {error.strip()}")
# Check for Standard Event Status
if stb & 0x20: # ESB bit set
esr = int(inst.query("*ESR?"))
print(f"Event Status Register: 0x{esr:02X}")
if esr & 0x20: # Command error
print("Command error detected")
if esr & 0x04: # Query error
print("Query error detected")
# Wait for operation complete
inst.write("*OPC")
while True:
stb = inst.read_stb()
if stb & 0x01: # OPC bit set
break
time.sleep(0.1)
except pyvisa.VisaIOError as e:
print(f"Status check error: {e}")
finally:
inst.close()def scan_gpib_bus(board=0, max_address=30):
"""Scan GPIB bus for responding devices."""
rm = pyvisa.ResourceManager('@py')
found_devices = []
for address in range(1, max_address + 1):
resource_name = f"GPIB{board}::{address}::INSTR"
try:
# Try to open device
inst = rm.open_resource(resource_name)
inst.timeout = 1000 # Short timeout for scanning
# Try to communicate
idn = inst.query("*IDN?")
found_devices.append({
'address': address,
'resource': resource_name,
'id': idn.strip()
})
inst.close()
except pyvisa.VisaIOError:
# Device not responding or not present
continue
except Exception as e:
# Other errors (might be non-SCPI device)
found_devices.append({
'address': address,
'resource': resource_name,
'id': f'Present but non-SCPI: {e}'
})
rm.close()
return found_devices
# Scan for devices
print("Scanning GPIB bus...")
devices = scan_gpib_bus()
for device in devices:
print(f"Address {device['address']}: {device['id']}")# Some GPIB devices support secondary addressing
# Resource format: GPIB[board]::primary::secondary::INSTR
try:
# Open device with secondary address
inst = rm.open_resource("GPIB0::5::2::INSTR")
# Communication works normally
idn = inst.query("*IDN?")
print(f"Device 5.2: {idn.strip()}")
except pyvisa.VisaIOError as e:
print(f"Secondary addressing error: {e}")
finally:
inst.close()GPIB resource strings follow the VISA standard:
GPIB[board]::primary_address[::secondary_address]::INSTR
GPIB[board]::INTFCComponents:
Examples:
GPIB0::10::INSTR - Device at primary address 10GPIB0::5::2::INSTR - Device at primary 5, secondary 2GPIB1::15::INSTR - Device on second GPIB boardGPIB0::INTFC - GPIB interface controllerGPIB-specific error handling and troubleshooting:
from pyvisa import VisaIOError
from pyvisa.constants import StatusCode
try:
inst = rm.open_resource("GPIB0::10::INSTR")
except VisaIOError as e:
if e.error_code == StatusCode.error_resource_not_found:
print("GPIB device not found - check address and connections")
elif e.error_code == StatusCode.error_resource_busy:
print("GPIB device busy - another application may be using it")
elif e.error_code == StatusCode.error_system_error:
print("GPIB system error - check interface card and drivers")
else:
print(f"GPIB open error: {e}")
# Handle communication timeouts
try:
response = inst.query("*IDN?", timeout=2000)
except VisaIOError as e:
if e.error_code == StatusCode.error_timeout:
print("GPIB timeout - device may not respond or be misconfigured")
elif e.error_code == StatusCode.error_io:
print("GPIB I/O error - check bus termination and cables")GPIB communication requires platform-specific GPIB drivers:
# Install linux-gpib support
pip install pyvisa-py[gpib-ctypes]
# Or use gpib-ctypes directly
pip install gpib-ctypes>=0.3.0# Install gpib-ctypes for Windows
pip install pyvisa-py[gpib-ctypes]
pip install gpib-ctypes>=0.3.0Driver Requirements:
Install with Tessl CLI
npx tessl i tessl/pypi-pyvisa-py