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
USB device communication supporting both USBTMC (USB Test & Measurement Class) protocol for test instruments and raw USB device access for specialized hardware. PyVISA-py provides comprehensive USB support through PyUSB with automatic device discovery and proper permission handling.
Base class for USB device communication providing common functionality for both USBTMC instruments and raw USB devices.
class USBSession:
"""Base class for USB device communication via PyUSB."""
def __init__(self, resource_manager_session, resource_name, parsed, open_timeout):
"""
Initialize USB session (base class).
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): USB resource name
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
"""
def read(self, count):
"""
Read data from USB device.
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 USB device.
Args:
data (bytes): Data to transmit
Returns:
Tuple[int, StatusCode]: Number of bytes written and status
"""
def close(self):
"""
Close USB connection and release device.
Returns:
StatusCode: Operation result
"""
@staticmethod
def list_resources():
"""
List available USB devices (implemented in subclasses).
Returns:
List[str]: List of USB device resource strings
"""Handles USB instrument communication using the USBTMC protocol, which is the standard for USB-connected test and measurement instruments.
class USBInstrSession(USBSession):
"""Session for USB instrument communication via USBTMC."""
def __init__(self, resource_manager_session, resource_name, parsed, open_timeout):
"""
Initialize USB USBTMC instrument session.
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): USB INSTR resource name
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
"""
def clear(self):
"""
Clear USB instrument (send USBTMC clear command).
Returns:
StatusCode: Operation result
"""
@staticmethod
def list_resources():
"""
List available USB USBTMC instruments.
Returns:
List[str]: List of USB INSTR resource strings
"""Provides raw USB device access for specialized communication protocols that don't use USBTMC.
class USBRawSession:
"""Session for raw USB device communication."""
def __init__(self, resource_manager_session, resource_name, parsed, open_timeout):
"""
Initialize raw USB session.
Args:
resource_manager_session (VISARMSession): Parent RM session
resource_name (str): Raw USB resource name
parsed (rname.ResourceName): Parsed resource name
open_timeout (int): Connection timeout in milliseconds
"""
def read(self, count):
"""
Read data from USB device via bulk/interrupt transfer.
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 USB device via bulk/interrupt transfer.
Args:
data (bytes): Data to transmit
Returns:
Tuple[int, StatusCode]: Number of bytes written and status
"""
def close(self):
"""
Close raw USB connection.
Returns:
StatusCode: Operation result
"""
@staticmethod
def list_resources():
"""
List available raw USB devices.
Returns:
List[str]: List of raw USB device resource strings
"""Control USB device configuration, interfaces, and endpoints for proper communication setup.
# USB configuration methods (internal use)
def _configure_device(device, interface_number):
"""Configure USB device interface for communication."""
def _find_endpoints(interface):
"""Find bulk IN and OUT endpoints for data transfer."""
def _claim_interface(device, interface_number):
"""Claim USB interface for exclusive access."""
def _release_interface(device, interface_number):
"""Release USB interface when done."""import pyvisa
# Use PyVISA-py backend
rm = pyvisa.ResourceManager('@py')
# List USB instruments
usb_resources = rm.list_resources('USB?*::INSTR')
print("USB instruments:", usb_resources)
# Resource string format: USB[board]::vendor_id::product_id::serial::interface::INSTR
# Example: "USB0::0x1234::0x5678::ABC123::0::INSTR"
if usb_resources:
try:
# Open USB instrument
inst = rm.open_resource(usb_resources[0])
# Configure timeout
inst.timeout = 5000 # 5 seconds
# Standard SCPI communication
inst.write("*RST") # Reset instrument
idn = inst.query("*IDN?")
print("Instrument ID:", idn.strip())
# Read measurement data
inst.write("MEAS:VOLT:DC?")
voltage = float(inst.read())
print(f"Voltage: {voltage} V")
except pyvisa.VisaIOError as e:
print(f"USB communication error: {e}")
finally:
inst.close()
rm.close()# Open raw USB device for custom protocols
raw_resources = rm.list_resources('USB?*::RAW')
print("Raw USB devices:", raw_resources)
if raw_resources:
try:
# Open raw USB device
device = rm.open_resource(raw_resources[0])
# Send custom command
command = b'\\x01\\x02\\x03\\x04' # Custom protocol command
bytes_written = device.write_raw(command)
print(f"Sent {bytes_written} bytes")
# Read response
response = device.read_raw(64) # Read up to 64 bytes
print(f"Received: {response.hex()}")
except pyvisa.VisaIOError as e:
print(f"Raw USB error: {e}")
finally:
device.close()# Discover USB devices with specific vendor/product IDs
def find_usb_device(vendor_id, product_id):
"""Find USB device by vendor and product ID."""
rm = pyvisa.ResourceManager('@py')
# List all USB resources
all_usb = rm.list_resources('USB?*')
# Filter by vendor/product ID
target_vid = f"{vendor_id:04X}"
target_pid = f"{product_id:04X}"
matching_devices = []
for resource in all_usb:
if f"::{target_vid}::{target_pid}::" in resource:
matching_devices.append(resource)
rm.close()
return matching_devices
# Find Keysight devices (vendor ID 0x2A8D)
keysight_devices = find_usb_device(0x2A8D, 0x0001) # Example product ID
print("Keysight USB devices:", keysight_devices)# High-speed data transfer for instruments that support it
inst = rm.open_resource("USB0::0x1234::0x5678::ABC123::0::INSTR")
try:
# Request large data block
inst.write("DATA:ARRAY?") # Request array data
# Read large binary data block
# Some instruments send data length first
header = inst.read_bytes(4) # Read length header
data_length = int.from_bytes(header, byteorder='big')
# Read the actual data
bulk_data = inst.read_bytes(data_length)
print(f"Received {len(bulk_data)} bytes of data")
# Process binary data (example: 16-bit integers)
import struct
values = struct.unpack(f'>{data_length//2}H', bulk_data)
print(f"First 10 values: {values[:10]}")
except pyvisa.VisaIOError as e:
print(f"Bulk transfer error: {e}")
finally:
inst.close()# Check USB device configuration
inst = rm.open_resource("USB0::0x1234::0x5678::ABC123::0::INSTR")
try:
# Get USB-specific attributes
manufacturer = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_MANF_NAME)
model = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_MODEL_NAME)
serial = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_USB_SERIAL_NUM)
print(f"Manufacturer: {manufacturer}")
print(f"Model: {model}")
print(f"Serial: {serial}")
# Check USB interface information
interface_num = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_USB_INTFC_NUM)
alt_setting = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_USB_ALT_SETTING)
print(f"Interface: {interface_num}, Alt Setting: {alt_setting}")
except Exception as e:
print(f"Error reading USB attributes: {e}")
finally:
inst.close()USB resource strings follow the VISA standard format:
USB[board]::vendor_id::product_id::serial_number::interface_number::[INSTR|RAW]Components:
Examples:
USB0::0x2A8D::0x0001::MY12345678::0::INSTR - Keysight USBTMC instrumentUSB0::0x1234::0x5678::SN123456::0::RAW - Raw USB deviceUSB::0x0957::0x2918::MY50001234::INSTR - Short form (board defaults to 0)Common USB communication errors and solutions:
from pyvisa import VisaIOError
from pyvisa.constants import StatusCode
try:
inst = rm.open_resource("USB0::0x1234::0x5678::ABC123::0::INSTR")
except VisaIOError as e:
if e.error_code == StatusCode.error_resource_not_found:
print("USB device not found - check connection and drivers")
elif e.error_code == StatusCode.error_resource_busy:
print("USB device busy - another application may be using it")
elif e.error_code == StatusCode.error_insufficient_location_information:
print("Invalid USB resource string format")
else:
print(f"USB 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("USB communication timeout - device may not respond to SCPI")
elif e.error_code == StatusCode.error_io:
print("USB I/O error - check USB connection")USB communication requires the PyUSB package and appropriate USB backend libraries:
# Install USB support
pip install pyvisa-py[usb]
# Or install PyUSB directly
pip install pyusbUSB Backend Requirements:
brew install libusb)USB devices may require proper permissions or udev rules:
# Add user to dialout group for USB access
sudo usermod -a -G dialout $USER
# Or create udev rule for specific devices
# /etc/udev/rules.d/99-usb-instruments.rules:
# SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"The USB Test & Measurement Class provides standardized communication for instruments:
Install with Tessl CLI
npx tessl i tessl/pypi-pyvisa-py