Skip to content
Open
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
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
PyVISA-py Changelog
===================

0.8.0 (unreleased)
------------------

- fix GPIB commands used in control_ren implementation PR #276

0.7.1 (26/10/2023)
------------------

Expand Down
2 changes: 1 addition & 1 deletion pyvisa_py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# package is not installed
pass

# noqa: we need to import so that __init_subclass__() is executed once
# We need to import so that __init_subclass__() is executed once
from . import attributes # noqa: F401
from .highlevel import PyVisaLibrary

Expand Down
68 changes: 53 additions & 15 deletions pyvisa_py/gpib.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from pyvisa import attributes, constants, logger
from pyvisa.constants import ResourceAttribute, StatusCode
from pyvisa.resources.gpib import GPIBCommand
from pyvisa.rname import GPIBInstr, GPIBIntfc

from .sessions import Session, UnknownAttribute
Expand Down Expand Up @@ -385,9 +386,11 @@ def read(self, count: int) -> Tuple[bytes, StatusCode]:
ifc = self.interface or self.controller

# END 0x2000
checker = lambda current: ifc.ibsta() & 0x2000
def checker(current):
return ifc.ibsta() & 0x2000

reader = lambda: ifc.read(count)
def reader():
return lambda: ifc.read(count)

return self._read(reader, count, checker, False, None, False, gpib.GpibError)

Expand Down Expand Up @@ -449,38 +452,73 @@ def gpib_control_ren(self, mode: constants.RENLineOperation) -> StatusCode:
):
return constants.StatusCode.error_nonsupported_operation

# INTFC don't have an interface so use the controller
ifc = self.interface or self.controller
# Commands and remote enable operation are common to the whole bus and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this even be allowed? (writing specifically about the 0x01 command here, but I guess this applies to most of the other stuff this function does) The user might not expect every instrument on their GPIB bus to go into local mode when they call a function on a single instrument. I think it's better to only expose gpib_control_ren() for bus controller objects. This way the user is forced to understand that they're doing something that impacts the whole bus. See #278 for a problem with that today.

I think sending a single instrument to local mode should be done with ibloc() because that's a device action, not a bus action. I don't see ibloc() exposed anywhere in pyvisa-py right now though.

# are hence handled by the board (ie self.controller)
try:
if mode == constants.VI_GPIB_REN_DEASSERT_GTL:
# Send GTL command byte (cf linux-gpib documentation)
ifc.command(chr(1))
# Make the instrument Go To Local
# Using ibloc is a nice way to avoid manually sending all the
# right commands but under the hood it does send GTL to the
# proper device.
# Only for INSTR hence sel.interface exists
self.interface.ibloc()
if mode in (
constants.VI_GPIB_REN_DEASSERT,
constants.VI_GPIB_REN_DEASSERT_GTL,
):
self.controller.remote_enable(0)

if mode == constants.VI_GPIB_REN_ASSERT_LLO:
# LLO
ifc.command(b"0x11")
# Send LLO to all devices addressed to listen as per the
# specification.
self.controller.command(b"\x11")
elif mode == constants.VI_GPIB_REN_ADDRESS_GTL:
# GTL
ifc.command(b"0x1")
# Make the instrument Go To Local
# Using ibloc is a nice way to avoid manually sending all the
# right commands but under the hood it does send GTL to the
# proper device.
# Only fro INSTR hence sel.interface exists
self.interface.ibloc()
elif mode == constants.VI_GPIB_REN_ASSERT_ADDRESS_LLO:
pass
assert isinstance(self.parsed, GPIBInstr)
# Make the board the controller, unlisten all devices, address
# the target device and send LLO
# Closely inspired from linux-glib implementation of ibloc but
# in the VISA spec the board cannot have a secondary address
board_pad = int(self.controller.ask(0x1)) # Request PAD of controller
device_pad = int(self.parsed.primary_address)
device_sad = (
int(self.parsed.secondary_address)
if self.parsed.secondary_address is not None
else 0
)
self.controller.command(
GPIBCommand.MTA(board_pad) # type: ignore
+ GPIBCommand.UNL
+ GPIBCommand.MLA(device_pad) # type: ignore
+ GPIBCommand.MSA(device_sad) # type: ignore
+ GPIBCommand.LLO
)
elif mode in (
constants.VI_GPIB_REN_ASSERT,
constants.VI_GPIB_REN_ASSERT_ADDRESS,
):
ifc.remote_enable(1)
self.controller.remote_enable(1)
if (
isinstance(self.parsed, GPIBInstr)
and mode == constants.VI_GPIB_REN_ASSERT_ADDRESS
):
# 0 for the secondary address means don't use it
ifc.listener(
self.parsed.primary_address, self.parsed.secondary_address
# Address the specified device,
device_pad = int(self.parsed.primary_address)
device_sad = (
int(self.parsed.secondary_address)
if self.parsed.secondary_address is not None
else 0
)
self.controller.command(
GPIBCommand.UNL
+ GPIBCommand.MLA(device_pad) # type: ignore
+ GPIBCommand.MSA(device_sad) # type: ignore
)
except gpib.GpibError as e:
return convert_gpib_error(e, self.interface.ibsta(), "perform control REN")
Expand Down
5 changes: 3 additions & 2 deletions pyvisa_py/protocols/usbtmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@ def __init__(
elif len(devices) > 1:
desc = "\n".join(str(dev) for dev in devices)
raise ValueError(
"{} devices found:\n{}\nPlease narrow the search"
" criteria".format(len(devices), desc)
"{} devices found:\n{}\nPlease narrow the search criteria".format(
len(devices), desc
)
)

self.usb_dev = devices[0]
Expand Down