diff --git a/bin/wait-for-it.sh b/bin/wait-for-it.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0bd0c104de461817575aafc4962fcc5ee786945e
--- /dev/null
+++ b/bin/wait-for-it.sh
@@ -0,0 +1,165 @@
+#!/usr/bin/env bash
+# shellcheck disable=SC2086,SC2064,SC2206,SC2124
+#   Use this script to test if a given TCP host/port are available
+#
+# Source: https://github.com/vishnubob/wait-for-it
+# License: MIT
+
+cmdname=$(basename $0)
+
+echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
+
+usage()
+{
+    cat << USAGE >&2
+Usage:
+    $cmdname host:port [-s] [-t timeout] [-- command args]
+    -h HOST | --host=HOST       Host or IP under test
+    -p PORT | --port=PORT       TCP port under test
+                                Alternatively, you specify the host and port as host:port
+    -s | --strict               Only execute subcommand if the test succeeds
+    -q | --quiet                Don't output any status messages
+    -t TIMEOUT | --timeout=TIMEOUT
+                                Timeout in seconds, zero for no timeout
+    -- COMMAND ARGS             Execute command with args after the test finishes
+USAGE
+    exit 1
+}
+
+wait_for()
+{
+    if [[ $TIMEOUT -gt 0 ]]; then
+        echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
+    else
+        echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
+    fi
+    start_ts=$(date +%s)
+    while :
+    do
+        (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
+        result=$?
+        if [[ $result -eq 0 ]]; then
+            end_ts=$(date +%s)
+            echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
+            break
+        fi
+        sleep 1
+    done
+    return $result
+}
+
+wait_for_wrapper()
+{
+    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
+    if [[ $QUIET -eq 1 ]]; then
+        timeout $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    else
+        timeout $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    fi
+    PID=$!
+    trap "kill -INT -$PID" INT
+    wait $PID
+    RESULT=$?
+    if [[ $RESULT -ne 0 ]]; then
+        echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
+    fi
+    return $RESULT
+}
+
+# process arguments
+while [[ $# -gt 0 ]]
+do
+    case "$1" in
+        *:* )
+        hostport=(${1//:/ })
+        HOST=${hostport[0]}
+        PORT=${hostport[1]}
+        shift 1
+        ;;
+        --child)
+        CHILD=1
+        shift 1
+        ;;
+        -q | --quiet)
+        QUIET=1
+        shift 1
+        ;;
+        -s | --strict)
+        STRICT=1
+        shift 1
+        ;;
+        -h)
+        HOST="$2"
+        if [[ $HOST == "" ]]; then break; fi
+        shift 2
+        ;;
+        --host=*)
+        HOST="${1#*=}"
+        shift 1
+        ;;
+        -p)
+        PORT="$2"
+        if [[ $PORT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --port=*)
+        PORT="${1#*=}"
+        shift 1
+        ;;
+        -t)
+        TIMEOUT="$2"
+        if [[ $TIMEOUT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --timeout=*)
+        TIMEOUT="${1#*=}"
+        shift 1
+        ;;
+        --)
+        shift
+        CLI="$@"
+        break
+        ;;
+        --help)
+        usage
+        ;;
+        *)
+        echoerr "Unknown argument: $1"
+        usage
+        ;;
+    esac
+done
+
+if [[ "$HOST" == "" || "$PORT" == "" ]]; then
+    echoerr "Error: you need to provide a host and port to test."
+    usage
+fi
+
+TIMEOUT=${TIMEOUT:-15}
+STRICT=${STRICT:-0}
+CHILD=${CHILD:-0}
+QUIET=${QUIET:-0}
+
+if [[ $CHILD -gt 0 ]]; then
+    wait_for
+    RESULT=$?
+    exit $RESULT
+else
+    if [[ $TIMEOUT -gt 0 ]]; then
+        wait_for_wrapper
+        RESULT=$?
+    else
+        wait_for
+        RESULT=$?
+    fi
+fi
+
+if [[ $CLI != "" ]]; then
+    if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
+        echoerr "$cmdname: strict mode, refusing to execute subprocess"
+        exit $RESULT
+    fi
+    exec $CLI
+else
+    exit $RESULT
+fi
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 1dc410d55bd9a81b45490fbb867f2bd0927ced91..343eac0520e9e4ece9a4e7144e8ebd1b1e165753 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -11,20 +11,26 @@ fi
 
 cd "$LOFAR20_DIR/docker-compose" || exit 1
 
