From ea7c0e9a687cbc56cdc17ae5e04c5ec71642c7b5 Mon Sep 17 00:00:00 2001
From: Auke Klazema <klazema@astron.nl>
Date: Thu, 12 May 2022 13:39:04 +0200
Subject: [PATCH] L2SS-631: Add skeleton BST device based on lofar_device

---
 .gitlab-ci.yml                                | 16 ++++++
 CDB/LOFAR_ConfigDb.json                       | 10 ++++
 docker-compose/device-bst.yml                 | 50 +++++++++++++++++++
 .../startup/01-devices.py                     |  3 +-
 sbin/run_integration_test.sh                  |  2 +-
 sbin/tag_and_push_docker_image.sh             |  1 +
 .../devices/{sst-xst.rst => bst-sst-xst.rst}  | 10 ++--
 tangostationcontrol/docs/source/index.rst     |  2 +-
 tangostationcontrol/setup.cfg                 |  1 +
 .../tangostationcontrol/devices/README.md     |  2 +-
 .../tangostationcontrol/devices/boot.py       |  1 +
 .../tangostationcontrol/devices/sdp/bst.py    | 30 +++++++++++
 .../devices/sdp/statistics_collector.py       |  9 ++++
 .../default/devices/test_device_bst.py        | 16 ++++++
 14 files changed, 146 insertions(+), 7 deletions(-)
 create mode 100644 docker-compose/device-bst.yml
 rename tangostationcontrol/docs/source/devices/{sst-xst.rst => bst-sst-xst.rst} (93%)
 create mode 100644 tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
 create mode 100644 tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_bst.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e38e66a4..f6865f565 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -102,6 +102,7 @@ docker_build_image_all:
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-recv latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sdp latest
+    - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-bst latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sst latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-unb2 latest
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-xst latest
@@ -364,6 +365,21 @@ docker_build_image_device_sdp:
   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-sdp $tag
+docker_build_image_device_bst:
+  extends: .base_docker_images
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+      when: never
+    - if: '$CI_COMMIT_TAG != null'
+      when: never
+    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+      when: never
+    - changes:
+      - docker-compose/device-bst.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-bst $tag
 docker_build_image_device_sst:
   extends: .base_docker_images_except
   only:
diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json
index de32af15d..748ab3351 100644
--- a/CDB/LOFAR_ConfigDb.json
+++ b/CDB/LOFAR_ConfigDb.json
@@ -148,6 +148,16 @@
                 }
             }
         },
