diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 57b53e5eb897d740c5ee9929fc72d699de5222b9..dde83f7e6853e8dd71d3fb408825aa97fde1829b 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -816,6 +816,82 @@ } } }, + "XST": { + "LTS": { + "XST": { + "LTS/XST/1": { + "properties": { + "Statistics_Client_Port": [ + "5002" + ], + "OPC_Server_Name": [ + "dop36.astron.nl" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ], + "FPGA_xst_offload_hdr_eth_destination_mac_RW_default": [ + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd", + "6c:2b:59:97:be:dd" + ], + "FPGA_xst_offload_hdr_ip_destination_address_RW_default": [ + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250" + ], + "FPGA_xst_offload_hdr_udp_destination_port_RW_default": [ + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002", + "5002" + ] + } + } + } + } + }, "UNB2": { "LTS": { "UNB2": { diff --git a/CDB/integration_ConfigDb.json b/CDB/integration_ConfigDb.json index debeae5263b85b15821ed515521223751ff9d37c..db261d4afb70413acb7057938c322c8b293d6fe9 100644 --- a/CDB/integration_ConfigDb.json +++ b/CDB/integration_ConfigDb.json @@ -164,6 +164,25 @@ } } } + }, + "UNB2": { + "LTS": { + "UNB2": { + "LTS/UNB2/1": { + "properties": { + "OPC_Server_Name": [ + "despi.astron.nl" + ], + "OPC_Server_Port": [ + "4842" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } } } } diff --git a/CDB/unb2-sim-config.json b/CDB/unb2-sim-config.json new file mode 100644 index 0000000000000000000000000000000000000000..a98fa27492e3835867b214cfd2789caf949de460 --- /dev/null +++ b/CDB/unb2-sim-config.json @@ -0,0 +1,23 @@ +{ + "servers": { + "UNB2": { + "LTS": { + "UNB2": { + "LTS/UNB2/1": { + "properties": { + "OPC_Server_Name": [ + "unb2-sim" + ], + "OPC_Server_Port": [ + "4844" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + } + } +} diff --git a/devices/common/baselines.py b/devices/common/baselines.py new file mode 100644 index 0000000000000000000000000000000000000000..b9b0ca8038c0d881d602df37f99203d733f283fc --- /dev/null +++ b/devices/common/baselines.py @@ -0,0 +1,59 @@ +""" + Baseline calculation functions. +""" + +import math + +def nr_baselines(nr_inputs: int) -> int: + """ Return the number of baselines (unique pairs) that exist between a given number of inputs. """ + return nr_inputs * (nr_inputs + 1) // 2 + +""" + + Baselines are ordered like: + 0-0, 1-0, 1-1, 2-0, 2-1, 2-2, ... + + if + b = baseline + x = stat1 (major) + y = stat2 (minor) + x >= y + then + b_xy = x * (x + 1) / 2 + y + let + u := b_x0 + then + u = x * (x + 1) / 2 + 8u = 4x^2 + 4x + 8u + 1 = 4x^2 + 4x + 1 = (2x + 1)^2 + sqrt(8u + 1) = 2x + 1 + x = (sqrt(8u + 1) - 1) / 2 + + Let us define + x'(b) = (sqrt(8b + 1) - 1) / 2 + which increases monotonically and is a continuation of y(b). + + Because y simply increases by 1 when b increases enough, we + can just take the floor function to obtain the discrete y(b): + x(b) = floor(x'(b)) + = floor(sqrt(8b + 1) - 1) / 2) + +""" + +def baseline_index(major: int, minor: int) -> int: + """ Provide a total ordering of baselines: give the unique array index for the baseline (major,minor), + with major >= minor. """ + + if major < minor: + raise ValueError(f"major < minor: {major} < {minor}. Since we do not store the conjugates this will lead to processing errors.") + + return major * (major + 1) // 2 + minor + +def baseline_from_index(index: int) -> tuple: + """ Return the (major,minor) input pair given a baseline index. """ + + major = int((math.sqrt(float(8 * index + 1)) - 0.99999) / 2) + minor = index - baseline_index(major,0) + + return (major,minor) + diff --git a/devices/devices/sdp/sst.py b/devices/devices/sdp/sst.py index 79fb6fb272b199d3069be03825cfd395f9d18929..a7e1e8e9958214469c08efe9a6fea16c9348eaf3 100644 --- a/devices/devices/sdp/sst.py +++ b/devices/devices/sdp/sst.py @@ -80,15 +80,17 @@ class SST(Statistics): FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_weighted_subbands_R"], datatype=numpy.bool_, 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_INPUTS,), datatype=numpy.uint64) + 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 - nof_payload_errors_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.uint64) + nof_payload_errors_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(SSTCollector.MAX_FPGAS,), datatype=numpy.uint64) # latest SSTs sst_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(SSTCollector.MAX_SUBBANDS, SSTCollector.MAX_INPUTS), datatype=numpy.uint64) # reported timestamp for each row in the latest SSTs sst_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.uint64) # integration interval for each row in the latest SSTs integration_interval_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.float32) + # whether the subband data was calibrated by the SDP (that is, were subband weights applied) + subbands_calibrated_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "subbands_calibrated"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.bool_) # -------- # Overloaded functions diff --git a/devices/devices/sdp/statistics_collector.py b/devices/devices/sdp/statistics_collector.py index d19ad01b2a10096ebc637b5a24d51917317afc9f..1bd8f3c12135a818526c48ecbff80408f290b7c9 100644 --- a/devices/devices/sdp/statistics_collector.py +++ b/devices/devices/sdp/statistics_collector.py @@ -3,7 +3,8 @@ from threading import Thread import logging import numpy -from .statistics_packet import SSTPacket +from .statistics_packet import SSTPacket, XSTPacket +from common.baselines import nr_baselines, baseline_index, baseline_from_index from clients.statistics_client_thread import StatisticsClientThread logger = logging.getLogger() @@ -11,11 +12,8 @@ logger = logging.getLogger() class StatisticsCollector: """ Base class to process statistics packets into parameters matrices. """ - # Maximum number of antenna inputs we support (used to determine array sizes) - MAX_INPUTS = 192 - - # Maximum number of subbands we support (used to determine array sizes) - MAX_SUBBANDS = 512 + # Maximum number of FPGAs we receive data from (used for diagnostics) + MAX_FPGAS = 16 def __init__(self): self.parameters = self._default_parameters() @@ -62,15 +60,16 @@ class SSTCollector(StatisticsCollector): defaults.update({ # Number of packets received so far that we could parse correctly and do not have a payload error - "nof_valid_payloads": numpy.zeros((self.MAX_INPUTS,), dtype=numpy.uint64), + "nof_valid_payloads": numpy.zeros((self.MAX_FPGAS,), dtype=numpy.uint64), # Packets that reported a payload error - "nof_payload_errors": numpy.zeros((self.MAX_INPUTS,), dtype=numpy.uint64), + "nof_payload_errors": numpy.zeros((self.MAX_FPGAS,), dtype=numpy.uint64), # Last value array we've constructed out of the packets "sst_values": numpy.zeros((self.MAX_INPUTS, self.MAX_SUBBANDS), dtype=numpy.uint64), "sst_timestamps": numpy.zeros((self.MAX_INPUTS,), dtype=numpy.float64), "integration_intervals": numpy.zeros((self.MAX_INPUTS,), dtype=numpy.float32), + "subbands_calibrated": numpy.zeros((self.MAX_INPUTS,), dtype=numpy.bool_), }) return defaults @@ -87,16 +86,120 @@ class SSTCollector(StatisticsCollector): if fields.payload_error: # cannot trust the data if a payload error is reported - self.parameters["nof_payload_errors"][input_index] += numpy.uint64(1) + self.parameters["nof_payload_errors"][fields.gn_index] += numpy.uint64(1) # don't raise, as packet is valid return # process the packet - self.parameters["nof_valid_payloads"][input_index] += numpy.uint64(1) + self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) self.parameters["sst_values"][input_index][:fields.nof_statistics_per_packet] = fields.payload self.parameters["sst_timestamps"][input_index] = numpy.float64(fields.timestamp().timestamp()) self.parameters["integration_intervals"][input_index] = fields.integration_interval() + self.parameters["subbands_calibrated"][input_index] = fields.subband_calibrated_flag + +class XSTCollector(StatisticsCollector): + """ Class to process XST statistics packets. """ + + # Maximum number of antenna inputs we support (used to determine array sizes) + MAX_INPUTS = 192 + + # Maximum number of baselines we can receive + MAX_BASELINES = nr_baselines(MAX_INPUTS) + + # Expected block size is BLOCK_LENGTH x BLOCK_LENGTH + BLOCK_LENGTH = 12 + + # Expected number of blocks: enough to cover all baselines without the conjugates (that is, the top-left triangle of the matrix). + MAX_BLOCKS = nr_baselines(MAX_INPUTS // BLOCK_LENGTH) + + # Maximum number of subbands we support (used to determine array sizes) + MAX_SUBBANDS = 512 + + # Complex values are (real, imag). A bit silly, but we don't want magical constants. + VALUES_PER_COMPLEX = 2 + + def _default_parameters(self): + defaults = super()._default_parameters() + + defaults.update({ + # Number of packets received so far that we could parse correctly and do not have a payload error + "nof_valid_payloads": numpy.zeros((self.MAX_FPGAS,), dtype=numpy.uint64), + + # Packets that reported a payload error + "nof_payload_errors": numpy.zeros((self.MAX_FPGAS,), dtype=numpy.uint64), + + # Last value array we've constructed out of the packets + "xst_blocks": numpy.zeros((self.MAX_BLOCKS, self.BLOCK_LENGTH * self.BLOCK_LENGTH * self.VALUES_PER_COMPLEX), dtype=numpy.int64), + "xst_timestamps": numpy.zeros((self.MAX_BLOCKS,), dtype=numpy.float64), + "xst_subbands": numpy.zeros((self.MAX_BLOCKS,), dtype=numpy.uint16), + "integration_intervals": numpy.zeros((self.MAX_BLOCKS,), dtype=numpy.float32), + }) + + return defaults + + def parse_packet(self, packet): + fields = XSTPacket(packet) + + if fields.payload_error: + # cannot trust the data if a payload error is reported + self.parameters["nof_payload_errors"][fields.gn_index] += numpy.uint64(1) + + # don't raise, as packet is valid + return + + # the blocks must be of size BLOCK_LENGTH x BLOCK_LENGTH + if fields.nof_signal_inputs != self.BLOCK_LENGTH: + raise ValueError("Packet describes a block of {0} x {0} baselines, but we can only parse blocks of {1} x {1} baselines".format(fields.nof_signal_inputs, self.BLOCK_LENGTH)) + + # check whether set of baselines in this packet are not out of bounds + for antenna in (0,1): + if fields.first_baseline[antenna] + fields.nof_signal_inputs >= self.MAX_INPUTS: + # packet describes an input that is out of bounds for us + raise ValueError("Packet describes {0} x {0} baselines starting at {1}, but we are limited to describing MAX_INPUTS={2}".format(fields.nof_signal_inputs, fields.first_baseline, self.MAX_INPUTS)) + + # the blocks of baselines need to be tightly packed, and thus be provided at exact intervals + if fields.first_baseline[antenna] % self.BLOCK_LENGTH != 0: + raise ValueError("Packet describes baselines starting at %s, but we require a multiple of BLOCK_LENGTH=%d" % (fields.first_baseline, self.MAX_INPUTS)) + + # the payload contains complex values for the block of baselines of size BLOCK_LENGTH x BLOCK_LENGTH + # starting at baseline first_baseline. + # + # we honour this format, as we want to keep the metadata together with these blocks. we do need to put the blocks in a linear + # and tight order, however, so we calculate a block index. + block_index = baseline_index(fields.first_baseline[0] // self.BLOCK_LENGTH, fields.first_baseline[1] // self.BLOCK_LENGTH) + + # process the packet + self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) + + block_index = baseline_index(fields.first_baseline[0], fields.first_baseline[1]) + + self.parameters["xst_blocks"][block_index][:fields.nof_statistics_per_packet] = fields.payload + self.parameters["xst_timestamps"][block_index] = numpy.float64(fields.timestamp().timestamp()) + self.parameters["xst_subbands"][block_index] = numpy.uint16(fields.subband_index) + self.parameters["integration_intervals"][block_index] = fields.integration_interval() + + def xst_values(self): + """ xst_blocks, but as a matrix[MAX_INPUTS][MAX_INPUTS] of complex values. """ + + matrix = numpy.zeros((self.MAX_INPUTS, self.MAX_INPUTS), dtype=numpy.complex64) + xst_blocks = self.parameters["xst_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 + block = xst_blocks[block_index].astype(numpy.float32).view(numpy.complex64) + + # reshape into [a][b] + block = block.reshape(self.BLOCK_LENGTH, self.BLOCK_LENGTH) + + # compute destination in matrix + first_baseline = baseline_from_index(block_index) + first_baseline = (first_baseline[0] * self.BLOCK_LENGTH, first_baseline[1] * self.BLOCK_LENGTH) + + # copy block into matrix + matrix[first_baseline[0]:first_baseline[0]+self.BLOCK_LENGTH, first_baseline[1]:first_baseline[1]+self.BLOCK_LENGTH] = block + + return matrix class StatisticsConsumer(Thread, StatisticsClientThread): @@ -159,4 +262,3 @@ class StatisticsConsumer(Thread, StatisticsClientThread): if self.is_alive(): # there is nothing we can do except wait (stall) longer, which could be indefinitely. logger.error(f"Statistics thread did not shut down after {self.DISCONNECT_TIMEOUT} seconds, just leaving it dangling. Please attach a debugger to thread ID {self.ident}.") - diff --git a/devices/devices/sdp/statistics_packet.py b/devices/devices/sdp/statistics_packet.py index 6843c99e62c79b2c9afa119aaf0b3b51709269f7..9bac227071dfbdec9ea0b0fd1fa63fa36176a8d9 100644 --- a/devices/devices/sdp/statistics_packet.py +++ b/devices/devices/sdp/statistics_packet.py @@ -117,9 +117,9 @@ class StatisticsPacket(object): self.nyquist_zone_index = get_bit_value(self.source_info, 13, 14) self.t_adc = get_bit_value(self.source_info, 12) self.fsub_type = get_bit_value(self.source_info, 11) - self.payload_error = get_bit_value(self.source_info, 10) - self.beam_repositioning_flag = get_bit_value(self.source_info, 9) - self.subband_calibrated_flag = get_bit_value(self.source_info, 8) + self.payload_error = (get_bit_value(self.source_info, 10) != 0) + self.beam_repositioning_flag = (get_bit_value(self.source_info, 9) != 0) + self.subband_calibrated_flag = (get_bit_value(self.source_info, 8) != 0) # self.source_info 5-7 are reserved self.gn_index = get_bit_value(self.source_info, 0, 4) @@ -210,6 +210,17 @@ class StatisticsPacket(object): return header + def payload(self, signed=False) -> numpy.array: + """ The payload of this packet, as a linear array. """ + + # derive which and how many elements to read from the packet header + bytecount_to_unsigned_struct_type = {1: 'b', 2: 'h', 4: 'i', 8: 'q'} if signed else {1: 'B', 2: 'H', 4: 'I', 8: 'Q'} + format_str = ">{}{}".format(self.nof_statistics_per_packet, + bytecount_to_unsigned_struct_type[self.nof_bytes_per_statistic]) + + return numpy.array( + struct.unpack(format_str, self.packet[self.header_size:self.header_size + struct.calcsize(format_str)])) + class SSTPacket(StatisticsPacket): """ @@ -245,16 +256,8 @@ class SSTPacket(StatisticsPacket): return header @property - def payload(self) -> numpy.array: - """ The payload of this packet, interpreted as SST data. """ - - # derive which and how many elements to read from the packet header - bytecount_to_unsigned_struct_type = {1: 'B', 2: 'H', 4: 'I', 8: 'Q'} - format_str = ">{}{}".format(self.nof_statistics_per_packet, - bytecount_to_unsigned_struct_type[self.nof_bytes_per_statistic]) - - return numpy.array( - struct.unpack(format_str, self.packet[self.header_size:self.header_size + struct.calcsize(format_str)])) + def payload(self): + return super().payload(signed=False) class XSTPacket(StatisticsPacket): @@ -263,9 +266,10 @@ class XSTPacket(StatisticsPacket): The following fields are exposed as properties & functions. - subband_index: subband number for which this packet contains statistics. - baseline: antenna pair for which this packet contains statistics. + first_baseline: first antenna pair for which this packet contains statistics. + + payload[nof_signal_inputs][nof_signal_inputs] the baselines, starting from first_baseline """ def __init__(self, packet): @@ -281,16 +285,20 @@ class XSTPacket(StatisticsPacket): super().unpack_data_id() self.subband_index = get_bit_value(self.data_id, 16, 24) - self.baseline = (get_bit_value(self.data_id, 8, 15), get_bit_value(self.data_id, 0, 7)) + self.first_baseline = (get_bit_value(self.data_id, 8, 15), get_bit_value(self.data_id, 0, 7)) def header(self): header = super().header() header["data_id"]["subband_index"] = self.subband_index - header["data_id"]["baseline"] = self.baseline + header["data_id"]["first_baseline"] = self.first_baseline return header + @property + def payload(self): + return super().payload(signed=True) + class BSTPacket(StatisticsPacket): """ diff --git a/devices/devices/sdp/xst.py b/devices/devices/sdp/xst.py new file mode 100644 index 0000000000000000000000000000000000000000..104936e107d6e86cf1ce7fe391895168697b8314 --- /dev/null +++ b/devices/devices/sdp/xst.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the XST project +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" XST Device Server for LOFAR2.0 + +""" + +# TODO(Corne): Remove sys.path.append hack once packaging is in place! +import os, sys +currentdir = os.path.dirname(os.path.realpath(__file__)) +parentdir = os.path.dirname(currentdir) +parentdir = os.path.dirname(parentdir) +sys.path.append(parentdir) + +# PyTango imports +from tango.server import run +from tango.server import device_property, attribute +from tango import AttrWriteType +# Additional import + +from clients.attribute_wrapper import attribute_wrapper +from clients.opcua_client import OPCUAConnection +from clients.statistics_client import StatisticsClient + +from devices.hardware_device import hardware_device + +from common.lofar_git import get_version +from common.lofar_logging import device_logging_to_python, log_exceptions + +from devices.sdp.statistics import Statistics +from devices.sdp.statistics_collector import XSTCollector + +import numpy + +__all__ = ["XST", "main"] + +class XST(Statistics): + + STATISTICS_COLLECTOR_CLASS = XSTCollector + + # ----------------- + # Device Properties + # ----------------- + + FPGA_xst_offload_hdr_eth_destination_mac_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_xst_offload_hdr_ip_destination_address_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_xst_offload_hdr_udp_destination_port_RW_default = device_property( + dtype='DevVarUShortArray', + mandatory=True + ) + + FPGA_xst_processing_enable_RW_default = device_property( + dtype='DevVarBooleanArray', + mandatory=False, + default_value=[True] * 16 + ) + + FPGA_xst_subband_select_RW_default = device_property( + dtype='DevVarULongArray', + mandatory=False, + default_value=[[0,102,0,0,0,0,0,0]] * 16 + ) + + # ---------- + # Attributes + # ---------- + + # FPGA control points for XSTs + FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(8,16), access=AttrWriteType.READ_WRITE) + FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(8,16)) + FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str_, dims=(16,)) + FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=numpy.str_, dims=(16,)) + FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) + FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(8,16), access=AttrWriteType.READ_WRITE) + FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(8,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) + # 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) + # latest XSTs + xst_blocks_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks"}, dims=(XSTCollector.BLOCK_LENGTH * XSTCollector.BLOCK_LENGTH * XSTCollector.VALUES_PER_COMPLEX, XSTCollector.MAX_BLOCKS), datatype=numpy.int64) + # reported timestamp for each row in the latest XSTs + xst_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(XSTCollector.MAX_BLOCKS,), datatype=numpy.uint64) + # which subband the XSTs describe + xst_subbands_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(XSTCollector.MAX_BLOCKS,), datatype=numpy.uint16) + # integration interval for each row in the latest XSTs + integration_interval_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(XSTCollector.MAX_BLOCKS,), datatype=numpy.float32) + + # xst_R, but as a matrix of input x input + xst_real_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),)) + xst_imag_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),)) + xst_power_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),)) + xst_phase_R = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),)) + + def read_xst_real_R(self): + return numpy.real(self.statistics_client.collector.xst_values()) + + def read_xst_imag_R(self): + return numpy.imag(self.statistics_client.collector.xst_values()) + + def read_xst_power_R(self): + return numpy.abs(self.statistics_client.collector.xst_values()) + + def read_xst_phase_R(self): + return numpy.angle(self.statistics_client.collector.xst_values()) + + # -------- + # Overloaded functions + # -------- + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- +def main(args=None, **kwargs): + """Main function of the XST Device module.""" + + from common.lofar_logging import configure_logger + configure_logger() + + return run((XST,), args=args, **kwargs) + + +if __name__ == '__main__': + main() diff --git a/devices/integration_test/devices/test_device_unb2.py b/devices/integration_test/devices/test_device_unb2.py new file mode 100644 index 0000000000000000000000000000000000000000..97f31ab6ee162f8183db963e92f4f03b9ee7f617 --- /dev/null +++ b/devices/integration_test/devices/test_device_unb2.py @@ -0,0 +1,59 @@ +# -*- 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. + +import time + +from tango import DeviceProxy +from tango._tango import DevState + +from integration_test import base + + +class TestDeviceUNB2(base.IntegrationTestCase): + + def setUp(self): + """Intentionally recreate the device object in each test""" + super(TestDeviceUNB2, self).setUp() + + def tearDown(self): + """Turn device Off in teardown to prevent blocking tests""" + d = DeviceProxy("LTS/UNB2/1") + + try: + d.Off() + except Exception as e: + """Failing to turn Off devices should not raise errors here""" + print(f"Failed to turn device off in teardown {e}") + + def test_device_proxy_unb2(self): + """Test if we can successfully create a DeviceProxy and fetch state""" + + d = DeviceProxy("LTS/UNB2/1") + + self.assertEqual(DevState.OFF, d.state()) + + def test_device_unb2_initialize(self): + """Test if we can transition to standby""" + + d = DeviceProxy("LTS/UNB2/1") + + d.initialise() + + self.assertEqual(DevState.STANDBY, d.state()) + + def test_device_unb2_on(self): + """Test if we can transition to on""" + + d = DeviceProxy("LTS/UNB2/1") + + d.initialise() + + d.on() + + self.assertEqual(DevState.ON, d.state()) diff --git a/devices/test/common/test_baselines.py b/devices/test/common/test_baselines.py new file mode 100644 index 0000000000000000000000000000000000000000..206b4ca0eccefe1012519c8236d158e52f1cdc38 --- /dev/null +++ b/devices/test/common/test_baselines.py @@ -0,0 +1,30 @@ +# -*- 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 common import baselines + +from test import base + + +class TestBaselines(base.TestCase): + def test_nr_baselines(self): + # no baselines if no antennas + self.assertEqual(0, baselines.nr_baselines(0)) + # one antenna only has autocorrelation + self.assertEqual(1, baselines.nr_baselines(1)) + # two antennas each have autocorrelations + a baseline between each other + self.assertEqual(3, baselines.nr_baselines(2)) + + def test_baseline_indices(self): + """ Test whether baseline_from_index and baseline_index line up. """ + + for major in range(192): + for minor in range(major + 1): + idx = baselines.baseline_index(major, minor) + self.assertEqual((major, minor), baselines.baseline_from_index(idx), msg=f'baseline_index({major},{minor}) resulted in {idx}, and should match baseline_from_index({idx})') diff --git a/devices/test/devices/test_statistics_collector.py b/devices/test/devices/test_statistics_collector.py new file mode 100644 index 0000000000000000000000000000000000000000..a3568b8e56452259b8754be3a76e862a20845fcb --- /dev/null +++ b/devices/test/devices/test_statistics_collector.py @@ -0,0 +1,80 @@ +from devices.sdp.statistics_collector import XSTCollector +from devices.sdp.statistics_packet import XSTPacket + +from test import base + +class TestXSTCollector(base.TestCase): + def test_valid_packet(self): + collector = XSTCollector() + + # a valid packet as obtained from SDP, with 64-bit BE 1+1j as payload + packet = b'X\x05\x00\x00\x00\x00\x00\x00\x10\x08\x00\x02\xfa\xef\x00f\x00\x00\x0c\x08\x01 \x14\x00\x00\x01!\xd9&z\x1b\xb3' + 288 * b'\x00\x00\x00\x00\x00\x00\x00\x01' + + # parse it ourselves to extract info nicely + fields = XSTPacket(packet) + fpga_index = fields.gn_index + + # this should not throw + collector.process_packet(packet) + + # counters should now be updated + self.assertEqual(1, collector.parameters["nof_packets"]) + self.assertEqual(0, collector.parameters["nof_invalid_packets"]) + + self.assertEqual(1, collector.parameters["nof_valid_payloads"][fpga_index]) + self.assertEqual(0, collector.parameters["nof_payload_errors"][fpga_index]) + + # check whether the data ended up in the right block, and the rest is still zero + xst_values = collector.xst_values() + + for baseline_a in range(collector.MAX_INPUTS): + for baseline_b in range(collector.MAX_INPUTS): + if baseline_b > baseline_a: + # only scan top-left triangle + continue + + baseline_a_was_in_packet = (fields.first_baseline[0] <= baseline_a < fields.first_baseline[0] + fields.nof_signal_inputs) + baseline_b_was_in_packet = (fields.first_baseline[1] <= baseline_b < fields.first_baseline[1] + fields.nof_signal_inputs) + + if baseline_a_was_in_packet and baseline_b_was_in_packet: + self.assertEqual(1+1j, xst_values[baseline_a][baseline_b], msg=f'element [{baseline_a}][{baseline_b}] did not end up in XST matrix.') + else: + self.assertEqual(0+0j, xst_values[baseline_a][baseline_b], msg=f'element [{baseline_a}][{baseline_b}] was not in packet, but was written to the XST matrix.') + + def test_invalid_packet(self): + collector = XSTCollector() + + # an invalid packet + packet = b'S\x05\x00\x00\x00\x00\x00\x00\x10\x08\x00\x02\xfa\xef\x00f\x00\x00\x0c\x08\x01 \x14\x00\x00\x01!\xd9&z\x1b\xb3' + 288 * b'\x00\x00\x00\x00\x00\x00\x00\x01' + + # this should throw + with self.assertRaises(ValueError): + collector.process_packet(packet) + + # counters should now be updated + self.assertEqual(1, collector.parameters["nof_packets"]) + self.assertEqual(1, collector.parameters["nof_invalid_packets"]) + + self.assertListEqual([0] * collector.MAX_FPGAS, list(collector.parameters["nof_valid_payloads"])) + self.assertListEqual([0] * collector.MAX_FPGAS, list(collector.parameters["nof_payload_errors"])) + + def test_payload_error(self): + collector = XSTCollector() + + # an valid packet with a payload error + packet = b'X\x05\x00\x00\x00\x00\x00\x00\x14\x08\x00\x02\xfa\xef\x00f\x00\x00\x0c\x08\x01 \x14\x00\x00\x01!\xd9&z\x1b\xb3' + 288 * b'\x00\x00\x00\x00\x00\x00\x00\x01' + + # parse it ourselves to extract info nicely + fields = XSTPacket(packet) + fpga_index = fields.gn_index + + # this should not throw + collector.process_packet(packet) + + # counters should now be updated + self.assertEqual(1, collector.parameters["nof_packets"]) + self.assertEqual(0, collector.parameters["nof_invalid_packets"]) + + self.assertEqual(0, collector.parameters["nof_valid_payloads"][fpga_index]) + self.assertEqual(1, collector.parameters["nof_payload_errors"][fpga_index]) + diff --git a/docker-compose/Makefile b/docker-compose/Makefile index 686f88f9e4887039cbe5206a5a88ecb8df9aed8c..40479deef5c00a426346b287fab30f1f8adc7e94 100644 --- a/docker-compose/Makefile +++ b/docker-compose/Makefile @@ -132,13 +132,13 @@ pull: ## pull the images from the Docker hub build: ## rebuild images # docker-compose does not support build dependencies, so manage those here - $(DOCKER_COMPOSE_ARGS) docker-compose -f lofar-device-base.yml -f networks.yml build - $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build $(SERVICE) + $(DOCKER_COMPOSE_ARGS) docker-compose -f lofar-device-base.yml -f networks.yml build --progress=plain + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --progress=plain $(SERVICE) build-nocache: ## rebuild images from scratch # docker-compose does not support build dependencies, so manage those here - $(DOCKER_COMPOSE_ARGS) docker-compose -f lofar-device-base.yml -f networks.yml build - $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --no-cache $(SERVICE) + $(DOCKER_COMPOSE_ARGS) docker-compose -f lofar-device-base.yml -f networks.yml build --progress=plain + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --no-cache --progress=plain $(SERVICE) up: minimal ## start the base TANGO system and prepare all services $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up --no-start diff --git a/docker-compose/device-xst.yml b/docker-compose/device-xst.yml new file mode 100644 index 0000000000000000000000000000000000000000..7e57a2f9ab507f193710787aac187c67e1d738fe --- /dev/null +++ b/docker-compose/device-xst.yml @@ -0,0 +1,44 @@ +# +# Docker compose file that launches an interactive iTango session. +# +# Connect to the interactive session with 'docker attach itango'. +# Disconnect with the Docker deattach sequence: <CTRL>+<P> <CTRL>+<Q> +# +# Defines: +# - itango: iTango interactive session +# +# Requires: +# - lofar-device-base.yml +# +version: '2' + +services: + device-xst: + image: device-xst + # build explicitly, as docker-compose does not understand a local image + # being shared among services. + build: + context: lofar-device-base + args: + SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}device-xst + networks: + - control + - data + ports: + - "5002:5002/udp" # port to receive XST UDP packets on + - "5706:5706" # unique port for this DS + volumes: + - ${TANGO_LOFAR_CONTAINER_MOUNT} + environment: + - TANGO_HOST=${TANGO_HOST} + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${TANGO_HOST} + - --timeout=30 + - --strict + - -- + # configure CORBA to _listen_ on 0:port, but tell others we're _reachable_ through ${HOSTNAME}:port, since CORBA + # can't know about our Docker port forwarding + - python3 -u ${TANGO_LOFAR_CONTAINER_DIR}/devices/devices/sdp/xst.py LTS -v -ORBendPoint giop:tcp:0:5706 -ORBendPointPublish giop:tcp:${HOSTNAME}:5706 + restart: on-failure diff --git a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index 504cdd2736714aef4a4744e51c98e17d8ba630c7..df75d5962a1327041995aa04c41d6d1e1c2ae914 100644 --- a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -2,7 +2,8 @@ recv = DeviceProxy("LTS/RECV/1") sdp = DeviceProxy("LTS/SDP/1") sst = DeviceProxy("LTS/SST/1") +xst = DeviceProxy("LTS/XST/1") unb2 = DeviceProxy("LTS/UNB2/1") # Put them in a list in case one wants to iterate -devices = [recv, sdp, sst, unb2] +devices = [recv, sdp, sst, xst, unb2] diff --git a/docker-compose/unb2-sim.yml b/docker-compose/unb2-sim.yml new file mode 100644 index 0000000000000000000000000000000000000000..e031e20f54ad6addec1fdbabf972661d6f4c8f9a --- /dev/null +++ b/docker-compose/unb2-sim.yml @@ -0,0 +1,20 @@ +# +# Docker compose file that launches a UNB2 simulator +# +# Defines: +# - unb2-sim +# +version: '2' + +services: + unb2-sim: + build: + context: unb2-sim + container_name: ${CONTAINER_NAME_PREFIX}unb2-sim + networks: + - control + volumes: + - ${HOME}:/hosthome + ports: + - "4844:4844" + restart: on-failure diff --git a/docker-compose/unb2-sim/Dockerfile b/docker-compose/unb2-sim/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..cbb4ce80185ee1cf0a84aabc457a7983e57b5651 --- /dev/null +++ b/docker-compose/unb2-sim/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:20.04 + +COPY requirements.txt /requirements.txt + +RUN apt-get update && apt-get install -y python3 python3-pip python3-yaml git && \ + pip3 install -r requirements.txt && \ + git clone --depth 1 --branch master https://git.astron.nl/lofar2.0/pypcc + +WORKDIR /pypcc +CMD ["python3","pypcc2.py","--simulator", "--port=4844", "--config=UNB2"] diff --git a/docker-compose/unb2-sim/requirements.txt b/docker-compose/unb2-sim/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..5badf0e57069366adedc43ca2c2b59dc7dc4b35d --- /dev/null +++ b/docker-compose/unb2-sim/requirements.txt @@ -0,0 +1,4 @@ +#check if this file is necessary +opcua +numpy +recordclass>=0.16,<0.16.1 \ No newline at end of file diff --git a/jupyter-notebooks/UNB2_notebook.ipynb b/jupyter-notebooks/UNB2_notebook.ipynb index 3e87179f3a0f0ef951da6a078ba5df3610a6696d..e140631ffc4ea0cee80e2374ec6b5f1289dbba24 100644 --- a/jupyter-notebooks/UNB2_notebook.ipynb +++ b/jupyter-notebooks/UNB2_notebook.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 25, "id": "waiting-chance", "metadata": {}, "outputs": [], @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 26, "id": "moving-alexandria", "metadata": {}, "outputs": [], @@ -22,7 +22,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 28, "id": "ranking-aluminum", "metadata": { "scrolled": false @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 29, "id": "0caa8146", "metadata": {}, "outputs": [ @@ -63,68 +63,68 @@ "name": "stdout", "output_type": "stream", "text": [ - "version_R *L2SS-268-LR1_2_Read_hardware_status_of_UB2c_from_SDPHW [1007a5c5462b1aa3e8f81268f890f6c058413218]\n", + "version_R *L2SS-268-LR1_2_Read_hardware_status_of_UB2c_from_SDPHW [b2db449162be8e52013dbbd1a44d6d90a12491b5]\n", "UNB2_Power_ON_OFF_RW [False False]\n", "UNB2_Front_Panel_LED_RW [0 0]\n", "UNB2_Front_Panel_LED_R [0 0]\n", "UNB2_mask_RW [False False]\n", "UNB2_I2C_bus_STATUS_R [False False]\n", - "UNB2_EEPROM_Unique_ID_R [5947666 5947666]\n", - "UNB2_DC_DC_48V_12V_VIN_R [29.18505859 29.18505859]\n", - "UNB2_DC_DC_48V_12V_VOUT_R [12.00146484 11.98486328]\n", - "UNB2_DC_DC_48V_12V_IOUT_R [3.625 3.625]\n", - "UNB2_DC_DC_48V_12V_TEMP_R [37. 37.]\n", - "UNB2_POL_QSFP_N01_VOUT_R [3.28686523 3.28686523]\n", - "UNB2_POL_QSFP_N01_IOUT_R [1.55078125 1.55078125]\n", - "UNB2_POL_QSFP_N01_TEMP_R [33.75 33.75]\n", - "UNB2_POL_QSFP_N23_VOUT_R [3.28710938 3.28710938]\n", - "UNB2_POL_QSFP_N23_IOUT_R [1.25195312 1.25195312]\n", - "UNB2_POL_QSFP_N23_TEMP_R [40.625 40.625]\n", - "UNB2_POL_SWITCH_1V2_VOUT_R [1.19970703 1.19970703]\n", - "UNB2_POL_SWITCH_1V2_IOUT_R [1.73632812 1.73632812]\n", - "UNB2_POL_SWITCH_1V2_TEMP_R [45.125 45.125]\n", - "UNB2_POL_SWITCH_PHY_VOUT_R [1.00024414 1.00024414]\n", - "UNB2_POL_SWITCH_PHY_IOUT_R [0.52050781 0.52050781]\n", - "UNB2_POL_SWITCH_PHY_TEMP_R [46.1875 46.1875]\n", - "UNB2_POL_CLOCK_VOUT_R [2.49951172 2.49951172]\n", - "UNB2_POL_CLOCK_IOUT_R [0.94042969 0.94042969]\n", - "UNB2_POL_CLOCK_TEMP_R [42.875 42.875]\n", - "UNB2_FPGA_DDR4_SLOT_TEMP_R [[27.5 27.5 29.25 27.75 28.75 29.25 28.5 28.5 ]\n", - " [27.5 27.5 29.25 27.75 28.75 29.25 28.5 28.5 ]]\n", - "UNB2_FPGA_POL_CORE_IOUT_R [[5.921875 4.109375 3.76171875 3.55859375]\n", - " [5.921875 4.1015625 3.76171875 3.55859375]]\n", - "UNB2_FPGA_POL_CORE_TEMP_R [[30.84375 31.46875 32.4375 34.75 ]\n", - " [30.84375 31.5 32.375 34.6875 ]]\n", - "UNB2_FPGA_POL_ERAM_VOUT_R [[0.8996582 0.90014648 0.90014648 0.8996582 ]\n", - " [0.8996582 0.8996582 0.90014648 0.8996582 ]]\n", - "UNB2_FPGA_POL_ERAM_IOUT_R [[0.08764648 0.0880127 0.18725586 0.08703613]\n", - " [0.02593994 0.0880127 0.18725586 0.08703613]]\n", - "UNB2_FPGA_POL_ERAM_TEMP_R [[38.75 39.25 41. 41.4375]\n", - " [38.75 39.25 41. 41.4375]]\n", - "UNB2_FPGA_POL_RXGXB_VOUT_R [[0.90014648 0.89990234 0.90014648 0.90014648]\n", - " [0.90014648 0.89990234 0.90014648 0.90014648]]\n", - "UNB2_FPGA_POL_RXGXB_IOUT_R [[0.49755859 0.41113281 0.40234375 0.48876953]\n", - " [0.49755859 0.41113281 0.40234375 0.48876953]]\n", - "UNB2_FPGA_POL_RXGXB_TEMP_R [[34.75 38.0625 36.5 38.1875]\n", - " [34.75 38.0625 36.5 38.1875]]\n", - "UNB2_FPGA_POL_TXGXB_VOUT_R [[0.89990234 0.90014648 0.90014648 0.89990234]\n", - " [0.89990234 0.90014648 0.90014648 0.89990234]]\n", - "UNB2_FPGA_POL_TXGXB_IOUT_R [[0.17480469 0.12219238 0.06433105 0.13110352]\n", - " [0.17480469 0.12219238 0.06433105 0.13110352]]\n", - "UNB2_FPGA_POL_HGXB_VOUT_R [[1.80004883 1.79956055 1.79980469 1.79980469]\n", - " [1.80004883 1.79956055 1.79980469 1.79980469]]\n", - "UNB2_FPGA_POL_HGXB_IOUT_R [[0.67089844 0.76269531 0.80664062 0.7265625 ]\n", - " [0.67089844 0.76269531 0.80664062 0.7265625 ]]\n", - "UNB2_FPGA_POL_HGXB_TEMP_R [[40.375 41.8125 44.3125 40.625 ]\n", - " [40.375 41.8125 44.3125 40.625 ]]\n", - "UNB2_FPGA_POL_PGM_VOUT_R [[1.80029297 1.80004883 1.79931641 1.80029297]\n", - " [1.80029297 1.80004883 1.79931641 1.80029297]]\n", - "UNB2_FPGA_POL_PGM_IOUT_R [[0.13818359 0.17089844 0.31542969 0.10656738]\n", - " [0.1550293 0.17089844 0.31542969 0.10656738]]\n", - "UNB2_FPGA_POL_PGM_TEMP_R [[40.0625 42.1875 44.3125 40.3125]\n", - " [40.0625 42.1875 44.3125 40.3125]]\n", - "State <function __get_command_func.<locals>.f at 0x7f636d295510>\n", - "Status <function __get_command_func.<locals>.f at 0x7f636d295510>\n" + "UNB2_EEPROM_Unique_ID_R [0 0]\n", + "UNB2_DC_DC_48V_12V_VIN_R [0. 0.]\n", + "UNB2_DC_DC_48V_12V_VOUT_R [0. 0.]\n", + "UNB2_DC_DC_48V_12V_IOUT_R [0. 0.]\n", + "UNB2_DC_DC_48V_12V_TEMP_R [0. 0.]\n", + "UNB2_POL_QSFP_N01_VOUT_R [0. 0.]\n", + "UNB2_POL_QSFP_N01_IOUT_R [0. 0.]\n", + "UNB2_POL_QSFP_N01_TEMP_R [0. 0.]\n", + "UNB2_POL_QSFP_N23_VOUT_R [0. 0.]\n", + "UNB2_POL_QSFP_N23_IOUT_R [0. 0.]\n", + "UNB2_POL_QSFP_N23_TEMP_R [0. 0.]\n", + "UNB2_POL_SWITCH_1V2_VOUT_R [0. 0.]\n", + "UNB2_POL_SWITCH_1V2_IOUT_R [0. 0.]\n", + "UNB2_POL_SWITCH_1V2_TEMP_R [0. 0.]\n", + "UNB2_POL_SWITCH_PHY_VOUT_R [0. 0.]\n", + "UNB2_POL_SWITCH_PHY_IOUT_R [0. 0.]\n", + "UNB2_POL_SWITCH_PHY_TEMP_R [0. 0.]\n", + "UNB2_POL_CLOCK_VOUT_R [0. 0.]\n", + "UNB2_POL_CLOCK_IOUT_R [0. 0.]\n", + "UNB2_POL_CLOCK_TEMP_R [0. 0.]\n", + "UNB2_FPGA_DDR4_SLOT_TEMP_R [[0. 0. 0. 0. 0. 0. 0. 0.]\n", + " [0. 0. 0. 0. 0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_CORE_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_CORE_TEMP_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_ERAM_VOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_ERAM_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_ERAM_TEMP_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_RXGXB_VOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_RXGXB_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_RXGXB_TEMP_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_TXGXB_VOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_TXGXB_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_HGXB_VOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_HGXB_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_HGXB_TEMP_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_PGM_VOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_PGM_IOUT_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "UNB2_FPGA_POL_PGM_TEMP_R [[0. 0. 0. 0.]\n", + " [0. 0. 0. 0.]]\n", + "State <function __get_command_func.<locals>.f at 0x7f4c210e1ea0>\n", + "Status <function __get_command_func.<locals>.f at 0x7f4c210e1ea0>\n" ] } ], @@ -138,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 30, "id": "929965c2", "metadata": {}, "outputs": [ @@ -171,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 22, "id": "6813164e", "metadata": {}, "outputs": [ @@ -201,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 23, "id": "e9b32ec7", "metadata": {}, "outputs": [ @@ -210,7 +210,7 @@ "output_type": "stream", "text": [ "Old values:\n", - " [ True True]\n", + " [False False]\n", "Values to be set:\n", " [False False]\n", "Values read back after setting:\n", @@ -231,25 +231,21 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 24, "id": "transsexual-battle", "metadata": {}, "outputs": [ { - "ename": "DevFailed", - "evalue": "DevFailed[\nDevError[\n desc = Read value for attribute FPGA_mask_RW has not been updated\n origin = Device_3Impl::read_attributes_no_except\n reason = API_AttrValueNotSet\nseverity = ERR]\n\nDevError[\n desc = Failed to read_attribute on device lts/sdp/1, attribute FPGA_mask_RW\n origin = DeviceProxy::read_attribute()\n reason = API_AttributeFailed\nseverity = ERR]\n]", + "ename": "AttributeError", + "evalue": "FPGA_mask_RW", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mDevFailed\u001b[0m Traceback (most recent call last)", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_22/2885399456.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m values = [\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mFPGA_mask_RW\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"FPGA_mask_RW\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mFPGA_scrap_R\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"FPGA_scrap_R\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mFPGA_scrap_RW\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"FPGA_scrap_RW\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mFPGA_status_R\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"FPGA_status_R\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/device_proxy.py\u001b[0m in \u001b[0;36m__DeviceProxy__getattr\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 319\u001b[0m \u001b[0mattr_info\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__get_attr_cache\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname_l\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 320\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mattr_info\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 321\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m__get_attribute_value\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr_info\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 322\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 323\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mname_l\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__get_pipe_cache\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/device_proxy.py\u001b[0m in \u001b[0;36m__get_attribute_value\u001b[0;34m(self, attr_info, name)\u001b[0m\n\u001b[1;32m 281\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__get_attribute_value\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mattr_info\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 282\u001b[0m \u001b[0m_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0menum_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mattr_info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 283\u001b[0;31m \u001b[0mattr_value\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_attribute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 284\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0menum_class\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 285\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0menum_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/green.py\u001b[0m in \u001b[0;36mgreener\u001b[0;34m(obj, *args, **kwargs)\u001b[0m\n\u001b[1;32m 193\u001b[0m \u001b[0mgreen_mode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0maccess\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'green_mode'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 194\u001b[0m \u001b[0mexecutor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mget_object_executor\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgreen_mode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 195\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mexecutor\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwait\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 196\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 197\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mgreener\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/green.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, fn, args, kwargs, wait, timeout)\u001b[0m\n\u001b[1;32m 107\u001b[0m \u001b[0;31m# Sychronous (no delegation)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 108\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masynchronous\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0min_executor_context\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 109\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 110\u001b[0m \u001b[0;31m# Asynchronous delegation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 111\u001b[0m \u001b[0maccessor\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdelegate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/device_proxy.py\u001b[0m in \u001b[0;36m__DeviceProxy__read_attribute\u001b[0;34m(self, value, extract_as)\u001b[0m\n\u001b[1;32m 439\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 440\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__DeviceProxy__read_attribute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mextract_as\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mExtractAs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNumpy\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 441\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0m__check_read_attribute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_read_attribute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mextract_as\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 442\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 443\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/device_proxy.py\u001b[0m in \u001b[0;36m__check_read_attribute\u001b[0;34m(dev_attr)\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__check_read_attribute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdev_attr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 156\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdev_attr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhas_failed\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 157\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mDevFailed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mdev_attr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_err_stack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 158\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mdev_attr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 159\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mDevFailed\u001b[0m: DevFailed[\nDevError[\n desc = Read value for attribute FPGA_mask_RW has not been updated\n origin = Device_3Impl::read_attributes_no_except\n reason = API_AttrValueNotSet\nseverity = ERR]\n\nDevError[\n desc = Failed to read_attribute on device lts/sdp/1, attribute FPGA_mask_RW\n origin = DeviceProxy::read_attribute()\n reason = API_AttributeFailed\nseverity = ERR]\n]" + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/tango/device_proxy.py\u001b[0m in \u001b[0;36m__DeviceProxy__getattr\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 353\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_pipe\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 354\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 355\u001b[0;31m \u001b[0msix\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mraise_from\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mAttributeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcause\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 356\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 357\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/six.py\u001b[0m in \u001b[0;36mraise_from\u001b[0;34m(value, from_value)\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: FPGA_mask_RW" ] } ], diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index a919b892767ef6a7d4eec83ba400cae79294190b..93b13300eb92afe2c95c7cb5c3292869019d9d96 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -8,8 +8,8 @@ fi # Start and stop sequence cd "$LOFAR20_DIR/docker-compose" || exit 1 -make stop device-sdp device-pcc device-sst sdptr-sim recv-sim -make start databaseds dsconfig jupyter elk +make stop device-sdp device-recv device-sst device-unb2 sdptr-sim recv-sim unb2-sim +make start databaseds dsconfig jupyter elk # Give dsconfig and databaseds time to start sleep 15 @@ -24,7 +24,7 @@ make start sdptr-sim recv-sim # Give the simulators time to start sleep 5 -make start device-sdp device-pcc device-sst +make start device-sdp device-recv device-sst device-unb2 # Give the devices time to start sleep 5