-
-
Notifications
You must be signed in to change notification settings - Fork 139
Add remote/local handling for VXI-11 and HiSLIP #636
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
Changes from 4 commits
f6adc8c
c193bc3
bb07dfa
a247d28
df50cfb
b911d9b
4626260
a81f269
35d01df
f1bc283
c4cd59d
1141ec3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -315,6 +315,52 @@ def write(self, data: bytes) -> Tuple[int, StatusCode]: | |
|
|
||
| return len(data), StatusCode.success | ||
|
|
||
| def gpib_control_ren(self, mode: constants.RENLineOperation) -> StatusCode: | ||
| """Controls the state of the GPIB Remote Enable (REN) interface line. | ||
|
|
||
| Optionally the remote/local state of the device is also controlled. | ||
|
|
||
| Corresponds to viGpibControlREN function of the VISA library. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| mode : constants.RENLineOperation | ||
| Specifies the state of the REN line and optionally the device | ||
| remote/local state. | ||
|
|
||
| Returns | ||
| ------- | ||
| StatusCode | ||
| Return value of the library call. | ||
|
|
||
| """ | ||
| valid_modes = ( | ||
| constants.RENLineOperation.address_gtl, | ||
| constants.RENLineOperation.asrt, | ||
| constants.RENLineOperation.asrt_address, | ||
| constants.RENLineOperation.asrt_address_llo, | ||
| constants.RENLineOperation.asrt_llo, | ||
| constants.RENLineOperation.deassert, | ||
| constants.RENLineOperation.deassert_gtl, | ||
| ) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a module level constant (private and marked Final).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. overriden by later comment |
||
| if mode not in valid_modes: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could catch the KeyError when looking up the method to avoid 2 look ups.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes |
||
| return StatusCode.error_nonsupported_operation | ||
|
|
||
| method = { | ||
| constants.RENLineOperation.address_gtl: "justGTL", | ||
| constants.RENLineOperation.asrt: "enableRemote", | ||
| constants.RENLineOperation.asrt_address: "enableAndGotoRemote", | ||
| constants.RENLineOperation.asrt_address_llo: "enableAndGTRLLO", | ||
| constants.RENLineOperation.asrt_llo: "enableAndLockoutLocal", | ||
| constants.RENLineOperation.deassert: "disableRemote", | ||
| constants.RENLineOperation.deassert_gtl: "disableAndGTL", | ||
| }[mode] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same, the dict should be a module level constant.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. overriden by later comment |
||
|
|
||
| interface = cast(hislip.Instrument, self.interface) | ||
| interface.async_remote_local_control(method) | ||
|
|
||
| return StatusCode.success | ||
|
|
||
| def clear(self) -> StatusCode: | ||
| """Clears a device. | ||
|
|
||
|
|
@@ -853,6 +899,47 @@ def write(self, data: bytes) -> Tuple[int, StatusCode]: | |
| except vxi11.Vxi11Error: | ||
| return 0, StatusCode.error_timeout | ||
|
|
||
| def gpib_control_ren(self, mode: constants.RENLineOperation) -> StatusCode: | ||
| """Controls the state of the GPIB Remote Enable (REN) interface line. | ||
|
|
||
| Optionally the remote/local state of the device is also controlled. | ||
|
|
||
| Corresponds to viGpibControlREN function of the VISA library. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| mode : constants.RENLineOperation | ||
| Specifies the state of the REN line and optionally the device | ||
| remote/local state. | ||
|
|
||
| Returns | ||
| ------- | ||
| StatusCode | ||
| Return value of the library call. | ||
|
|
||
| """ | ||
| if mode not in ( | ||
| constants.RENLineOperation.address_gtl, | ||
| constants.RENLineOperation.asrt_address, | ||
| constants.RENLineOperation.asrt_address_llo, | ||
| constants.RENLineOperation.deassert_gtl, | ||
| ): | ||
| return constants.StatusCode.error_nonsupported_operation | ||
|
|
||
| if mode in ( | ||
| constants.RENLineOperation.asrt_address, | ||
| constants.RENLineOperation.asrt_address_llo, | ||
| ): | ||
| error = self.interface.device_remote( | ||
| self.link, 0, self.lock_timeout, self._io_timeout | ||
| ) | ||
| else: | ||
| error = self.interface.device_local( | ||
| self.link, 0, self.lock_timeout, self._io_timeout | ||
| ) | ||
|
|
||
| return VXI11_ERRORS_TO_VISA[error] | ||
|
hb020 marked this conversation as resolved.
Outdated
|
||
|
|
||
| def _get_attribute(self, attribute: ResourceAttribute) -> Tuple[Any, StatusCode]: | ||
| """Get the value for a given VISA attribute for this session. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """Unit tests for VXI11 and hislip remote/local operations.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from unittest.mock import MagicMock | ||
|
|
||
| import pytest | ||
|
|
||
| from pyvisa import constants | ||
| from pyvisa_py.tcpip import TCPIPInstrHiSLIP, TCPIPInstrVxi11 | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "mode, expected_method", | ||
| [ | ||
| (constants.RENLineOperation.address_gtl, "device_local"), | ||
| (constants.RENLineOperation.asrt_address, "device_remote"), | ||
| (constants.RENLineOperation.asrt_address_llo, "device_remote"), | ||
| (constants.RENLineOperation.deassert_gtl, "device_local"), | ||
| ], | ||
| ) | ||
| def test_vxi11_gpib_control_ren_calls_expected_device_method(mode, expected_method): | ||
| session = object.__new__(TCPIPInstrVxi11) | ||
| session.interface = MagicMock() | ||
| session.link = 7 | ||
| session.lock_timeout = 1234 | ||
| session._io_timeout = 5678 | ||
|
|
||
| session.interface.device_local.return_value = 0 | ||
| session.interface.device_remote.return_value = 0 | ||
|
|
||
| assert session.gpib_control_ren(mode) == constants.StatusCode.success | ||
|
|
||
| getattr(session.interface, expected_method).assert_called_once_with( | ||
| session.link, 0, session.lock_timeout, session._io_timeout | ||
| ) | ||
|
|
||
| if expected_method == "device_remote": | ||
| session.interface.device_local.assert_not_called() | ||
| else: | ||
| session.interface.device_remote.assert_not_called() | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("invalid_mode", [-1, 999, "bogus", None, object()]) | ||
| def test_vxi11_gpib_control_ren_rejects_unsupported_modes(invalid_mode): | ||
| session = object.__new__(TCPIPInstrVxi11) | ||
| session.interface = MagicMock() | ||
| session.link = 7 | ||
| session.lock_timeout = 1234 | ||
| session._io_timeout = 5678 | ||
|
|
||
| assert session.gpib_control_ren(invalid_mode) == ( | ||
| constants.StatusCode.error_nonsupported_operation | ||
| ) | ||
| session.interface.device_local.assert_not_called() | ||
| session.interface.device_remote.assert_not_called() | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "mode, expected_method", | ||
| [ | ||
| (constants.RENLineOperation.address_gtl, "justGTL"), | ||
| (constants.RENLineOperation.asrt, "enableRemote"), | ||
| (constants.RENLineOperation.asrt_address, "enableAndGotoRemote"), | ||
| (constants.RENLineOperation.asrt_address_llo, "enableAndGTRLLO"), | ||
| (constants.RENLineOperation.asrt_llo, "enableAndLockoutLocal"), | ||
| (constants.RENLineOperation.deassert, "disableRemote"), | ||
| (constants.RENLineOperation.deassert_gtl, "disableAndGTL"), | ||
| ], | ||
| ) | ||
| def test_hislip_gpib_control_ren_calls_expected_interface_method(mode, expected_method): | ||
| session = object.__new__(TCPIPInstrHiSLIP) | ||
| session.interface = MagicMock() | ||
|
|
||
| assert session.gpib_control_ren(mode) == constants.StatusCode.success | ||
| session.interface.async_remote_local_control.assert_called_once_with( | ||
| expected_method | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("invalid_mode", [-1, 999, "bogus", None, object()]) | ||
| def test_hislip_gpib_control_ren_rejects_unsupported_modes(invalid_mode): | ||
| session = object.__new__(TCPIPInstrHiSLIP) | ||
| session.interface = MagicMock() | ||
|
|
||
| assert session.gpib_control_ren(invalid_mode) == ( | ||
| constants.StatusCode.error_nonsupported_operation | ||
| ) | ||
| session.interface.async_remote_local_control.assert_not_called() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parity with NI-VISA is good but did you check the visa specs ? Some of the above are a bit surprising for VXI-11 (LLO that works but does not lock is weird).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 rules:
100% conform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I'll adapt the faq to mention that