+        "BST": {
+            "STAT": {
+                "BST": {
+                    "STAT/BST/1": {
+                        "properties": {
+                        }
+                    }
+                }
+            }
+        },
         "SST": {
             "STAT": {
                 "SST": {
diff --git a/docker-compose/device-bst.yml b/docker-compose/device-bst.yml
new file mode 100644
index 000000000..57ef90b8f
--- /dev/null
+++ b/docker-compose/device-bst.yml
@@ -0,0 +1,50 @@
+#
+# 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-bst:
+    image: device-bst
+    # 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-bst
+    logging:
+      driver: "json-file"
+      options:
+        max-size: "100m"
+        max-file: "10"
+    networks:
+        - control
+        - data
+    ports:
+        - "5003:5003/udp" # port to receive SST UDP packets on
+        - "5103:5103/tcp" # port to emit SST TCP packets on
+        - "5717:5717" # 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-bst BST STAT -v -ORBendPoint giop:tcp:0:5717 -ORBendPointPublish giop:tcp:${HOSTNAME}:5717
+    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 ba7ce483e..26bd47d70 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
@@ -3,6 +3,7 @@ apsct = DeviceProxy("STAT/APSCT/1")
 apspu = DeviceProxy("STAT/APSPU/1")
 recv = DeviceProxy("STAT/RECV/1")
 sdp = DeviceProxy("STAT/SDP/1")
+bst = DeviceProxy("STAT/BST/1")
 sst = DeviceProxy("STAT/SST/1")
 xst = DeviceProxy("STAT/XST/1")
 unb2 = DeviceProxy("STAT/UNB2/1")
@@ -16,4 +17,4 @@ docker = DeviceProxy("STAT/Docker/1")
 temperaturemanager = DeviceProxy("STAT/TemperatureManager/1")
 
 # Put them in a list in case one wants to iterate
-devices = [apsct, apspu, recv, sdp, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker]
+devices = [apsct, apspu, recv, sdp, bst, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker]
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 7e0cf3b27..9e38cf0d7 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -20,7 +20,7 @@ sleep 1 # dsconfig container must be up and running...
 # shellcheck disable=SC2016
 echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true' | make run dsconfig bash -
 
-DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-pdu device-antennafield device-temperature-manager"
+DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-pdu device-antennafield device-temperature-manager"
 SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim"
 
 # Build only the required images, please do not build everything that makes CI
diff --git a/sbin/tag_and_push_docker_image.sh b/sbin/tag_and_push_docker_image.sh
index 3689a26b4..1ec8c3751 100755
--- a/sbin/tag_and_push_docker_image.sh
+++ b/sbin/tag_and_push_docker_image.sh
@@ -89,6 +89,7 @@ LOCAL_IMAGES=(
   "device-recv device-recv y" "device-temperature-manager y"
   "device-sdp device-sdp y" "device-sst device-sst y"
   "device-unb2 device-unb2 y" "device-xst device-xst y"
+  "device-bst device-bst y"
 
   "itango docker-compose_itango y"
 
diff --git a/tangostationcontrol/docs/source/devices/sst-xst.rst b/tangostationcontrol/docs/source/devices/bst-sst-xst.rst
similarity index 93%
rename from tangostationcontrol/docs/source/devices/sst-xst.rst
rename to tangostationcontrol/docs/source/devices/bst-sst-xst.rst
index b3b0ec460..90bc0df19 100644
--- a/tangostationcontrol/docs/source/devices/sst-xst.rst
+++ b/tangostationcontrol/docs/source/devices/bst-sst-xst.rst
@@ -1,7 +1,7 @@
-SST and XST
+BST, SST, and XST
 ====================
 
-The ``sst == DeviceProxy("STAT/SST/1")`` and ``xst == DeviceProxy("STAT/XST/1")`` devices manages the SSTs (subband statistics) and XSTs (crosslet statistics), respectively. The statistics are emitted piece-wise through UDP packets by the FPGAs on the Uniboards in SDP. By default, each device configures the statistics to be streamed to itself (the device), from where the user can obtain them.
+The ``bst == DeviceProxy("STAT/BST/1")``, ``sst == DeviceProxy("STAT/SST/1")`` and ``xst == DeviceProxy("STAT/XST/1")`` devices manages the BSTs (beamlet statistics) SSTs (subband statistics) and XSTs (crosslet statistics), respectively. The statistics are emitted piece-wise through UDP packets by the FPGAs on the Uniboards in SDP. By default, each device configures the statistics to be streamed to itself (the device), from where the user can obtain them.
 
 The statistics are exposed in two ways, as:
 
@@ -10,11 +10,15 @@ The statistics are exposed in two ways, as:
 
 If the statistics are not received or zero, see :ref:`statistics-debugging`.
 
-See the following links for a full description of the SST and XST monitoring and control points:
+See the following links for a full description of the BST, SST, and XST 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
 
+BST Statistics attributes
+------------------------------
+
+
 SST Statistics attributes
 ------------------------------
 
diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst
index 380863715..34caec36a 100644
--- a/tangostationcontrol/docs/source/index.rst
+++ b/tangostationcontrol/docs/source/index.rst
@@ -28,7 +28,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st
    devices/pdu
    devices/recv
    devices/sdp
-   devices/sst-xst
+   devices/bst-sst-xst
    devices/temperature-manager
    devices/configure
    configure_station
diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg
index 6af6b55d6..c8e9a4390 100644
--- a/tangostationcontrol/setup.cfg
+++ b/tangostationcontrol/setup.cfg
@@ -48,6 +48,7 @@ console_scripts =
     l2ss-observation-control = tangostationcontrol.devices.observation_control:main
     l2ss-receiver = tangostationcontrol.devices.recv:main
     l2ss-sdp = tangostationcontrol.devices.sdp.sdp:main
+    l2ss-bst = tangostationcontrol.devices.sdp.bst:main
     l2ss-sst = tangostationcontrol.devices.sdp.sst:main
     l2ss-statistics-reader = tangostationcontrol.statistics_writer.statistics_reader:main
     l2ss-statistics-writer = tangostationcontrol.statistics_writer.statistics_writer:main
diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md
index 566fb78e5..9f07b1db0 100644
--- a/tangostationcontrol/tangostationcontrol/devices/README.md
+++ b/tangostationcontrol/tangostationcontrol/devices/README.md
@@ -10,7 +10,7 @@ If a new device is added, it will (likely) need to be referenced in several plac
 - Adjust `docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter,
 - 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: 5716
+                            current _unused_ port value: 5718
 - 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,
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index c14c74760..bc3855646 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -239,6 +239,7 @@ class Boot(lofar_device):
                        "STAT/RECV/1",   # RCUs are input for SDP, so initialise them first
                        "STAT/UNB2/1",   # Uniboards host SDP, so initialise them first
                        "STAT/SDP/1",    # SDP controls the mask for SST/XST/BST/Beamlet, so initialise it first
+                       "STAT/BST/1",
                        "STAT/SST/1",
                        "STAT/XST/1",
                        "STAT/Beamlet/1",
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
new file mode 100644
index 000000000..ba569fc5f
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the TANGO project
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+""" BST Device Server for LOFAR2.0
+
+"""
+
+# Own imports
+from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.sdp.statistics_collector import BSTCollector
+
+__all__ = ["BST", "main"]
+
+class BST(lofar_device):
+    STATISTICS_COLLECTOR_CLASS = BSTCollector
+
+
+# ----------
+# Run server
+# ----------
+def main(**kwargs):
+    """Main function of the BST Device module."""
+    return entry(BST, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
index 3a067aa9f..31f34ba00 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py
@@ -47,6 +47,15 @@ class StatisticsCollector:
         raise NotImplementedError
 
 
+class BSTCollector(StatisticsCollector):
+    """ Class to process BST statistics packets. """
+    def _default_parameters(self):
+        defaults = super()._default_parameters()
+
+    def parse_packet(self, packet):
+        pass
+
+
 class SSTCollector(StatisticsCollector):
     """ Class to process SST statistics packets. """
 
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_bst.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_bst.py
new file mode 100644
index 000000000..8e7aa81af
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_bst.py
@@ -0,0 +1,16 @@
+
+# -*- 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 .base import AbstractTestBases
+
+
+class TestDeviceBST(AbstractTestBases.TestDeviceBase):
+    def setUp(self):
+        """Intentionally recreate the device object in each test"""
+        super().setUp("STAT/BST/1")
-- 
GitLab