From f65306d37cb88a3cae0e606e0bb6ded10cd5fd9e Mon Sep 17 00:00:00 2001 From: thijs snijder <snijder@astron.nl> Date: Thu, 17 Mar 2022 16:56:39 +0100 Subject: [PATCH] started DigitalBeam branch by copying Beamlet device --- docker-compose/device-digitalbeam.yml | 47 ++++++ .../startup/01-devices.py | 3 +- .../docs/source/devices/DigitalBeam.rst | 4 + tangostationcontrol/docs/source/index.rst | 1 + tangostationcontrol/setup.cfg | 1 + .../tangostationcontrol/devices/boot.py | 1 + .../devices/sdp/DigitalBeam.py | 136 ++++++++++++++++++ 7 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 docker-compose/device-digitalbeam.yml create mode 100644 tangostationcontrol/docs/source/devices/DigitalBeam.rst create mode 100644 tangostationcontrol/tangostationcontrol/devices/sdp/DigitalBeam.py diff --git a/docker-compose/device-digitalbeam.yml b/docker-compose/device-digitalbeam.yml new file mode 100644 index 000000000..891c7fc8a --- /dev/null +++ b/docker-compose/device-digitalbeam.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-digitalbeam: + image: device-digitalbeam + # 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-digitalbeam + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5712:5712" # 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-digitalbeam DigitalBeam STAT -v -ORBendPoint giop:tcp:0:5712 -ORBendPointPublish giop:tcp:${HOSTNAME}:5712 + 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 82afee40e..9a64688d7 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 @@ -9,7 +9,8 @@ unb2 = DeviceProxy("STAT/UNB2/1") boot = DeviceProxy("STAT/Boot/1") tilebeam = DeviceProxy("STAT/TileBeam/1") beamlet = DeviceProxy("STAT/Beamlet/1") +beamlet = DeviceProxy("STAT/DigitalBeam/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, docker] +devices = [apsct, apspu, recv, sdp, sst, xst, unb2, boot, tilebeam, beamlet, DigitalBeam, docker] diff --git a/tangostationcontrol/docs/source/devices/DigitalBeam.rst b/tangostationcontrol/docs/source/devices/DigitalBeam.rst new file mode 100644 index 000000000..90d9a75d4 --- /dev/null +++ b/tangostationcontrol/docs/source/devices/DigitalBeam.rst @@ -0,0 +1,4 @@ +DigitalBeam +==================== + +``DigitalBeam == DeviceProxy("STAT/DigitalBeam/1")`` diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index 0fd199ad8..ab4b696c0 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -21,6 +21,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st devices/using devices/tilebeam devices/beamlet + devices/DigitalBeam devices/boot devices/docker devices/recv diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index cfc0a249b..6a438752e 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -37,6 +37,7 @@ console_scripts = l2ss-apspu = tangostationcontrol.devices.apspu:main l2ss-tilebeam = tangostationcontrol.devices.tilebeam:main l2ss-beamlet = tangostationcontrol.devices.sdp.beamlet:main + l2ss-DigitalBeam = tangostationcontrol.devices.sdp.DigitalBeam: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/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py index ba9279092..0b496636f 100644 --- a/tangostationcontrol/tangostationcontrol/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -242,6 +242,7 @@ class Boot(lofar_device): "STAT/XST/1", "STAT/Beamlet/1", "STAT/TileBeam/1", # Accesses RECV and Beamlet + "STAT/DigitalBeam/1", ], ) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/DigitalBeam.py b/tangostationcontrol/tangostationcontrol/devices/sdp/DigitalBeam.py new file mode 100644 index 000000000..e226ec094 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/DigitalBeam.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" DigitalBeam Device Server for LOFAR2.0 + +""" + +# PyTango imports +from tango.server import device_property +from tango import AttrWriteType +# Additional import + +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.opcua_device import opcua_device +from tangostationcontrol.devices.sdp.sdp import SDP + +import numpy + +__all__ = ["DigitalBeam", "main"] + + +class DigitalBeam(opcua_device): + + # ----------------- + # Device Properties + # ----------------- + + FPGA_beamlet_output_hdr_eth_destination_mac_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_beamlet_output_hdr_ip_destination_address_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_beamlet_output_hdr_udp_destination_port_RW_default = device_property( + dtype='DevVarUShortArray', + mandatory=True + ) + + FPGA_beamlet_output_enable_RW_default = device_property( + dtype='DevVarBooleanArray', + mandatory=False, + default_value=[False] * 16 + ) + + FPGA_beamlet_output_scale_RW_default = device_property( + dtype='DevVarDoubleArray', + mandatory=False, + default_value=[1.0] * 16 + ) + + first_default_settings = [ + 'FPGA_beamlet_output_hdr_eth_destination_mac_RW', + 'FPGA_beamlet_output_hdr_ip_destination_address_RW', + 'FPGA_beamlet_output_hdr_udp_destination_port_RW', + + 'FPGA_beamlet_output_enable_RW' + ] + + # ---------- + # Attributes + # ---------- + + FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) + FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) + FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) + FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(16,)) + FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(16,), access=AttrWriteType.READ_WRITE) + + # List of OPC-UA CP for BF beamlets + S_pn = SDP.S_pn + N_pn = SDP.N_pn + A_pn = 6 + N_pol = 2 + N_beamlets_ctrl = 488 + N_pol_bf = 2 + + # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl] + # Co-polarization BF weights. The N_pol = 2 parameter index is: + # 0 for antenna polarization X in beamlet polarization X, + # 1 for antenna polarization Y in beamlet polarization Y. + FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.int16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.int16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + + # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl] + # Cross-polarization BF weights. The N_pol = 2 parameter index is (note that index pol in range 0:N_pol-1 is the antenna polarization, so index !pol is the beamlet polarization): + # 0 for antenna polarization X in beamlet polarization Y, + # 1 for antenna polarization Y in beamlet polarization X. + FPGA_bf_weights_xy_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_R"], datatype=numpy.int16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_xy_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_RW"], datatype=numpy.int16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + + # cint16[N_pn][N_pol_bf][A_pn][N_pol][N_beamlets_ctrl] + # Full Jones matrix of BF weights. + FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.int16, dims=(N_pol_bf * A_pn * N_pol * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.int16, dims=(N_pol_bf * A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + + # cint16[N_pn][A_pn][N_beamlets_ctrl] + # BF weights for separate access to respectively w_xx, w_xy, w_yx, and w_yy. + FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn)) + FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE) + + # ---------- + # Summarising Attributes + # ---------- + + # -------- + # Overloaded functions + # -------- + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the SST Device module.""" + return entry(DigitalBeam, **kwargs) -- GitLab