Skip to content
Snippets Groups Projects
Commit 263caa9f authored by Jan David Mol's avatar Jan David Mol
Browse files

L2SS-624: Add summarizing attributes for state, improve/fix boot procedure of various devices

parent 76286f5c
Branches
Tags
1 merge request!244L2SS-624: Add summarizing attributes for state, improve/fix boot procedure of various devices
Showing
with 281 additions and 186 deletions
......@@ -3,13 +3,19 @@
Boot
====================
The ``boot == DeviceProxy("STAT/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. This device provides the following commands:
The ``boot == DeviceProxy("STAT/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. It is the only device that starts in the ``ON`` state, so it can be used immediately to initialise other devices.
:boot(): Stop and start the other devices in the correct order, set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Initialisation is aborted if an error is encountered.
This device provides the following commands:
:boot(): Start the other devices in the correct order, if they are not ON. Set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Initialisation is aborted if an error is encountered.
:returns: ``None``
:warm_boot(): Like ``boot()``, but do not initialise the hardware. Just start our software devices.
:returns: ``None``
:resume(): Resume an earlier boot attempt: start initialising devices from the first one that failed to initialise, instead of from scratch.
:reboot(): Like ``boot()``, but turn off all other devices first.
:returns: ``None``
......
......@@ -20,17 +20,18 @@ The state of a device is then queried with ``device.state()``. Each device can b
- ``DevState.OFF``: The device is not operating,
- ``DevState.INIT``: The device is being initialised,
- ``DevState.STANDBY``: The device is initialised and ready to be configured further,
- ``DevState.ON``: The device is operational.
- ``DevState.ON``: The device is operational,
- ``DevState.ALARM``: The device is operational, but one or more attributes are in alarm,
- ``DevState.FAULT``: The device is malfunctioning. Functionality cannot be counted on.
- The ``device.state()`` function can throw an error, if the device cannot be reached at all. For example, because it's docker container is not running. See the :ref:`docker` device on how to start it.
Each device provides the following commands to change the state:
:off(): Turn the device ``OFF`` from any state.
:boot(): Turn on the device, and initialise the hardware. Moves from ``OFF`` to ``ON``.
:initialise(): Initialise the device from the ``OFF`` state, to bring it to the ``STANDBY`` state.
:warm_boot(): Turn on the device, but do not change the hardware. Moves from ``OFF`` to ``ON``.
:on(): Mark the device as operational, from the ``STANDBY`` state, bringing it to ``ON``.
:off(): Turn the device ``OFF`` from any state.
The following procedure is a good way to bring a device to ``ON`` from any state::
......@@ -38,9 +39,7 @@ The following procedure is a good way to bring a device to ``ON`` from any state
if device.state() == DevState.FAULT:
device.off()
if device.state() == DevState.OFF:
device.initialise()
if device.state() == DevState.STANDBY:
device.on()
device.boot()
return device.state()
......@@ -77,7 +76,13 @@ Most devices provide the following commands, in order to configure the hardware
:initialise_hardware(): For devices that control hardware, this command runs the hardware initialisation procedure.
Typically, ``set_defaults()`` and ``initialise_hardware()`` are called in that order in the ``STANDBY`` state. See also :ref:`boot`, which provides functionality to initialise all the devices.
Typically, ``set_defaults()`` and ``initialise_hardware()`` are called in that order in the ``STANDBY`` state, during ``boot()``. To manually go through the boot sequence, use the following commands:
:initialise(): Initialise the device (connect to the hardware). Moves from ``OFF`` to ``STANDBY``.
:on(): Mark the device as operational. Moves from ``STANDBY`` to ``ON``.
See also :ref:`boot`, which provides functionality to initialise all the devices.
.. _attributes:
......
......@@ -44,29 +44,25 @@ After bootstrapping, and after a reboot, the software and hardware of the statio
The following commands start all the software devices to control the station hardware, and initialise the hardware with the configured default settings. Go to http://localhost:8888, start a new *Station Control* notebook, and initiate the software boot sequence::
# reset our boot device
boot.off()
assert boot.state() == DevState.OFF
boot.initialise()
assert boot.state() == DevState.STANDBY
boot.on()
assert boot.state() == DevState.ON
# start and initialise the other devices
boot.initialise_station()
boot.boot()
# wait for the devices to be initialised
import time
while boot.initialising_station_R:
print(f"Still initialising station. {boot.initialisation_progress_R}% complete. State: {boot.initialisation_status_R}")
while boot.booting_R:
print(f"Still initialising station. {boot.progress_R}% complete. State: {boot.status_R}")
time.sleep(1)
# print conclusion
if boot.initialisation_progress_R == 100:
if boot.progress_R == 100:
print("Done initialising station.")
else:
print(f"Failed to initialise station: {boot.initialisation_status_R}")
print(f"Failed to initialise station: {boot.status_R}")
# print what did and did not get initialised
print(f"Initialised devices: {boot.initialised_devices_R}")
print(f"Uninitialised devices: {boot.uninitialised_devices_R}")
See :ref:`boot` for more information on the ``boot`` device.
......
......@@ -13,7 +13,7 @@
# PyTango imports
from tango import DebugIt
from tango.server import command
from tango.server import command, attribute, device_property
from tango import AttrWriteType, DevState
import numpy
# Additional import
......@@ -36,6 +36,12 @@ class APSCT(opcua_device):
# Device Properties
# -----------------
APSCTTR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
# ----------
# Attributes
# ----------
......@@ -66,6 +72,15 @@ class APSCT(opcua_device):
APSCT_PWR_PPSDIST_3V3_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R" ],datatype=numpy.float64)
APSCT_TEMP_R = attribute_wrapper(comms_annotation=["APSCT_TEMP_R" ],datatype=numpy.float64)
# ----------
# Summarising Attributes
# ----------
APSCT_error_R = attribute(dtype=bool)
def read_APSCT_error_R(self):
return ((self.proxy.APSCTTR_I2C_error_R > 0)
| self.alarm_val("APSCT_PCB_ID_R"))
# --------
# overloaded functions
# --------
......
......@@ -13,6 +13,7 @@
# PyTango imports
from tango import AttrWriteType
from tango.server import attribute, device_property
import numpy
# Additional import
......@@ -30,6 +31,12 @@ class APSPU(opcua_device):
# Device Properties
# -----------------
APSPUTR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
# ----------
# Attributes
# ----------
......@@ -53,6 +60,18 @@ class APSPU(opcua_device):
APSPU_RCU2D_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_TEMP_R" ],datatype=numpy.float64)
APSPU_RCU2D_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_VOUT_R" ],datatype=numpy.float64)
# ----------
# Summarising Attributes
# ----------
APSPU_error_R = attribute(dtype=bool)
def read_APSPU_error_R(self):
return ((self.proxy.APSPUTR_I2C_error_R > 0)
| self.alarm_val("APSPU_PCB_ID_R")
| self.alarm_val("APSPU_FAN1_RPM_R")
| self.alarm_val("APSPU_FAN2_RPM_R")
| self.alarm_val("APSPU_FAN3_RPM_R"))
# --------
# overloaded functions
# --------
......
......@@ -17,7 +17,7 @@ Boots the rest of the station software.
from tango import DebugIt
from tango.server import command
from tango.server import device_property, attribute
from tango import AttrWriteType, DeviceProxy, DevState
from tango import AttrWriteType, DeviceProxy, DevState, DevSource
# Additional import
import numpy
......@@ -40,17 +40,18 @@ class InitialisationException(Exception):
class DevicesInitialiser(object):
"""
Initialise devices on this station.
Initialise devices on this station which are not already on (reboot=False),
or all of them (reboot=True).
Devices which are unreachable are assumed to be brought down explicitly,
and are ignored (unless ignore_unavailable_devices == False).
and are ignored.
Initialisation happens in a separate thread. It is started by calling
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, ignore_unavailable_devices=True, initialise_hardware=True, proxy_timeout=10.0):
self.ignore_unavailable_devices = ignore_unavailable_devices
def __init__(self, device_names, reboot=False, initialise_hardware=True, proxy_timeout=10.0):
self.reboot = reboot
self.initialise_hardware = initialise_hardware
self.device_names = device_names
......@@ -74,10 +75,11 @@ class DevicesInitialiser(object):
self.set_status(f"Obtaining a DeviceProxy to {name}")
devices[name] = DeviceProxy(name)
# set the timeout for all proxies
# set the timeout for all proxies, and never read state from a cache
self.set_status("Configuring DeviceProxies")
for device in devices.values():
device.set_timeout_millis(int(self.proxy_timeout * 1000))
device.set_source(DevSource.DEV)
return devices
......@@ -150,8 +152,10 @@ class DevicesInitialiser(object):
if self.device_initialised[device]:
continue
if self.is_available(device) or not self.ignore_unavailable_devices:
self.start_device(device)
if self.is_available(device):
if self.reboot or self.devices[device].state() not in [DevState.ON, DevState.ALARM]:
self.stop_device(device)
self.boot_device(device)
# mark device as initialised
self.device_initialised[device] = True
......@@ -185,40 +189,25 @@ class DevicesInitialiser(object):
proxy.Off()
if proxy.state() != DevState.OFF:
raise InitialisationException(f"Could not turn off device {device_name}. Please look at its logs.")
raise InitialisationException(f"Could not turn off device {device_name}. It reports status: {proxy.status()}")
self.set_status(f"[stopping {device_name}] Stopped device.")
def start_device(self, device_name: str):
def boot_device(self, device_name: str):
""" Run the startup sequence for device 'device_name'. """
proxy = self.devices[device_name]
# go to a well-defined state, which may be needed if the user calls
# this function explicitly.
self.stop_device(device_name)
# setup connections to hardware
self.set_status(f"[restarting {device_name}] Initialising device.")
proxy.Initialise()
if proxy.state() != DevState.STANDBY:
raise InitialisationException(f"Could not initialise device {device_name}. Please look at its logs.")
# configure the device
self.set_status(f"[restarting {device_name}] Setting defaults.")
proxy.set_defaults()
self.set_status(f"[restarting {device_name}] Booting device.")
if self.initialise_hardware:
self.set_status(f"[restarting {device_name}] Initialising hardware.")
proxy.initialise_hardware()
proxy.boot()
else:
proxy.warm_boot()
# mark as ready for service
self.set_status(f"[restarting {device_name}] Turning on device.")
proxy.On()
if proxy.state() != DevState.ON:
raise InitialisationException(f"Could not turn on device {device_name}. Please look at its logs.")
if proxy.state() not in [DevState.ON, DevState.ALARM]: # ALARM still means booting was succesful
raise InitialisationException(f"Could not boot device {device_name}. It reports status: {proxy.status()}")
self.set_status(f"[restarting {device_name}] Succesfully started.")
self.set_status(f"[restarting {device_name}] Succesfully booted.")
@device_logging_to_python()
class Boot(lofar_device):
......@@ -255,16 +244,6 @@ class Boot(lofar_device):
],
)
# By default, we assume any device is not available
# because its docker container was not started, which
# is an explicit and thus intentional action.
# We ignore such devices when initialising the station.
Ignore_Unavailable_Devices = device_property(
dtype='DevBoolean',
mandatory=False,
default_value=True,
)
# ----------
# Attributes
# ----------
......@@ -274,22 +253,17 @@ class Boot(lofar_device):
initialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if initialised], doc="Which devices were initialised succesfully")
uninitialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if not initialised], doc="Which devices have not been initialised or failed to initialise")
@log_exceptions()
def delete_device(self):
"""Hook to delete resources allocated in init_device.
This method allows for any memory or other resources allocated in the
init_device method to be released. This method is called by the device
destructor and by the device Init command (a Tango built-in).
"""
logger.debug("Shutting down...")
self.Off()
logger.debug("Shut down. Good bye.")
# --------
# overloaded functions
# --------
def init_device(self):
super().init_device()
# always turn on automatically, so the user doesn't have to boot the boot device
# note: we overloaded our own boot() to boot the station, so explicitly call our own initialisation
self.Initialise()
self.On()
@log_exceptions()
def configure_for_off(self):
""" user code here. is called when the state is set to OFF """
......@@ -301,21 +275,16 @@ class Boot(lofar_device):
@log_exceptions()
def configure_for_initialise(self):
# create an initialiser object so we can query it even before starting the (first) initialisation
self.initialiser = DevicesInitialiser(self.Device_Names, self.Ignore_Unavailable_Devices, self.Initialise_Hardware, self.DeviceProxy_Time_Out)
self.initialiser = DevicesInitialiser(self.Device_Names, False, self.Initialise_Hardware, self.DeviceProxy_Time_Out)
@command()
@DebugIt()
@only_in_states([DevState.ON])
@fault_on_error()
@log_exceptions()
def boot(self):
def _boot(self, reboot=False, initialise_hardware=True):
"""
Initialise or re-initialise all devices on the station.
Initialise all devices on the station that are not yet on (reboot=False), or shut them down first (reboot=True).
This command will take a while to execute, so should be called asynchronously.
If initialise_hardware is set, the hardware behind the devices is also explicitly reinitialised. Turn this
off to perform a warm boot.
If resume == True, a previously started attempt is resumed from the device
that failed to initialise earlier.
This command will take a while to execute, so should be called asynchronously.
:return:None
"""
......@@ -324,7 +293,6 @@ class Boot(lofar_device):
# already initialising
return
# join any previous attempt, if any
try:
self.initialiser.stop()
......@@ -332,30 +300,29 @@ class Boot(lofar_device):
pass
# start new initialisation attempt
self.initialiser = DevicesInitialiser(self.Device_Names, self.Ignore_Unavailable_Devices, self.Initialise_Hardware, self.DeviceProxy_Time_Out)
self.initialiser = DevicesInitialiser(self.Device_Names, reboot, initialise_hardware, self.DeviceProxy_Time_Out)
self.initialiser.start()
@command()
@DebugIt()
@only_in_states([DevState.ON])
@fault_on_error()
@log_exceptions()
def resume(self):
"""
Resume booting. A previously started boot() attempt is resumed from
the first device that failed to initialise.
This command will take a while to execute, so should be called asynchronously.
:return:None
"""
def boot(self):
self._boot(reboot=False, initialise_hardware=self.Initialise_Hardware)
if self.initialiser.is_running():
# already initialising
return
@command()
@DebugIt()
@only_in_states([DevState.ON])
@log_exceptions()
def reboot(self):
self._boot(reboot=True, initialise_hardware=self.Initialise_Hardware)
# just start it again
self.initialiser.start()
@command()
@DebugIt()
@only_in_states([DevState.ON])
@log_exceptions()
def warm_boot(self):
self._boot(reboot=False, initialise_hardware=False)
# ----------
# Run server
......
......@@ -13,7 +13,7 @@
# PyTango imports
from tango.server import attribute, command, Device, DeviceMeta
from tango import AttrWriteType, DevState, DebugIt, Attribute, DeviceProxy
from tango import AttrWriteType, DevState, DebugIt, Attribute, DeviceProxy, AttrDataFormat
import time
import math
......@@ -266,10 +266,36 @@ class lofar_device(Device, metaclass=DeviceMeta):
# This is just the command version of _initialise_hardware().
self._initialise_hardware()
def _boot_device(self, initialise_hardware=True):
# setup connections
self.Initialise()
if initialise_hardware:
# initialise settings
self.set_defaults()
# powercycle backing hardware
self.initialise_hardware()
# make device available
self.On()
@only_in_states([DevState.OFF])
@command()
def boot(self):
self._boot(initialise_hardware=True)
@only_in_states([DevState.OFF])
@command()
def warm_boot(self):
self._boot(initialise_hardware=False)
def _initialise_hardware(self):
""" Override this method to initialise any hardware after configuring it. """
pass
def wait_attribute(self, attr_name, value, timeout=10, pollperiod=0.2):
""" Wait until the given attribute obtains the given value.
......@@ -287,3 +313,34 @@ class lofar_device(Device, metaclass=DeviceMeta):
time.sleep(pollperiod)
raise Exception(f"{attr_name} != {value} after {timeout} seconds still.")
def alarm_val(self, attr_name):
""" Returns whether min_alarm < attr_value < max_alarm for the given attribute,
if these values are set. For arrays, an array of booleans of the same shape
is returned. """
# fetch attribute configuration
attr_config = self.proxy.get_attribute_config(attr_name)
alarms = attr_config.alarms
is_scalar = attr_config.data_format == AttrDataFormat.SCALAR
# fetch attribute value as an array
value = self.proxy.read_attribute(attr_name).value
if is_scalar:
value = numpy.array(value)
# construct alarm state, in the same shape as the attribute
alarm_state = numpy.zeros(value.shape, dtype=bool)
if alarms.max_alarm != 'Not specified':
alarm_state |= value >= value.dtype.type(alarms.max_alarm)
if alarms.min_alarm != 'Not specified':
alarm_state |= value <= value.dtype.type(alarms.min_alarm)
# return alarm state, as the same type as the attribute
if is_scalar:
return alarm_state[0]
else:
return alarm_state
......@@ -49,6 +49,18 @@ class RECV(opcua_device):
default_value=[True] * 32
)
RCU_mask_lock = device_property(
dtype='DevVarBooleanArray',
mandatory=False,
default_value=[False] * 32
)
RECVTR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
HBAT_bf_delay_step_delays = device_property(
dtype="DevVarFloatArray",
mandatory=False,
......@@ -100,9 +112,6 @@ class RECV(opcua_device):
# ----------
# Attributes
# ----------
ANT_status_R = attribute(dtype=(str,), max_dim_x=3, max_dim_y=32)
RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32, fget=lambda self: (2 * self.proxy.RCU_LED_green_on_R + 4 * self.proxy.RCU_LED_red_on_R).astype(numpy.uint32))
ANT_mask_RW = attribute_wrapper(comms_annotation=["ANT_mask_RW" ],datatype=numpy.bool_ , dims=(3,32), access=AttrWriteType.READ_WRITE)
# The HBAT beamformer delays represent 32 delays for each of the 96 inputs.
......@@ -155,6 +164,28 @@ class RECV(opcua_device):
dtype=((numpy.float,),), max_dim_x=3, max_dim_y=96,
fget=lambda self: numpy.array(self.HBAT_reference_itrf).reshape(96,3))
# ----------
# Summarising Attributes
# ----------
RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32)
def read_RCU_LED_colour_R(self):
return (2 * self.proxy.RCU_LED_green_on_R + 4 * self.proxy.RCU_LED_red_on_R).astype(numpy.uint32)
RCU_error_R = attribute(dtype=(bool,), max_dim_x=32)
ANT_error_R = attribute(dtype=((bool,),), max_dim_x=3, max_dim_y=32)
def read_RCU_error_R(self):
return self.proxy.RCU_mask_RW & (
(self.proxy.RECVTR_I2C_error_R > 0)
| self.alarm_val("RCU_PCB_ID_R")
)
def read_ANT_error_R(self):
return self.proxy.ANT_mask_RW & (
~self.proxy.RCU_ADC_locked_R
)
# --------
# overloaded functions
# --------
......@@ -248,68 +279,9 @@ class RECV(opcua_device):
self.RCU_on()
self.wait_attribute("RECVTR_translator_busy_R", False, 5)
def read_RCU_status_R(self):
""" Returns a set of strings denoting the status of each RCU.
An empty string means no problems were detected. A non-empty
string means the RCU seems unusable.
This function can be used as input to modify the RCU_mask_RW. """
rcu_mask = self.proxy.RCU_mask_RW
i2c_errors = self.proxy.RCU_I2C_STATUS_R
nr_rcus = len(rcu_mask)
rcu_status = [""] * nr_rcus
# construct status of each RCU
for rcu in range(nr_rcus):
status = []
if not i2c_status[rcu]:
status.append("[I2C error]")
rcu_status[rcu] = " ".join(status)
return rcu_status
def read_ANT_status_R(self):
""" Returns a set of strings denoting the status of each antenna.
An empty string means no problems were detected. A non-empty
string means the antenna seems unusable.
This function can be used as input to modify the Ant_mask_RW. """
ant_mask = self.proxy.ANT_mask_RW
rcu_mask = self.proxy.RCU_mask_RW
adc_lock = self.proxy.RCU_ADC_locked_R
i2c_errors = self.proxy.RCU_I2C_STATUS_R
nr_rcus = len(ant_mask)
nr_ants_per_rcu = len(ant_mask[0])
# Collect status, join them into a single string per antenna later
ant_status = [""] * nr_ants
for rcu in range(nr_rcus):
for ant in range(nr_ants_per_rcu):
status = []
if i2c_status[rcu] != 0:
status.append("[I2C error]")
if not rcu_mask[rcu]:
status.append("[RCU masked out]")
if not adc_lock[rcu][ant]:
status.append("[ADC lock error]")
ant_status[rcu][ant] = " ".join(status)
return ant_status
# Turn off DTH by default
recv.RCU_DTH_off()
self.wait_attribute("RECVTR_translator_busy_R", False, 5)
# ----------
# Run server
......
......@@ -12,7 +12,7 @@
"""
# PyTango imports
from tango.server import device_property
from tango.server import device_property, attribute
from tango import AttrWriteType
# Additional import
......@@ -205,7 +205,22 @@ class SDP(opcua_device):
FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn))
FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.int16, dims=(A_pn * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE)
# ----------
# Summarising Attributes
# ----------
FPGA_error_R = attribute(dtype=(bool,), max_dim_x=16)
FPGA_processing_error_R = attribute(dtype=(bool,), max_dim_x=16)
def read_FPGA_error_R(self):
return self.proxy.TR_fpga_mask_RW & (
self.proxy.TR_fpga_communication_error_R
)
def read_FPGA_processing_error_R(self):
return self.proxy.TR_fpga_mask_RW & (
~self.proxy.FPGA_processing_enable_R
| ~self.proxy.FPGA_wg_enable_R.any(axis=1)
)
# --------
# overloaded functions
......
......@@ -12,8 +12,7 @@
"""
# PyTango imports
from tango.server import command
from tango.server import device_property
from tango.server import command, attribute, device_property
from tango import AttrWriteType, DebugIt, DevState
# Additional import
......@@ -39,6 +38,12 @@ class UNB2(opcua_device):
default_value=[True] * 2
)
UNB2TR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
# ----------
# Attributes
# ----------
......@@ -114,6 +119,30 @@ class UNB2(opcua_device):
UNB2_POL_SWITCH_PHY_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"],datatype=numpy.float64, dims=(2,))
UNB2_PWR_on_R = attribute_wrapper(comms_annotation=["UNB2_PWR_on_R" ],datatype=numpy.bool_ , dims=(2,))
# ----------
# Summarising Attributes
# ----------
UNB2_error_R = attribute(dtype=(bool,), max_dim_x=2)
UNB2_FPGA_error_R = attribute(dtype=((bool,),), max_dim_x=4, max_dim_y=2)
UNB2_QSFP_error_R = attribute(dtype=((bool,),), max_dim_x=24, max_dim_y=2)
def read_UNB2_error_R(self):
return self.proxy.UNB2_mask_RW & (
(self.proxy.UNB2TR_I2C_bus_error_R > 0)
| self.alarm_val("UNB2_PCB_ID_R")
)
def read_UNB2_FPGA_error_R(self):
return self.proxy.UNB2_mask_RW & (
(self.proxy.UNB2TR_I2C_bus_DDR4_error_R > 0)
| (self.proxy.UNB2TR_I2C_bus_FPGA_PS_error_R > 0)
)
def read_UNB2_QSFP_error_R(self):
return self.proxy.UNB2_mask_RW & (
(self.proxy.UNB2TR_I2C_bus_QSFP_error_R > 0)
)
# --------
# overloaded functions
# --------
......@@ -142,6 +171,15 @@ class UNB2(opcua_device):
"""
self.opcua_connection.call_method(["UNB2_on"])
def _initialise_hardware(self):
""" Initialise the UNB2 hardware. """
# Cycle UNB2s
self.UNB2_off()
self.wait_attribute("UNB2TR_translator_busy_R", False, 5)
self.UNB2_on()
self.wait_attribute("UNB2TR_translator_busy_R", False, 5)
# ----------
# Run server
# ----------
......
......@@ -9,21 +9,26 @@
import time
from .base import AbstractTestBases
from tango import DevState
from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
from tangostationcontrol.integration_test import base
class TestDeviceBoot(AbstractTestBases.TestDeviceBase):
class TestDeviceBoot(base.IntegrationTestCase):
def setUp(self):
super().setUp("STAT/Boot/1")
self.proxy = TestDeviceProxy("STAT/Boot/1")
def test_start_in_on(self):
"""Test whether we start in the ON state"""
def test_device_boot_initialise_station(self):
"""Test if we can initialise the station"""
self.assertEqual(DevState.ON, self.proxy.state())
self.proxy.initialise()
self.proxy.on()
def test_reboot(self):
"""Test if we can reinitialise the station"""
self.proxy.boot()
self.proxy.reboot()
# wait for a few seconds for the station to initialise
timeout = 10
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment