From 2fafb9af04884a77a540e2ade49e26f720e1cb33 Mon Sep 17 00:00:00 2001 From: Jens Peter Secher Date: Thu, 4 Jan 2024 11:05:04 +0100 Subject: [PATCH] Use *OPC? instead of delays --- docs/examples/QDevil/QSwitch/Debugging.ipynb | 90 ++++++++++++-- docs/examples/QDevil/QSwitch/Usage.ipynb | 113 +++++++++++++++--- .../drivers/QDevil/QSwitch.py | 6 +- .../test_sim_qswitch_direct_operation.py | 21 ++-- .../QDevil/test_sim_qswitch_operation.py | 27 +++-- 5 files changed, 209 insertions(+), 48 deletions(-) diff --git a/docs/examples/QDevil/QSwitch/Debugging.ipynb b/docs/examples/QDevil/QSwitch/Debugging.ipynb index 90bb734ff..9f04b0b33 100644 --- a/docs/examples/QDevil/QSwitch/Debugging.ipynb +++ b/docs/examples/QDevil/QSwitch/Debugging.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "85f2a1e0", "metadata": {}, "outputs": [ @@ -18,7 +18,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Quantum Machines QSwitch (serial:5, firmware:0.160) in 0.11s\n" + "Connected to: Quantum Machines QSwitch (serial:2, firmware:0.178) in 0.11s\n" ] } ], @@ -26,7 +26,7 @@ "import pprint\n", "pp = pprint.PrettyPrinter()\n", "from qcodes_contrib_drivers.drivers.QDevil import QSwitch\n", - "qswitch_addr = '192.168.8.18'\n", + "qswitch_addr = '192.168.8.20'\n", "qswitch = QSwitch.QSwitch('switch', visalib='@py', address=f'TCPIP::{qswitch_addr}::5025::SOCKET')" ] }, @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "d0c7fc28", "metadata": {}, "outputs": [], @@ -50,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "64f0cbe6", "metadata": {}, "outputs": [ @@ -60,7 +60,7 @@ "'0,\"No error\"'" ] }, - "execution_count": 4, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -77,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "0d8a7693", "metadata": {}, "outputs": [ @@ -85,7 +85,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "['*rst', 'stat?', 'clos (@5!9)', 'open (@5!0)', 'clos (@5!5)', 'all?']\n" + "['*rst',\n", + " 'stat?',\n", + " 'clos (@5!9)',\n", + " '*opc?',\n", + " 'open (@5!0)',\n", + " '*opc?',\n", + " 'clos (@5!5)',\n", + " '*opc?',\n", + " 'all?']\n" ] } ], @@ -93,6 +101,16 @@ "pp.pprint(qswitch.get_recorded_scpi_commands())" ] }, + { + "cell_type": "code", + "execution_count": 8, + "id": "995394e6", + "metadata": {}, + "outputs": [], + "source": [ + "qswitch.close()" + ] + }, { "cell_type": "markdown", "id": "588fabac", @@ -176,6 +194,62 @@ "source": [ "See https://github.com/QDevil/qdac2-tools for more debugging tools." ] + }, + { + "cell_type": "markdown", + "id": "8428f8bd", + "metadata": {}, + "source": [ + "The QSwitch only supports a single Ethernet connection at a time. If you find yourself in a situation where you cannot connect to the instrument, then it might be because some process on your computer still has a connection to the instrument. To identify which process, do something like" + ] + }, + { + "cell_type": "markdown", + "id": "06be4a1a", + "metadata": {}, + "source": [ + "```\n", + "$ netstat -ntpn | grep '192.168.8.21'\n", + "tcp 0 0 192.168.8.66:43772 192.168.8.21:5025 ESTABLISHED 153450/python3\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "8708065e", + "metadata": {}, + "source": [ + "Then you can forcefully kill the process like" + ] + }, + { + "cell_type": "markdown", + "id": "945dcaf4", + "metadata": {}, + "source": [ + "```\n", + "$ kill 153450\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "b39d8c3c", + "metadata": {}, + "source": [ + "and then wait for the TCP connection to let go:" + ] + }, + { + "cell_type": "markdown", + "id": "8e9d32f9", + "metadata": {}, + "source": [ + "```\n", + "$ netstat -ntpn | grep '192.168.8.21'\n", + "tcp 0 0 192.168.8.66:43772 192.168.8.21:5025 TIME_WAIT -\n", + "```" + ] } ], "metadata": { diff --git a/docs/examples/QDevil/QSwitch/Usage.ipynb b/docs/examples/QDevil/QSwitch/Usage.ipynb index 62fbca324..91e71909e 100644 --- a/docs/examples/QDevil/QSwitch/Usage.ipynb +++ b/docs/examples/QDevil/QSwitch/Usage.ipynb @@ -17,7 +17,6 @@ "source": [ "import pprint\n", "pp = pprint.PrettyPrinter()\n", - "import numpy as np\n", "import qcodes\n", "from qcodes_contrib_drivers.drivers.QDevil import QSwitch" ] @@ -32,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "id": "5787c333-0d69-47db-bfe3-37bead44a7c5", "metadata": {}, "outputs": [ @@ -40,7 +39,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Quantum Machines QSwitch (serial:4, firmware:0.160) in 0.07s\n" + "Connected to: Quantum Machines QSwitch (serial:2, firmware:0.178) in 0.05s\n" ] } ], @@ -67,12 +66,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "Connected to: Quantum Machines QSwitch (serial:5, firmware:0.160) in 0.13s\n" + "Connected to: Quantum Machines QSwitch (serial:2, firmware:0.178) in 0.12s\n" ] } ], "source": [ - "qswitch_addr = '192.168.8.16'\n", + "qswitch_addr = '192.168.8.21'\n", "qswitch = QSwitch.QSwitch('switch', visalib='@py', address=f'TCPIP::{qswitch_addr}::5025::SOCKET')" ] }, @@ -110,6 +109,35 @@ "cell_type": "markdown", "id": "2fc0260b-8052-457a-b820-15edd7a699d3", "metadata": {}, + "source": [ + "Or in expanded form:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c592efa5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'(@1!0,2!0,3!0,4!0,5!0,6!0,7!0,8!0,9!0,10!0,11!0,12!0,13!0,14!0,15!0,16!0,17!0,18!0,19!0,20!0,21!0,22!0,23!0,24!0)'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "QSwitch.expand_channel_list(qswitch.state())" + ] + }, + { + "cell_type": "markdown", + "id": "f20fa87f", + "metadata": {}, "source": [ "Or expressed as a Python array:" ] @@ -293,7 +321,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 10, "id": "9d3d65c5", "metadata": {}, "outputs": [], @@ -313,7 +341,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "3f7f92ca", "metadata": {}, "outputs": [], @@ -331,7 +359,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "id": "45ae7eea", "metadata": {}, "outputs": [], @@ -358,7 +386,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "id": "ac31add0", "metadata": {}, "outputs": [], @@ -376,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "86cfd2da", "metadata": {}, "outputs": [], @@ -403,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "id": "e0ad0e89", "metadata": {}, "outputs": [], @@ -440,7 +468,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "245cd62c", "metadata": {}, "outputs": [], @@ -458,7 +486,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "54374fb6", "metadata": {}, "outputs": [], @@ -485,17 +513,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "f48f9830", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'1': ['grounded'],\n", + " '2': ['grounded'],\n", + " '3': ['grounded'],\n", + " '4': ['grounded'],\n", + " 'sensor': ['grounded'],\n", + " '6': ['grounded'],\n", + " '7': ['grounded'],\n", + " '8': ['grounded'],\n", + " '9': ['grounded'],\n", + " '10': ['grounded'],\n", + " '11': ['grounded'],\n", + " '12': ['grounded'],\n", + " '13': ['grounded'],\n", + " '14': ['grounded'],\n", + " '15': ['grounded'],\n", + " '16': ['grounded'],\n", + " '17': ['grounded'],\n", + " '18': ['grounded'],\n", + " '19': ['grounded'],\n", + " '20': ['grounded'],\n", + " '21': ['grounded'],\n", + " 'plunger': ['connected', 'breakout DMM'],\n", + " '24': ['breakout 1']}" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "qswitch.overview()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "b5030c09", "metadata": {}, "outputs": [], @@ -521,7 +582,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "dfdba65e", "metadata": {}, "outputs": [], @@ -529,6 +590,24 @@ "qswitch.auto_save('on')\n", "qswitch.auto_save('off')" ] + }, + { + "cell_type": "markdown", + "id": "bff23cac", + "metadata": {}, + "source": [ + "The QSwitch only supports a single Ethernet connection at a time, so you can explicitly tell Python to let go of the connection:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44bac656", + "metadata": {}, + "outputs": [], + "source": [ + "qswitch.close()" + ] } ], "metadata": { diff --git a/qcodes_contrib_drivers/drivers/QDevil/QSwitch.py b/qcodes_contrib_drivers/drivers/QDevil/QSwitch.py index 45b66d870..05d73d269 100644 --- a/qcodes_contrib_drivers/drivers/QDevil/QSwitch.py +++ b/qcodes_contrib_drivers/drivers/QDevil/QSwitch.py @@ -9,7 +9,7 @@ Tuple, Sequence, List, Dict, Set, Union, Optional) from packaging.version import parse -# Version 0.4.0 +# Version 0.5.0 State = Sequence[Tuple[int, int]] @@ -317,7 +317,7 @@ def write(self, cmd: str) -> None: """ try: self._write(cmd) - sleep_s(0.075) + self.ask('*opc?') errors = super().ask('all?') except Exception as error: raise ValueError(f'Error: {repr(error)} after executing {cmd}') @@ -418,7 +418,7 @@ def _check_for_wrong_model(self) -> None: def _check_for_incompatiable_firmware(self) -> None: firmware = self.IDN()['firmware'] - least_compatible_fw = '0.155' + least_compatible_fw = '0.178' if parse(firmware) < parse(least_compatible_fw): raise ValueError(f'Incompatible firmware {firmware}. You need at ' f'least {least_compatible_fw}') diff --git a/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_direct_operation.py b/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_direct_operation.py index a1988bb78..4754ac292 100644 --- a/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_direct_operation.py +++ b/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_direct_operation.py @@ -35,9 +35,10 @@ def test_set_state_only_sends_diff(qswitch): # noqa [(24, 8), (24, 8), (22, 7), (20, 6), (1, 9), (2, 0)]) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() + print(commands) assert commands == [ - 'clos (@20!6,22!7,24!8,1!9)', - 'open (@1!0,3!0:24!0)' + 'clos (@20!6,22!7,24!8,1!9)', '*opc?', + 'open (@1!0,3!0:24!0)', '*opc?' ] @@ -69,7 +70,7 @@ def test_individual_relays_can_be_closed(qswitch): # noqa qswitch.close_relays([(14, 1), (22, 7)]) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@14!1,22!7)'] + assert commands == ['clos (@14!1,22!7)', '*opc?'] def test_individual_relay_can_be_closed(qswitch): # noqa @@ -77,7 +78,7 @@ def test_individual_relay_can_be_closed(qswitch): # noqa qswitch.close_relay(22, 7) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@22!7)'] + assert commands == ['clos (@22!7)', '*opc?'] def test_individual_relays_can_be_opened(qswitch): # noqa @@ -85,7 +86,7 @@ def test_individual_relays_can_be_opened(qswitch): # noqa qswitch.open_relays([(14, 0), (22, 0), (1, 1)]) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['open (@14!0,22!0)'] + assert commands == ['open (@14!0,22!0)', '*opc?'] def test_individual_relay_can_be_opened(qswitch): # noqa @@ -93,7 +94,7 @@ def test_individual_relay_can_be_opened(qswitch): # noqa qswitch.open_relay(14, 0) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['open (@14!0)'] + assert commands == ['open (@14!0)', '*opc?'] def test_beeper_can_be_turned_on(qswitch): # noqa @@ -101,7 +102,7 @@ def test_beeper_can_be_turned_on(qswitch): # noqa qswitch.error_indicator('on') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['beep:stat on'] + assert commands == ['beep:stat on', '*opc?'] def test_beeper_can_be_turned_off(qswitch): # noqa @@ -109,7 +110,7 @@ def test_beeper_can_be_turned_off(qswitch): # noqa qswitch.error_indicator('off') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['beep:stat off'] + assert commands == ['beep:stat off', '*opc?'] def test_beeper_state_can_be_queried(qswitch): # noqa @@ -126,7 +127,7 @@ def test_autosave_can_be_turned_on(qswitch): # noqa qswitch.auto_save('on') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['aut on'] + assert commands == ['aut on', '*opc?'] def test_autosave_can_be_turned_off(qswitch): # noqa @@ -134,7 +135,7 @@ def test_autosave_can_be_turned_off(qswitch): # noqa qswitch.auto_save('off') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['aut off'] + assert commands == ['aut off', '*opc?'] def test_autosave_state_can_be_queried(qswitch): # noqa diff --git a/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_operation.py b/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_operation.py index 304ec892e..46b932660 100644 --- a/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_operation.py +++ b/qcodes_contrib_drivers/tests/QDevil/test_sim_qswitch_operation.py @@ -11,7 +11,7 @@ def test_ground_by_name(qswitch): # noqa qswitch.ground('15') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@15!0)', 'open (@15!9)'] + assert commands == ['clos (@15!0)', '*opc?', 'open (@15!9)', '*opc?'] def test_ground_by_names(qswitch): # noqa @@ -24,7 +24,9 @@ def test_ground_by_names(qswitch): # noqa qswitch.ground(['15', '14']) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@14!0:15!0)', 'open (@14!9:15!9)'] + assert commands == [ + 'clos (@14!0:15!0)', '*opc?', + 'open (@14!9:15!9)', '*opc?'] def test_connect_by_name(qswitch): # noqa @@ -32,7 +34,7 @@ def test_connect_by_name(qswitch): # noqa qswitch.connect('15') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@15!9)', 'open (@15!0)'] + assert commands == ['clos (@15!9)', '*opc?', 'open (@15!0)', '*opc?'] def test_connect_by_names(qswitch): # noqa @@ -40,7 +42,9 @@ def test_connect_by_names(qswitch): # noqa qswitch.connect(['14', '15']) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@14!9:15!9)', 'open (@14!0:15!0)'] + assert commands == [ + 'clos (@14!9:15!9)', '*opc?', + 'open (@14!0:15!0)', '*opc?'] def test_breakout_by_name(qswitch): # noqa @@ -48,7 +52,7 @@ def test_breakout_by_name(qswitch): # noqa qswitch.breakout('22', '7') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@22!7)', 'open (@22!0)'] + assert commands == ['clos (@22!7)', '*opc?', 'open (@22!0)', '*opc?'] def test_arrangement_gives_names_to_connections(qswitch): # noqa @@ -62,8 +66,8 @@ def test_arrangement_gives_names_to_connections(qswitch): # noqa # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() assert commands == [ - 'clos (@14!1)', 'open (@14!0)', - 'clos (@3!9)', 'open (@3!0)'] + 'clos (@14!1)', '*opc?', 'open (@14!0)', '*opc?', + 'clos (@3!9)', '*opc?', 'open (@3!0)', '*opc?'] def test_ground_disconnects_everything(qswitch): # noqa @@ -75,7 +79,9 @@ def test_ground_disconnects_everything(qswitch): # noqa qswitch.ground('15') # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@15!0)', 'open (@15!1,15!9)'] + assert commands == [ + 'clos (@15!0)', '*opc?', + 'open (@15!1,15!9)', '*opc?'] def test_ground_disconnects_multiple(qswitch): # noqa @@ -90,5 +96,6 @@ def test_ground_disconnects_multiple(qswitch): # noqa qswitch.ground(['15', '14']) # ----------------------------------------------------------------------- commands = qswitch.get_recorded_scpi_commands() - assert commands == ['clos (@14!0:15!0)', 'open (@14!1:15!1,14!9:15!9)'] - + assert commands == [ + 'clos (@14!0:15!0)', '*opc?', + 'open (@14!1:15!1,14!9:15!9)', '*opc?']