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

gpib: send the proper byte when using command #276

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
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 @@
ifc = self.interface or self.controller

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

Check warning on line 390 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L389-L390

Added lines #L389 - L390 were not covered by tests

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

Check warning on line 392 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L392

Added line #L392 was not covered by tests
return lambda: ifc.read(count)

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

Expand Down Expand Up @@ -449,38 +452,73 @@
):
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
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()

Check warning on line 464 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L464

Added line #L464 was not covered by tests
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")

Check warning on line 474 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L474

Added line #L474 was not covered by tests
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()

Check warning on line 481 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L481

Added line #L481 was not covered by tests
elif mode == constants.VI_GPIB_REN_ASSERT_ADDRESS_LLO:
pass
assert isinstance(self.parsed, GPIBInstr)

Check warning on line 483 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L483

Added line #L483 was not covered by tests
# 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 = (

Check warning on line 490 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L488-L490

Added lines #L488 - L490 were not covered by tests
int(self.parsed.secondary_address)
if self.parsed.secondary_address is not None
else 0
)
self.controller.command(

Check warning on line 495 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L495

Added line #L495 was not covered by tests
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)

Check warning on line 506 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L506

Added line #L506 was not covered by tests
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 = (

Check warning on line 513 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L512-L513

Added lines #L512 - L513 were not covered by tests
int(self.parsed.secondary_address)
if self.parsed.secondary_address is not None
else 0
)
self.controller.command(

Check warning on line 518 in pyvisa_py/gpib.py

View check run for this annotation

Codecov / codecov/patch

pyvisa_py/gpib.py#L518

Added line #L518 was not covered by tests
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
Loading