From 855cb03ce7da4287475a3b25f7203d2b7814d307 Mon Sep 17 00:00:00 2001 From: Stefano Di Frischia <stefano.difrischia@inaf.it> Date: Tue, 30 May 2023 13:48:29 +0000 Subject: [PATCH] Resolve L2SS-1272 "Sdp firmware device" --- CDB/LOFAR_ConfigDb.json | 11 + CDB/hierarchies/power.json | 20 +- .../digitalbeam_cluster_ConfigDb.json | 32 +++ CDB/stations/CS001_ConfigDb.json | 57 +++-- CDB/stations/DTS_ConfigDb.json | 104 +++++---- CDB/stations/DTS_Outside_ConfigDb.json | 55 +++-- CDB/stations/LTS_ConfigDb.json | 25 ++- CDB/stations/README.md | 2 +- CDB/stations/simulators_ConfigDb.json | 19 ++ docker-compose/device-sdpfirmware.yml | 55 +++++ .../startup/01-devices.py | 4 + .../lofar2-fast-policy.json | 2 + .../lofar2-policy.json | 6 +- jupyter-notebooks/DEMO_Firmware.ipynb | 202 ++++++++++++++++++ sbin/run_integration_test.sh | 4 +- .../docs/source/configure_station.rst | 4 + .../docs/source/devices/sdp.rst | 18 +- .../docs/source/devices/sdpfirmware.rst | 34 +++ tangostationcontrol/docs/source/faq.rst | 2 +- tangostationcontrol/docs/source/index.rst | 1 + tangostationcontrol/setup.cfg | 1 + .../tangostationcontrol/devices/README.md | 6 +- .../tangostationcontrol/devices/boot.py | 1 + .../tangostationcontrol/devices/docker.py | 8 + .../devices/sdp/beamlet.py | 5 +- .../tangostationcontrol/devices/sdp/bst.py | 4 +- .../devices/sdp/firmware.py | 146 +++++++++++++ .../tangostationcontrol/devices/sdp/sdp.py | 96 ++------- .../tangostationcontrol/devices/sdp/sst.py | 4 +- .../devices/sdp/statistics.py | 21 +- .../tangostationcontrol/devices/sdp/xst.py | 4 +- .../configDB/simulators_ConfigDb.json | 19 ++ .../interfaces/test_power_hierarchy.py | 32 ++- .../devices/test_device_antennafield.py | 8 + .../devices/test_device_calibration.py | 8 + .../devices/test_device_digitalbeam.py | 14 ++ .../devices/test_device_observation.py | 8 + .../test_device_observation_control.py | 8 + .../default/devices/test_device_sdp.py | 11 - .../devices/test_device_sdpfirmware.py | 21 ++ .../default/devices/test_device_sst.py | 9 + .../test_device_temperature_manager.py | 10 + .../test_digitalbeam_performance.py | 8 +- 43 files changed, 883 insertions(+), 226 deletions(-) create mode 100644 docker-compose/device-sdpfirmware.yml create mode 100644 jupyter-notebooks/DEMO_Firmware.ipynb create mode 100644 tangostationcontrol/docs/source/devices/sdpfirmware.rst create mode 100644 tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py create mode 100644 tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdpfirmware.py diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 13faba11e..a237a7981 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -143,6 +143,7 @@ "RCU2L, RECV_TEMP_error_R" ], "Shutdown_Device_List": [ + "STAT/SDPFirmware/1", "STAT/SDP/1", "STAT/UNB2/1", "STAT/RCU2H/1", @@ -319,6 +320,16 @@ } } }, + "SDPFirmware": { + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { + "properties": { + } + } + } + } + }, "SDP": { "STAT": { "SDP": { diff --git a/CDB/hierarchies/power.json b/CDB/hierarchies/power.json index 240ff71fc..e273364de 100644 --- a/CDB/hierarchies/power.json +++ b/CDB/hierarchies/power.json @@ -28,7 +28,7 @@ ], "Power_Children": [ "STAT/CCD/1", - "STAT/SDP/1" + "STAT/SDPFirmware/1" ] } } @@ -136,13 +136,29 @@ } } }, + "SDPFirmware": { + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { + "properties": { + "Power_Parent": [ + "STAT/PSOC/1" + ], + "Power_Children": [ + "STAT/SDP/1" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { "STAT/SDP/1": { "properties": { "Power_Parent": [ - "STAT/PSOC/1" + "STAT/SDPFirmware/1" ], "Power_Children": [ "STAT/Beamlet/1", diff --git a/CDB/integrations/digitalbeam_cluster_ConfigDb.json b/CDB/integrations/digitalbeam_cluster_ConfigDb.json index 18f410cef..1ba01d270 100644 --- a/CDB/integrations/digitalbeam_cluster_ConfigDb.json +++ b/CDB/integrations/digitalbeam_cluster_ConfigDb.json @@ -1,5 +1,37 @@ { "servers": { + "SDPFirmware":{ + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1":{ + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + }, + "STAT/SDPFirmware/2":{ + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { diff --git a/CDB/stations/CS001_ConfigDb.json b/CDB/stations/CS001_ConfigDb.json index 6f22e81df..92ec6ea53 100644 --- a/CDB/stations/CS001_ConfigDb.json +++ b/CDB/stations/CS001_ConfigDb.json @@ -242,7 +242,7 @@ "10010", "10010", "10010" - ], + ] } } } @@ -644,6 +644,43 @@ } } }, + "SDPFirmware":{ + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1":{ + "properties": { + "OPC_Server_Name": [ + "10.99.0.250" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ], + "TR_fpga_mask_RW_default": [ + "True", + "True", + "True", + "True", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { @@ -675,24 +712,6 @@ "903", "903", "903" - ], - "TR_fpga_mask_RW_default": [ - "True", - "True", - "True", - "True", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False" ] } } diff --git a/CDB/stations/DTS_ConfigDb.json b/CDB/stations/DTS_ConfigDb.json index 921c3e3a3..2db2c9f1b 100644 --- a/CDB/stations/DTS_ConfigDb.json +++ b/CDB/stations/DTS_ConfigDb.json @@ -611,6 +611,74 @@ } } }, + "SDPFirmware":{ + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/LBA":{ + "properties": { + "OPC_Server_Name": [ + "10.99.0.250" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ], + "TR_fpga_mask_RW_default": [ + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True" + ] + } + }, + "STAT/SDPFirmware/HBA":{ + "properties": { + "OPC_Server_Name": [ + "10.99.0.250" + ], + "OPC_Server_Port": [ + "4842" + ], + "OPC_Time_Out": [ + "5.0" + ], + "TR_fpga_mask_RW_default": [ + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "True", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { @@ -642,24 +710,6 @@ "902", "902", "902" - ], - "TR_fpga_mask_RW_default": [ - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True" ] } }, @@ -691,24 +741,6 @@ "902", "902", "902" - ], - "TR_fpga_mask_RW_default": [ - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "True", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False" ] } } diff --git a/CDB/stations/DTS_Outside_ConfigDb.json b/CDB/stations/DTS_Outside_ConfigDb.json index b709db966..c94f67afd 100644 --- a/CDB/stations/DTS_Outside_ConfigDb.json +++ b/CDB/stations/DTS_Outside_ConfigDb.json @@ -373,6 +373,43 @@ } } }, + "SDPFirmware":{ + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { + "properties": { + "OPC_Server_Name": [ + "10.99.0.250" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ], + "TR_fpga_mask_RW_default": [ + "True", + "True", + "True", + "True", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False", + "False" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { @@ -404,24 +441,6 @@ "903", "903", "903" - ], - "TR_fpga_mask_RW_default": [ - "True", - "True", - "True", - "True", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False", - "False" ] } } diff --git a/CDB/stations/LTS_ConfigDb.json b/CDB/stations/LTS_ConfigDb.json index e23cf5466..3b750f8a5 100644 --- a/CDB/stations/LTS_ConfigDb.json +++ b/CDB/stations/LTS_ConfigDb.json @@ -144,10 +144,10 @@ } } }, - "SDP": { + "SDPFirmware":{ "STAT": { - "SDP": { - "STAT/SDP/1": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { "properties": { "OPC_Server_Name": [ "dop369.astron.nl" @@ -163,6 +163,25 @@ "False", "False", "False", "False", "False", "False", "False", "True", "False", "False", "False", "False" + ] + } + } + } + } + }, + "SDP": { + "STAT": { + "SDP": { + "STAT/SDP/1": { + "properties": { + "OPC_Server_Name": [ + "dop369.astron.nl" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" ], "FPGA_sdp_info_station_id_RW_default": [ "901", diff --git a/CDB/stations/README.md b/CDB/stations/README.md index ff2223891..9bc38762e 100644 --- a/CDB/stations/README.md +++ b/CDB/stations/README.md @@ -7,7 +7,7 @@ These are the required changes that need to be made in order to support multiple - add all the new devices under the "STAT/DEVICE/2" name with the correct IP addresses, ports and other properties. This includes: APSCT, APSPU, RECV and UNB2. - Put the new devices in the "Device_Names" list for the boot devices - - Set the first 8 bools in "STAT/SDP/1" ... "TR_fpga_mask_RW_default" to True (instead of the first 4 with 1 subrack). This enables the new FPGA's + - Set the first 8 bools in "STAT/SDPFirmware/1" ... "TR_fpga_mask_RW_default" to True (instead of the first 4 with 1 subrack). This enables the new FPGA's diff --git a/CDB/stations/simulators_ConfigDb.json b/CDB/stations/simulators_ConfigDb.json index 89aa897e7..f76dd050d 100644 --- a/CDB/stations/simulators_ConfigDb.json +++ b/CDB/stations/simulators_ConfigDb.json @@ -183,6 +183,25 @@ } } }, + "SDPFirmware": { + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { diff --git a/docker-compose/device-sdpfirmware.yml b/docker-compose/device-sdpfirmware.yml new file mode 100644 index 000000000..b643bb0b0 --- /dev/null +++ b/docker-compose/device-sdpfirmware.yml @@ -0,0 +1,55 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 +# +# Docker compose file that launches an interactive iTango session. +# +# Connect to the interactive session with 'docker attach itango'. +# Disconnect with the Docker deattach sequence: <CTRL>+<P> <CTRL>+<Q> +# +# Defines: +# - itango: iTango interactive session +# +# Requires: +# - lofar-device-base.yml +# +version: '2.1' + +services: + device-sdpfirmware: + image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/lofar-device-base + hostname: device-sdpfirmware + container_name: device-sdpfirmware + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5727:5727" # unique port for this DS + - "5827:5827" # ZeroMQ event port + - "5927:5927" # ZeroMQ heartbeat port + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ..:/opt/lofar/tango:rw + environment: + - TANGO_HOST=${TANGO_HOST} + - TANGO_ZMQ_EVENT_PORT=5827 + - TANGO_ZMQ_HEARTBEAT_PORT=5927 + healthcheck: + test: l2ss-health STAT/SDPFirmware/1 + interval: 1m + timeout: 30s + retries: 3 + start_period: 30s + working_dir: /opt/lofar/tango + entrypoint: + - bin/start-ds.sh + # configure CORBA to _listen_ on 0:port, but tell others we're _reachable_ through ${HOSTNAME}:port, since CORBA + # can't know about our Docker port forwarding + - l2ss-sdpfirmware SDPFirmware STAT -v -ORBendPoint giop:tcp:device-sdpfirmware:5727 -ORBendPointPublish giop:tcp:${HOSTNAME}:5727 + restart: unless-stopped + stop_signal: SIGINT # request a graceful shutdown of Tango + stop_grace_period: 2s diff --git a/docker-compose/jupyterlab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyterlab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index 065d12a2d..d84d4b201 100644 --- a/docker-compose/jupyterlab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyterlab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -30,6 +30,7 @@ unb2_l1 = OptionalDeviceProxy("STAT/UNB2/L1") unb2_h0 = OptionalDeviceProxy("STAT/UNB2/H0") unb2s = [unb2_l0, unb2_l1, unb2_h0] +sdpfirmware_l = OptionalDeviceProxy("STAT/SDPFirmware/LBA") sdp_l = OptionalDeviceProxy("STAT/SDP/LBA") bst_l = OptionalDeviceProxy("STAT/BST/LBA") sst_l = OptionalDeviceProxy("STAT/SST/LBA") @@ -38,6 +39,7 @@ beamlet_l = OptionalDeviceProxy("STAT/Beamlet/LBA") digitalbeam_l = OptionalDeviceProxy("STAT/DigitalBeam/LBA") antennafield_l = OptionalDeviceProxy("STAT/AntennaField/LBA") +sdpfirmware_h = OptionalDeviceProxy("STAT/SDPFirmware/HBA") sdp_h = OptionalDeviceProxy("STAT/SDP/HBA") bst_h = OptionalDeviceProxy("STAT/BST/HBA") sst_h = OptionalDeviceProxy("STAT/SST/HBA") @@ -67,6 +69,7 @@ devices = ( docker, temperaturemanager, configuration, + sdpfirmware_l, sdp_l, bst_l, sst_l, @@ -74,6 +77,7 @@ devices = ( beamlet_l, digitalbeam_l, antennafield_l, + sdpfirmware_h, sdp_h, bst_h, sst_h, diff --git a/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json index 33b628d4f..36348097d 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json @@ -40,6 +40,8 @@ }, "stat/rcu2l/1": { }, + "stat/sdpfirmware/1":{ + }, "stat/sdp/1": { "include": [ "Duration_*" diff --git a/docker-compose/tango-prometheus-exporter/lofar2-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-policy.json index 81c9a01d7..96edbf29f 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-policy.json @@ -78,10 +78,12 @@ "*_ITRF_offsets_R" ] }, - "stat/sdp/*": { + "stat/sdpfirmware/*": { "include": [ "TR_fpga_mask_RW" - ], + ] + }, + "stat/sdp/*": { "exclude": [ "FPGA_subband_weights_*", "FPGA_signal_input_samples_delay_*", diff --git a/jupyter-notebooks/DEMO_Firmware.ipynb b/jupyter-notebooks/DEMO_Firmware.ipynb new file mode 100644 index 000000000..f1e1d8880 --- /dev/null +++ b/jupyter-notebooks/DEMO_Firmware.ipynb @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "51527517-5dfe-4888-9465-c8672ce8004f", + "metadata": {}, + "outputs": [], + "source": [ + "# Devices\n", + "firmware = DeviceProxy(\"stat/sdpfirmware/1\")\n", + "sdp = DeviceProxy(\"stat/sdp/1\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df645dd1-95cf-4ba7-8c2c-6827e5e005bb", + "metadata": {}, + "outputs": [], + "source": [ + "# Turn on Firmware\n", + "firmware.off()\n", + "firmware.warm_boot() # hardware not initialised == factory image\n", + "firmware.state()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41f47d35-a5c4-4a90-bb4b-6d0abfbd8669", + "metadata": {}, + "outputs": [], + "source": [ + "# Turn on SDP\n", + "sdp.off()\n", + "sdp.warm_boot()\n", + "sdp.state()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e8be729-cf0d-44d6-bccc-f337a472fdd6", + "metadata": {}, + "outputs": [], + "source": [ + "# FPGA image (0 == factory image, 1 == user image)\n", + "firmware.FPGA_boot_image_RW" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0940df82-b9ad-4830-8017-306d1f6a6c0c", + "metadata": {}, + "outputs": [], + "source": [ + "# SDP points not available\n", + "sdp.FPGA_processing_enable_R" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83994c93-7310-48db-8a80-13b120976754", + "metadata": {}, + "outputs": [], + "source": [ + "# Other Firmware monitor points\n", + "print(f\"TR_fpga_mask_R -> {firmware.TR_fpga_mask_R}\")\n", + "print()\n", + "print(f\"TR_fpga_communication_error_R -> {firmware.TR_fpga_communication_error_R}\")\n", + "print()\n", + "print(f\"FPGA_firmware_version_R -> {firmware.FPGA_firmware_version_R}\")\n", + "print()\n", + "print(f\"FPGA_error_R -> {firmware.FPGA_error_R}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a22a5e7a-25f3-41b2-bd88-759da854c3d9", + "metadata": {}, + "outputs": [], + "source": [ + "# Boot user image\n", + "firmware.use_user_image()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2afc3b22-40a1-4a34-aa3d-46019bb6354b", + "metadata": {}, + "outputs": [], + "source": [ + "# Communication error while booting\n", + "firmware.TR_fpga_communication_error_R" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "152aa1e0-6da9-48b2-b36e-190d218350af", + "metadata": {}, + "outputs": [], + "source": [ + "# FPGA image (0 == factory image, 1 == user image)\n", + "firmware.FPGA_boot_image_RW " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb8f678d-5c5b-44df-8026-0db9e23de8f7", + "metadata": {}, + "outputs": [], + "source": [ + "# Other Firmware monitor points\n", + "print(f\"TR_fpga_mask_R -> {firmware.TR_fpga_mask_R}\")\n", + "print()\n", + "print(f\"TR_fpga_communication_error_R -> {firmware.TR_fpga_communication_error_R}\")\n", + "print()\n", + "print(f\"FPGA_firmware_version_R -> {firmware.FPGA_firmware_version_R}\")\n", + "print()\n", + "print(f\"FPGA_error_R -> {firmware.FPGA_error_R}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13870ada-0384-4a12-9d2f-7a5c387efe19", + "metadata": {}, + "outputs": [], + "source": [ + "# SDP points now should be available\n", + "sdp.FPGA_processing_enable_R" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7be6f84e-1673-4bcf-a331-6363d567294b", + "metadata": {}, + "outputs": [], + "source": [ + "# Reverse to factory image\n", + "sdp.off()\n", + "firmware.use_factory_image()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d9515bc-7a8d-4005-8696-869c426a57d6", + "metadata": {}, + "outputs": [], + "source": [ + "# FPGA image (0 == factory image, 1 == user image)\n", + "firmware.FPGA_boot_image_RW " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1eebd2f-3b15-4d9e-b31a-0b189b999985", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea3f514f-1780-4c7b-aeff-4d3dc704c4c3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "StationControl", + "language": "python", + "name": "stationcontrol" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index ba60f62ee..48d18866f 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -76,7 +76,7 @@ echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true # Devices list is used to explitly word split when supplied to commands, must # disable shellcheck SC2086 for each case. -DEVICES=(device-station-manager device-boot device-apsct device-ccd device-apspu device-sdp device-rcu2h device-rcu2l device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control device-configuration device-calibration) +DEVICES=(device-station-manager device-boot device-apsct device-ccd device-apspu device-sdpfirmware device-sdp device-rcu2h device-rcu2l device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control device-configuration device-calibration) SIMULATORS=(sdptr-sim rcu2h-sim rcu2l-sim unb2-sim apsct-sim apspu-sim ccd-sim) @@ -124,7 +124,7 @@ integration_test default integration_test tilebeam_performance "device-rcu2h device-rcu2l device-tilebeam device-antennafield" "${LOFAR20_DIR}/CDB/integrations/tilebeam_cluster_ConfigDb.json" -integration_test digitalbeam_performance "device-sdp device-rcu2h device-rcu2l device-digitalbeam device-beamlet device-antennafield" "${LOFAR20_DIR}/CDB/integrations/digitalbeam_cluster_ConfigDb.json" +integration_test digitalbeam_performance "device-sdpfirmware device-sdp device-rcu2h device-rcu2l device-digitalbeam device-beamlet device-antennafield" "${LOFAR20_DIR}/CDB/integrations/digitalbeam_cluster_ConfigDb.json" integration_test configuration "device-configuration" diff --git a/tangostationcontrol/docs/source/configure_station.rst b/tangostationcontrol/docs/source/configure_station.rst index 0796d0980..fa45b4c34 100644 --- a/tangostationcontrol/docs/source/configure_station.rst +++ b/tangostationcontrol/docs/source/configure_station.rst @@ -22,6 +22,10 @@ Without these settings, you will not obtain the associated functionality: :type: ``string`` +:SDPFirmware.OPC_Server_Name: Hostname of SDPTR. + + :type: ``string`` + :SDP.OPC_Server_Name: Hostname of SDPTR. :type: ``string`` diff --git a/tangostationcontrol/docs/source/devices/sdp.rst b/tangostationcontrol/docs/source/devices/sdp.rst index d3d8f4054..9432c6747 100644 --- a/tangostationcontrol/docs/source/devices/sdp.rst +++ b/tangostationcontrol/docs/source/devices/sdp.rst @@ -1,13 +1,7 @@ SDP --------------------- -The ``sdp == DeviceProxy("STAT/SDP/1")``` device controls the digital signal processing in SDP, performed by the firmware on the FPGAs on the Uniboards. Central to its operation is the mask (see also :ref:`attribute-masks`): - -:TR_fpga_mask_RW: Controls which FPGAs will actually be configured when attributes referring to FPGAs are written. - - :type: ``bool[N_fpgas]`` - -Typically, ``N_fpgas == 16``. +The ``sdp == DeviceProxy("STAT/SDP/1")``` device controls the digital signal processing in SDP, performed by the firmware on the FPGAs on the Uniboards. See the following links for a full description of the SDP monitoring and control points: @@ -23,10 +17,6 @@ The following points are significant for the operations of this device: :type: ``bool[N_fpgas]`` -:TR_fpga_communication_error_R: Whether the FPGAs can be reached. - - :type: ``bool[N_fpgas]`` - Frequency management ``````````````````````````` @@ -72,10 +62,6 @@ Error information These attributes summarise the basic state of the device. Any elements which are not present in ``FPGA_mask_RW`` will be ignored and thus not report errors: -:FPGA_error_R: Whether the FPGAs appear usable. - - :type: ``bool[N_fpgas]`` - :FPGA_procesing_error_R: Whether the FPGAs are processing their input from the RCUs. NB: This will also raise an error if the Waveform Generator is enabled. :type: ``bool[N_fpgas]`` @@ -126,7 +112,7 @@ Usage example For example, the following code inserts a wave on LBA subband 102 on FPGAs 8 - 11:: # configure FPGAs to control - sdp.TR_fpga_mask_RW = [False] * 8 + [True] * 4 + [False] * 4 + sdpfirmware.TR_fpga_mask_RW = [False] * 8 + [True] * 4 + [False] * 4 # configure waveform generator sdp.FPGA_wg_phase_RW = [[0] * 12] * 16 diff --git a/tangostationcontrol/docs/source/devices/sdpfirmware.rst b/tangostationcontrol/docs/source/devices/sdpfirmware.rst new file mode 100644 index 000000000..e7328e752 --- /dev/null +++ b/tangostationcontrol/docs/source/devices/sdpfirmware.rst @@ -0,0 +1,34 @@ +SDP Firmware +--------------------- + +The ``sdpfirmware == DeviceProxy("STAT/SDPFirmware/1")``` device controls the firmware functionalities related to the digital signal processing in SDP device. Central to its operation is the mask (see also :ref:`attribute-masks`): + +:TR_fpga_mask_RW: Controls which FPGAs will actually be configured when attributes referring to FPGAs are written. + + :type: ``bool[N_fpgas]`` + +Typically, ``N_fpgas == 16``. + +See the following links for a full description of the SDP monitoring and control points: + +- https://support.astron.nl/confluence/pages/viewpage.action?spaceKey=L2M&title=L2+STAT+Decision%3A+SC+-+SDP+OPC-UA+interface +- https://plm.astron.nl/polarion/#/project/LOFAR2System/wiki/L2%20Interface%20Control%20Documents/SC%20to%20SDP%20ICD + +Basic configuration +````````````````````` + +The following points are significant for the operations of this device: + +:TR_fpga_communication_error_R: Whether the FPGAs can be reached. + + :type: ``bool[N_fpgas]`` + +Error information +``````````````````````````` + +These attributes summarise the basic state of the device. Any elements which are not present in ``FPGA_mask_RW`` will be ignored and thus not report errors: + +:FPGA_error_R: Whether the FPGAs appear usable. + + :type: ``bool[N_fpgas]`` + diff --git a/tangostationcontrol/docs/source/faq.rst b/tangostationcontrol/docs/source/faq.rst index 4e2264ae0..d02726dc6 100644 --- a/tangostationcontrol/docs/source/faq.rst +++ b/tangostationcontrol/docs/source/faq.rst @@ -77,7 +77,7 @@ In general, the settings ought to be correct after the following: The ``sdp.set_defaults()`` command, followed by ``sst.set_defaults()`` / ``xst.set_defaults()``, should reset that device to its default settings, which should result in a working system again. Also, check the following settings: -- ``sdp.TR_fpga_mask_RW[x] == True``, to make sure we're actually configuring the FPGAs, +- ``sdpfirmware.TR_fpga_mask_RW[x] == True``, to make sure we're actually configuring the FPGAs, - ``sdp.FPGA_communication_error_R[x] == False``, to verify the FPGAs can be reached by SDP. - ``sdp.FPGA_processing_enabled_R[x] == True``, to verify that the FPGAs are processing, or the values and timestamps will be zero, - ``sdp.FPGA_signal_input_bsn_R`` is increasing, to verify that the FPGA processing is subject to the clock. diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index acb3d1bae..0f731794b 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -24,6 +24,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st devices/tilebeam-digitalbeam devices/beamlet devices/rcu2h-rcu2l + devices/sdpfirmware devices/sdp devices/bst-sst-xst devices/boot diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index 3894847c2..538b6514d 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -48,6 +48,7 @@ console_scripts = l2ss-observationcontrol = tangostationcontrol.devices.observation_control:main l2ss-rcu2h = tangostationcontrol.devices.recv.rcu2h:main l2ss-rcu2l = tangostationcontrol.devices.recv.rcu2l:main + l2ss-sdpfirmware = tangostationcontrol.devices.sdp.firmware:main l2ss-sdp = tangostationcontrol.devices.sdp.sdp:main l2ss-bst = tangostationcontrol.devices.sdp.bst:main l2ss-sst = tangostationcontrol.devices.sdp.sst:main diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md index df47d0be1..eb7aa8bc6 100644 --- a/tangostationcontrol/tangostationcontrol/devices/README.md +++ b/tangostationcontrol/tangostationcontrol/devices/README.md @@ -10,7 +10,8 @@ If a new device is added, it will (likely) need to be referenced in several plac - Add the device hierarchies in `CDB/hierarchies` to define the power, control and clock configuration, - Adjust `docker-compose/jupyterlab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter-Lab, - Adjust `tangostationcontrol/tangostationcontrol/devices/boot.py` to add the device to the station initialisation sequence, -- Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned (current _unused_ port value: 5727), a unique 58xx port for ZMQ events, and a unique 59xx port for ZMQ heartbeat +- Adjust `tangostationcontrol/tangostationcontrol/devices/docker.py` to have the device container available as R and RW attributes, +- Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned (current _unused_ port value: 5728), a unique 58xx port for ZMQ events, and a unique 59xx port for ZMQ heartbeat - Adjust `tangostationcontrol/setup.cfg` to add an entry point for the device in the package installation, - Add to `tangostationcontrol/tangostationcontrol/integration_test/default/devices/` to add an integration test, - Adjust `sbin/run_integration_test.sh` to have the device started when running the integration tests, @@ -19,5 +20,4 @@ If a new device is added, it will (likely) need to be referenced in several plac - Add to `tangostationcontrol/docs/source/devices/` to mention the device in the end-user documentation. - Adjust `tangostationcontrol/docs/source/index.rst` to include the newly created file in `docs/source/devices/`. - Adjust `docker-compose/tango-prometheus-exporter/lofar2-policy.json` (in all lowercase) to include this device in the prometheus exporter -- Adjust `docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json` (in all lowercase) to include this device in the prometheus exporter -- Adjust `tangostationcontrol/tangostationcontrol/devices/docker.py` to have the device container available as R and RW attributes. +- Adjust `docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json` (in all lowercase) to include this device in the prometheus exporter. diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py index 509df3cd8..a401fbb02 100644 --- a/tangostationcontrol/tangostationcontrol/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -268,6 +268,7 @@ class Boot(LOFARDevice): "STAT/RCU2H/1", "STAT/RCU2L/1", "STAT/UNB2/1", # Uniboards host SDP, so initialise them first + "STAT/SDPFirmware/1", "STAT/SDP/1", # SDP controls the mask for SST/XST/BST/Beamlet, so initialise it first "STAT/BST/1", diff --git a/tangostationcontrol/tangostationcontrol/devices/docker.py b/tangostationcontrol/tangostationcontrol/devices/docker.py index 89dc8e7b9..0af26fce4 100644 --- a/tangostationcontrol/tangostationcontrol/devices/docker.py +++ b/tangostationcontrol/tangostationcontrol/devices/docker.py @@ -128,6 +128,14 @@ class Docker(LOFARDevice): datatype=bool, access=AttrWriteType.READ_WRITE, ) + device_sdpfirmware_R = AttributeWrapper( + comms_annotation={"container": "device-sdpfirmware"}, datatype=bool + ) + device_sdpfirmware_RW = AttributeWrapper( + comms_annotation={"container": "device-sdpfirmware"}, + datatype=bool, + access=AttrWriteType.READ_WRITE, + ) device_sdp_R = AttributeWrapper( comms_annotation={"container": "device-sdp"}, datatype=bool ) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py index 7c1356e4e..46d829388 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py @@ -434,7 +434,7 @@ class Beamlet(OPCUADevice): def read_subband_select_RW(self): # We can only return a single value, so we assume the FPGA is configured coherently. # Which is something that is to be checked by an independent monitoring system anyway. - mask = self.sdp_proxy.TR_fpga_mask_RW + mask = self.sdpfirmware_proxy.TR_fpga_mask_RW subbands = self.read_attribute("FPGA_beamlet_subband_select_RW") subbands_in_mask = [s for idx, s in enumerate(subbands) if mask[idx]] @@ -467,6 +467,9 @@ class Beamlet(OPCUADevice): def configure_for_initialise(self): super().configure_for_initialise() + self.sdpfirmware_proxy = DeviceProxy("STAT/SDPFirmware/1") + self.sdpfirmware_proxy.set_source(DevSource.DEV) + self.sdp_proxy = DeviceProxy(self.SDP_device) self.sdp_proxy.set_source(DevSource.DEV) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py index 7e104c211..9f1a61a49 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py @@ -23,6 +23,8 @@ __all__ = ["BST", "main"] class BST(Statistics): + """BST Device Server for LOFAR2.0""" + STATISTICS_COLLECTOR_CLASS = BSTCollector # ----------------- @@ -164,7 +166,7 @@ class BST(Statistics): FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=N_pn) def read_FPGA_processing_error_R(self): - return self.sdp_proxy.TR_fpga_mask_RW & ( + return self.sdpfirmware_proxy.TR_fpga_mask_RW & ( ~self.read_attribute("FPGA_bst_offload_enable_R") ) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py b/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py new file mode 100644 index 000000000..737765a3c --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py @@ -0,0 +1,146 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +""" SDP Firmware Device Server for LOFAR2.0 + +""" + +import logging +import numpy +from attribute_wrapper.attribute_wrapper import AttributeWrapper +from tango import AttrWriteType, DebugIt + +# PyTango imports +from tango.server import device_property, attribute, command + +# Additional import +from tangostationcontrol.common.constants import N_pn +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import log_exceptions +from tangostationcontrol.common.lofar_logging import device_logging_to_python +from tangostationcontrol.devices.interfaces.opcua_device import OPCUADevice +from tangostationcontrol.devices.device_decorators import only_in_states +from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES + +logger = logging.getLogger() + +__all__ = ["SDPFirmware", "main"] + + +@device_logging_to_python() +class SDPFirmware(OPCUADevice): + """SDP Firmware Device server for LOFAR 2.0""" + + # ----------------- + # Device Properties + # ----------------- + + TR_fpga_mask_RW_default = device_property( + dtype="DevVarBooleanArray", mandatory=False, default_value=[True] * N_pn + ) + + TRANSLATOR_DEFAULT_SETTINGS = ["TR_fpga_mask_RW"] + + # ---------- + # Attributes + # ---------- + + TR_fpga_mask_R = AttributeWrapper( + comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(N_pn,) + ) + TR_fpga_mask_RW = AttributeWrapper( + comms_annotation=["TR_fpga_mask_RW"], + datatype=bool, + dims=(N_pn,), + access=AttrWriteType.READ_WRITE, + ) + TR_fpga_communication_error_R = AttributeWrapper( + comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(N_pn,) + ) + FPGA_boot_image_R = AttributeWrapper( + comms_annotation=["FPGA_boot_image_R"], + datatype=numpy.int32, + dims=(N_pn,), + doc="Active FPGA image (0=factory, 1=user)", + ) + FPGA_boot_image_RW = AttributeWrapper( + comms_annotation=["FPGA_boot_image_RW"], + datatype=numpy.int32, + dims=(N_pn,), + access=AttrWriteType.READ_WRITE, + ) + FPGA_firmware_version_R = AttributeWrapper( + comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,) + ) + + # ---------- + # Summarising Attributes + # ---------- + + FPGA_error_R = attribute( + dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed" + ) + + def read_FPGA_error_R(self): + return self.read_attribute("TR_fpga_mask_R") & ( + self.read_attribute("TR_fpga_communication_error_R") + | (self.read_attribute("FPGA_firmware_version_R") == "") + # we cannot assume all inputs of an FPGA are working until we have a mask for it + # | (self.read_attribute("FPGA_jesd204b_csr_dev_syncn_R") == 0).any(axis=1) + ) + + # -------- + # overloaded functions + # -------- + def _prepare_hardware(self): + """Boot the SDP Firmware user image""" + # FPGAs that are actually reachable and we care about + wait_for = ~( + self.read_attribute("TR_fpga_communication_error_R") + ) & self.read_attribute("TR_fpga_mask_R") + + # Order the correct firmare to be loaded + self.proxy.FPGA_boot_image_RW = [1] * N_pn + + # Wait for the firmware to be loaded (ignoring masked out elements) + self.wait_attribute( + "FPGA_boot_image_R", lambda attr: ((attr == 1) | ~wait_for).all(), 60 + ) + + def _disable_hardware(self): + """Use the SDP Firmware factory image""" + # Save actual mask values + TR_fpga_mask = self.proxy.TR_fpga_mask_RW + # Set the mask to all Trues + self.proxy.TR_fpga_mask_RW = [True] * N_pn + # Boot the boot image firmware + self.proxy.FPGA_boot_image_RW = [0] * N_pn + # Restore the mask + self.proxy.TR_fpga_mask_RW = TR_fpga_mask + + # -------- + # Commands + # -------- + @command() + @only_in_states(DEFAULT_COMMAND_STATES) + @DebugIt() + @log_exceptions() + def use_user_image(self): + """Boot the SDP Firmware user image""" + self._prepare_hardware() + + @command() + @only_in_states(DEFAULT_COMMAND_STATES) + @DebugIt() + @log_exceptions() + def use_factory_image(self): + """Use the SDP Firmware factory image""" + self._disable_hardware() + + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the SDP Firmware module.""" + return entry(SDPFirmware, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py index db3f3718e..53b675303 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py @@ -7,7 +7,7 @@ import numpy from attribute_wrapper.attribute_wrapper import AttributeWrapper -from tango import AttrWriteType +from tango import AttrWriteType, DeviceProxy, DevSource # PyTango imports from tango.server import device_property, attribute @@ -36,14 +36,12 @@ __all__ = ["SDP", "main"] @device_logging_to_python() class SDP(OPCUADevice): + """SDP Device Server for LOFAR2.0""" + # ----------------- # Device Properties # ----------------- - TR_fpga_mask_RW_default = device_property( - dtype="DevVarBooleanArray", mandatory=False, default_value=[True] * N_pn - ) - FPGA_processing_enable_RW_default = device_property( dtype="DevVarBooleanArray", mandatory=False, default_value=[True] * N_pn ) @@ -95,27 +93,10 @@ class SDP(OPCUADevice): dtype="DevULong", mandatory=False, default_value=CLK_200_MHZ ) - TRANSLATOR_DEFAULT_SETTINGS = ["TR_fpga_mask_RW"] - # ---------- # Attributes # ---------- - FPGA_firmware_version_R = AttributeWrapper( - comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,) - ) - FPGA_boot_image_R = AttributeWrapper( - comms_annotation=["FPGA_boot_image_R"], - datatype=numpy.int32, - dims=(N_pn,), - doc="Active FPGA image (0=factory, 1=user)", - ) - FPGA_boot_image_RW = AttributeWrapper( - comms_annotation=["FPGA_boot_image_RW"], - datatype=numpy.int32, - dims=(N_pn,), - access=AttrWriteType.READ_WRITE, - ) FPGA_global_node_index_R = AttributeWrapper( comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, @@ -339,18 +320,6 @@ class SDP(OPCUADevice): dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE, ) - TR_fpga_mask_R = AttributeWrapper( - comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(N_pn,) - ) - TR_fpga_mask_RW = AttributeWrapper( - comms_annotation=["TR_fpga_mask_RW"], - datatype=bool, - dims=(N_pn,), - access=AttrWriteType.READ_WRITE, - ) - TR_fpga_communication_error_R = AttributeWrapper( - comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(N_pn,) - ) TR_sdp_config_first_fpga_nr_R = AttributeWrapper( comms_annotation=["TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32 ) @@ -520,7 +489,7 @@ class SDP(OPCUADevice): # (0=LBA, 1=HBA) if first_input == "HBA": antenna_band[idx] = 1 - self.FPGA_sdp_info_antenna_band_index_RW = antenna_band + self.proxy.FPGA_sdp_info_antenna_band_index_RW = antenna_band def read_nyquist_zone_RW(self): return self._nyquist_zone @@ -547,17 +516,19 @@ class SDP(OPCUADevice): # Update the packet headers. self.proxy.FPGA_sdp_info_nyquist_sampling_zone_index_RW = nyquist_zone_per_fpga - # Use the correct spectral inversion setting, to make sure the subbands are ascending in frequency + # Use the correct spectral inversion setting, + # to make sure the subbands are ascending in frequency self.proxy.FPGA_spectral_inversion_RW = self._nyquist_zone % 2 def read_clock_RW(self): - # We can only return a single value, so we assume the FPGA is configured coherently. Which is something - # that is to be checked by an independent monitoring system anyway. - mask = self.read_attribute("TR_fpga_mask_RW") + # We can only return a single value, so we assume the FPGA is configured coherently. + # Which is something that is to be checked by an independent monitoring system anyway. + mask = self.sdpfirmware_proxy.TR_fpga_mask_RW clocks = self.read_attribute("FPGA_pps_expected_cnt_RW") clocks_in_mask = [clock for idx, clock in enumerate(clocks) if mask[idx]] - # We return first setting within the mask. If there are no FPGAs selected at all, just return a sane default. + # We return first setting within the mask. + # If there are no FPGAs selected at all, just return a sane default. return ( numpy.uint32(clocks_in_mask[0]) if clocks_in_mask else self.clock_RW_default ) @@ -604,9 +575,6 @@ class SDP(OPCUADevice): # ---------- # Summarising Attributes # ---------- - FPGA_error_R = attribute( - dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed" - ) FPGA_processing_error_R = attribute( dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed" ) @@ -614,22 +582,14 @@ class SDP(OPCUADevice): dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed" ) - def read_FPGA_error_R(self): - return self.read_attribute("TR_fpga_mask_R") & ( - self.read_attribute("TR_fpga_communication_error_R") - | (self.read_attribute("FPGA_firmware_version_R") == "") - # we cannot assume all inputs of an FPGA are working until we have a mask for it - # | (self.read_attribute("FPGA_jesd204b_csr_dev_syncn_R") == 0).any(axis=1) - ) - def read_FPGA_processing_error_R(self): - return self.read_attribute("TR_fpga_mask_R") & ( + return self.sdpfirmware_proxy.TR_fpga_mask_R & ( ~self.read_attribute("FPGA_processing_enable_R") - | (self.read_attribute("FPGA_boot_image_R") <= 0) + | (self.sdpfirmware_proxy.FPGA_boot_image_R <= 0) ) def read_FPGA_input_error_R(self): - return self.read_attribute("TR_fpga_mask_R") & ( + return self.sdpfirmware_proxy.TR_fpga_mask_R & ( self.read_attribute("FPGA_wg_enable_R").any(axis=1) | (self.read_attribute("FPGA_signal_input_rms_R") == 0).any(axis=1) ) @@ -640,6 +600,9 @@ class SDP(OPCUADevice): def configure_for_initialise(self): super().configure_for_initialise() + # Retrieve reference to SDP Firmware + self.sdpfirmware_proxy = DeviceProxy("STAT/SDPFirmware/1") + self.sdpfirmware_proxy.set_source(DevSource.DEV) # Store which type of antenna and band filter is connected to each input. # @@ -647,31 +610,6 @@ class SDP(OPCUADevice): self._antenna_type = numpy.array([["LBA"] * S_pn] * N_pn, dtype=str) self._nyquist_zone = numpy.array([[0] * S_pn] * N_pn, dtype=numpy.uint32) - def _prepare_hardware(self): - # FPGAs that are actually reachable and we care about - wait_for = ~( - self.read_attribute("TR_fpga_communication_error_R") - ) & self.read_attribute("TR_fpga_mask_R") - - # Order the correct firmare to be loaded - self.proxy.FPGA_boot_image_RW = [1] * N_pn - - # Wait for the firmware to be loaded (ignoring masked out elements) - self.wait_attribute( - "FPGA_boot_image_R", lambda attr: ((attr == 1) | ~wait_for).all(), 60 - ) - - def _disable_hardware(self): - """Disable the SDP hardware.""" - # Save actual mask values - TR_fpga_mask = self.proxy.TR_fpga_mask_RW - # Set the mask to all Trues - self.TR_fpga_mask_RW = [True] * N_pn - # Boot the boot image firmware - self.FPGA_boot_image_RW = [0] * N_pn - # Restore the mask - self.TR_fpga_mask_RW = TR_fpga_mask - # -------- # Commands # -------- diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py index 3d5c53494..d1b3502f4 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py @@ -25,6 +25,8 @@ __all__ = ["SST", "main"] class SST(Statistics): + """SST Device Server for LOFAR2.0""" + STATISTICS_COLLECTOR_CLASS = SSTCollector # ----------------- @@ -198,7 +200,7 @@ class SST(Statistics): FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=N_pn) def read_FPGA_processing_error_R(self): - return self.sdp_proxy.TR_fpga_mask_RW & ( + return self.sdpfirmware_proxy.TR_fpga_mask_RW & ( ~self.read_attribute("FPGA_sst_offload_enable_R") ) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py index 4beee6aeb..e546901c5 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py @@ -8,6 +8,7 @@ # Additional import import asyncio import logging +import numpy from attribute_wrapper.attribute_wrapper import AttributeWrapper from tango import DeviceProxy, DevSource @@ -21,12 +22,12 @@ from tangostationcontrol.devices.interfaces.opcua_device import OPCUADevice logger = logging.getLogger() -import numpy - __all__ = ["Statistics"] class Statistics(OPCUADevice): + """Base device for Statistics (SST/BST/XST)""" + # In derived classes, set this to a subclass of StatisticsCollector @property def STATISTICS_COLLECTOR_CLASS(self): @@ -152,7 +153,7 @@ class Statistics(OPCUADevice): try: self.statistics_client.sync_stop() - except Exception as e: + except Exception as _e: logger.exception( "Exception while stopping statistics_client in configure_for_off. Exception ignored" ) @@ -161,7 +162,6 @@ class Statistics(OPCUADevice): @log_exceptions() def configure_for_initialise(self): - """user code here. is called when the sate is set to INIT""" """Initialises the attributes and properties of the statistics device.""" super().configure_for_initialise() @@ -194,8 +194,8 @@ class Statistics(OPCUADevice): _ = future.result() # proxy the SDP device in case we need the FPGA mask - self.sdp_proxy = DeviceProxy("STAT/SDP/1") - self.sdp_proxy.set_source(DevSource.DEV) + self.sdpfirmware_proxy = DeviceProxy("STAT/SDPFirmware/1") + self.sdpfirmware_proxy.set_source(DevSource.DEV) async def _connect_statistics(self): # map an access helper class @@ -203,13 +203,14 @@ class Statistics(OPCUADevice): try: if i.comms_id == StatisticsClient: await i.async_set_comm_client(self, self.statistics_client) - except Exception as e: + except Exception as exc: # use the pass function instead of setting read/write fails i.set_pass_func(self) logger.warning( - "error while setting the sst attribute {} read/write function. {}. using pass function instead".format( - i, e - ) + "error while setting the sst attribute %s read/write function. %s. \ + Using pass function instead", + i, + exc, ) await self.statistics_client.start() diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py index 88ef3b59c..bcb7fbbf8 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py @@ -34,6 +34,8 @@ __all__ = ["XST", "main"] class XST(Statistics): + """XST Device Server for LOFAR2.0""" + STATISTICS_COLLECTOR_CLASS = XSTCollector # ----------------- @@ -704,7 +706,7 @@ class XST(Statistics): FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=N_pn) def read_FPGA_processing_error_R(self): - return self.sdp_proxy.TR_fpga_mask_RW & ( + return self.sdpfirmware_proxy.TR_fpga_mask_RW & ( ~self.read_attribute("FPGA_xst_offload_enable_R") | ~self.read_attribute("FPGA_xst_processing_enable_R") ) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/configuration/configDB/simulators_ConfigDb.json b/tangostationcontrol/tangostationcontrol/integration_test/configuration/configDB/simulators_ConfigDb.json index 12ccd43e7..07957d944 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/configuration/configDB/simulators_ConfigDb.json +++ b/tangostationcontrol/tangostationcontrol/integration_test/configuration/configDB/simulators_ConfigDb.json @@ -183,6 +183,25 @@ } } }, + "SDPFirmware": { + "STAT": { + "SDPFirmware": { + "STAT/SDPFirmware/1": { + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, "SDP": { "STAT": { "SDP": { diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/interfaces/test_power_hierarchy.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/interfaces/test_power_hierarchy.py index 541549b35..813c81aa6 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/interfaces/test_power_hierarchy.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/interfaces/test_power_hierarchy.py @@ -11,7 +11,7 @@ from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy class TestPowerHierarchy(base.IntegrationTestCase): stationmanager_name = "STAT/StationManager/1" psoc_name = "STAT/PSOC/1" - sdp_name = "STAT/SDP/1" + sdpfirmware_name = "STAT/SDPFirmware/1" def setUp(self): return super().setUp() @@ -34,26 +34,21 @@ class TestPowerHierarchy(base.IntegrationTestCase): psoc_proxy.off() power_properties = { "Power_Parent": ["STAT/StationManager/1"], - "Power_Children": ["STAT/CCD/1", "STAT/SDP/1"], + "Power_Children": ["STAT/CCD/1", "STAT/SDPFirmware/1"], } psoc_proxy.put_property(power_properties) return psoc_proxy - def setup_sdp_proxy(self): - """Initialise SDP device""" - sdp_proxy = TestDeviceProxy(self.sdp_name) - sdp_proxy.off() + def setup_sdpfirmware_proxy(self): + """Initialise SDP Firmware device""" + sdpfirmware_proxy = TestDeviceProxy(self.sdpfirmware_name) + sdpfirmware_proxy.off() power_properties = { "Power_Parent": ["STAT/PSOC/1"], - "Power_Children": [ - "STAT/Beamlet/1", - "STAT/BST/1", - "STAT/SST/1", - "STAT/XST/1", - ], + "Power_Children": ["STAT/SDP/1"], } - sdp_proxy.put_property(power_properties) - return sdp_proxy + sdpfirmware_proxy.put_property(power_properties) + return sdpfirmware_proxy def test_power_sequence_definition(self): """ @@ -61,18 +56,19 @@ class TestPowerHierarchy(base.IntegrationTestCase): """ self.setup_stationmanager_proxy() self.setup_psoc_proxy() - self.setup_sdp_proxy() + self.setup_sdpfirmware_proxy() stationmanager_ph = PowerHierarchy() stationmanager_ph.init(self.stationmanager_name) children_hierarchy = stationmanager_ph.children(depth=2) # Check if PSOC is child of StationManager - self.assertTrue(self.psoc_name in children_hierarchy.keys()) + self.assertTrue(self.psoc_name in children_hierarchy) self.assertTrue( isinstance(children_hierarchy["STAT/PSOC/1"]["proxy"], DeviceProxy) ) - # Check if SDP is child of PSOC + # Check if SDPFirmware is child of PSOC self.assertTrue( - self.sdp_name in children_hierarchy["STAT/PSOC/1"]["children"].keys() + self.sdpfirmware_name + in children_hierarchy["STAT/PSOC/1"]["children"].keys() ) # Check if PSOC retrieves correctly its parent state (StationManager -> ON) psoc_ph = PowerHierarchy() diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py index 945b32160..ab763ba84 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py @@ -35,6 +35,7 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): } ) self.recv_proxy = self.setup_recv_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.addCleanup(self.shutdown_recv) @@ -72,6 +73,13 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): recv_proxy.set_defaults() return recv_proxy + def setup_sdpfirmware_proxy(self): + # setup SDPFirmware + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP sdp_proxy = TestDeviceProxy("STAT/SDP/1") diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_calibration.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_calibration.py index 246cddd79..49ff5e3d7 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_calibration.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_calibration.py @@ -80,6 +80,7 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): } ) self.recv_proxy = self.setup_recv_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.addCleanup(self.shutdown_recv) @@ -125,6 +126,13 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): recv_proxy.set_defaults() return recv_proxy + def setup_sdpfirmware_proxy(self): + # setup SDP + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP sdp_proxy = TestDeviceProxy("STAT/SDP/1") diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py index cadb3af2c..87a62bfb5 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py @@ -35,6 +35,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): antennafield_iden = "STAT/AntennaField/HBA" beamlet_iden = "STAT/Beamlet/1" recv_iden = "STAT/RCU2H/1" + sdpfirmware_iden = "STAT/SDPFirmware/1" sdp_iden = "STAT/SDP/1" def setUp(self): @@ -47,6 +48,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): self.addCleanup(TestDeviceProxy.test_device_turn_off, self.recv_iden) self.recv_proxy = self.setup_recv_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.beamlet_proxy = self.initialise_beamlet_proxy() @@ -70,6 +72,14 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): beamlet_proxy.set_defaults() return beamlet_proxy + def setup_sdpfirmware_proxy(self): + # setup SDPFirmware + sdpfirmware_proxy = TestDeviceProxy(self.sdpfirmware_iden) + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + sdpfirmware_proxy.set_defaults() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP, on which this device depends sdp_proxy = TestDeviceProxy(self.sdp_iden) @@ -109,6 +119,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): self.addCleanup(TestDeviceProxy.test_device_turn_off, self.sdp_iden) self.addCleanup(TestDeviceProxy.test_device_turn_off, self.antennafield_iden) + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok) @@ -152,6 +163,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): self.addCleanup(TestDeviceProxy.test_device_turn_off, self.sdp_iden) self.addCleanup(TestDeviceProxy.test_device_turn_off, self.antennafield_iden) + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok) @@ -198,6 +210,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): self.addCleanup(TestDeviceProxy.test_device_turn_off, self.sdp_iden) self.addCleanup(TestDeviceProxy.test_device_turn_off, self.antennafield_iden) + self.setup_sdpfirmware_proxy() self.setup_sdp_proxy() self.antennafield_proxy = self.setup_antennafield_proxy( self.antenna_qualities_ok, self.antenna_use_ok @@ -251,6 +264,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): self.addCleanup(TestDeviceProxy.test_device_turn_off, self.sdp_iden) self.addCleanup(TestDeviceProxy.test_device_turn_off, self.antennafield_iden) + self.setup_sdpfirmware_proxy() self.setup_sdp_proxy() self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py index dd375e946..28325f09d 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py @@ -122,6 +122,7 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase): super().setUp("STAT/Observation/1") self.VALID_JSON = TestObservationBase.VALID_JSON self.recv_proxy = self.setup_recv_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.antennafield_proxy = self.setup_antennafield_proxy() self.beamlet_proxy = self.setup_beamlet_proxy() @@ -136,6 +137,13 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase): recv_proxy.set_defaults() return recv_proxy + def setup_sdpfirmware_proxy(self): + # setup SDPFirmware + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP sdp_proxy = TestDeviceProxy("STAT/SDP/1") diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py index 4111ed8b4..890e12e14 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py @@ -121,6 +121,7 @@ class TestObservationControlDevice(AbstractTestBases.TestDeviceBase): self.recv_proxy = self.setup_recv_proxy() self.antennafield_proxy = self.setup_antennafield_proxy() self.beamlet_proxy = self.setup_beamlet_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() self.digitalbeam_proxy = self.setup_digitalbeam_proxy() self.tilebeam_proxy = self.setup_tilebeam_proxy() @@ -133,6 +134,13 @@ class TestObservationControlDevice(AbstractTestBases.TestDeviceBase): recv_proxy.set_defaults() return recv_proxy + def setup_sdpfirmware_proxy(self): + # setup SDPFirmware + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP sdp_proxy = TestDeviceProxy("STAT/SDP/1") diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdp.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdp.py index ca1337802..a49f76cb9 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdp.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdp.py @@ -1,8 +1,6 @@ # Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) # SPDX-License-Identifier: Apache-2.0 -from tangostationcontrol.common.constants import N_pn - from .base import AbstractTestBases @@ -10,12 +8,3 @@ class TestDeviceSDP(AbstractTestBases.TestDeviceBase): def setUp(self): """Intentionally recreate the device object in each test""" super().setUp("STAT/SDP/1") - - def test_device_sdp_read_attribute(self): - """Test if we can read an attribute obtained over OPC-UA""" - - self.proxy.warm_boot() - - self.assertListEqual( - [True] * N_pn, list(self.proxy.TR_fpga_communication_error_R) - ) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdpfirmware.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdpfirmware.py new file mode 100644 index 000000000..bce1b837a --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sdpfirmware.py @@ -0,0 +1,21 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +from tangostationcontrol.common.constants import N_pn + +from .base import AbstractTestBases + + +class TestDeviceSDPFirmware(AbstractTestBases.TestDeviceBase): + def setUp(self): + """Intentionally recreate the device object in each test""" + super().setUp("STAT/SDPFirmware/1") + + def test_device_sdpfirmware_read_attribute(self): + """Test if we can read an attribute obtained over OPC-UA""" + + self.proxy.warm_boot() + + self.assertListEqual( + [True] * N_pn, list(self.proxy.TR_fpga_communication_error_R) + ) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sst.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sst.py index b54bdc5fc..6b2565f7f 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sst.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_sst.py @@ -18,10 +18,19 @@ class TestDeviceSST(AbstractTestBases.TestDeviceBase): def test_device_read_all_attributes(self): # We need to connect to SDP first to read some of our attributes + self.sdpfirmware_proxy = self.setup_sdpfirmware() self.sdp_proxy = self.setup_sdp() super().test_device_read_all_attributes() + def setup_sdpfirmware(self): + # setup SDP Firmware + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + sdpfirmware_proxy.set_defaults() + return sdpfirmware_proxy + def setup_sdp(self): # setup SDP, on which this device depends sdp_proxy = TestDeviceProxy("STAT/SDP/1") diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_temperature_manager.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_temperature_manager.py index 393f72eb9..c33129378 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_temperature_manager.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_temperature_manager.py @@ -24,6 +24,7 @@ class TestDeviceTemperatureManager(AbstractTestBases.TestDeviceBase): def setUp(self): """Intentionally recreate the device object in each test""" self.recv_proxy = self.setup_recv_proxy() + self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() super().setUp("STAT/TemperatureManager/1") @@ -40,6 +41,14 @@ class TestDeviceTemperatureManager(AbstractTestBases.TestDeviceBase): self.assertTrue(recv_proxy.is_attribute_polled("HBAT_LED_on_RW")) return recv_proxy + def setup_sdpfirmware_proxy(self): + # setup SDPFirmware + sdpfirmware_proxy = TestDeviceProxy("STAT/SDPFirmware/1") + sdpfirmware_proxy.off() + sdpfirmware_proxy.warm_boot() + sdpfirmware_proxy.set_defaults() + return sdpfirmware_proxy + def setup_sdp_proxy(self): # setup SDP, on which this device depends sdp_proxy = TestDeviceProxy("STAT/SDP/1") @@ -60,6 +69,7 @@ class TestDeviceTemperatureManager(AbstractTestBases.TestDeviceBase): self.proxy.initialise() self.proxy.on() self.setup_recv_proxy() + self.setup_sdpfirmware_proxy() self.setup_sdp_proxy() # make sure none of the devices are in the OFF or FAULT state. Any other state is fine diff --git a/tangostationcontrol/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py b/tangostationcontrol/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py index 6e035960c..9bc5bf258 100644 --- a/tangostationcontrol/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py @@ -29,19 +29,21 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): antenna_field_proxies, beamlet_proxies, beam_proxies, + sdpfirmware_proxies, sdp_proxies, recv_proxies, tracking=False, ): # Setup multi SDP / recv and separate hba / lba antennafield / digitalbeams for i, item in enumerate(["HBA", "LBA"]): + sdpfirmware_proxies.append(TestDeviceProxy(f"STAT/SDPFirmware/{i + 1}")) sdp_proxies.append(TestDeviceProxy(f"STAT/SDP/{i + 1}")) beamlet_proxies.append(TestDeviceProxy(f"STAT/Beamlet/{i + 1}")) antenna_field_proxies.append(TestDeviceProxy(f"STAT/AntennaField/{item}")) beam_proxies.append(TestDeviceProxy(f"STAT/DigitalBeam/{item}")) recv_proxies.append(TestDeviceProxy(f"STAT/RCU2H/{i + 1}")) - for sdp in sdp_proxies + recv_proxies + beamlet_proxies: + for sdp in sdpfirmware_proxies + sdp_proxies + recv_proxies + beamlet_proxies: sdp.off() self.assertTrue(sdp.state() is DevState.OFF) sdp.warm_boot() @@ -109,6 +111,7 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): antenna_field_proxies = [] beamlet_proxies = [] beam_proxies = [] + sdpfirmware_proxies = [] sdp_proxies = [] recv_proxies = [] @@ -116,6 +119,7 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): antenna_field_proxies=antenna_field_proxies, beamlet_proxies=beamlet_proxies, beam_proxies=beam_proxies, + sdpfirmware_proxies=sdpfirmware_proxies, sdp_proxies=sdp_proxies, recv_proxies=recv_proxies, tracking=False, @@ -153,6 +157,7 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): antenna_field_proxies = [] beamlet_proxies = [] beam_proxies = [] + sdpfirmware_proxies = [] sdp_proxies = [] recv_proxies = [] @@ -160,6 +165,7 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): antenna_field_proxies=antenna_field_proxies, beamlet_proxies=beamlet_proxies, beam_proxies=beam_proxies, + sdpfirmware_proxies=sdpfirmware_proxies, sdp_proxies=sdp_proxies, recv_proxies=recv_proxies, tracking=True, -- GitLab