From 44e4974db73c3fe038f7dba81c7aacad48878162 Mon Sep 17 00:00:00 2001 From: Auke Klazema <klazema@astron.nl> Date: Wed, 6 Apr 2022 16:01:29 +0200 Subject: [PATCH] L2SS-704: Implement AntennaField device with tests Integration tests are minimal and will be followed up with another ticket. The reason for this is that the RECV device talks to the simulator that does not mimic the real behavior. This means that a setting of RW point doesn't reflect in a R point change. This makes integrating testing very limited in comparison to the unit testing. --- .gitlab-ci.yml | 12 + CDB/LOFAR_ConfigDb.json | 7 + docker-compose/device-antennafield.yml | 47 +++ .../startup/01-devices.py | 3 +- sbin/run_integration_test.sh | 6 +- .../docs/source/devices/antennafield.rst | 4 + tangostationcontrol/docs/source/index.rst | 1 + tangostationcontrol/setup.cfg | 1 + .../devices/antennafield.py | 239 ++++++++++++++ .../tangostationcontrol/devices/boot.py | 1 + .../devices/test_device_antennafield.py | 32 ++ .../test/devices/test_antennafield_device.py | 295 ++++++++++++++++++ .../test/devices/test_lofar_device.py | 1 + 13 files changed, 645 insertions(+), 4 deletions(-) create mode 100644 docker-compose/device-antennafield.yml create mode 100644 tangostationcontrol/docs/source/devices/antennafield.rst create mode 100644 tangostationcontrol/tangostationcontrol/devices/antennafield.py create mode 100644 tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py create mode 100644 tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eef96688b..b73c4eaed 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -100,6 +100,7 @@ docker_build_image_all: - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-tilebeam latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-beamlet latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-digitalbeam latest + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-antennafield latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-boot latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-docker latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control latest @@ -319,6 +320,17 @@ docker_build_image_device_ovservation_control: script: # Do not remove 'bash' or statement will be ignored by primitive docker shell - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control $tag +docker_build_image_device_antennafield: + extends: .base_docker_images_except + only: + refs: + - merge_requests + changes: + - docker-compose/device-antennafield.yml + - docker-compose/lofar-device-base/* + script: +# Do not remove 'bash' or statement will be ignored by primitive docker shell + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-antennafield $tag docker_build_image_device_recv: extends: .base_docker_images_except only: diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 75da3c114..3bcb37f45 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -14,6 +14,13 @@ } } }, + "AntennaField": { + "STAT": { + "AntennaField": { + "STAT/AntennaField/1": {} + } + } + }, "TileBeam": { "STAT": { "TileBeam": { diff --git a/docker-compose/device-antennafield.yml b/docker-compose/device-antennafield.yml new file mode 100644 index 000000000..b10f1e082 --- /dev/null +++ b/docker-compose/device-antennafield.yml @@ -0,0 +1,47 @@ +# +# 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' + +services: + device-antennafield: + image: device-antennafield + # build explicitly, as docker-compose does not understand a local image + # being shared among services. + build: + context: .. + dockerfile: docker-compose/lofar-device-base/Dockerfile + args: + SOURCE_IMAGE: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}device-antennafield + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5714:5714" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ..:/opt/lofar/tango:rw + environment: + - TANGO_HOST=${TANGO_HOST} + 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-antennafield AntennaField STAT -v -ORBendPoint giop:tcp:0:5714 -ORBendPointPublish giop:tcp:${HOSTNAME}:5714 + restart: unless-stopped diff --git a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index cf3e092e8..cc8593fab 100644 --- a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -10,7 +10,8 @@ boot = DeviceProxy("STAT/Boot/1") tilebeam = DeviceProxy("STAT/TileBeam/1") beamlet = DeviceProxy("STAT/Beamlet/1") digitalbeam = DeviceProxy("STAT/DigitalBeam/1") +antennafield = DeviceProxy("STAT/AntennaField/1") docker = DeviceProxy("STAT/Docker/1") # Put them in a list in case one wants to iterate -devices = [apsct, apspu, recv, sdp, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, docker] +devices = [apsct, apspu, recv, sdp, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, docker] diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index 780faa73f..a044d46c9 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -14,13 +14,13 @@ cd "$LOFAR20_DIR/docker-compose" || exit 1 # Build only the required images, please do not build everything that makes CI # take really long to finish, especially grafana / jupyter / prometheus. # jupyter is physically large > 2.5gb and overlayfs is really slow. -make build device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam +make build device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-antennafield make build sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim make build databaseds dsconfig elk integration-test make build archiver-timescale hdbppts-cm hdbppts-es # Start and stop sequence -make stop device-boot device-docker device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim hdbppts-es hdbppts-cm archiver-timescale +make stop device-boot device-docker device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-antennafield device-tilebeam sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim hdbppts-es hdbppts-cm archiver-timescale make start databaseds dsconfig elk # Give dsconfig and databaseds time to start @@ -38,7 +38,7 @@ make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim # Give the simulators time to start sleep 5 -make start device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-tilebeam device-beamlet device-digitalbeam +make start device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-tilebeam device-beamlet device-digitalbeam device-antennafield # Archive devices -> starting order is important make start archiver-timescale hdbppts-cm hdbppts-es diff --git a/tangostationcontrol/docs/source/devices/antennafield.rst b/tangostationcontrol/docs/source/devices/antennafield.rst new file mode 100644 index 000000000..e91a3ba71 --- /dev/null +++ b/tangostationcontrol/docs/source/devices/antennafield.rst @@ -0,0 +1,4 @@ +antennfield +==================== + +``antennafield == DeviceProxy("STAT/AntennaField/1")`` diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index 97f827210..4e199d8d9 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -22,6 +22,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st devices/tilebeam devices/beamlet devices/digitalbeam + devices/antennafield devices/boot devices/docker devices/recv diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index e9d1b0ada..526c20ad0 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -38,6 +38,7 @@ console_scripts = l2ss-tilebeam = tangostationcontrol.devices.tilebeam:main l2ss-beamlet = tangostationcontrol.devices.sdp.beamlet:main l2ss-digitalbeam = tangostationcontrol.devices.sdp.digitalbeam:main + l2ss-antennafield = tangostationcontrol.devices.antennafield:main l2ss-boot = tangostationcontrol.devices.boot:main l2ss-docker-device = tangostationcontrol.devices.docker_device:main l2ss-observation = tangostationcontrol.devices.observation:main diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py new file mode 100644 index 000000000..197589b7d --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -0,0 +1,239 @@ +# -*- coding: utf-8 -*- +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" AntennaField Device Server for LOFAR2.0 + +""" +from tango import DeviceProxy +from tango.server import device_property, attribute, AttrWriteType +import numpy + +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.devices.lofar_device import lofar_device +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions + +import logging +logger = logging.getLogger() + + +__all__ = ["AntennaField", "main"] + +@device_logging_to_python() +class AntennaField(lofar_device): + + HBAT_Power_to_RECV_mapping = device_property( + dtype=((numpy.int32),), + doc='The mapping of HBAT power lines to RECV mapping. Each RECV can handle 96 inputs. The HBAT number is the index and the value shows to which receiver device it is connected and on which input. The first integer is the input. The second integer is the RECV id. Example: [0, 3] = first receiver of property RECV_devices with input 3. -1 means that the HBAT is not connected', + mandatory=False, + default_value = [[-1, -1]] * 48 + ) + + HBAT_Control_to_RECV_mapping = device_property( + dtype=((numpy.int32),), + doc='The mapping of HBAT control lines to RECV mapping. Each RECV can handle 96 inputs. The HBAT number is the index and the value shows to which receiver device it is connected and on which input. The first integer is the input. The second interger is the RECV id. Example: [1, 3] = STAT/RECV/1 with input 3. -1 means that the HBAT is not connected', + mandatory=False, + default_value = [[-1, -1]] * 48 + ) + + RECV_devices = device_property( + dtype=(str,), + doc='Which Recv devices are in use by the AntennaField. The order is important and it should match up with the order of the mapping.', + mandatory=False, + default_value = [] + ) + + HBAT_ANT_mask_RW = attribute(dtype=(numpy.bool_,), max_dim_x=48, access=AttrWriteType.READ_WRITE, fget="get_hbat_ant_mask", fset="set_hbat_ant_mask") + HBAT_BF_delay_steps_R = attribute(dtype=((numpy.int64,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ, fget="get_hbat_bf_delay_steps") + HBAT_BF_delay_steps_RW = attribute(dtype=((numpy.int64,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ_WRITE, fget="get_hbat_bf_delay_steps", fset="set_hbat_bf_delay_steps") + HBAT_LED_on_R = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ, fget="get_hbat_led_on") + HBAT_LED_on_RW = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ_WRITE, fget="get_hbat_led_on", fset="set_hbat_led_on") + HBAT_PWR_LNA_on_R = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ, fget="get_hbat_pwr_lna_on") + HBAT_PWR_LNA_on_RW = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ_WRITE, fget="get_hbat_pwr_lna_on", fset="set_hbat_pwr_lna_on") + HBAT_PWR_on_R = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ, fget="get_hbat_pwr_on") + HBAT_PWR_on_RW = attribute(dtype=((numpy.bool_,),), max_dim_x=32, max_dim_y=48, access=AttrWriteType.READ_WRITE, fget="get_hbat_pwr_on", fset="set_hbat_pwr_on") + + @log_exceptions() + def configure_for_initialise(self): + super().configure_for_initialise() + self.__setup_all_receiver_proxies() + self.__setup_mapper() + + def __setup_all_receiver_proxies(self): + self.recv_proxies = [] + + for recv in self.RECV_devices: + self.recv_proxies.append(DeviceProxy(recv)) + + def __setup_mapper(self): + number_of_receivers = len(self.RECV_devices) + self.__mapper = HBATToRecvMapper(self.HBAT_Control_to_RECV_mapping, self.HBAT_Power_to_RECV_mapping, + number_of_receivers) + + def get_hbat_ant_mask(self): + recv_results = [] + for recv_proxy in self.recv_proxies: + recv_results.append(recv_proxy.ANT_mask_RW) + + mapped_ant_mask = self.__mapper.map_ant_mask_r(recv_results) + + return mapped_ant_mask + + def set_hbat_ant_mask(self, mask): + mapped_ant_mask = self.__mapper.map_ant_mask_rw(mask) + + for idx, recv_proxy in enumerate(self.recv_proxies): + recv_proxy.ANT_mask_RW = mapped_ant_mask[idx] + + def get_hbat_bf_delay_steps(self): + recv_results = [] + for recv_proxy in self.recv_proxies: + recv_results.append(recv_proxy.HBAT_BF_delay_steps_R) + + mapped_bf_delay_steps = self.__mapper.map_bf_delay_steps_r(recv_results) + + return mapped_bf_delay_steps + + def set_hbat_bf_delay_steps(self, delay_steps): + mapped_bf_delay_steps = self.__mapper.map_bf_delay_steps_rw(delay_steps) + + for idx, recv_proxy in enumerate(self.recv_proxies): + recv_proxy.HBAT_BF_delay_steps_RW = mapped_bf_delay_steps[idx] + + def get_hbat_led_on(self): + recv_results = [] + for recv_proxy in self.recv_proxies: + recv_results.append(recv_proxy.HBAT_LED_on_R) + + mapped_led_on = self.__mapper.map_led_on_r(recv_results) + + return mapped_led_on + + def set_hbat_led_on(self, leds): + mapped_led_on = self.__mapper.map_led_on_rw(leds) + + for idx, recv_proxy in enumerate(self.recv_proxies): + recv_proxy.HBAT_LED_on_RW = mapped_led_on[idx] + + def get_hbat_pwr_lna_on(self): + recv_results = [] + for recv_proxy in self.recv_proxies: + recv_results.append(recv_proxy.HBAT_PWR_LNA_on_R) + + mapped_lna_on = self.__mapper.map_pwr_lna_on_r(recv_results) + + return mapped_lna_on + + def set_hbat_pwr_lna_on(self, lna): + mapped_pwr_lna_on = self.__mapper.map_pwr_lna_on_rw(lna) + + for idx, recv_proxy in enumerate(self.recv_proxies): + recv_proxy.HBAT_PWR_LNA_on_RW = mapped_pwr_lna_on[idx] + + def get_hbat_pwr_on(self): + recv_results = [] + for recv_proxy in self.recv_proxies: + recv_results.append(recv_proxy.HBAT_PWR_on_R) + + mapped_lna_on = self.__mapper.map_pwr_on_r(recv_results) + + return mapped_lna_on + + def set_hbat_pwr_on(self, pwr): + mapped_pwr_on = self.__mapper.map_pwr_on_rw(pwr) + + for idx, recv_proxy in enumerate(self.recv_proxies): + recv_proxy.HBAT_PWR_on_RW = mapped_pwr_on[idx] + +class HBATToRecvMapper(object): + def __init__(self, hbat_control_to_recv_mapping, hbat_power_to_recv_mapping, number_of_receivers): + self.__control_mapping = hbat_control_to_recv_mapping + self.__power_mapping = hbat_power_to_recv_mapping + self.__number_of_receivers = number_of_receivers + + def map_ant_mask_r(self, recv_results): + default_values = [False] * 48 + + return self._mapped_r_values(recv_results, default_values) + + def map_ant_mask_rw(self, set_values): + default_values = [False] * 96 + + mapped_values = self._mapped_rw_values(set_values, default_values) + + mapped_values = numpy.reshape(mapped_values, (self.__number_of_receivers, 32, 3)) + + return mapped_values + + def map_bf_delay_steps_r(self, recv_results): + default_values = [[0] * 32] * 48 + + return self._mapped_r_values(recv_results, default_values) + + def map_bf_delay_steps_rw(self, set_values): + default_values = [[0] * 32] * 96 + + return self._mapped_rw_values(set_values, default_values) + + def map_led_on_r(self, recv_results): + default_values = [[False] * 32] * 48 + + return self._mapped_r_values(recv_results, default_values) + + def map_led_on_rw(self, set_values): + default_values = [[False] * 32] * 96 + + return self._mapped_rw_values(set_values, default_values) + + def map_pwr_lna_on_r(self, recv_results): + default_values = [[False] * 32] * 48 + + return self._mapped_r_values(recv_results, default_values) + + def map_pwr_lna_on_rw(self, set_values): + default_values = [[False] * 32] * 96 + + return self._mapped_rw_values(set_values, default_values) + + def map_pwr_on_r(self, recv_results): + default_values = [[False] * 32] * 48 + + return self._mapped_r_values(recv_results, default_values) + + def map_pwr_on_rw(self, set_values): + default_values = [[False] * 32] * 96 + + return self._mapped_rw_values(set_values, default_values) + + def _mapped_r_values(self, recv_results, default_values): + mapped_values = default_values + + for idx, mapping in enumerate(self.__control_mapping): + recv = mapping[0] + rcu = mapping[1] + if recv > 0: + mapped_values[idx] = recv_results[recv - 1][rcu] + + return mapped_values + + def _mapped_rw_values(self, set_values, default_values): + mapped_values = [] + + for i in range(self.__number_of_receivers): + mapped_values.append(default_values) + + for idx, mapping in enumerate(self.__control_mapping): + recv = mapping[0] + rcu = mapping[1] + if recv > 0: + mapped_values[recv - 1][rcu] = set_values[idx] + + return mapped_values + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the ObservationControl module.""" + return entry(AntennaField, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py index 0b496636f..beefe5b8f 100644 --- a/tangostationcontrol/tangostationcontrol/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -243,6 +243,7 @@ class Boot(lofar_device): "STAT/Beamlet/1", "STAT/TileBeam/1", # Accesses RECV and Beamlet "STAT/DigitalBeam/1", + "STAT/AntennaField/1", ], ) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py new file mode 100644 index 000000000..b41a75047 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy + +from .base import AbstractTestBases + +class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): + + def setUp(self): + super().setUp("STAT/AntennaField/1") + self.proxy.put_property({"RECV_devices": ["STAT/RECV/1"], + "HBAT_Power_to_RECV_mapping": [1, 1, 1, 0] + [-1] * 92}) + + def setup_recv_proxy(self): + # setup RECV + recv_proxy = TestDeviceProxy("STAT/RECV/1") + recv_proxy.off() + recv_proxy.warm_boot() + recv_proxy.set_defaults() + return recv_proxy + + def test_property_recv_devices_has_one_receiver(self): + self.proxy.warm_boot() + result = self.proxy.get_property("RECV_devices") + self.assertSequenceEqual(result["RECV_devices"], ["STAT/RECV/1"]) diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py new file mode 100644 index 000000000..625ec3088 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import numpy +import unittest + +from tangostationcontrol.devices.antennafield import HBATToRecvMapper + +class TestHBATToRecvMapper(unittest.TestCase): + def test_ant_mask_r_no_mapping(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 3) + + receiver_values = [[[False] * 3] * 32, [[False] * 3] * 32, [[False] * 3] * 32] + expected = [False] * 48 + actual = mapper.map_ant_mask_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_ant_mask_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 3) + + receiver_values = [[False, True, False], [[False] * 3] * 31, [[False] * 3] * 32, [[False] * 3] * 32] + expected = [True, False] + [False] * 46 + actual = mapper.map_ant_mask_r(receiver_values) + + numpy.testing.assert_equal(expected, actual) + + def test_bf_delay_steps_r_no_mapping(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 3) + + receiver_values = [[[0] * 32] * 96, [[0] * 32] * 96, [[0] * 32] * 96] + expected = [[0] * 32] * 48 + actual = mapper.map_bf_delay_steps_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_bf_delay_steps_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 3) + + receiver_values = [[[2] * 32, [1] * 32] + [[0] * 32] * 94, [[0] * 32] * 96, [[0] * 32] * 96] + expected = [[1] * 32, [2] * 32] + [[0] * 32] * 46 + actual = mapper.map_bf_delay_steps_r(receiver_values) + + numpy.testing.assert_equal(expected, actual) + + def test_map_led_on_r_unmapped(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 3) + + receiver_values = [[[False] * 32] * 96, [[False] * 32] * 96, [[False] * 32] * 96] + expected = [[False] * 32] * 48 + actual = mapper.map_led_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_led_on_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 3) + + receiver_values = [[[False, True] * 16, [True, False] * 16] + [[False] * 32] * 94, [[False] * 32] * 96, [[False] * 32] * 96] + + expected = [[True, False] * 16, [False, True] * 16] + [[False] * 32] * 46 + actual = mapper.map_led_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_lna_on_r_unmapped(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 3) + + receiver_values = [[[False] * 32] * 96, [[False] * 32] * 96, [[False] * 32] * 96] + expected = [[False] * 32] * 48 + actual = mapper.map_pwr_lna_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_lna_on_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 3) + + receiver_values = [[[False, True] * 16, [True, False] * 16] + [[False] * 32] * 94, [[False] * 32] * 96, [[False] * 32] * 96] + + expected = [[True, False] * 16, [False, True] * 16] + [[False] * 32] * 46 + actual = mapper.map_pwr_lna_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_on_r_unmapped(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 3) + + receiver_values = [[[False] * 32] * 96, [[False] * 32] * 96, [[False] * 32] * 96] + expected = [[False] * 32] * 48 + actual = mapper.map_pwr_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_on_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 3) + + receiver_values = [[[False, True] * 16, [True, False] * 16] + [[False] * 32] * 94, [[False] * 32] * 96, [[False] * 32] * 96] + + expected = [[True, False] * 16, [False, True] * 16] + [[False] * 32] * 46 + actual = mapper.map_pwr_on_r(receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_ant_mask_rw_no_mapping_and_one_receiver(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 1) + + set_values = [False] * 48 + expected = [[[False] * 3] * 32] + actual = mapper.map_ant_mask_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_ant_mask_rw_no_mapping_and_two_receivers(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 2) + + set_values = [False] * 48 + expected = [[[False] * 3] * 32] * 2 + actual = mapper.map_ant_mask_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_ant_mask_rw_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 1) + + set_values = [True, False] + [False] * 46 + expected = [[[False, True, False]] + [[False] * 3] * 31] + actual = mapper.map_ant_mask_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_bf_delay_steps_rw_no_mapping_and_one_receiver(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 1) + + set_values = [[1] * 32] * 48 + expected = [[[0] * 32] * 96] + actual = mapper.map_bf_delay_steps_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_bf_delay_steps_rw_no_mapping_and_two_receivers(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 2) + + set_values = [[1] * 32] * 48 + expected = [[[0] * 32] * 96, [[0] * 32] * 96] + actual = mapper.map_bf_delay_steps_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_bf_delay_steps_rw_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 1) + + set_values = [[1] * 32, [2] * 32] + [[0] * 32] * 46 + expected = [[[2] * 32, [1] * 32] + [[0] * 32] * 94] + actual = mapper.map_bf_delay_steps_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_led_on_rw_no_mapping_and_one_receiver(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 1) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96] + actual = mapper.map_led_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_led_on_rw_no_mapping_and_two_receivers(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 2) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96, [[False] * 32] * 96] + actual = mapper.map_led_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_led_on_rw_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 1) + + set_values = [[False, True] * 16, [True, False] * 16] + [[False] * 32] * 46 + expected = [[[True, False] * 16, [False, True] * 16] + [[0] * 32] * 94] + actual = mapper.map_led_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_lna_on_rw_no_mapping_and_one_receiver(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 1) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96] + actual = mapper.map_pwr_lna_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_lna_on_rw_no_mapping_and_two_receivers(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 2) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96, [[False] * 32] * 96] + actual = mapper.map_pwr_lna_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_lna_on_rw_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 1) + + set_values = [[False, True] * 16, [True, False] * 16] + [[False] * 32] * 46 + expected = [[[True, False] * 16, [False, True] * 16] + [[0] * 32] * 94] + actual = mapper.map_pwr_lna_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_on_rw_no_mapping_and_one_receiver(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 1) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96] + actual = mapper.map_pwr_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_lna_on_rw_no_mapping_and_two_receivers(self): + control_not_connected = [[-1, -1] * 48] + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_not_connected, power_not_connected, 2) + + set_values = [[False] * 32] * 48 + expected = [[[False] * 32] * 96, [[False] * 32] * 96] + actual = mapper.map_pwr_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_pwr_on_rw_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + control_hba_0_and_1_on_rcu_1_and_0_of_recv_1 = [[1, 1], [1, 0]] + [[-1, -1]] * 46 + power_not_connected = [[-1, -1] * 48] + + mapper = HBATToRecvMapper(control_hba_0_and_1_on_rcu_1_and_0_of_recv_1, power_not_connected, 1) + + set_values = [[False, True] * 16, [True, False] * 16] + [[False] * 32] * 46 + expected = [[[True, False] * 16, [False, True] * 16] + [[0] * 32] * 94] + actual = mapper.map_pwr_on_rw(set_values) + numpy.testing.assert_equal(expected, actual) + diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py index 46004707e..15434810d 100644 --- a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py +++ b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py @@ -52,3 +52,4 @@ class TestLofarDevice(base.TestCase): proxy.initialise() self.assertEqual(42.0, proxy.read_attribute_A) self.assertListEqual([42.0, 43.0], proxy.read_attribute_B_array.tolist()) + -- GitLab