+# Start the database server first
+make build databaseds dsconfig
+make start databaseds dsconfig
+
+# Give dsconfig and databaseds time to start
+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 -
+
 # 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 sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
-make build databaseds dsconfig elk integration-test
+make build 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 start databaseds dsconfig elk
-
-# Give dsconfig and databaseds time to start
-sleep 60
+make start elk
 
 # Update the dsconfig
 # Do not remove `bash`, otherwise statement ignored by gitlab ci shell!
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 0b496636fbd30550255c488ef458e294468c07aa..59427165c20f5c8f9a65e9f59b0d85c4a3fa8837 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -50,7 +50,7 @@ class DevicesInitialiser(object):
         the start() method, and progress can be followed by inspecting the
         members progress (0-100), status (string), and is_running() (bool).
     """
-    def __init__(self, device_names, reboot=False, initialise_hardware=True, proxy_timeout=10.0):
+    def __init__(self, device_names, reboot=False, initialise_hardware=True, proxy_timeout=60.0):
         self.reboot = reboot
         self.initialise_hardware = initialise_hardware
 
@@ -218,7 +218,7 @@ class Boot(lofar_device):
     DeviceProxy_Time_Out = device_property(
         dtype='DevDouble',
         mandatory=False,
-        default_value=30.0,
+        default_value=60.0,
     )
 
     # Initialise the hardware when initialising a station. Can end badly when using simulators.
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index fc5c661b7937bf2489da23e6ed000f2050e97630..50368d15d59fd94794edfaafdb2c451513b60b24 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -314,6 +314,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
     @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
     @fault_on_error()
     @command()
+    @DebugIt()
     def prepare_hardware(self):
         """ Load firmware required before configuring anything. """
 
@@ -323,6 +324,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
     @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
     @fault_on_error()
     @command()
+    @DebugIt()
     def initialise_hardware(self):
         """ Initialise the hardware after configuring it. """
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index 8836e2c9415be916625edf089a292d0fe945d6f1..1c21c006221289d2847033f9830fef8760009c3e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -126,6 +126,18 @@ class RECV(opcua_device):
 
     # ----- Position information
 
+    Antenna_Field_Reference_ITRF = device_property(
+        doc="ITRF position (XYZ) of each antenna field",
+        dtype='DevVarFloatArray',
+        mandatory=False
+    )
+
+    Antenna_Field_Reference_ETRS = device_property(
+        doc="ETRS position (XYZ) of each antenna field",
+        dtype='DevVarFloatArray',
+        mandatory=False
+    )
+
     HBAT_reference_ITRF = device_property(
         doc="ITRF position (XYZ) of each HBAT (leave empty to auto-derive from ETRS)",
         dtype='DevVarFloatArray',
@@ -218,6 +230,10 @@ class RECV(opcua_device):
 
     # ----- Position information
 
+    Antenna_Field_Reference_ITRF_R = attribute(access=AttrWriteType.READ,
+        doc='Absolute reference position of antenna field, in ITRF',
+        dtype=(numpy.float,), max_dim_x=3)
+
     HBAT_antenna_ITRF_offsets_R = attribute(access=AttrWriteType.READ,
         doc='Offsets of the antennas within a tile, in ITRF ("iHBADeltas"). True shape: 96x16x3.',
         dtype=((numpy.float,),), max_dim_x=48, max_dim_y=96)
@@ -226,6 +242,15 @@ class RECV(opcua_device):
         doc='Absolute reference position of each tile, in ITRF',
         dtype=((numpy.float,),), max_dim_x=3, max_dim_y=96)
 
+    def read_Antenna_Field_Reference_ITRF_R(self):
+        # provide ITRF field coordinates if they were configured
+        if self.Antenna_Field_Reference_ITRF:
+            return numpy.array(self.Antenna_Field_Reference_ITRF).reshape(3)
+
+        # calculate them from ETRS coordinates if not, using the configured ITRF reference
+        ETRS_coordinates = numpy.array(self.Antenna_Field_Reference_ETRS).reshape(3)
+        return ETRS_to_ITRF(ETRS_coordinates, self.ITRF_Reference_Frame, self.ITRF_Reference_Epoch)
+    
     def read_HBAT_antenna_ITRF_offsets_R(self):
         base_antenna_offsets        = numpy.array(self.HBAT_base_antenna_offsets).reshape(16,3)
         PQR_to_ETRS_rotation_matrix = numpy.array(self.HBAT_PQR_to_ETRS_rotation_matrix).reshape(3,3)
@@ -252,7 +277,7 @@ class RECV(opcua_device):
     # ----------
     # Summarising Attributes
     # ----------
-    RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32)
+    RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32, fisallowed="is_attribute_wrapper_allowed")
 
     def read_RCU_LED_colour_R(self):
         return (2 * self.read_attribute("RCU_LED_green_on_R") + 4 * self.read_attribute("RCU_LED_red_on_R")).astype(numpy.uint32)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index e490722440967062030e20df8ba0dec97b2ffb78..dbbc644364cab4706f2b46e21b798b671b487455 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -92,6 +92,24 @@ class Beamlet(opcua_device):
     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
+
+    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_beamlets_ctrl, N_pn))
+    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_beamlets_ctrl, N_pn))
+
+    # uint16[N_pn][A_pn][N_pol][N_beamlets_ctrl]
+    # Select subband per dual-polarisation beamlet.
+    # 0 for antenna polarization X in beamlet polarization X,
+    # 1 for antenna polarization Y in beamlet polarization Y.
+    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn))
+    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint16, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE)
+
     # 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,
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index c4dc14a165f69ce471e7c416fef14dd0771b54cb..44e89a6cb2c8f3c1c1ddba17a2b94e3e34236e7e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -108,6 +108,14 @@ class SDP(opcua_device):
     FPGA_pps_expected_cnt_RW = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=numpy.bool_, dims=(16,))
     FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_node_offset_R = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_R"], datatype=numpy.uint32, dims=(16,))
+    FPGA_ring_node_offset_RW = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_nof_nodes_R = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_R"], datatype=numpy.uint32, dims=(16,))
+    FPGA_ring_nof_nodes_RW = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_next_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_R"], datatype=numpy.bool_, dims=(16,))
+    FPGA_ring_use_cable_to_next_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_previous_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=numpy.bool_, dims=(16,))
+    FPGA_ring_use_cable_to_previous_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,))
     FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(8192,), access=AttrWriteType.READ_WRITE)
     FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(16,))
@@ -122,7 +130,7 @@ class SDP(opcua_device):
     FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(12 * 512, 16))
     FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(12 * 512, 16), access=AttrWriteType.READ_WRITE)
-    FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.uint32, dims=(16,))
+    FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(16,))
     FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(16,))
     FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(12, 16))
     FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE)
@@ -156,10 +164,10 @@ class SDP(opcua_device):
     FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
     FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
 
-    FPGA_bsn_monitor_input_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-    FPGA_bsn_monitor_input_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_bsn_monitor_input_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_bsn_monitor_input_nof_err_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_err_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_signal_input_bsn_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_signal_input_nof_blocks_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_blocks_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_signal_input_nof_samples_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_samples_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_signal_input_nof_err_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_err_R"], datatype=numpy.int32, dims=(N_pn,))
     FPGA_signal_input_samples_delay_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
     FPGA_signal_input_samples_delay_RW = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_RW"], datatype=numpy.uint32, dims=(S_pn, N_pn), access=AttrWriteType.READ_WRITE)
 
@@ -194,17 +202,14 @@ class SDP(opcua_device):
     # --------
 
     def _prepare_hardware(self):
-        # FPGA firmware loading disabled, as it causes SDPTR to crash,
-        # see https://support.astron.nl/jira/browse/L2SDP-670
-        """
-        # FPGAs need the correct firmware loaded 
-        self.FPGA_boot_image_RW = [1] * self.N_pn
-
-        # wait for the firmware to be loaded (ignoring masked out elements)
-        mask = self.proxy.TR_fpga_mask_RW
-        self.wait_attribute("FPGA_boot_image_R", lambda attr: ((attr == 1) | ~mask).all(), 10)
-        """
-        pass
+        # 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] * self.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)
 
     # --------
     # Commands
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
index c7e9c95844b93768caa3622488ea2520244b38d9..1228cdc99d6ab8037f7c8bfe4ec859b5185cdd9e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
@@ -90,6 +90,9 @@ class SST(Statistics):
     FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=numpy.bool_, dims=(16,))
 
+    FPGA_sst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_packets_R"], datatype=numpy.int32, dims=(16,))
+    FPGA_sst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_valid_R"], datatype=numpy.int32, dims=(16,))
+
     # number of packets with valid payloads
     nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(SSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
     # number of packets with invalid payloads
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
index 8be9cdb483ef4f21818791009a19e8fbc2b91cb9..73a5d85bb742f06bf5412926cadefe4db0455716 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
@@ -110,6 +110,11 @@ class XST(Statistics):
 
     FPGA_xst_offload_nof_crosslets_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_xst_offload_nof_crosslets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_R"], datatype=numpy.uint32, dims=(16,))
+    FPGA_xst_ring_nof_transport_hops_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_ring_nof_transport_hops_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(16,))
+
+    FPGA_xst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_packets_R"], datatype=numpy.int32, dims=(16,))
+    FPGA_xst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_valid_R"], datatype=numpy.int32, dims=(16,))
 
     # number of packets with valid payloads
     nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_recv_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_recv_device.py
index 1fde8856cf55a79a03aaec2cc53ba34a4ad818f0..49de70bd5aecc1faab3bf7402f7adad059bd3823 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_recv_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_recv_device.py
@@ -19,7 +19,8 @@ from tangostationcontrol.test import base
 class TestRecvDevice(base.TestCase):
 
     # some dummy values for mandatory properties
-    recv_properties = {'OPC_Server_Name': 'example.com', 'OPC_Server_Port': 4840, 'OPC_Time_Out': 5.0}
+    recv_properties = {'OPC_Server_Name': 'example.com', 'OPC_Server_Port': 4840, 'OPC_Time_Out': 5.0, 
+    'Antenna_Field_Reference_ITRF' : [3.0, 3.0, 3.0], 'Antenna_Field_Reference_ETRS' : [7.0, 7.0, 7.0]}
 
     def setUp(self):
         super(TestRecvDevice, self).setUp()     
@@ -31,11 +32,20 @@ class TestRecvDevice(base.TestCase):
                 device, 'DeviceProxy')
             proxy_patcher.start()
             self.addCleanup(proxy_patcher.stop)
-    
-    
+       
     def test_calculate_HBAT_bf_delay_steps(self):
         """Verify HBAT beamforming calculations are correctly executed"""
         with DeviceTestContext(recv.RECV, properties=self.recv_properties, process=True) as proxy:
             delays = numpy.random.rand(96,16).flatten()
             HBAT_bf_delay_steps = proxy.calculate_HBAT_bf_delay_steps(delays)
             self.assertEqual(3072, len(HBAT_bf_delay_steps))                             # 96x32=3072
+    
+    def test_read_Antenna_Field_Reference(self):
+        """Verify if Antenna coordinates are correctly provided"""
+        # Device uses ITRF coordinates by default
+        with DeviceTestContext(recv.RECV, properties=self.recv_properties, process=True) as proxy:          
+            self.assertEqual(3.0, proxy.Antenna_Field_Reference_ITRF_R[0])
+        # Device derives coordinates from ETRS if ITRF ones are not found
+        recv_properties_v2 = {'OPC_Server_Name': 'example.com', 'OPC_Server_Port': 4840, 'OPC_Time_Out': 5.0, 'Antenna_Field_Reference_ETRS' : [7.0, 7.0, 7.0]}
+        with DeviceTestContext(recv.RECV, properties=recv_properties_v2, process=True) as proxy:            
+            self.assertNotEqual(3.0, proxy.Antenna_Field_Reference_ITRF_R[0])  # value = 6.948998835785814