Skip to content
Snippets Groups Projects
Commit ec1fde3e authored by Stefano Di Frischia's avatar Stefano Di Frischia
Browse files

Merge branch 'master' into L2SS-404-archiving-setup-development

parents 179d0dd3 7fa05349
Branches
Tags
1 merge request!253Resolve L2SS-404 "Archiving setup development"
Showing
with 286 additions and 136 deletions
...@@ -99,10 +99,10 @@ class StatisticsClient(AsyncCommClient): ...@@ -99,10 +99,10 @@ class StatisticsClient(AsyncCommClient):
def read_function(): def read_function():
if annotation.get("reshape", False): if annotation.get("reshape", False):
# force array into the shape of the attribute # force array into the shape of the attribute
if attribute.max_dim_y > 1: if attribute.dim_y > 1:
return self.collector.parameters[parameter].reshape(attribute.max_dim_y, attribute.max_dim_x) return self.collector.parameters[parameter].reshape(attribute.dim_y, attribute.dim_x)
else: else:
return self.collector.parameters[parameter].reshape(attribute.max_dim_x) return self.collector.parameters[parameter].reshape(attribute.dim_x)
else: else:
return self.collector.parameters[parameter] return self.collector.parameters[parameter]
elif annotation["type"] == "udp": elif annotation["type"] == "udp":
......
...@@ -79,12 +79,12 @@ class APSCT(opcua_device): ...@@ -79,12 +79,12 @@ class APSCT(opcua_device):
def read_APSCT_error_R(self): def read_APSCT_error_R(self):
return ((self.proxy.APSCTTR_I2C_error_R > 0) return ((self.proxy.APSCTTR_I2C_error_R > 0)
| self.alarm_val("APSCT_PCB_ID_R") or self.alarm_val("APSCT_PCB_ID_R")
| ~self.proxy.APSCT_INPUT_10MHz_good_R or (not self.proxy.APSCT_INPUT_10MHz_good_R)
| (~self.proxy.APSCT_INPUT_PPS_good_R & ~self.proxy.ASPCT_PPS_ignore_R) or (not self.proxy.APSCT_INPUT_PPS_good_R and not self.proxy.APSCT_PPS_ignore_R)
| (~self.proxy.APSCT_PLL_160MHz_locked_R & ~self.proxy.APSCT_PLL_200MHz_locked_R) or (not self.proxy.APSCT_PLL_160MHz_locked_R and not self.proxy.APSCT_PLL_200MHz_locked_R)
| (self.proxy.APSCT_PLL_200MHz_locked_R & self.proxy.APSCT_PLL_200MHz_error_R) or (self.proxy.APSCT_PLL_200MHz_locked_R and self.proxy.APSCT_PLL_200MHz_error_R)
| (self.proxy.APSCT_PLL_160MHz_locked_R & self.proxy.APSCT_PLL_160MHz_error_R) or (self.proxy.APSCT_PLL_160MHz_locked_R and self.proxy.APSCT_PLL_160MHz_error_R)
) )
APSCT_TEMP_error_R = attribute(dtype=bool) APSCT_TEMP_error_R = attribute(dtype=bool)
...@@ -95,13 +95,13 @@ class APSCT(opcua_device): ...@@ -95,13 +95,13 @@ class APSCT(opcua_device):
def read_APSCT_VOUT_error_R(self): def read_APSCT_VOUT_error_R(self):
return ( self.alarm_val("APSCT_PWR_PPSDIST_3V3_R") return ( self.alarm_val("APSCT_PWR_PPSDIST_3V3_R")
| self.alarm_val("APSCT_PWR_CLKDIST1_3V3_R") or self.alarm_val("APSCT_PWR_CLKDIST1_3V3_R")
| self.alarm_val("APSCT_PWR_CLKDIST2_3V3_R") or self.alarm_val("APSCT_PWR_CLKDIST2_3V3_R")
| self.alarm_val("APSCT_PWR_CTRL_3V3_R") or self.alarm_val("APSCT_PWR_CTRL_3V3_R")
| self.alarm_val("APSCT_PWR_INPUT_3V3_R") or self.alarm_val("APSCT_PWR_INPUT_3V3_R")
| (self.proxy.APSCT_PWR_PLL_160MHz_on_R & self.alarm_val("APSCT_PWR_PLL_160MHz_3V3_R")) or (self.proxy.APSCT_PWR_PLL_160MHz_on_R and self.alarm_val("APSCT_PWR_PLL_160MHz_3V3_R"))
| (self.proxy.APSCT_PWR_PLL_200MHz_on_R & self.alarm_val("APSCT_PWR_PLL_200MHz_3V3_R")) or (self.proxy.APSCT_PWR_PLL_200MHz_on_R and self.alarm_val("APSCT_PWR_PLL_200MHz_3V3_R"))
| ~self.proxy.APSCT_PWR_on_R or (not self.proxy.APSCT_PWR_on_R)
) )
# -------- # --------
......
...@@ -67,10 +67,10 @@ class APSPU(opcua_device): ...@@ -67,10 +67,10 @@ class APSPU(opcua_device):
def read_APSPU_error_R(self): def read_APSPU_error_R(self):
return ((self.proxy.APSPUTR_I2C_error_R > 0) return ((self.proxy.APSPUTR_I2C_error_R > 0)
| self.alarm_val("APSPU_PCB_ID_R") or self.alarm_val("APSPU_PCB_ID_R")
| self.alarm_val("APSPU_FAN1_RPM_R") or self.alarm_val("APSPU_FAN1_RPM_R")
| self.alarm_val("APSPU_FAN2_RPM_R") or self.alarm_val("APSPU_FAN2_RPM_R")
| self.alarm_val("APSPU_FAN3_RPM_R")) or self.alarm_val("APSPU_FAN3_RPM_R"))
APSPU_IOUT_error_R = attribute(dtype=bool) APSPU_IOUT_error_R = attribute(dtype=bool)
APSPU_TEMP_error_R = attribute(dtype=bool) APSPU_TEMP_error_R = attribute(dtype=bool)
...@@ -78,20 +78,20 @@ class APSPU(opcua_device): ...@@ -78,20 +78,20 @@ class APSPU(opcua_device):
def read_APSPU_IOUT_error_R(self): def read_APSPU_IOUT_error_R(self):
return ( self.alarm_val("APSPU_LBA_IOUT_R") return ( self.alarm_val("APSPU_LBA_IOUT_R")
| self.alarm_val("APSPU_RCU2A_IOUT_R") or self.alarm_val("APSPU_RCU2A_IOUT_R")
| self.alarm_val("APSPU_RCU2D_IOUT_R") or self.alarm_val("APSPU_RCU2D_IOUT_R")
) )
def read_APSPU_TEMP_error_R(self): def read_APSPU_TEMP_error_R(self):
return ( self.alarm_val("APSPU_LBA_TEMP_R") return ( self.alarm_val("APSPU_LBA_TEMP_R")
| self.alarm_val("APSPU_RCU2A_TEMP_R") or self.alarm_val("APSPU_RCU2A_TEMP_R")
| self.alarm_val("APSPU_RCU2D_TEMP_R") or self.alarm_val("APSPU_RCU2D_TEMP_R")
) )
def read_APSPU_VOUT_error_R(self): def read_APSPU_VOUT_error_R(self):
return ( self.alarm_val("APSPU_LBA_VOUT_R") return ( self.alarm_val("APSPU_LBA_VOUT_R")
| self.alarm_val("APSPU_RCU2A_VOUT_R") or self.alarm_val("APSPU_RCU2A_VOUT_R")
| self.alarm_val("APSPU_RCU2D_VOUT_R") or self.alarm_val("APSPU_RCU2D_VOUT_R")
) )
# -------- # --------
......
...@@ -12,7 +12,7 @@ import datetime ...@@ -12,7 +12,7 @@ import datetime
from json import loads from json import loads
from tango.server import attribute, command, device_property from tango.server import attribute, command, device_property
from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray, DevString from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray, DevString, DevSource
from threading import Thread, Lock, Condition from threading import Thread, Lock, Condition
# Additional import # Additional import
...@@ -67,6 +67,16 @@ class Beam(lofar_device): ...@@ -67,6 +67,16 @@ class Beam(lofar_device):
dtype=(numpy.double,), max_dim_x=96, dtype=(numpy.double,), max_dim_x=96,
fget=lambda self: self._hbat_pointing_timestamp_r) fget=lambda self: self._hbat_pointing_timestamp_r)
HBAT_tracking_enabled_R = attribute(access=AttrWriteType.READ,
doc="Whether the HBAT tile beam is updated periodically",
dtype=numpy.bool,
fget=lambda self: self.HBAT_beam_tracker.is_alive())
HBAT_tracking_enabled_RW = attribute(access=AttrWriteType.READ_WRITE,
doc="Whether the HBAT tile beam should be updated periodically",
dtype=numpy.bool,
fget=lambda self: self._hbat_tracking_enabled_rw)
# Directory where the casacore measures that we use, reside. We configure ~/.casarc to # Directory where the casacore measures that we use, reside. We configure ~/.casarc to
# use the symlink /opt/IERS/current, which we switch to the actual set of files to use. # use the symlink /opt/IERS/current, which we switch to the actual set of files to use.
measures_directory_R = attribute(dtype=str, access=AttrWriteType.READ, fget = lambda self: get_measures_directory()) measures_directory_R = attribute(dtype=str, access=AttrWriteType.READ, fget = lambda self: get_measures_directory())
...@@ -86,8 +96,12 @@ class Beam(lofar_device): ...@@ -86,8 +96,12 @@ class Beam(lofar_device):
self._hbat_pointing_direction_r = numpy.zeros((96,3), dtype="<U32") self._hbat_pointing_direction_r = numpy.zeros((96,3), dtype="<U32")
self._hbat_pointing_direction_rw = numpy.array([["AZELGEO","0deg","90deg"]] * 96, dtype="<U32") self._hbat_pointing_direction_rw = numpy.array([["AZELGEO","0deg","90deg"]] * 96, dtype="<U32")
# Initialise tracking control
self._hbat_tracking_enabled_rw = True
# Set a reference of RECV device # Set a reference of RECV device
self.recv_proxy = DeviceProxy("STAT/RECV/1") self.recv_proxy = DeviceProxy("STAT/RECV/1")
self.recv_proxy.set_source(DevSource.DEV)
# Retrieve positions from RECV device # Retrieve positions from RECV device
HBAT_reference_itrf = self.recv_proxy.HBAT_reference_itrf_R HBAT_reference_itrf = self.recv_proxy.HBAT_reference_itrf_R
...@@ -107,15 +121,15 @@ class Beam(lofar_device): ...@@ -107,15 +121,15 @@ class Beam(lofar_device):
super().configure_for_on() super().configure_for_on()
# Start beam tracking thread # Start beam tracking thread
if self._hbat_tracking_enabled_rw:
self.HBAT_beam_tracker.start() self.HBAT_beam_tracker.start()
@log_exceptions @log_exceptions()
def configure_for_off(self): def configure_for_off(self):
super().configure_for_off()
# Stop thread object # Stop thread object
self.HBAT_beam_tracker.stop() self.HBAT_beam_tracker.stop()
self.HBAT_beam_tracker = None
super().configure_for_off()
# -------- # --------
# internal functions # internal functions
...@@ -132,6 +146,15 @@ class Beam(lofar_device): ...@@ -132,6 +146,15 @@ class Beam(lofar_device):
# force update across tiles if pointing changes # force update across tiles if pointing changes
self.HBAT_beam_tracker.force_update() self.HBAT_beam_tracker.force_update()
logger.info("Pointing direction update requested")
def write_HBAT_tracking_enabled_RW(self, value):
self._hbat_tracking_enabled_rw = value
if value:
self.HBAT_beam_tracker.start()
else:
self.HBAT_beam_tracker.stop()
def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()): def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
""" """
...@@ -166,7 +189,7 @@ class Beam(lofar_device): ...@@ -166,7 +189,7 @@ class Beam(lofar_device):
# Record where we now point to, now that we've updated the weights. # Record where we now point to, now that we've updated the weights.
# Only the entries within the mask have been updated # Only the entries within the mask have been updated
mask = self.recv_proxy.Ant_mask_RW.flatten() mask = self.recv_proxy.ANT_mask_RW.flatten()
for rcu in range(96): for rcu in range(96):
if mask[rcu]: if mask[rcu]:
self._hbat_pointing_direction_r[rcu] = pointing_direction[rcu] self._hbat_pointing_direction_r[rcu] = pointing_direction[rcu]
...@@ -225,6 +248,7 @@ class Beam(lofar_device): ...@@ -225,6 +248,7 @@ class Beam(lofar_device):
@command(dtype_in=DevVarStringArray) @command(dtype_in=DevVarStringArray)
@DebugIt() @DebugIt()
@log_exceptions()
@only_in_states([DevState.ON]) @only_in_states([DevState.ON])
def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()): def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()):
""" """
...@@ -275,25 +299,39 @@ class BeamTracker(): ...@@ -275,25 +299,39 @@ class BeamTracker():
""" Object that encapsulates a Thread, resposible for beam tracking operations """ """ Object that encapsulates a Thread, resposible for beam tracking operations """
def __init__(self, device: lofar_device): def __init__(self, device: lofar_device):
self.thread = Thread(target=self._update_HBAT_pointing_direction) self.thread = None
self.device = device self.device = device
# Condition to trigger a forced update or early abort # Condition to trigger a forced update or early abort
self.update_lock = Lock() self.update_lock = Lock()
self.update_condition = Condition(self.update_lock) self.update_condition = Condition(self.update_lock)
# Whether the pointing has to be forced updated
self.stale_pointing = True
def start(self): def start(self):
""" Starts the Beam Tracking thread """ """ Starts the Beam Tracking thread """
if self.thread:
# already started
return
self.done = False self.done = False
self.thread = Thread(target=self._update_HBAT_pointing_direction, name=f"BeamTracker of {self.device.get_name()}")
self.thread.start() self.thread.start()
logger.info("BeamTracking thread started")
def is_alive(self): def is_alive(self):
""" Returns True just before the Thread run() method starts until just after the Thread run() method terminates. """ """ Returns True just before the Thread run() method starts until just after the Thread run() method terminates. """
return self.thread.is_alive() return self.thread and self.thread.is_alive()
def force_update(self): def force_update(self):
""" Force the pointing to be updated. """ """ Force the pointing to be updated. """
self.stale_pointing = True
self.unlock_thread()
def unlock_thread(self):
# inform the thread to stop waiting # inform the thread to stop waiting
with self.update_lock: with self.update_lock:
self.update_condition.notify() self.update_condition.notify()
...@@ -301,6 +339,11 @@ class BeamTracker(): ...@@ -301,6 +339,11 @@ class BeamTracker():
def stop(self): def stop(self):
""" Stops the Beam Tracking loop """ """ Stops the Beam Tracking loop """
if not self.thread:
return
logger.info("BeamTracking thread stopping")
self.done = True self.done = True
self.force_update() self.force_update()
...@@ -310,6 +353,10 @@ class BeamTracker(): ...@@ -310,6 +353,10 @@ class BeamTracker():
if self.is_alive(): if self.is_alive():
logger.error("BeamTracking Thread did not properly terminate") logger.error("BeamTracking Thread did not properly terminate")
self.thread = None
logger.info("BeamTracking thread stopped")
def _get_sleep_time(self): def _get_sleep_time(self):
""" Computes the sleep time (in seconds) that needs to be waited for the next beam tracking update """ """ Computes the sleep time (in seconds) that needs to be waited for the next beam tracking update """
now = datetime.datetime.now().timestamp() now = datetime.datetime.now().timestamp()
...@@ -325,13 +372,21 @@ class BeamTracker(): ...@@ -325,13 +372,21 @@ class BeamTracker():
else: else:
return sleep_time return sleep_time
# @fault_on_error routes errors here. we forward them to our device
def Fault(self, msg):
self.device.Fault(msg)
@log_exceptions()
@fault_on_error()
def _update_HBAT_pointing_direction(self): def _update_HBAT_pointing_direction(self):
""" Updates the beam weights using a fixed interval of time """ """ Updates the beam weights using a fixed interval of time """
# Check if flag beamtracking is true # Check if flag beamtracking is true
with self.update_lock: with self.update_lock:
while not self.done: while not self.done:
self.device.HBAT_set_pointing(numpy.array(self.device.proxy.HBAT_pointing_direction_RW).flatten()) self.stale_pointing = False
self.device._HBAT_set_pointing(self.device._hbat_pointing_direction_rw, datetime.datetime.now())
# sleep until the next update, or when interrupted (this releases the lock, allowing for notification) # sleep until the next update, or when interrupted (this releases the lock, allowing for notification)
self.update_condition.wait(self._get_sleep_time()) # note that we need wait_for as conditions can be triggered multiple times in succession
self.update_condition.wait_for(lambda: self.done or self.stale_pointing, self._get_sleep_time())
...@@ -430,5 +430,8 @@ class lofar_device(Device, metaclass=DeviceMeta): ...@@ -430,5 +430,8 @@ class lofar_device(Device, metaclass=DeviceMeta):
alarm_state |= value <= value.dtype.type(alarms.min_alarm) alarm_state |= value <= value.dtype.type(alarms.min_alarm)
# return alarm state, with the same dimensions as the attribute # return alarm state, with the same dimensions as the attribute
if is_scalar:
return alarm_state.item()
else:
return alarm_state return alarm_state
...@@ -196,9 +196,9 @@ class RECV(opcua_device): ...@@ -196,9 +196,9 @@ class RECV(opcua_device):
RECV_VOUT_error_R = attribute(dtype=(bool,), max_dim_x=32) RECV_VOUT_error_R = attribute(dtype=(bool,), max_dim_x=32)
def read_RECV_IOUT_error_R(self): def read_RECV_IOUT_error_R(self):
return self.proxy.ANT_mask_RW & ( return (self.proxy.ANT_mask_RW & (
self.alarm_val("RCU_PWR_ANT_IOUT_R") self.alarm_val("RCU_PWR_ANT_IOUT_R")
).any(axis=1) )).any(axis=1)
def read_RECV_TEMP_error_R(self): def read_RECV_TEMP_error_R(self):
# Don't apply the mask here --- we always want to know if things get too hot! # Don't apply the mask here --- we always want to know if things get too hot!
...@@ -210,13 +210,13 @@ class RECV(opcua_device): ...@@ -210,13 +210,13 @@ class RECV(opcua_device):
return (self.proxy.ANT_mask_RW & ( return (self.proxy.ANT_mask_RW & (
self.alarm_val("RCU_PWR_ANT_VIN_R") self.alarm_val("RCU_PWR_ANT_VIN_R")
| self.alarm_val("RCU_PWR_ANT_VOUT_R") | self.alarm_val("RCU_PWR_ANT_VOUT_R")
).any(axis=1) | (self.proxy.RCU_mask_RW & ( )).any(axis=1) | (self.proxy.RCU_mask_RW & (
self.alarm_val("RCU_PWR_1V8_R") self.alarm_val("RCU_PWR_1V8_R")
| self.alarm_val("RCU_PWR_2V5_R") | self.alarm_val("RCU_PWR_2V5_R")
| self.alarm_val("RCU_PWR_3V3_R") | self.alarm_val("RCU_PWR_3V3_R")
| ~self.proxy.RCU_PWR_DIGITAL_on_R | ~self.proxy.RCU_PWR_DIGITAL_on_R
| ~self.proxy.RCU_PWR_good_R | ~self.proxy.RCU_PWR_good_R
))) ))
# -------- # --------
# overloaded functions # overloaded functions
......
...@@ -129,8 +129,6 @@ class SDP(opcua_device): ...@@ -129,8 +129,6 @@ class SDP(opcua_device):
FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(12 * 512, 16)) 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_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(12 * 512, 16), access=AttrWriteType.READ_WRITE)
FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(16,)) FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(16,))
FPGA_weights_R = attribute_wrapper(comms_annotation=["FPGA_weights_R"], datatype=numpy.int16, dims=(12 * 488 * 2, 16))
FPGA_weights_RW = attribute_wrapper(comms_annotation=["FPGA_weights_RW"], datatype=numpy.int16, dims=(12 * 488 * 2, 16), access=AttrWriteType.READ_WRITE)
FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(12, 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) FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE)
FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=numpy.bool_, dims=(12, 16)) FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=numpy.bool_, dims=(12, 16))
...@@ -211,11 +209,12 @@ class SDP(opcua_device): ...@@ -211,11 +209,12 @@ class SDP(opcua_device):
# ---------- # ----------
FPGA_error_R = attribute(dtype=(bool,), max_dim_x=16) FPGA_error_R = attribute(dtype=(bool,), max_dim_x=16)
FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=16) FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=16)
FPGA_input_error_R = attribute(dtype=(bool,), max_dim_x=16)
def read_FPGA_error_R(self): def read_FPGA_error_R(self):
return self.proxy.TR_fpga_mask_RW & ( return self.proxy.TR_fpga_mask_RW & (
self.proxy.TR_fpga_communication_error_R self.proxy.TR_fpga_communication_error_R
| self.proxy.FPGA_firmware_version_R != "" | (self.proxy.FPGA_firmware_version_R != "")
| (self.proxy.FPGA_jesd204b_csr_dev_syncn_R == 0).any(axis=1) | (self.proxy.FPGA_jesd204b_csr_dev_syncn_R == 0).any(axis=1)
) )
...@@ -223,8 +222,12 @@ class SDP(opcua_device): ...@@ -223,8 +222,12 @@ class SDP(opcua_device):
return self.proxy.TR_fpga_mask_RW & ( return self.proxy.TR_fpga_mask_RW & (
~self.proxy.FPGA_processing_enable_R ~self.proxy.FPGA_processing_enable_R
| (self.proxy.FPGA_boot_image_R == 0) | (self.proxy.FPGA_boot_image_R == 0)
| self.proxy.FPGA_wg_enable_R.any(axis=1) )
| (self.proxy.FPGA_signal_input_rms_R == 0)
def read_FPGA_input_error_R(self):
return self.proxy.TR_fpga_mask_RW & (
self.proxy.FPGA_wg_enable_R.any(axis=1)
| (self.proxy.FPGA_signal_input_rms_R == 0).any(axis=1)
) )
# -------- # --------
...@@ -237,7 +240,7 @@ class SDP(opcua_device): ...@@ -237,7 +240,7 @@ class SDP(opcua_device):
# wait for the firmware to be loaded (ignoring masked out elements) # wait for the firmware to be loaded (ignoring masked out elements)
mask = self.proxy.TR_fpga_mask_RW mask = self.proxy.TR_fpga_mask_RW
self.wait_attribute("FPGA_boot_image_R", lambda attr: (attr == 1) | ~mask, 10) self.wait_attribute("FPGA_boot_image_R", lambda attr: ((attr == 1) | ~mask).all(), 10)
# -------- # --------
# Commands # Commands
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# PyTango imports # PyTango imports
from tango.server import device_property from tango.server import device_property
from tango import DeviceProxy from tango import DeviceProxy, DevSource
# Additional import # Additional import
import asyncio import asyncio
...@@ -126,6 +126,7 @@ class Statistics(opcua_device): ...@@ -126,6 +126,7 @@ class Statistics(opcua_device):
# proxy the SDP device in case we need the FPGA mask # proxy the SDP device in case we need the FPGA mask
self.sdp_proxy = DeviceProxy("STAT/SDP/1") self.sdp_proxy = DeviceProxy("STAT/SDP/1")
self.sdp_proxy.set_source(DevSource.DEV)
async def _connect_statistics(self): async def _connect_statistics(self):
# map an access helper class # map an access helper class
......
...@@ -151,7 +151,7 @@ class XSTCollector(StatisticsCollector): ...@@ -151,7 +151,7 @@ class XSTCollector(StatisticsCollector):
# When the youngest data for each subband was received # When the youngest data for each subband was received
"xst_timestamps": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.float64), "xst_timestamps": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.float64),
"xst_subbands": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.uint16), "xst_subbands": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.uint16),
"integration_intervals": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.float32), "xst_integration_intervals": numpy.zeros((self.MAX_PARALLEL_SUBBANDS,), dtype=numpy.float32),
}) })
return defaults return defaults
...@@ -234,7 +234,7 @@ class XSTCollector(StatisticsCollector): ...@@ -234,7 +234,7 @@ class XSTCollector(StatisticsCollector):
self.parameters["xst_timestamps"][subband_slot] = numpy.float64(fields.timestamp().timestamp()) self.parameters["xst_timestamps"][subband_slot] = numpy.float64(fields.timestamp().timestamp())
self.parameters["xst_conjugated"][subband_slot, block_index] = conjugated self.parameters["xst_conjugated"][subband_slot, block_index] = conjugated
self.parameters["xst_subbands"][subband_slot] = numpy.uint16(fields.subband_index) self.parameters["xst_subbands"][subband_slot] = numpy.uint16(fields.subband_index)
self.parameters["integration_intervals"][subband_slot] = fields.integration_interval() self.parameters["xst_integration_intervals"][subband_slot] = fields.integration_interval()
def xst_values(self, subband_indices=range(MAX_PARALLEL_SUBBANDS)): def xst_values(self, subband_indices=range(MAX_PARALLEL_SUBBANDS)):
""" xst_blocks, but as a matrix[len(subband_indices)][MAX_INPUTS][MAX_INPUTS] of complex values. """ xst_blocks, but as a matrix[len(subband_indices)][MAX_INPUTS][MAX_INPUTS] of complex values.
...@@ -246,7 +246,7 @@ class XSTCollector(StatisticsCollector): ...@@ -246,7 +246,7 @@ class XSTCollector(StatisticsCollector):
xst_blocks = self.parameters["xst_blocks"] xst_blocks = self.parameters["xst_blocks"]
xst_conjugated = self.parameters["xst_conjugated"] xst_conjugated = self.parameters["xst_conjugated"]
for subband_index in subband_indices: for matrix_idx, subband_index in enumerate(subband_indices):
for block_index in range(self.MAX_BLOCKS): for block_index in range(self.MAX_BLOCKS):
# convert real/imag int to complex float values. this works as real/imag come in pairs # convert real/imag int to complex float values. this works as real/imag come in pairs
block = xst_blocks[subband_index][block_index].astype(numpy.float32).view(numpy.complex64) block = xst_blocks[subband_index][block_index].astype(numpy.float32).view(numpy.complex64)
...@@ -263,7 +263,7 @@ class XSTCollector(StatisticsCollector): ...@@ -263,7 +263,7 @@ class XSTCollector(StatisticsCollector):
first_baseline = (first_baseline[0] * self.BLOCK_LENGTH, first_baseline[1] * self.BLOCK_LENGTH) first_baseline = (first_baseline[0] * self.BLOCK_LENGTH, first_baseline[1] * self.BLOCK_LENGTH)
# copy block into matrix # copy block into matrix
matrix[subband_index][first_baseline[0]:first_baseline[0]+self.BLOCK_LENGTH, first_baseline[1]:first_baseline[1]+self.BLOCK_LENGTH] = block matrix[matrix_idx][first_baseline[0]:first_baseline[0]+self.BLOCK_LENGTH, first_baseline[1]:first_baseline[1]+self.BLOCK_LENGTH] = block
return matrix return matrix
......
...@@ -116,15 +116,15 @@ class XST(Statistics): ...@@ -116,15 +116,15 @@ class XST(Statistics):
# number of packets with invalid payloads # number of packets with invalid payloads
nof_payload_errors_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64) nof_payload_errors_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
# latest XSTs # latest XSTs
xst_blocks_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(XSTCollector.BLOCK_LENGTH * XSTCollector.BLOCK_LENGTH * XSTCollector.VALUES_PER_COMPLEX, XSTCollector.MAX_BLOCKS), datatype=numpy.int64) xst_blocks_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(XSTCollector.MAX_BLOCKS * XSTCollector.BLOCK_LENGTH * XSTCollector.BLOCK_LENGTH * XSTCollector.VALUES_PER_COMPLEX, XSTCollector.MAX_PARALLEL_SUBBANDS), datatype=numpy.int64)
# whether the values in the block are conjugated and transposed # whether the values in the block are conjugated and transposed
xst_conjugated_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(XSTCollector.MAX_BLOCKS,), datatype=numpy.bool_) xst_conjugated_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(XSTCollector.MAX_BLOCKS, XSTCollector.MAX_PARALLEL_SUBBANDS), datatype=numpy.bool_)
# reported timestamp for each subband in the latest XSTs # reported timestamp for each subband in the latest XSTs
xst_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64) xst_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
# which subband the XSTs describe # which subband the XSTs describe
xst_subbands_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16) xst_subbands_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16)
# integration interval for each subband in the latest XSTs # integration interval for each subband in the latest XSTs
integration_interval_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32) xst_integration_interval_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_integration_intervals"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32)
# xst_R, but as a matrix of subband x (input x input) # xst_R, but as a matrix of subband x (input x input)
xst_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),)) xst_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
...@@ -145,57 +145,57 @@ class XST(Statistics): ...@@ -145,57 +145,57 @@ class XST(Statistics):
return numpy.angle(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS) return numpy.angle(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS)
# xst_R, but as a matrix of input x input, for each specific subband index # xst_R, but as a matrix of input x input, for each specific subband index
xst_0_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(0)) xst_0_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(0))
xst_0_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(0)) xst_0_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(0))
xst_0_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(0)) xst_0_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(0))
xst_0_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(0)) xst_0_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(0))
xst_1_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(1)) xst_1_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(1))
xst_1_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(1)) xst_1_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(1))
xst_1_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(1)) xst_1_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(1))
xst_1_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(1)) xst_1_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(1))
xst_2_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(2)) xst_2_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(2))
xst_2_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(2)) xst_2_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(2))
xst_2_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(2)) xst_2_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(2))
xst_2_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(2)) xst_2_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(2))
xst_3_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(3)) xst_3_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(3))
xst_3_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(3)) xst_3_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(3))
xst_3_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(3)) xst_3_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(3))
xst_3_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(3)) xst_3_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(3))
xst_4_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(4)) xst_4_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(4))
xst_4_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(4)) xst_4_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(4))
xst_4_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(4)) xst_4_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(4))
xst_4_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(4)) xst_4_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(4))
xst_5_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(5)) xst_5_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(5))
xst_5_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(5)) xst_5_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(5))
xst_5_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(5)) xst_5_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(5))
xst_5_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(5)) xst_5_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(5))
xst_6_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(6)) xst_6_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(6))
xst_6_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(6)) xst_6_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(6))
xst_6_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(6)) xst_6_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(6))
xst_6_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(6)) xst_6_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(6))
xst_7_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real(7)) xst_7_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(7))
xst_7_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag(7)) xst_7_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(7))
xst_7_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power(7)) xst_7_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(7))
xst_7_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase(7)) xst_7_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(7))
def read_xst_N_real_R(self, subband_idx): def read_xst_N_real_R(self, subband_idx):
return numpy.real(self.statistics_client.collector.xst_values(subband_idx)[0]) return numpy.real(self.statistics_client.collector.xst_values([subband_idx])[0])
def read_xst_N_imag_R(self, subband_idx): def read_xst_N_imag_R(self, subband_idx):
return numpy.imag(self.statistics_client.collector.xst_values(subband_idx)[0]) return numpy.imag(self.statistics_client.collector.xst_values([subband_idx])[0])
def read_xst_N_power_R(self, subband_idx): def read_xst_N_power_R(self, subband_idx):
return numpy.abs(self.statistics_client.collector.xst_values(subband_idx)[0]) return numpy.abs(self.statistics_client.collector.xst_values([subband_idx])[0])
def read_xst_N_phase_R(self, subband_idx): def read_xst_N_phase_R(self, subband_idx):
return numpy.angle(self.statistics_client.collector.xst_values(subband_idx)[0]) return numpy.angle(self.statistics_client.collector.xst_values([subband_idx])[0])
# ---------- # ----------
# Summarising Attributes # Summarising Attributes
......
...@@ -61,9 +61,30 @@ class AbstractTestBases: ...@@ -61,9 +61,30 @@ class AbstractTestBases:
self.self.assertListEqual([], self.proxy.opcua_missing_attributes_R) self.self.assertListEqual([], self.proxy.opcua_missing_attributes_R)
def test_device_on(self): def test_device_on(self):
"""Test if we can transition to on""" """Test if we can transition off -> standby -> on"""
self.proxy.initialise() self.proxy.initialise()
self.proxy.on() self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state()) self.assertEqual(DevState.ON, self.proxy.state())
def test_device_warm_boot(self):
"""Test if we can transition off -> on using a warm boot"""
self.proxy.warm_boot()
self.assertEqual(DevState.ON, self.proxy.state())
def test_device_read_all_attributes(self):
"""Test if we can read all of the exposed attributes in the ON state.
This test covers the reading logic of all attributes. """
self.proxy.initialise()
self.proxy.on()
for attribute_name in self.proxy.get_attribute_list():
try:
_ = self.proxy.read_attribute(attribute_name).value
except Exception as e:
raise AssertionError(f"Could not read attribute {attribute_name} from device {self.name}") from e
...@@ -12,7 +12,6 @@ import numpy ...@@ -12,7 +12,6 @@ import numpy
import datetime import datetime
import json import json
from tango import DevState
from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
from .base import AbstractTestBases from .base import AbstractTestBases
...@@ -36,11 +35,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -36,11 +35,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
# setup RECV # setup RECV
recv_proxy = TestDeviceProxy("STAT/RECV/1") recv_proxy = TestDeviceProxy("STAT/RECV/1")
recv_proxy.off() recv_proxy.off()
recv_proxy.initialise() recv_proxy.warm_boot()
self.assertEqual(DevState.STANDBY, recv_proxy.state())
recv_proxy.set_defaults() recv_proxy.set_defaults()
recv_proxy.on()
self.assertEqual(DevState.ON, recv_proxy.state())
return recv_proxy return recv_proxy
def test_HBAT_delays_dims(self): def test_HBAT_delays_dims(self):
...@@ -48,12 +44,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -48,12 +44,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
self.setup_recv_proxy() self.setup_recv_proxy()
# setup BEAM # setup BEAM
self.proxy.init() self.proxy.warm_boot()
self.proxy.Initialise()
self.assertEqual(DevState.STANDBY, self.proxy.state())
self.proxy.set_defaults()
self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state())
# verify HBAT_delays method returns the correct dimensions # verify HBAT_delays method returns the correct dimensions
HBAT_delays = self.proxy.HBAT_delays(self.pointing_direction) HBAT_delays = self.proxy.HBAT_delays(self.pointing_direction)
...@@ -64,12 +55,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -64,12 +55,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
recv_proxy = self.setup_recv_proxy() recv_proxy = self.setup_recv_proxy()
# setup BEAM # setup BEAM
self.proxy.init() self.proxy.warm_boot()
self.proxy.Initialise() self.proxy.HBAT_tracking_enabled_RW = False
self.assertEqual(DevState.STANDBY, self.proxy.state())
self.proxy.set_defaults()
self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state())
# Verify attribute is present (all zeros if never used before) # Verify attribute is present (all zeros if never used before)
HBAT_delays_r1 = numpy.array(recv_proxy.read_attribute('HBAT_BF_delay_steps_RW').value) HBAT_delays_r1 = numpy.array(recv_proxy.read_attribute('HBAT_BF_delay_steps_RW').value)
...@@ -89,8 +76,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -89,8 +76,8 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
# setup RECV as well # setup RECV as well
recv_proxy = self.setup_recv_proxy() recv_proxy = self.setup_recv_proxy()
self.proxy.initialise() self.proxy.warm_boot()
self.proxy.on() self.proxy.HBAT_tracking_enabled_RW = False
# Point to Zenith # Point to Zenith
self.proxy.HBAT_set_pointing(numpy.array([["AZELGEO","0deg","90deg"]] * 96).flatten()) self.proxy.HBAT_set_pointing(numpy.array([["AZELGEO","0deg","90deg"]] * 96).flatten())
...@@ -101,12 +88,39 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -101,12 +88,39 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
numpy.testing.assert_equal(calculated_HBAT_delay_steps, expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps, expected_HBAT_delay_steps)
def test_pointing_across_horizon(self):
# setup RECV as well
recv_proxy = self.setup_recv_proxy()
self.proxy.warm_boot()
self.proxy.HBAT_tracking_enabled_RW = False
# point at north on the horizon
self.proxy.HBAT_set_pointing(["AZELGEO","0deg","0deg"] * 96)
# obtain delays of the X polarisation of all the elements of the first tile
north_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
# delays must differ under rotation, or our test will give a false positive
self.assertNotEqual(north_beam_delay_steps.tolist(), numpy.rot90(north_beam_delay_steps).tolist())
for angle in (90,180,270):
# point at angle degrees (90=E, 180=S, 270=W)
self.proxy.HBAT_set_pointing(["AZELGEO",f"{angle}deg","0deg"] * 96)
# obtain delays of the X polarisation of all the elements of the first tile
angled_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
expected_delay_steps = numpy.rot90(north_beam_delay_steps, k=-(angle/90))
self.assertListEqual(expected_delay_steps.tolist(), angled_beam_delay_steps.tolist(), msg=f"angle={angle}")
def test_delays_same_as_LOFAR_ref_pointing(self): def test_delays_same_as_LOFAR_ref_pointing(self):
# setup RECV as well # setup RECV as well
recv_proxy = self.setup_recv_proxy() recv_proxy = self.setup_recv_proxy()
self.proxy.initialise() self.proxy.warm_boot()
self.proxy.on() self.proxy.HBAT_tracking_enabled_RW = False
# Point to LOFAR 1 ref pointing (0.929342, 0.952579, J2000) # Point to LOFAR 1 ref pointing (0.929342, 0.952579, J2000)
pointings = numpy.array([["J2000", "0.929342rad", "0.952579rad"]] * 96).flatten() pointings = numpy.array([["J2000", "0.929342rad", "0.952579rad"]] * 96).flatten()
...@@ -131,3 +145,20 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -131,3 +145,20 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
expected_HBAT_delay_steps = numpy.array([24, 25, 27, 29, 17, 18, 20, 21, 10, 11, 13, 14, 3, 4, 5, 7] * 2, dtype=numpy.int64) expected_HBAT_delay_steps = numpy.array([24, 25, 27, 29, 17, 18, 20, 21, 10, 11, 13, 14, 3, 4, 5, 7] * 2, dtype=numpy.int64)
numpy.testing.assert_equal(calculated_HBAT_delay_steps[0], expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps[0], expected_HBAT_delay_steps)
numpy.testing.assert_equal(calculated_HBAT_delay_steps[48], expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps[48], expected_HBAT_delay_steps)
def test_beam_tracking(self):
# setup RECV as well
recv_proxy = self.setup_recv_proxy()
self.proxy.warm_boot()
# check if we're really tracking
self.assertTrue(self.proxy.HBAT_tracking_enabled_R)
# point somewhere
new_pointings = [("J2000",f"{tile}deg","0deg") for tile in range(96)]
self.proxy.HBAT_pointing_direction_RW = new_pointings
# check pointing
self.assertListEqual(new_pointings, list(self.proxy.HBAT_pointing_direction_R))
...@@ -19,7 +19,6 @@ class TestDeviceSDP(AbstractTestBases.TestDeviceBase): ...@@ -19,7 +19,6 @@ class TestDeviceSDP(AbstractTestBases.TestDeviceBase):
def test_device_sdp_read_attribute(self): def test_device_sdp_read_attribute(self):
"""Test if we can read an attribute obtained over OPC-UA""" """Test if we can read an attribute obtained over OPC-UA"""
self.proxy.initialise() self.proxy.warm_boot()
self.proxy.on()
self.assertListEqual([True]*16, list(self.proxy.TR_fpga_communication_error_R)) self.assertListEqual([True]*16, list(self.proxy.TR_fpga_communication_error_R))
...@@ -12,6 +12,7 @@ import sys ...@@ -12,6 +12,7 @@ import sys
import time import time
from tango._tango import DevState from tango._tango import DevState
from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
from .base import AbstractTestBases from .base import AbstractTestBases
...@@ -22,14 +23,24 @@ class TestDeviceSST(AbstractTestBases.TestDeviceBase): ...@@ -22,14 +23,24 @@ class TestDeviceSST(AbstractTestBases.TestDeviceBase):
"""Intentionally recreate the device object in each test""" """Intentionally recreate the device object in each test"""
super().setUp("STAT/SST/1") super().setUp("STAT/SST/1")
def test_device_read_all_attributes(self):
# We need to connect to SDP first to read some of our attributes
self.sdp_proxy = self.setup_sdp()
super().test_device_read_all_attributes()
def setup_sdp(self):
# setup SDP, on which this device depends
sdp_proxy = TestDeviceProxy("STAT/SDP/1")
sdp_proxy.off()
sdp_proxy.warm_boot()
sdp_proxy.set_defaults()
return sdp_proxy
def test_device_sst_send_udp(self): def test_device_sst_send_udp(self):
port_property = {"Statistics_Client_TCP_Port": "4998"} port_property = {"Statistics_Client_TCP_Port": "4998"}
self.proxy.put_property(port_property) self.proxy.put_property(port_property)
self.proxy.initialise() self.proxy.warm_boot()
self.assertEqual(DevState.STANDBY, self.proxy.state())
self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state()) self.assertEqual(DevState.ON, self.proxy.state())
...@@ -44,13 +55,7 @@ class TestDeviceSST(AbstractTestBases.TestDeviceBase): ...@@ -44,13 +55,7 @@ class TestDeviceSST(AbstractTestBases.TestDeviceBase):
def test_device_sst_connect_tcp_receive(self): def test_device_sst_connect_tcp_receive(self):
port_property = {"Statistics_Client_TCP_Port": "5101"} port_property = {"Statistics_Client_TCP_Port": "5101"}
self.proxy.put_property(port_property) self.proxy.put_property(port_property)
self.proxy.initialise() self.proxy.warm_boot()
self.assertEqual(DevState.STANDBY, self.proxy.state())
self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state())
time.sleep(2) time.sleep(2)
......
# -*- 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
from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
class TestDeviceSST(AbstractTestBases.TestDeviceBase):
def setUp(self):
"""Intentionally recreate the device object in each test"""
super().setUp("STAT/XST/1")
def test_device_read_all_attributes(self):
# We need to connect to SDP first to read some of our attributes
self.sdp_proxy = self.setup_sdp()
super().test_device_read_all_attributes()
def setup_sdp(self):
# setup SDP, on which this device depends
sdp_proxy = TestDeviceProxy("STAT/SDP/1")
sdp_proxy.off()
sdp_proxy.warm_boot()
sdp_proxy.set_defaults()
return sdp_proxy
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment