# -*- coding: utf-8 -*- # # This file is part of the SDP project # # # # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. """ SDP Device Server for LOFAR2.0 """ # PyTango imports from tango.server import run from tango.server import device_property, attribute from tango import AttrWriteType # Additional import from clients.opcua_connection import OPCUAConnection from util.attribute_wrapper import attribute_wrapper from util.hardware_device import hardware_device from util.lofar_logging import device_logging_to_python, log_exceptions from util.lofar_git import get_version import numpy __all__ = ["SDP", "main"] @device_logging_to_python({"device": "SDP"}) class SDP(hardware_device): """ **Properties:** - Device Property OPC_Server_Name - Type:'DevString' OPC_Server_Port - Type:'DevULong' OPC_Time_Out - Type:'DevDouble' """ # ----------------- # Device Properties # ----------------- OPC_Server_Name = device_property( dtype='DevString', mandatory=True ) OPC_Server_Port = device_property( dtype='DevULong', mandatory=True ) OPC_Time_Out = device_property( dtype='DevDouble', mandatory=True ) # ---------- # Attributes # ---------- version_R = attribute(dtype=str, access=AttrWriteType.READ, fget=lambda self: get_version()) # SDP will switch from FPGA_mask_RW to TR_FPGA_mask_RW, offer both for now as its a critical flag FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_firmware_version_R"], datatype=numpy.str_, dims=(16,)) FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_hardware_version_R"], datatype=numpy.str_, dims=(16,)) FPGA_mask_R = attribute_wrapper(comms_annotation=["2:FPGA_mask_R"], datatype=numpy.bool_, dims=(16,)) FPGA_mask_RW = attribute_wrapper(comms_annotation=["2:FPGA_mask_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_scrap_R = attribute_wrapper(comms_annotation=["2:FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,)) FPGA_scrap_RW = attribute_wrapper(comms_annotation=["2:FPGA_scrap_RW"], datatype=numpy.int32, dims=(8192,), access=AttrWriteType.READ_WRITE) FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_f_sub_type_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_f_sub_type_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(16,)) FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sst_offload_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) FPGA_sst_offload_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str_, dims=(16,)) FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=numpy.str_, dims=(16,)) FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_sst_offload_selector_R = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_selector_R"], datatype=numpy.bool_, dims=(16,)) FPGA_sst_offload_selector_RW = attribute_wrapper(comms_annotation=["2:FPGA_sst_offload_selector_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_status_R = attribute_wrapper(comms_annotation=["2:FPGA_status_R"], datatype=numpy.bool_, dims=(16,)) FPGA_temp_R = attribute_wrapper(comms_annotation=["2:FPGA_temp_R"], datatype=numpy.float_, dims=(16,)) FPGA_version_R = attribute_wrapper(comms_annotation=["2:FPGA_version_R"], datatype=numpy.str_, dims=(16,)) FPGA_weights_R = attribute_wrapper(comms_annotation=["2:FPGA_weights_R"], datatype=numpy.int16, dims=(16, 12 * 488 * 2)) FPGA_weights_RW = attribute_wrapper(comms_annotation=["2:FPGA_weights_RW"], datatype=numpy.int16, dims=(16, 12 * 488 * 2), access=AttrWriteType.READ_WRITE) FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(16, 12)) FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(16, 12), access=AttrWriteType.READ_WRITE) FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_enable_R"], datatype=numpy.bool_, dims=(16, 12)) FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_enable_RW"], datatype=numpy.bool_, dims=(16, 12), access=AttrWriteType.READ_WRITE) FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(16, 12)) FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(16, 12), access=AttrWriteType.READ_WRITE) FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_phase_R"], datatype=numpy.float_, dims=(16, 12)) FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_phase_R"], datatype=numpy.float_, dims=(16, 12), access=AttrWriteType.READ_WRITE) TR_busy_R = attribute_wrapper(comms_annotation=["2:TR_busy_R"], datatype=numpy.bool_) TR_reload_RW = attribute_wrapper(comms_annotation=["2:TR_reload_RW"], datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) TR_software_version_R = attribute_wrapper(comms_annotation=["2:TR_software_version_R"], datatype=numpy.str_) TR_tod_R = attribute_wrapper(comms_annotation=["2:TR_tod_R"], datatype=numpy.uint64) TR_uptime_R = attribute_wrapper(comms_annotation=["2:TR_uptime_R"], datatype=numpy.uint64) def always_executed_hook(self): """Method always executed before any TANGO command is executed.""" pass @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). """ self.debug_stream("Shutting down...") self.Off() self.debug_stream("Shut down. Good bye.") # -------- # overloaded functions # -------- @log_exceptions() def configure_for_off(self): """ user code here. is called when the state is set to OFF """ # Stop keep-alive try: self.opcua_connection.stop() except Exception as e: self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e)) @log_exceptions() def configure_for_initialise(self): """ user code here. is called when the sate is set to INIT """ """Initialises the attributes and properties of the SDP.""" # set up the OPC ua client self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self) # map an access helper class for i in self.attr_list(): try: i.set_comm_client(self.OPCua_client) except Exception as e: # use the pass function instead of setting read/write fails i.set_pass_func() self.warn_stream("error while setting the SDP attribute {} read/write function. {}".format(i, e)) pass self.OPCua_client.start() # -------- # Commands # -------- # ---------- # Run server # ---------- def main(args=None, **kwargs): """Main function of the SDP module.""" from util.lofar_logging import configure_logger import logging configure_logger(logging.getLogger()) return run((SDP,), args=args, **kwargs) if __name__ == '__main__': main()