fix: tie query()/read() host timeout to the controller's read_tmo_ms
Found against real hardware: a fixed 2.0s host-side read timeout was
shorter than the device's configured read_tmo_ms (3000ms). The
controller keeps a "++read" outstanding internally until EOI or its
own timeout, so the client gave up and sent the next command first --
that command's reply then got lost/delayed behind the still-pending
read, surfacing as a spurious TransportTimeout on the *following* call
(observed: query("*IDN?") timed out as expected with no instrument
attached, then srq() right after it timed out too, on a device with
read_tmo_ms=3000).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ from .exceptions import CommandError
|
||||
from .transport import EthernetTransport, SerialTransport, Transport
|
||||
|
||||
_DEFAULT_COMMAND_TIMEOUT = 1.0 # seconds, for ++cmd query replies
|
||||
_DEFAULT_READ_TIMEOUT = 2.0 # seconds, for ++read / query() instrument data
|
||||
_READ_TIMEOUT_MARGIN = 0.5 # seconds, added on top of read_tmo_ms (see _instrument_read_timeout)
|
||||
|
||||
|
||||
class GpibController:
|
||||
@@ -59,6 +59,22 @@ class GpibController:
|
||||
if self.mode != 0:
|
||||
raise CommandError(f"++{command_name} is only valid in DEVICE mode")
|
||||
|
||||
def _instrument_read_timeout(self, explicit: float | None) -> float:
|
||||
"""Host-side timeout for reading instrument data.
|
||||
|
||||
Must be longer than the controller's own `read_tmo_ms`: the
|
||||
controller keeps a "++read" outstanding internally (waiting for
|
||||
EOI or its own timeout) before it will process the next command,
|
||||
so a shorter host-side timeout gives up and sends the next command
|
||||
while the controller is still finishing the previous read -- that
|
||||
reply then arrives late and gets mistaken for the next command's
|
||||
reply (or times out entirely). Costs one extra round trip when the
|
||||
caller doesn't pass an explicit timeout; pass one to skip it.
|
||||
"""
|
||||
if explicit is not None:
|
||||
return explicit
|
||||
return (self.read_tmo_ms / 1000.0) + _READ_TIMEOUT_MARGIN
|
||||
|
||||
# -- config properties ------------------------------------------------
|
||||
|
||||
@property
|
||||
@@ -260,7 +276,7 @@ class GpibController:
|
||||
raise ValueError("terminator char must be between 0 and 255")
|
||||
command = f"read {char}"
|
||||
self._send_command(command)
|
||||
return self._transport.read_until_quiet(timeout=timeout or _DEFAULT_READ_TIMEOUT)
|
||||
return self._transport.read_until_quiet(timeout=self._instrument_read_timeout(timeout))
|
||||
|
||||
# -- raw instrument I/O ---------------------------------------------
|
||||
|
||||
@@ -280,4 +296,4 @@ class GpibController:
|
||||
"""
|
||||
self.write(data)
|
||||
self._send_command("read eoi")
|
||||
return self._transport.read_until_quiet(timeout=read_timeout or _DEFAULT_READ_TIMEOUT)
|
||||
return self._transport.read_until_quiet(timeout=self._instrument_read_timeout(read_timeout))
|
||||
|
||||
Reference in New Issue
Block a user