Builds a modern, testable API for the Prologix GPIB-ETHERNET controller (GPIB-USB structurally supported but untested, no hardware available): Transport abstraction (Ethernet now, serial later), GpibController for the full "++" command set, a clean-room netfinder discovery client that fixes a real chr()/struct-format bug present in vendortools/nfutil.py, and a CLI (discover/config/info/terminal). vendortools/, pty-gpib-emulator/, sampledata.txt and the manual PDF are kept untouched as reference material. Depends on the sibling bits package (editable, not yet pinned -- see its own commit) for MAC formatting and IEEE-488.2 status-byte bit access. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
85 lines
2.8 KiB
Python
85 lines
2.8 KiB
Python
import time
|
|
|
|
import pytest
|
|
from bits import Bit
|
|
|
|
from progpib.controller import GpibController
|
|
from progpib.exceptions import CommandError
|
|
|
|
|
|
def _wait_until(condition, timeout=2.0, interval=0.02):
|
|
deadline = time.monotonic() + timeout
|
|
while time.monotonic() < deadline:
|
|
if condition():
|
|
return True
|
|
time.sleep(interval)
|
|
return condition()
|
|
|
|
|
|
def test_mode_property_roundtrip(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
ctrl.mode = 1
|
|
assert ctrl.mode == 1
|
|
ctrl.mode = 0
|
|
assert ctrl.mode == 0
|
|
|
|
|
|
def test_addr_property_roundtrip_as_tuple(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
ctrl.addr = (5, 96)
|
|
assert ctrl.addr == (5, 96)
|
|
ctrl.addr = 12
|
|
assert ctrl.addr == 12
|
|
|
|
|
|
def test_ver_returns_server_version(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
assert ctrl.ver() == server.version
|
|
|
|
|
|
def test_write_escapes_special_bytes_on_the_wire(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
ctrl.write("*IDN?\r\n+test")
|
|
expected = b"*IDN?\x1b\r\x1b\n\x1b+test\n"
|
|
assert _wait_until(lambda: bytes(server.raw_received) == expected)
|
|
|
|
|
|
def test_read_tmo_ms_range_validation_without_network(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
with pytest.raises(ValueError):
|
|
ctrl.read_tmo_ms = 5000
|
|
# unchanged: the invalid value was never sent
|
|
assert ctrl.read_tmo_ms == 500
|
|
|
|
|
|
def test_status_and_lon_raise_in_controller_mode(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
server.state["mode"] = "1" # CONTROLLER
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
with pytest.raises(CommandError):
|
|
_ = ctrl.status
|
|
with pytest.raises(CommandError):
|
|
_ = ctrl.lon
|
|
|
|
|
|
def test_status_and_spoll_return_bits_with_rqs_at_index_6(fake_gpib_server):
|
|
server, tcp_server = fake_gpib_server
|
|
server.state["mode"] = "0" # DEVICE
|
|
server.state["status"] = "72" # 0x48: RQS (bit 6) and bit 3 set
|
|
server.spoll_response = 72
|
|
|
|
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
|
status = ctrl.status
|
|
assert int(status) == 72
|
|
assert status[6] == Bit(1)
|
|
assert status[5] == Bit(0)
|
|
|
|
result = ctrl.spoll()
|
|
assert int(result) == 72
|
|
assert result[6] == Bit(1)
|