From ea1c4e345f8aae30ac7831ca288c2784a079d464 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Thu, 25 Jun 2026 16:05:52 -0700 Subject: [PATCH 01/15] Modify GPIB code to use symbolic constants Create a file of symbolic constants (IntEnum classes) for the various libgpib interface calls. Use these symbols rather than hard-coded integers. Remove now-extraneous commentary about what the hard-coded integers mean. --- pyvisa_py/gpib.py | 115 ++++++++++-------------- pyvisa_py/gpib_constants.py | 172 ++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 69 deletions(-) create mode 100644 pyvisa_py/gpib_constants.py diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 3c9b696b..e8c1e449 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -19,6 +19,7 @@ from .common import LOGGER from .sessions import Session, UnavailableSession, UnknownAttribute, VISARMSession +from . import gpib_constants # NOTE dummy implementation that is overwritten when a GPIB library is found # Allow to provide session listing even when no GPIB library is available. @@ -205,21 +206,17 @@ def _analyse_lines_value(value: int, line: int): """ if line == constants.VI_ATTR_GPIB_REN_STATE: - # REN bit valid = 0x10, REN bit value = 0x100 - validity_mask = 0x10 - value_mask = 0x100 + validity_mask = gpib_constants.lines.ValidREN + value_mask = gpib_constants.lines.BusREN elif line == constants.VI_ATTR_GPIB_ATN_STATE: - # ATN bit valid = 0x40, ATN bit value = 0x4000 - validity_mask = 0x40 - value_mask = 0x4000 + validity_mask = gpib_constants.lines.ValidATN + value_mask = gpib_constants.lines.BusATN elif line == constants.VI_ATTR_GPIB_NDAC_STATE: - # NDAC bit valid = 0x2, NDAC bit value = 0x200 - validity_mask = 0x2 - value_mask = 0x200 + validity_mask = gpib_constants.lines.ValidNDAC + value_mask = gpib_constants.lines.BusNDAC elif line == constants.VI_ATTR_GPIB_SRQ_STATE: - # SRQ bit valid = 0x20, SRQ bit value = 0x2000 - validity_mask = 0x20 - value_mask = 0x2000 + validity_mask = gpib_constants.lines.ValidSRQ + value_mask = gpib_constants.lines.BusSRQ if not value & validity_mask: return constants.LineState.unknown, StatusCode.success @@ -273,8 +270,8 @@ def convert_gpib_error( Status code matching the GPIB error. """ - # First check the imeout condition in the status byte - if status & 0x4000: + # First check the timeout condition in the status byte + if status & gpib_constants.status.TIMO: return StatusCode.error_timeout # All other cases are hard errors. # In particular linux-gpib simply gives a string we could parse but that @@ -284,26 +281,24 @@ def convert_gpib_error( LOGGER.debug("Failed to %s.", operation, exc_info=error) if not GPIB_CTYPES: return StatusCode.error_system_error - if error.code == 1: + if error.code == GPIBerror.ECIC: return StatusCode.error_not_cic - elif error.code == 2: + elif error.code == GPIBerror.ENOL: return StatusCode.error_no_listeners - elif error.code == 4: + elif error.code == GPIBerror.EARG: return StatusCode.error_invalid_mode - elif error.code == 11: + elif error.code == GPIBerror.ECAP: return StatusCode.error_nonsupported_operation - elif error.code == 1: - return StatusCode.error_not_cic - elif error.code == 21: + elif error.code == GPIBerror.ELCK: return StatusCode.error_resource_locked else: return StatusCode.error_system_error def convert_gpib_status(status: int) -> StatusCode: - if status & 0x4000: + if status & gpib_constants.status.TIMO: return StatusCode.error_timeout - elif status & 0x8000: + elif status & gpib_constants.status.ERR: return StatusCode.error_system_error else: return StatusCode.success @@ -351,7 +346,7 @@ def after_parsing(self) -> None: # Secondary address (SAD) values should be in the range 96 to 126, # 0 means the SAD is disabled. sad = 0 - timeout = 13 + timeout = gpib_constants.timeout.T10s send_eoi = 1 eos_mode = 0 self.interface = None @@ -389,9 +384,7 @@ def _get_timeout( self, attribute: constants.ResourceAttribute ) -> Tuple[int, StatusCode]: if self.interface: - # 0x3 is the hexadecimal reference to the IbaTMO (timeout) configuration - # option in linux-gpib. - gpib_timeout = self.interface.ask(3) + gpib_timeout = self.interface.ask(gpib_constants.ask.IbaTMO) if gpib_timeout and gpib_timeout < len(TIMETABLE): self.timeout = TIMETABLE[gpib_timeout] else: @@ -466,8 +459,7 @@ def read(self, count: int) -> Tuple[bytes, StatusCode]: # INTFC don't have an interface so use the controller ifc = self.interface or self.controller - # END 0x2000 - checker = lambda current: ifc.ibsta() & 0x2000 # noqa: E731 + checker = lambda current: ifc.ibsta() & gpib_constants.status.END # noqa: E731 reader = lambda: ifc.read(count) # noqa: E731 @@ -536,7 +528,7 @@ def gpib_control_ren(self, mode: constants.RENLineOperation) -> StatusCode: try: if mode == constants.VI_GPIB_REN_DEASSERT_GTL: # Send GTL command byte (cf linux-gpib documentation) - ifc.command(chr(1)) + ifc.command(gpib_constants.command.IcGTL) if mode in ( constants.VI_GPIB_REN_DEASSERT, constants.VI_GPIB_REN_DEASSERT_GTL, @@ -544,11 +536,9 @@ def gpib_control_ren(self, mode: constants.RENLineOperation) -> StatusCode: self.controller.remote_enable(0) if mode == constants.VI_GPIB_REN_ASSERT_LLO: - # LLO - ifc.command(b"0x11") + ifc.command(gpib_constants.command.IcLLO) elif mode == constants.VI_GPIB_REN_ADDRESS_GTL: - # GTL - ifc.command(b"0x1") + ifc.command(gpib_constants.command.IcGTL) elif mode == constants.VI_GPIB_REN_ASSERT_ADDRESS_LLO: pass elif mode in ( @@ -598,15 +588,13 @@ def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode] ifc = self.interface or self.controller if attribute == ResourceAttribute.gpib_primary_address: - # IbaPAD 0x1 - return ifc.ask(1), StatusCode.success + return ifc.ask(gpib_constants.ask.IbaPAD), StatusCode.success elif attribute == ResourceAttribute.gpib_secondary_address: - # IbaSAD 0x2 # Remove 0x60 because National Instruments. - _ = ifc.ask(2) - if ifc.ask(2): - return ifc.ask(2) - 96, StatusCode.success + _ = ifc.ask(gpib_constants.ask.IbaSAD) + if ifc.ask(gpib_constants.ask.IbaSAD): + return ifc.ask(gpib_constants.ask.IbaSAD) - 96, StatusCode.success else: return constants.VI_NO_SEC_ADDR, StatusCode.success @@ -621,24 +609,22 @@ def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode] elif attribute == ResourceAttribute.send_end_enabled: # Do not use IbaEndBitIsNormal 0x1a which relates to EOI on read() # not write(). see issue #196 - # IbcEOT 0x4 - if ifc.ask(4): + if ifc.ask(gpib_constants.ask.IbaEOT): return constants.VI_TRUE, StatusCode.success else: return constants.VI_FALSE, StatusCode.success elif attribute == ResourceAttribute.interface_number: - # IbaBNA 0x200 - return ifc.ask(512), StatusCode.success + return ifc.ask(gpib_constants.ask.IbaBNA), StatusCode.success elif attribute == ResourceAttribute.interface_type: return constants.InterfaceType.gpib, StatusCode.success elif attribute == ResourceAttribute.termchar: - return ifc.ask(0x0F), StatusCode.success + return ifc.ask(gpib_constants.ask.IbaEOSchar), StatusCode.success elif attribute == ResourceAttribute.termchar_enabled: - return ifc.ask(0x0C), StatusCode.success + return ifc.ask(gpib_constants.ask.IbaEOSrd), StatusCode.success raise UnknownAttribute(attribute) @@ -672,28 +658,25 @@ def _set_attribute( ifc = self.interface or self.controller if attribute == ResourceAttribute.gpib_readdress_enabled: - # IbcREADDR 0x6 # Setting has no effect in linux-gpib. if isinstance(attribute_state, int): - ifc.config(6, attribute_state) + ifc.config(gpib_constants.config.IbcREADDR, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == ResourceAttribute.gpib_primary_address: - # IbcPAD 0x1 if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: - ifc.config(1, attribute_state) + ifc.config(gpib_constants.config.IbcPAD, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == ResourceAttribute.gpib_secondary_address: - # IbcSAD 0x2 # Add 0x60 because National Instruments. if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: - if ifc.ask(2): - ifc.config(2, attribute_state + 96) + if ifc.ask(gpib_constants.ask.IbaSAD): + ifc.config(gpib_constants.config.IbcSAD, attribute_state + 96) return StatusCode.success else: return StatusCode.error_nonsupported_attribute @@ -701,9 +684,8 @@ def _set_attribute( return StatusCode.error_nonsupported_attribute_state elif attribute == ResourceAttribute.gpib_unadress_enable: - # IbcUnAddr 0x1b try: - ifc.config(27, attribute_state) + ifc.config(gpib_constants.config.IbcUnAddr, attribute_state) return StatusCode.success except gpib.GpibError: return StatusCode.error_nonsupported_attribute_state @@ -711,24 +693,23 @@ def _set_attribute( elif attribute == ResourceAttribute.send_end_enabled: # Do not use IbaEndBitIsNormal 0x1a which relates to EOI on read() # not write(). see issue #196 - # IbcEOT 0x4 if isinstance(attribute_state, int): - ifc.config(4, attribute_state) + ifc.config(gpib_constants.config.IbcEOT, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == ResourceAttribute.termchar: if isinstance(attribute_state, int): - ifc.config(0x0F, attribute_state) ## IbcEOSchar - ifc.config(0x0E, 1) ## IbcEOScmp + ifc.config(gpib_constants.config.IbcEOSchar, attribute_state) + ifc.config(gpib_constants.config.IbcEOScmp, 1) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == ResourceAttribute.termchar_enabled: if isinstance(attribute_state, int): - ifc.config(0x0C, attribute_state) ## IbcEOSrd + ifc.config(gpib_constants.config.IbcEOSrd, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state @@ -843,13 +824,11 @@ def _get_attribute( ifc = self.interface if attribute == constants.VI_ATTR_GPIB_READDR_EN: - # IbaREADDR 0x6 # Setting has no effect in linux-gpib. - return ifc.ask(6), StatusCode.success + return ifc.ask(gpib_constants.ask.IbaREADDR), StatusCode.success elif attribute == constants.VI_ATTR_GPIB_UNADDR_EN: - # IbaUnAddr 0x1b - if ifc.ask(27): + if ifc.ask(gpib_constants.ask.IbaUnAddr): return constants.VI_TRUE, StatusCode.success else: return constants.VI_FALSE, StatusCode.success @@ -883,18 +862,16 @@ def _set_attribute( ifc = self.interface if attribute == constants.VI_ATTR_GPIB_READDR_EN: - # IbcREADDR 0x6 # Setting has no effect in linux-gpib. if isinstance(attribute_state, int): - ifc.config(6, attribute_state) + ifc.config(GPIBConfig.IbcREADDR, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_GPIB_UNADDR_EN: - # IbcUnAddr 0x1b try: - ifc.config(27, attribute_state) + ifc.config(GPIBConfig.IbcUnAddr, attribute_state) return StatusCode.success except gpib.GpibError: return StatusCode.error_nonsupported_attribute_state @@ -1054,7 +1031,7 @@ def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode] if attribute == constants.VI_ATTR_GPIB_CIC_STATE: # ibsta CIC = 0x0020 - if ifc.ibsta() & 0x0020: + if ifc.ibsta() & gpib_constants.status.CIC: return constants.VI_TRUE, StatusCode.success else: return constants.VI_FALSE, StatusCode.success diff --git a/pyvisa_py/gpib_constants.py b/pyvisa_py/gpib_constants.py new file mode 100644 index 00000000..2a20e600 --- /dev/null +++ b/pyvisa_py/gpib_constants.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- + +# Derived from gpib_ctypes/constants.py + +from enum import IntEnum + +class timeout(IntEnum): + TNONE = 0 # infinite + T10us = 1 # 10 usec + T30us = 2 # 30 usec + T100us = 3 # 100 usec + T300us = 4 # 300 usec + T1ms = 5 # 1 msec + T3ms = 6 # 3 msec + T10ms = 7 # 10 msec + T30ms = 8 # 30 msec + T100ms = 9 # 100 msec + T300ms = 10 # 300 msec + T1s = 11 # 1 sec + T3s = 12 # 3 sec + T10s = 13 # 10 sec + T30s = 14 # 30 sec + T100s = 15 # 100 sec + T300s = 16 # 300 sec + T1000s = 17 # 1000 sec + + +class config(IntEnum): + IbcPAD = 0x1 + IbcSAD = 0x2 + IbcTMO = 0x3 + IbcEOT = 0x4 + IbcPPC = 0x5 # board only + IbcREADDR = 0x6 # device only + IbcAUTOPOLL = 0x7 # board only + IbcCICPROT = 0x8 # board only + IbcIRQ = 0x9 # board only + IbcSC = 0xa # board only + IbcSRE = 0xb # board only + IbcEOSrd = 0xc + IbcEOSwrt = 0xd + IbcEOScmp = 0xe + IbcEOSchar = 0xf + IbcPP2 = 0x10 # board only + IbcTIMING = 0x11 # board only + IbcDMA = 0x12 # board only + IbcReadAdjust = 0x13 + IbcWriteAdjust = 0x14 + IbcEventQueue = 0x15 # board only + IbcSPollBit = 0x16 # board only + IbcSpollBit = 0x16 # board only + IbcSendLLO = 0x17 # board only + IbcSPollTime = 0x18 # device only + IbcPPollTime = 0x19 # board only + IbcEndBitIsNormal = 0x1a + IbcUnAddr = 0x1b # device only + IbcHSCableLength = 0x1f # board only + IbcIst = 0x20 # board only + IbcRsv = 0x21 # board only + IbcBNA = 0x200 # device only + + +class ask(IntEnum): + IbaPAD = 0x1 + IbaSAD = 0x2 + IbaTMO = 0x3 + IbaEOT = 0x4 + IbaPPC = 0x5 # board only + IbaREADDR = 0x6 # device only + IbaAUTOPOLL = 0x7 # board only + IbaCICPROT = 0x8 # board only + IbaIRQ = 0x9 # board only + IbaSC = 0xa # board only + IbaSRE = 0xb # board only + IbaEOSrd = 0xc + IbaEOSwrt = 0xd + IbaEOScmp = 0xe + IbaEOSchar = 0xf + IbaPP2 = 0x10 # board only + IbaTIMING = 0x11 # board only + IbaDMA = 0x12 # board only + IbaReadAdjust = 0x13 + IbaWriteAdjust = 0x14 + IbaEventQueue = 0x15 # board only + IbaSPollBit = 0x16 # board only + IbaSpollBit = 0x16 # board only + IbaSendLLO = 0x17 # board only + IbaSPollTime = 0x18 # device only + IbaPPollTime = 0x19 # board only + IbaEndBitIsNormal = 0x1a + IbaUnAddr = 0x1b # device only + IbaHSCableLength = 0x1f # board only + IbaIst = 0x20 # board only + IbaRsv = 0x21 # board only + IbaBNA = 0x200 # device only + Iba7BitEOS = 0x1000 # board only, linux-gpib only + + +class status(IntEnum): + DCAS = 0x0001 # device clear state + DTAS = 0x0002 # device trigger state + LACS = 0x0004 # interface is Listener + TACS = 0x0008 # interface is Talker + ATN = 0x0010 # attention + CIC = 0x0020 # Controller-in-Charge + REM = 0x0040 # remote state + LOK = 0x0080 # lockout state + CMPL = 0x0100 # IO completed + EVENT = 0x0200 # DCAS, DTAS, or IFC occurred + SPOLL = 0x0400 # board serial-polled by busmaster + RQS = 0x0800 # device requesting service + SRQI = 0x1000 # SRQ is asserted + END = 0x2000 # EOI or EOS + TIMO = 0x4000 # timeout + ERR = 0x8000 # error + + +class lines(IntEnum): + ValidDAV = 0x1 # the BusDAV bit is valid + ValidNDAC = 0x2 # the BusNDAC bit is valid + ValidNRFD = 0x4 # the BusNRFD bit is valid + ValidIFC = 0x8 # the BusIFC bit is valid + ValidREN = 0x10 # the BusREN bit is valid + ValidSRQ = 0x20 # the BusSRQ bit is valid + ValidATN = 0x40 # the BusATN bit is valid + ValidEOI = 0x80 # the BusEOI bit is valid + BusDAV = 0x100 # DAV line is asserted + BusNDAC = 0x200 # NDAC line is asserted + BusNRFD = 0x400 # NRFD line is asserted + BusIFC = 0x800 # IFC line is asserted + BusREN = 0x1000 # REN line is asserted + BusSRQ = 0x2000 # SRQ line is asserted + BusATN = 0x4000 # ATN line is asserted + BusEOI = 0x8000 # EOI line is asserted + +class sad(IntEnum): + NO_SAD = 0 + ALL_SAD = -1 + + +class stb(IntEnum): + IbStbRQS = 0x40 + IbStbESB = 0x20 + IbStbMAV = 0x10 + +class command(IntEnum): + IcGTL = 1 # go to local + IcLLO = 3 # local lock out + +class error(IntEnum): + EDVR = 0 # system error + ECIC = 1 # not CIC + ENOL = 2 # no listener + EADR = 3 # CIC and not addressed before IO + EARG = 4 # bad argument to function call + ESAC = 5 # not SAC + EABO = 6 # IO aborted + ENEB = 7 # GPIB board offline + EDMA = 8 # DMA hardware error + EOIP = 10 # previous IO still in progress + ECAP = 11 # not capable + EFSO = 12 # file system operation error + EBUS = 14 # bus error + ESTB = 15 # lost serial poll bytes + ESRQ = 16 # SRQ stuck on + ETAB = 20 # table overflow + ELCK = 21 # interface locked + EARM = 22 # failed to rearm + EHDL = 23 # invalid handle + EWIP = 26 # previous wait still in progress + ERST = 27 # event notification cancelled due to reset + EPWR = 28 # interface lost power From b72571475b7891079627cfe9940b02b9123c17dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 19:32:32 +0000 Subject: [PATCH 02/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyvisa_py/gpib.py | 1 + pyvisa_py/gpib_constants.py | 258 ++++++++++++++++++------------------ 2 files changed, 132 insertions(+), 127 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index e8c1e449..9e32dd7a 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -21,6 +21,7 @@ from . import gpib_constants + # NOTE dummy implementation that is overwritten when a GPIB library is found # Allow to provide session listing even when no GPIB library is available. def _find_listeners() -> Iterator[Tuple[int, int, int]]: diff --git a/pyvisa_py/gpib_constants.py b/pyvisa_py/gpib_constants.py index 2a20e600..2b4fea6c 100644 --- a/pyvisa_py/gpib_constants.py +++ b/pyvisa_py/gpib_constants.py @@ -4,25 +4,26 @@ from enum import IntEnum + class timeout(IntEnum): - TNONE = 0 # infinite - T10us = 1 # 10 usec - T30us = 2 # 30 usec - T100us = 3 # 100 usec - T300us = 4 # 300 usec - T1ms = 5 # 1 msec - T3ms = 6 # 3 msec - T10ms = 7 # 10 msec - T30ms = 8 # 30 msec - T100ms = 9 # 100 msec - T300ms = 10 # 300 msec - T1s = 11 # 1 sec - T3s = 12 # 3 sec - T10s = 13 # 10 sec - T30s = 14 # 30 sec - T100s = 15 # 100 sec - T300s = 16 # 300 sec - T1000s = 17 # 1000 sec + TNONE = 0 # infinite + T10us = 1 # 10 usec + T30us = 2 # 30 usec + T100us = 3 # 100 usec + T300us = 4 # 300 usec + T1ms = 5 # 1 msec + T3ms = 6 # 3 msec + T10ms = 7 # 10 msec + T30ms = 8 # 30 msec + T100ms = 9 # 100 msec + T300ms = 10 # 300 msec + T1s = 11 # 1 sec + T3s = 12 # 3 sec + T10s = 13 # 10 sec + T30s = 14 # 30 sec + T100s = 15 # 100 sec + T300s = 16 # 300 sec + T1000s = 17 # 1000 sec class config(IntEnum): @@ -30,34 +31,34 @@ class config(IntEnum): IbcSAD = 0x2 IbcTMO = 0x3 IbcEOT = 0x4 - IbcPPC = 0x5 # board only - IbcREADDR = 0x6 # device only - IbcAUTOPOLL = 0x7 # board only - IbcCICPROT = 0x8 # board only - IbcIRQ = 0x9 # board only - IbcSC = 0xa # board only - IbcSRE = 0xb # board only - IbcEOSrd = 0xc - IbcEOSwrt = 0xd - IbcEOScmp = 0xe - IbcEOSchar = 0xf - IbcPP2 = 0x10 # board only - IbcTIMING = 0x11 # board only - IbcDMA = 0x12 # board only + IbcPPC = 0x5 # board only + IbcREADDR = 0x6 # device only + IbcAUTOPOLL = 0x7 # board only + IbcCICPROT = 0x8 # board only + IbcIRQ = 0x9 # board only + IbcSC = 0xA # board only + IbcSRE = 0xB # board only + IbcEOSrd = 0xC + IbcEOSwrt = 0xD + IbcEOScmp = 0xE + IbcEOSchar = 0xF + IbcPP2 = 0x10 # board only + IbcTIMING = 0x11 # board only + IbcDMA = 0x12 # board only IbcReadAdjust = 0x13 IbcWriteAdjust = 0x14 - IbcEventQueue = 0x15 # board only - IbcSPollBit = 0x16 # board only - IbcSpollBit = 0x16 # board only - IbcSendLLO = 0x17 # board only - IbcSPollTime = 0x18 # device only - IbcPPollTime = 0x19 # board only - IbcEndBitIsNormal = 0x1a - IbcUnAddr = 0x1b # device only - IbcHSCableLength = 0x1f # board only - IbcIst = 0x20 # board only - IbcRsv = 0x21 # board only - IbcBNA = 0x200 # device only + IbcEventQueue = 0x15 # board only + IbcSPollBit = 0x16 # board only + IbcSpollBit = 0x16 # board only + IbcSendLLO = 0x17 # board only + IbcSPollTime = 0x18 # device only + IbcPPollTime = 0x19 # board only + IbcEndBitIsNormal = 0x1A + IbcUnAddr = 0x1B # device only + IbcHSCableLength = 0x1F # board only + IbcIst = 0x20 # board only + IbcRsv = 0x21 # board only + IbcBNA = 0x200 # device only class ask(IntEnum): @@ -65,73 +66,74 @@ class ask(IntEnum): IbaSAD = 0x2 IbaTMO = 0x3 IbaEOT = 0x4 - IbaPPC = 0x5 # board only - IbaREADDR = 0x6 # device only - IbaAUTOPOLL = 0x7 # board only - IbaCICPROT = 0x8 # board only - IbaIRQ = 0x9 # board only - IbaSC = 0xa # board only - IbaSRE = 0xb # board only - IbaEOSrd = 0xc - IbaEOSwrt = 0xd - IbaEOScmp = 0xe - IbaEOSchar = 0xf - IbaPP2 = 0x10 # board only - IbaTIMING = 0x11 # board only - IbaDMA = 0x12 # board only + IbaPPC = 0x5 # board only + IbaREADDR = 0x6 # device only + IbaAUTOPOLL = 0x7 # board only + IbaCICPROT = 0x8 # board only + IbaIRQ = 0x9 # board only + IbaSC = 0xA # board only + IbaSRE = 0xB # board only + IbaEOSrd = 0xC + IbaEOSwrt = 0xD + IbaEOScmp = 0xE + IbaEOSchar = 0xF + IbaPP2 = 0x10 # board only + IbaTIMING = 0x11 # board only + IbaDMA = 0x12 # board only IbaReadAdjust = 0x13 IbaWriteAdjust = 0x14 - IbaEventQueue = 0x15 # board only - IbaSPollBit = 0x16 # board only - IbaSpollBit = 0x16 # board only - IbaSendLLO = 0x17 # board only - IbaSPollTime = 0x18 # device only - IbaPPollTime = 0x19 # board only - IbaEndBitIsNormal = 0x1a - IbaUnAddr = 0x1b # device only - IbaHSCableLength = 0x1f # board only - IbaIst = 0x20 # board only - IbaRsv = 0x21 # board only - IbaBNA = 0x200 # device only - Iba7BitEOS = 0x1000 # board only, linux-gpib only + IbaEventQueue = 0x15 # board only + IbaSPollBit = 0x16 # board only + IbaSpollBit = 0x16 # board only + IbaSendLLO = 0x17 # board only + IbaSPollTime = 0x18 # device only + IbaPPollTime = 0x19 # board only + IbaEndBitIsNormal = 0x1A + IbaUnAddr = 0x1B # device only + IbaHSCableLength = 0x1F # board only + IbaIst = 0x20 # board only + IbaRsv = 0x21 # board only + IbaBNA = 0x200 # device only + Iba7BitEOS = 0x1000 # board only, linux-gpib only class status(IntEnum): - DCAS = 0x0001 # device clear state - DTAS = 0x0002 # device trigger state - LACS = 0x0004 # interface is Listener - TACS = 0x0008 # interface is Talker - ATN = 0x0010 # attention - CIC = 0x0020 # Controller-in-Charge - REM = 0x0040 # remote state - LOK = 0x0080 # lockout state - CMPL = 0x0100 # IO completed - EVENT = 0x0200 # DCAS, DTAS, or IFC occurred - SPOLL = 0x0400 # board serial-polled by busmaster - RQS = 0x0800 # device requesting service - SRQI = 0x1000 # SRQ is asserted - END = 0x2000 # EOI or EOS - TIMO = 0x4000 # timeout - ERR = 0x8000 # error + DCAS = 0x0001 # device clear state + DTAS = 0x0002 # device trigger state + LACS = 0x0004 # interface is Listener + TACS = 0x0008 # interface is Talker + ATN = 0x0010 # attention + CIC = 0x0020 # Controller-in-Charge + REM = 0x0040 # remote state + LOK = 0x0080 # lockout state + CMPL = 0x0100 # IO completed + EVENT = 0x0200 # DCAS, DTAS, or IFC occurred + SPOLL = 0x0400 # board serial-polled by busmaster + RQS = 0x0800 # device requesting service + SRQI = 0x1000 # SRQ is asserted + END = 0x2000 # EOI or EOS + TIMO = 0x4000 # timeout + ERR = 0x8000 # error class lines(IntEnum): - ValidDAV = 0x1 # the BusDAV bit is valid - ValidNDAC = 0x2 # the BusNDAC bit is valid - ValidNRFD = 0x4 # the BusNRFD bit is valid - ValidIFC = 0x8 # the BusIFC bit is valid - ValidREN = 0x10 # the BusREN bit is valid - ValidSRQ = 0x20 # the BusSRQ bit is valid - ValidATN = 0x40 # the BusATN bit is valid - ValidEOI = 0x80 # the BusEOI bit is valid - BusDAV = 0x100 # DAV line is asserted - BusNDAC = 0x200 # NDAC line is asserted - BusNRFD = 0x400 # NRFD line is asserted - BusIFC = 0x800 # IFC line is asserted - BusREN = 0x1000 # REN line is asserted - BusSRQ = 0x2000 # SRQ line is asserted - BusATN = 0x4000 # ATN line is asserted - BusEOI = 0x8000 # EOI line is asserted + ValidDAV = 0x1 # the BusDAV bit is valid + ValidNDAC = 0x2 # the BusNDAC bit is valid + ValidNRFD = 0x4 # the BusNRFD bit is valid + ValidIFC = 0x8 # the BusIFC bit is valid + ValidREN = 0x10 # the BusREN bit is valid + ValidSRQ = 0x20 # the BusSRQ bit is valid + ValidATN = 0x40 # the BusATN bit is valid + ValidEOI = 0x80 # the BusEOI bit is valid + BusDAV = 0x100 # DAV line is asserted + BusNDAC = 0x200 # NDAC line is asserted + BusNRFD = 0x400 # NRFD line is asserted + BusIFC = 0x800 # IFC line is asserted + BusREN = 0x1000 # REN line is asserted + BusSRQ = 0x2000 # SRQ line is asserted + BusATN = 0x4000 # ATN line is asserted + BusEOI = 0x8000 # EOI line is asserted + class sad(IntEnum): NO_SAD = 0 @@ -143,30 +145,32 @@ class stb(IntEnum): IbStbESB = 0x20 IbStbMAV = 0x10 + class command(IntEnum): - IcGTL = 1 # go to local - IcLLO = 3 # local lock out + IcGTL = 1 # go to local + IcLLO = 3 # local lock out + class error(IntEnum): - EDVR = 0 # system error - ECIC = 1 # not CIC - ENOL = 2 # no listener - EADR = 3 # CIC and not addressed before IO - EARG = 4 # bad argument to function call - ESAC = 5 # not SAC - EABO = 6 # IO aborted - ENEB = 7 # GPIB board offline - EDMA = 8 # DMA hardware error - EOIP = 10 # previous IO still in progress - ECAP = 11 # not capable - EFSO = 12 # file system operation error - EBUS = 14 # bus error - ESTB = 15 # lost serial poll bytes - ESRQ = 16 # SRQ stuck on - ETAB = 20 # table overflow - ELCK = 21 # interface locked - EARM = 22 # failed to rearm - EHDL = 23 # invalid handle - EWIP = 26 # previous wait still in progress - ERST = 27 # event notification cancelled due to reset - EPWR = 28 # interface lost power + EDVR = 0 # system error + ECIC = 1 # not CIC + ENOL = 2 # no listener + EADR = 3 # CIC and not addressed before IO + EARG = 4 # bad argument to function call + ESAC = 5 # not SAC + EABO = 6 # IO aborted + ENEB = 7 # GPIB board offline + EDMA = 8 # DMA hardware error + EOIP = 10 # previous IO still in progress + ECAP = 11 # not capable + EFSO = 12 # file system operation error + EBUS = 14 # bus error + ESTB = 15 # lost serial poll bytes + ESRQ = 16 # SRQ stuck on + ETAB = 20 # table overflow + ELCK = 21 # interface locked + EARM = 22 # failed to rearm + EHDL = 23 # invalid handle + EWIP = 26 # previous wait still in progress + ERST = 27 # event notification cancelled due to reset + EPWR = 28 # interface lost power From c1b2c097c76b4e1545ef3895e08a797a5d3e7c02 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Fri, 26 Jun 2026 12:32:33 -0700 Subject: [PATCH 03/15] Document the GPIB symbolic-constants change --- CHANGES | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 505bc0f2..6ff83b54 100644 --- a/CHANGES +++ b/CHANGES @@ -25,7 +25,8 @@ PyVISA-py Changelog Other transports (GPIB, USBTMC, HiSLIP, Serial) remain unsupported for now. PR #577 - Pass termchar information to USBTMC devices when reading PR #598 - Properly configure termchar on GPIB devices. This fix timeout issues for old GPIB devices which do not signal EOI PR #599 - +- Clean up GPIB calls to the ib*() routines, by using symbolic definitions + rather than bare integers. PR #601 0.8.1 (04-09-2025) ------------------ From e7e006e6547860bf7b9271870afae847654998c4 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Fri, 26 Jun 2026 15:10:06 -0700 Subject: [PATCH 04/15] Add symbolic constants for secondary device address handling Turn 0, 96, and 126 into symbolic constants for the SAD. --- pyvisa_py/gpib.py | 18 +++++++++--------- pyvisa_py/gpib_constants.py | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 9e32dd7a..f1dc2b74 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -62,8 +62,8 @@ def __new__( # type: ignore[misc] def list_resources() -> List[str]: return [ "GPIB%d::%d::INSTR" % (board, pad) - if sad == 0 - else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - 0x60) + if sad == gpib_constants.sad.NO_SAD + else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - gpib_constants.sad.FIRST_SAD) for board, pad, sad in _find_listeners() ] @@ -174,7 +174,7 @@ def _find_listeners() -> Iterator[Tuple[int, int, int]]: # type: ignore[no-rede if boardpad != i and gpib.listener(board, i): yield board, i, j elif boardpad != i: - for j in range(96, 126): + for j in range(gpib_constants.sad.FIRST_SAD, gpib_constants.sad.LAST_SAD): if gpib.listener(board, i, j): yield board, i, j except gpib.GpibError as e: @@ -346,7 +346,7 @@ def after_parsing(self) -> None: minor = int(self.parsed.board) # Secondary address (SAD) values should be in the range 96 to 126, # 0 means the SAD is disabled. - sad = 0 + sad = gpib_constants.sad.NO_SAD timeout = gpib_constants.timeout.T10s send_eoi = 1 eos_mode = 0 @@ -354,7 +354,7 @@ def after_parsing(self) -> None: if isinstance(self.parsed, GPIBInstr): pad = int(self.parsed.primary_address) if self.parsed.secondary_address is not None: - sad = int(self.parsed.secondary_address) + 0x60 + sad = int(self.parsed.secondary_address) + gpib_constants.sad.FIRST_SAD # Used to talk to a specific resource self.interface = Gpib( name=minor, @@ -595,7 +595,7 @@ def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode] # Remove 0x60 because National Instruments. _ = ifc.ask(gpib_constants.ask.IbaSAD) if ifc.ask(gpib_constants.ask.IbaSAD): - return ifc.ask(gpib_constants.ask.IbaSAD) - 96, StatusCode.success + return ifc.ask(gpib_constants.ask.IbaSAD) - gpib_constants.sad.FIRST_SAD, StatusCode.success else: return constants.VI_NO_SEC_ADDR, StatusCode.success @@ -677,7 +677,7 @@ def _set_attribute( # Add 0x60 because National Instruments. if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: if ifc.ask(gpib_constants.ask.IbaSAD): - ifc.config(gpib_constants.config.IbcSAD, attribute_state + 96) + ifc.config(gpib_constants.config.IbcSAD, attribute_state + gpib_constants.sad.FIRST_SAD) return StatusCode.success else: return StatusCode.error_nonsupported_attribute @@ -735,8 +735,8 @@ class GPIBSession(_GPIBCommon): # type: ignore[no-redef] def list_resources() -> List[str]: return [ "GPIB%d::%d::INSTR" % (board, pad) - if sad == 0 - else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - 0x60) + if sad == gpib_constants.sad.NO_SAD + else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - gpib_constants.sad.FIRST_SAD) for board, pad, sad in _find_listeners() ] diff --git a/pyvisa_py/gpib_constants.py b/pyvisa_py/gpib_constants.py index 2b4fea6c..847ee16b 100644 --- a/pyvisa_py/gpib_constants.py +++ b/pyvisa_py/gpib_constants.py @@ -138,6 +138,8 @@ class lines(IntEnum): class sad(IntEnum): NO_SAD = 0 ALL_SAD = -1 + FIRST_SAD = 0x60 + LAST_SAD = 0x7E class stb(IntEnum): From c7055aea812c58a3a89e4223fd2a518b5628efa1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 22:11:23 +0000 Subject: [PATCH 05/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyvisa_py/gpib.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index f1dc2b74..f522d79a 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -63,7 +63,8 @@ def list_resources() -> List[str]: return [ "GPIB%d::%d::INSTR" % (board, pad) if sad == gpib_constants.sad.NO_SAD - else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - gpib_constants.sad.FIRST_SAD) + else "GPIB%d::%d::%d::INSTR" + % (board, pad, sad - gpib_constants.sad.FIRST_SAD) for board, pad, sad in _find_listeners() ] @@ -174,7 +175,9 @@ def _find_listeners() -> Iterator[Tuple[int, int, int]]: # type: ignore[no-rede if boardpad != i and gpib.listener(board, i): yield board, i, j elif boardpad != i: - for j in range(gpib_constants.sad.FIRST_SAD, gpib_constants.sad.LAST_SAD): + for j in range( + gpib_constants.sad.FIRST_SAD, gpib_constants.sad.LAST_SAD + ): if gpib.listener(board, i, j): yield board, i, j except gpib.GpibError as e: @@ -595,7 +598,9 @@ def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode] # Remove 0x60 because National Instruments. _ = ifc.ask(gpib_constants.ask.IbaSAD) if ifc.ask(gpib_constants.ask.IbaSAD): - return ifc.ask(gpib_constants.ask.IbaSAD) - gpib_constants.sad.FIRST_SAD, StatusCode.success + return ifc.ask( + gpib_constants.ask.IbaSAD + ) - gpib_constants.sad.FIRST_SAD, StatusCode.success else: return constants.VI_NO_SEC_ADDR, StatusCode.success @@ -677,7 +682,10 @@ def _set_attribute( # Add 0x60 because National Instruments. if isinstance(attribute_state, int) and 0 <= attribute_state <= 30: if ifc.ask(gpib_constants.ask.IbaSAD): - ifc.config(gpib_constants.config.IbcSAD, attribute_state + gpib_constants.sad.FIRST_SAD) + ifc.config( + gpib_constants.config.IbcSAD, + attribute_state + gpib_constants.sad.FIRST_SAD, + ) return StatusCode.success else: return StatusCode.error_nonsupported_attribute @@ -736,7 +744,8 @@ def list_resources() -> List[str]: return [ "GPIB%d::%d::INSTR" % (board, pad) if sad == gpib_constants.sad.NO_SAD - else "GPIB%d::%d::%d::INSTR" % (board, pad, sad - gpib_constants.sad.FIRST_SAD) + else "GPIB%d::%d::%d::INSTR" + % (board, pad, sad - gpib_constants.sad.FIRST_SAD) for board, pad, sad in _find_listeners() ] From 97eb8ae5b05e429507ec777248da7cdf858cda4e Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Fri, 26 Jun 2026 21:02:54 -0700 Subject: [PATCH 06/15] Fix fencepost error when iterating sub-addresses The range() operator which allows iteration through the allowed GPIB sub-addresses (0 through 30, mapped up to 96 through 126) needs to have its stop value set to 127 (LAST_SAD + 1) rather than 126 (LAST_SAD). Otherwise it will look for subaddresses 0 through 29, and not see a device at subaddress 30. --- pyvisa_py/gpib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index f522d79a..cdaf9536 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -176,7 +176,8 @@ def _find_listeners() -> Iterator[Tuple[int, int, int]]: # type: ignore[no-rede yield board, i, j elif boardpad != i: for j in range( - gpib_constants.sad.FIRST_SAD, gpib_constants.sad.LAST_SAD + gpib_constants.sad.FIRST_SAD, + gpib_constants.sad.LAST_SAD + 1 ): if gpib.listener(board, i, j): yield board, i, j From dcba3f4c68aa4b12df19d613b3dcc7be5a5cffa6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 27 Jun 2026 04:09:38 +0000 Subject: [PATCH 07/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyvisa_py/gpib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index cdaf9536..9937f81b 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -176,8 +176,7 @@ def _find_listeners() -> Iterator[Tuple[int, int, int]]: # type: ignore[no-rede yield board, i, j elif boardpad != i: for j in range( - gpib_constants.sad.FIRST_SAD, - gpib_constants.sad.LAST_SAD + 1 + gpib_constants.sad.FIRST_SAD, gpib_constants.sad.LAST_SAD + 1 ): if gpib.listener(board, i, j): yield board, i, j From 024775d0d3e3c722919c4d2ca38920b7886d9f66 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Tue, 30 Jun 2026 16:21:45 -0700 Subject: [PATCH 08/15] Update CHANGES per suggestion Co-authored-by: Matthieu Dartiailh --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 6ff83b54..db40e5a6 100644 --- a/CHANGES +++ b/CHANGES @@ -27,6 +27,7 @@ PyVISA-py Changelog - Properly configure termchar on GPIB devices. This fix timeout issues for old GPIB devices which do not signal EOI PR #599 - Clean up GPIB calls to the ib*() routines, by using symbolic definitions rather than bare integers. PR #601 + 0.8.1 (04-09-2025) ------------------ From 7916b9461c4906960f66fb8be0a1671a6077cc07 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Wed, 1 Jul 2026 16:10:49 -0700 Subject: [PATCH 09/15] Fix bad import/use of GPIB error symbols Oops... missed one set of cases where I had initially used GPIBwhatever and now (with imported symbols) need to use gpib_constants.whatever Also, sort the gpib_constants import statement --- pyvisa_py/gpib.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 9937f81b..e25ea9cf 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -15,11 +15,11 @@ from pyvisa.constants import ResourceAttribute, StatusCode from pyvisa.rname import GPIBInstr, GPIBIntfc, parse_resource_name +from . import gpib_constants from . import prologix from .common import LOGGER from .sessions import Session, UnavailableSession, UnknownAttribute, VISARMSession -from . import gpib_constants # NOTE dummy implementation that is overwritten when a GPIB library is found @@ -285,15 +285,15 @@ def convert_gpib_error( LOGGER.debug("Failed to %s.", operation, exc_info=error) if not GPIB_CTYPES: return StatusCode.error_system_error - if error.code == GPIBerror.ECIC: + if error.code == gpib_constants.error.ECIC: return StatusCode.error_not_cic - elif error.code == GPIBerror.ENOL: + elif error.code == gpib_constants.error.ENOL: return StatusCode.error_no_listeners - elif error.code == GPIBerror.EARG: + elif error.code == gpib_constants.error.EARG: return StatusCode.error_invalid_mode - elif error.code == GPIBerror.ECAP: + elif error.code == gpib_constants.error.ECAP: return StatusCode.error_nonsupported_operation - elif error.code == GPIBerror.ELCK: + elif error.code == gpib_constants.error.ELCK: return StatusCode.error_resource_locked else: return StatusCode.error_system_error From 4feea5d670b3995921fef5f00c92e6903b44aad8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 23:20:27 +0000 Subject: [PATCH 10/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyvisa_py/gpib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index e25ea9cf..623e42ac 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -21,7 +21,6 @@ from .sessions import Session, UnavailableSession, UnknownAttribute, VISARMSession - # NOTE dummy implementation that is overwritten when a GPIB library is found # Allow to provide session listing even when no GPIB library is available. def _find_listeners() -> Iterator[Tuple[int, int, int]]: From ab05b04abfaeab1acd72e553782da1358eb569f5 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Wed, 1 Jul 2026 16:24:47 -0700 Subject: [PATCH 11/15] Fix GPIBconfig member names Another one I missed: GPIBconfig -> gpib_constants.config --- pyvisa_py/gpib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 623e42ac..5aa5fe3d 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -873,14 +873,14 @@ def _set_attribute( if attribute == constants.VI_ATTR_GPIB_READDR_EN: # Setting has no effect in linux-gpib. if isinstance(attribute_state, int): - ifc.config(GPIBConfig.IbcREADDR, attribute_state) + ifc.config(gpib_constants.config.IbcREADDR, attribute_state) return StatusCode.success else: return StatusCode.error_nonsupported_attribute_state elif attribute == constants.VI_ATTR_GPIB_UNADDR_EN: try: - ifc.config(GPIBConfig.IbcUnAddr, attribute_state) + ifc.config(gpib_constants.config.IbcUnAddr, attribute_state) return StatusCode.success except gpib.GpibError: return StatusCode.error_nonsupported_attribute_state From 6dafd3e62a021251b965dfc4cb486e4a543e39d8 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Wed, 1 Jul 2026 17:18:04 -0700 Subject: [PATCH 12/15] Coerce "sad" type to int() to avoid lint complaint Apparently, in this case, an IntEnum is not sufficiently like an int to be type-matched. --- pyvisa_py/gpib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 5aa5fe3d..f7e0e889 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -356,7 +356,7 @@ def after_parsing(self) -> None: if isinstance(self.parsed, GPIBInstr): pad = int(self.parsed.primary_address) if self.parsed.secondary_address is not None: - sad = int(self.parsed.secondary_address) + gpib_constants.sad.FIRST_SAD + sad = int(self.parsed.secondary_address) + int(gpib_constants.sad.FIRST_SAD) # Used to talk to a specific resource self.interface = Gpib( name=minor, From 8d90179c6646dcbcc076a4fa23d574fd77185d3a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 00:20:49 +0000 Subject: [PATCH 13/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyvisa_py/gpib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index f7e0e889..996be58c 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -356,7 +356,9 @@ def after_parsing(self) -> None: if isinstance(self.parsed, GPIBInstr): pad = int(self.parsed.primary_address) if self.parsed.secondary_address is not None: - sad = int(self.parsed.secondary_address) + int(gpib_constants.sad.FIRST_SAD) + sad = int(self.parsed.secondary_address) + int( + gpib_constants.sad.FIRST_SAD + ) # Used to talk to a specific resource self.interface = Gpib( name=minor, From 32f656ae9df50713325ea96fb8593597112bc5f0 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Wed, 1 Jul 2026 17:24:54 -0700 Subject: [PATCH 14/15] Try the SAD fix a different way... --- pyvisa_py/gpib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index f7e0e889..08fb78aa 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -348,7 +348,7 @@ def after_parsing(self) -> None: minor = int(self.parsed.board) # Secondary address (SAD) values should be in the range 96 to 126, # 0 means the SAD is disabled. - sad = gpib_constants.sad.NO_SAD + sad = gpib_constants.sad.NO_SAD.value timeout = gpib_constants.timeout.T10s send_eoi = 1 eos_mode = 0 @@ -356,7 +356,7 @@ def after_parsing(self) -> None: if isinstance(self.parsed, GPIBInstr): pad = int(self.parsed.primary_address) if self.parsed.secondary_address is not None: - sad = int(self.parsed.secondary_address) + int(gpib_constants.sad.FIRST_SAD) + sad = int(self.parsed.secondary_address) + gpib_constants.sad.FIRST_SAD # Used to talk to a specific resource self.interface = Gpib( name=minor, From dd282984fd140f9e49b3343f8a2a7c31326eebef Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Thu, 2 Jul 2026 09:17:49 -0700 Subject: [PATCH 15/15] Fix import using ruff Run ruff on gpib.py, merging two import statements into one. --- pyvisa_py/gpib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyvisa_py/gpib.py b/pyvisa_py/gpib.py index 08fb78aa..86b884a8 100644 --- a/pyvisa_py/gpib.py +++ b/pyvisa_py/gpib.py @@ -15,8 +15,7 @@ from pyvisa.constants import ResourceAttribute, StatusCode from pyvisa.rname import GPIBInstr, GPIBIntfc, parse_resource_name -from . import gpib_constants -from . import prologix +from . import gpib_constants, prologix from .common import LOGGER from .sessions import Session, UnavailableSession, UnknownAttribute, VISARMSession