Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle Visa IO Error on first connection #172

Merged
merged 3 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions src/tm_devices/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1072,20 +1072,30 @@ def __clear_visa_output_buffer_and_get_idn(visa_resource: MessageBasedResource)
Raises:
SystemError: Indicates that the buffer was unable to be cleared.
"""
if 16 & visa_resource.read_stb():
# 16 is the MAV bit (Message Available) from the Status Byte register
# MAV flag is only one bit and turns off after a single response is successfully read,
# even if there's more in the buffer
# use a try-except block to avoid any errors caused by Visa instruments that may not
# respond correctly to the read_stb or clear functions.
try:
if 16 & visa_resource.read_stb():
# 16 is the MAV bit (Message Available) from the Status Byte register
# MAV flag is only one bit and turns off after a single response is
# successfully read, even if there is more in the buffer.
warnings.warn(
f"\nThe device `{visa_resource.resource_info.resource_name}` had data "
"sitting in the VISA Output Buffer on first connection. "
"\nDetected data in the buffer via the Status Byte register. "
"\nThe device_clear() will be called so VISA I/O buffers get flushed.",
stacklevel=1,
)
# always flush the VISA I/O Buffers on the device to clean up any stale data.
# (note: the Events are kept in different buffers, so *ESR? is not impacted)
visa_resource.clear()
except visa.VisaIOError as e:
warnings.warn(
f"\nThe device `{visa_resource.resource_info.resource_name}` had data "
"sitting in the VISA Output Buffer on first connection. "
"\nDetected data in the buffer via the Status Byte register. "
"\nThe device_clear() will be called so VISA I/O buffers get flushed.",
f"A VISA IO error occurred when attempting to read the status byte or clear the "
f"output buffer of the resource `{visa_resource.resource_info.resource_name}`.\n"
f"Error: {e}",
stacklevel=1,
)
# always flush the VISA I/O Buffers on the device to clean up any stale data.
# (note: the Events are kept in different buffers, so *ESR? is not impacted)
visa_resource.clear()
visa_resource.write("*IDN?")
idn_response = ""
error_msg = None
Expand Down
34 changes: 33 additions & 1 deletion tests/test_device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,12 +459,44 @@ def test_failed_cleanup(self, device_manager: DeviceManager) -> None:
device_manager.cleanup_all_devices()
device_manager.remove_device(alias="bad-afg")

def test_warnings(self, device_manager: DeviceManager) -> None:
"""Verify some of the warning printouts that the DeviceManager can log.
Args:
device_manager: The DeviceManager object.
"""
# Remove all previous devices
device_manager.remove_all_devices()
# Test the warning logged with bad read_stb() call
with mock.patch(
"pyvisa.resources.messagebased.MessageBasedResource.read_stb",
mock.MagicMock(side_effect=visa.VisaIOError(pyvisa.constants.VI_ERROR_INV_SETUP)),
), pytest.warns(
UserWarning,
match="A VISA IO error occurred when attempting to read the status byte or "
"clear the output buffer of the resource",
):
device_manager.add_afg("afg3kc-hostname", alias="warning_bad_read_stb")
device_manager.remove_device(alias="warning_bad_read_stb")

# Test the warning logged with message available (MAV) bit set
# patched the stb to return 16 (message available)
with mock.patch(
"pyvisa.resources.messagebased.MessageBasedResource.read_stb",
mock.MagicMock(return_value=16),
), pytest.warns(
UserWarning, match="had data sitting in the VISA Output Buffer on first connection."
):
device_manager.add_afg("afg3kc-hostname", alias="warning_mav")
device_manager.remove_device(alias="warning_mav")

def test_exceptions(self, device_manager: DeviceManager) -> None:
"""Verify some of the exceptions that the DeviceManager can raise.
Args:
device_manager: The DeviceManager object.
"""
# Remove all previous devices
device_manager.remove_all_devices()

# Test getting a device type that was not the specified type
Expand Down Expand Up @@ -502,7 +534,7 @@ def test_exceptions(self, device_manager: DeviceManager) -> None:
mock.MagicMock(return_value=5),
), mock.patch(
"pyvisa.resources.messagebased.MessageBasedResource.read",
mock.MagicMock(side_effect=visa.VisaIOError(pyvisa.constants.StatusCode.error_timeout)),
mock.MagicMock(side_effect=visa.VisaIOError(pyvisa.constants.VI_ERROR_TMO)),
):
# patched the stb to return 16 (message available)
with pytest.warns(UserWarning), pytest.raises(SystemError) as error:
Expand Down
Loading