Commit c61b7fe6 authored by Elisabetta Giani's avatar Elisabetta Giani
Browse files

AT5-262: implementation of the MidCspMasterBase class.

Still in progress:work has to be done to generate and add the
CSP.LMC Common package import.
parent 16e72889
Loading
Loading
Loading
Loading
+519 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
#
# This file is part of the MidCspMasterBase project
#
# INAF-SKA Telescope
#
# Distributed under the terms of the GPL license.
# See LICENSE.txt for more info.

""" MidCspMasterBase class

The base class for MID CspMAster.
Fuctionality to monitor CSP.LMC Capabilities are 
implemented in separate TANGO Devices.
"""

# PROTECTED REGION ID (CspMaster.standardlibray_import) ENABLED START #
# Python standard library
from __future__ import absolute_import
import sys
import os
from future.utils import with_metaclass
from collections import defaultdict
# PROTECTED REGION END# //CspMaster.standardlibray_import

# tango imports# PROTECTED REGION ID (CspMaster.add_path) ENABLED START #

import tango
from tango import DebugIt
from tango.server import run
from tango.server import Device, DeviceMeta
from tango.server import attribute, command
from tango.server import device_property
from tango import AttrQuality, EventType, DevState
from tango import AttrWriteType, DeviceProxy
# Additional import
# PROTECTED REGION ID(CspMaster.additionnal_import) ENABLED START #
#
from skabase.SKAMaster  import SKAMaster
from skabase.auxiliary import utils
# PROTECTED REGION END #    //  CspMaster.additionnal_import

# PROTECTED REGION ID (CspMaster.add_path) ENABLED START #
# add the path to import global_enum package.
file_path = os.path.dirname(os.path.abspath(__file__))
utils_path = os.path.abspath(os.path.join(file_path, os.pardir)) + "/../csp-lmc-common/utils"
# TO REMOVE once csp-lmc-common python package has been released!
package_path = os.path.abspath(os.path.join(file_path, os.pardir)) + "/../csp-lmc-common/csp-lmc-common"
print("utilpath:", utils_path)
print("package_path:", package_path)
sys.path.insert(0, utils_path)
sys.path.insert(0, package_path)
import cspcommons
from cspcommons import HealthState, AdminMode
from CspMaster import CspMaster
# PROTECTED REGION END# //CspMaster.add_path
__all__ = ["MidCspMasterBase", "main"]


class MidCspMasterBase(with_metaclass(DeviceMeta, CspMaster)):
    """
    The base class for MID CspMAster.
    Fuctionality to monitor CSP.LMC Capabilities are 
    implemented in separate TANGO Devices.

    **Properties:**

    - Device Property
    
    """
    __metaclass__ = DeviceMeta
    # PROTECTED REGION ID(MidCspMasterBase.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  MidCspMasterBase.class_variable

    # -----------------
    # Device Properties
    # -----------------

    # ----------
    # Attributes
    # ----------

    availableCapabilities = attribute(
        dtype=('DevString',),
        max_dim_x=20,
        doc="A list of available number of instances of each capability type, e.g. `CORRELATOR:512`, `PSS-BEAMS:4`.",
    )
    """
    *Class attribute*

    The list of available instances of each capability type.

    Note:
        This attribute is defined in SKAMaster Class from which CspMaster class inherits.\
        To override the attribute *read* method, the *availableCapabilities* attribute \
        is added again\
        ("overload" button enabled in POGO).
    """
    
    receptorMembership = attribute(
        dtype=('DevUShort',),
        max_dim_x=197,
        label="Receptor Memebership",
        doc="The receptors affiliation to MID CSP sub-arrays.",
    )

    unassignedReceptorIDs = attribute(
        dtype=('DevUShort',),
        max_dim_x=197,
        label="Unassigned receptors IDs",
        doc="The list of available receptors IDs.",
    )
    reportSearchBeamState = attribute(name="reportSearchBeamState",
        label="SearchBeam Capabilities State",
        forwarded=True
    )
    reportSearchBeamHealthState = attribute(name="reportSearchBeamHealthState",
        label="SearchBeam Capabilities healthState",
        forwarded=True
    )
    reportSearchBeamObsState = attribute(name="reportSearchBeamObsState",
        label="SearchBeam Capabilities obsState",
        forwarded=True
    )
    reportSearchBeamAdminMode = attribute(name="reportSearchBeamAdminMode",
        label="SearchBeam Capabilities adminMode",
        forwarded=True
    )
    reportTimingBeamState = attribute(name="reportTimingBeamState",
        label="TimingBeam Capabilities State",
        forwarded=True
    )
    reportTimingBeamHealthState = attribute(name="reportTimingBeamHealthState",
        label="TimingBeam Capabilities healthState",
        forwarded=True
    )
    reportTimingBeamObsState = attribute(name="reportTimingBeamObsState",
        label="TimingBeam Capabilities obsState",
        forwarded=True
    )
    reportTimingBeamAdminMode = attribute(name="reportTimingBeamAdminMode",
        label="TimingBeam Capabilities adminMode",
        forwarded=True
    )
    reportVlbiBeamState = attribute(name="reportVlbiBeamState",
        label="VlbiBeam Capabilities State",
        forwarded=True
    )
    reportVlbiBeamHealthState = attribute(name="reportVlbiBeamHealthState",
        label="VlbiBeam Capabilities healthState",
        forwarded=True
    )
    reportVlbiBeamObsState = attribute(name="reportVlbiBeamObsState",
        label="VlbiBeam Capabilities obsState",
        forwarded=True
    )
    reportVlbiBeamAdminMode = attribute(name="reportVlbiBeamAdminMode",
        label="VlbiBeam Capabilities adminMode",
        forwarded=True
    )
    searchBeamAddresses = attribute(name="searchBeamAddresses",
        label="SearchBeams Capability devices addresses",
        forwarded=True
    )
    timingBeamAddresses = attribute(name="timingBeamAddresses",
        label="TimingBeams Capability devices addresses",
        forwarded=True
    )
    vlbiBeamAddresses = attribute(name="vlbiBeamAddresses",
        label="VlbiBeams Capability devices addresses",
        forwarded=True
    )
    reservedSearchBeamIDs = attribute(name="reservedSearchBeamIDs",
        label="IDs of reserved SeachBeam Capabilities",
        forwarded=True
    )
    unassignedVlbiBeamIDs = attribute(name="unassignedVlbiBeamIDs",
        label="Unassigned VlbiBeam Capabilities IDs",
        forwarded=True
    )
    unassignedTimingBeamIDs = attribute(name="unassignedTimingBeamIDs",
        label="Unassigned TimingBeam Capabilities IDs",
        forwarded=True
    )
    unassignedSearchBeamIDs = attribute(name="unassignedSearchBeamIDs",
        label="Unassigned SeachBeam Capabilities IDs",
        forwarded=True
    )
    reservedSearchBeamNum = attribute(name="reservedSearchBeamNum",
        label="Number of reserved SeachBeam Capabilities",
        forwarded=True
    )
    searchBeamMembership = attribute(name="searchBeamMembership",
        label="SearchBeam Membership",
        forwarded=True
    )
    timingBeamMembership = attribute(name="timingBeamMembership",
        label="TimingBeam Membership",
        forwarded=True
    )
    vlbiBeamMembership = attribute(name="vlbiBeamMembership",
        label="VlbiBeam Membership",
        forwarded=True
    )
    vccCapabilityAddress = attribute(name="vccCapabilityAddress",
        label="vccCapabilityAddress",
        forwarded=True
    )
    fspCapabilityAddress = attribute(name="fspCapabilityAddress",
        label="fspCapabilityAddress",
        forwarded=True
    )
    reportVCCState = attribute(name="reportVCCState",
        label="reportVCCState",
        forwarded=True
    )
    reportVCCHealthState = attribute(name="reportVCCHealthState",
        label="reportVCCHealthState",
        forwarded=True
    )
    reportVCCAdminMode = attribute(name="reportVCCAdminMode",
        label="reportVCCAdminMode",
        forwarded=True
    )
    reportFSPState = attribute(name="reportFSPState",
        label="reportFSPState",
        forwarded=True
    )
    reportFSPHealthState = attribute(name="reportFSPHealthState",
        label="reportFSPHealthState",
        forwarded=True
    )
    reportFSPAdminMode = attribute(name="reportFSPAdminMode",
        label="reportFSPAdminMode",
        forwarded=True
    )
    fspMembership = attribute(name="fspMembership",
        label="fspMembership",
        forwarded=True
    )
    vccMembership = attribute(name="vccMembership",
        label="vccMembership",
        forwarded=True
    )
    #
    # Class private methods
    #
    def __get_maxnum_of_receptors(self):
        """
        Get the maximum number of receptors that can be used for observations.
        This number can be less than 197.
        """

        capability_dict = {}
        if self._is_device_running(self.CspCbf, self._se_proxies):
            try:
                proxy = self._se_proxies[self.CspCbf]
                vcc_to_receptor = proxy.vccToReceptor
                self._vcc_to_receptor_map = dict([int(ID) for ID in pair.split(":")]
                                                for pair in vcc_to_receptor)
                # get the number of each Capability type allocated by CBF
                cbf_max_capabilities = proxy.maxCapabilities
                for capability in cbf_max_capabilities:
                    cap_type, cap_num = capability.split(':')
                    capability_dict[cap_type] = int(cap_num)
                self._receptors_maxnum = capability_dict["VCC"]
                self._receptorsMembership = [0]* self._receptors_maxnum
            except KeyError as key_err:
                log_msg = "Error: no key found for {}".format(str(key_err))
                self.dev_logging(log_msg, int(tango.LogLevel.LOG_ERROR))

            except AttributeError as attr_err:
                log_msg = "Error reading{}: {}".format(str(attr_err.args[0]),
                                                    attr_err.__doc__)
                self.dev_logging(log_msg, int(tango.LogLevel.LOG_ERROR))
            except tango.DevFailed as df:
                log_msg = "Error: " + str(df.args[0].reason)
                self.dev_logging(log_msg, int(tango.LogLevel.LOG_ERROR))
        
    # ---------------
    # General methods
    # ---------------

    def init_device(self):
        """Initialises the attributes and properties of the MidCspMasterBase."""
        CspMaster.init_device(self)
        print("Receptors:", self._max_capabilities["Receptors"])
        
        # PROTECTED REGION ID(MidCspMasterBase.init_device) ENABLED START #
        # NOTE: VCC (Receptors) and FSP capabilities are implemented at
        #       CBF sub-element level. Need to evaluate if these capabilities
        #       have to be implemented also at CSP level.
        #       To retieve the information on the number of instances provided
        #       by CBF the CSP master has to connect to the Cbf Master. For this
        #       reason the __get_maxnum_of_receptors() method gas to be called
        #       after connection.
        self._vcc_to_receptor_map = {}
        self._receptorsMembership = [0] * self._max_capabilities["Receptors"]
        self._available_capabilities = defaultdict(lambda:0)
        self._unassigned_receptor_id = []
        
        # read the mapping between VCC IDs and receptor IDs
        if self._is_device_running(self.CspCbf, self._se_proxies):
            proxy = self._se_proxies[self.CspCbf] 
            vcc_to_receptor = proxy.vccToReceptor
            self._vcc_to_receptor_map = dict([int(ID) for ID in pair.split(":")]
                                             for pair in vcc_to_receptor)
        
        # PROTECTED REGION END #    //  MidCspMasterBase.init_device

    def always_executed_hook(self):
        """Method always executed before any TANGO command is executed."""
        # PROTECTED REGION ID(MidCspMasterBase.always_executed_hook) ENABLED START #
        # PROTECTED REGION END #    //  MidCspMasterBase.always_executed_hook

    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.
        """
        # PROTECTED REGION ID(MidCspMasterBase.delete_device) ENABLED START #
        CspMaster.delete_device(self)
        self._vcc_to_receptor_map.clear()
        self._receptorsMembership.clear()
        # PROTECTED REGION END #    //  MidCspMasterBase.delete_device
    # ------------------
    # Attributes methods
    # ------------------

    def read_availableCapabilities(self):
        # PROTECTED REGION ID(MidCspMasterBase.availableCapabilities_read) ENABLED START #
        """
        Override read attribute method.

        :return:
            A list of strings with the number of available resources for each
            capability/resource type.
        Example:
            ["Receptors:95", "SearchBeam:1000", "TimingBeam:16", "VlbiBeam:20"]
        :raises:
            tango.DevFailed
        """
        # PROTECTED REGION ID(CspMaster.availableCapabilities_read) ENABLED START #
        try:
            #proxy = tango.DeviceProxy(self.get_name())
            unassigned_receptors = self.read_unassignedReceptorIDs()
            print("unassigned_receptors:",  unassigned_receptors)
            # NOTE: if there is no available receptor, this call returns an array
            # [0] whose length is 1 (not 0)
            
            cap_type = [keys for keys,values in self._max_capabilities.items()]
            print("cap_type:", cap_type)
            if not unassigned_receptors:
                self._available_capabilities["Receptors"] = 0
            else:
                self._available_capabilities["Receptors"] = len(unassigned_receptors)
            index = 1
            for fqdn in self._capability_fqdn:
                print("fqdn:", fqdn)
                if self._is_device_running(fqdn, self._capability_proxy):
                    self._available_capabilities[cap_type[index]] = self._capability_proxy[fqdn].numOfUnassignedIDs
                index += 1                                 
        except tango.DevFailed as df:
            msg = "Attribute reading failure: {}".format(df.args[0].desc)
            self.dev_logging(msg, tango.LogLevel.LOG_ERROR)
            tango.Except.throw_exception("Attribute reading failure",
                                         df.args[0].desc,
                                         "read_availableCapabilities",
                                         tango.ErrSeverity.ERR)
        except AttributeError as attr_err:
            msg = "Error in reading {}: {} ".format(str(attr_err.args[0]),
                                                    attr_err.__doc__)
            tango.Except.throw_exception("Attribute reading failure",
                                         msg,
                                         "read_availableCapabilities",
                                         tango.ErrSeverity.ERR)
        return utils.convert_dict_to_list(self._available_capabilities)
        # PROTECTED REGION END #    //  MidCspMasterBase.availableCapabilities_read

    def read_receptorMembership(self):
        # PROTECTED REGION ID(MidCspMasterBase.receptorMembership_read) ENABLED START #
        """
        Class attribute method.

        :return:
           The subarray affiliation of the receptors.
        """
        # PROTECTED REGION ID(CspMaster.receptorMembership_read) ENABLED START #
        if self._is_device_running(self.CspCbf, self._se_proxies):
            try:
                proxy = self._se_proxies[self.CspCbf]
                vcc_membership = proxy.reportVccSubarrayMembership
                for vcc_id, receptorID in self._vcc_to_receptor_map.items():
                    self._receptorsMembership[receptorID - 1] = vcc_membership[vcc_id - 1]
            except tango.DevFailed as df:
                tango.Except.re_throw_exception(df,
                                                "CommandFailed",
                                                "read_receptorsMembership failed",
                                                "Command()")
            except KeyError as key_err:
                msg = "Can't retrieve the information of key {}".format(key_err)
                self.dev_logging(msg, tango.LogLevel.LOG_ERROR)
                tango.Except.throw_exception("Attribute reading failure",
                                             msg,
                                             "read_receptorMembership",
                                             tango.ErrSeverity.ERR)
            except AttributeError as attr_err:
                msg = "Error in reading {}: {} ".format(str(attr_err.args[0]), attr_err.__doc__)
                tango.Except.throw_exception("Attribute reading failure",
                                             msg,
                                             "read_receptorMembership",
                                             tango.ErrSeverity.ERR)
        return self._receptorsMembership
        # PROTECTED REGION END #    //  CspMaster.receptorMembership_read

        # PROTECTED REGION END #    //  MidCspMasterBase.receptorMembership_read

    def read_unassignedReceptorIDs(self):
        # PROTECTED REGION ID(MidCspMasterBase.unassignedReceptorIDs_read) ENABLED START #
        """
        Class attribute method.

        Returns:
            The list of the available receptors IDs.
            The list includes all the receptors that are not assigned to any subarray and,
            from the side of CSP, are considered "full working". This means:\n
            * a valid link connection receptor-VCC\n
            * the connected VCC healthState OK

            *Type*: array of DevUShort
        Raises:
            tango.DevFailed: if there is no DeviceProxy providing interface to the\
                    CBF sub-element Master Device or an error is caught during\
                    command execution.
        """
        # PROTECTED REGION ID(CspMaster.availableReceptorIDs_read) ENABLED START #
        self._unassigned_receptor_id.clear()
        if not self._is_device_running(self.CspCbf, self._se_proxies):
            return self._unassigned_receptor_id
        try:
            proxy = self._se_proxies[self.CspCbf]
            # get the State and sub-array affiliation of the VCC
            # Note: Mid CBF should also provide information about receptors!
            vcc_state = proxy.reportVCCState
            vcc_membership = proxy.reportVccSubarrayMembership
            # check if the VCC-receptor map is already defined
            if not self._vcc_to_receptor_map:
                vcc_to_receptor = proxy.vccToReceptor
                self._vcc_to_receptor_map = dict([int(ID) for ID in pair.split(":")]
                                                 for pair in vcc_to_receptor)
            # get the list with the IDs of the available VCC
            for vcc_id, receptorID in self._vcc_to_receptor_map.items():
                try:
                    if vcc_state[vcc_id - 1] not in [tango.DevState.UNKNOWN]:
                        # skip the vcc already assigned to a sub-array
                        if vcc_membership[vcc_id - 1] != 0:
                            continue
                        # OSS: valid receptorIDs are in [1,197] range
                        # receptorID = 0 means the link connection between
                        # the receptor and the VCC is off
                        if receptorID > 0:
                            self._unassigned_receptor_id.append(receptorID)
                        else:
                            log_msg = ("Link problem with receptor connected"
                                       " to Vcc {}".format(vcc_id + 1))
                            self.dev_logging(log_msg, tango.LogLevel.LOG_WARN)
                except KeyError as key_err:
                    log_msg = ("No key {} found while accessing VCC {}".format(str(key_err),
                                                                               vcc_id))
                    self.dev_logging(log_msg, tango.LogLevel.LOG_WARN)
                except IndexError as idx_error:
                    log_msg = ("Error accessing VCC"
                               " element {}: {}".format(vcc_id,
                                                        str(idx_error)))
                    self.dev_logging(log_msg, tango.LogLevel.LOG_WARN)
        except KeyError as key_err:
            log_msg = "Can't retrieve the information of key {}".format(key_err)
            tango.Except.throw_exception("Attribute reading failure",
                                         log_msg,
                                         "read_availableReceptorIDs",
                                         tango.ErrSeverity.ERR)
        except tango.DevFailed as df:
            log_msg = "Error in read_unassignedReceptorIDs: {}".format(df.args[0].reason)
            self.dev_logging(log_msg, int(tango.LogLevel.LOG_ERROR))
            tango.Except.throw_exception("Attribute reading failure",
                                         log_msg,
                                         "read_unassignedReceptorIDs",
                                         tango.ErrSeverity.ERR)
        except AttributeError as attr_err:
            msg = "Error in reading {}: {} ".format(str(attr_err.args[0]),
                                                    attr_err.__doc__)
            tango.Except.throw_exception("Attribute reading failure",
                                         msg,
                                         "read_unassignedReceptorIDs",
                                         tango.ErrSeverity.ERR)
        
        return self._unassigned_receptor_id
       
        # PROTECTED REGION END #    //  MidCspMasterBase.unassignedReceptorIDs_read


    # --------
    # Commands
    # --------

# ----------
# Run server
# ----------


def main(args=None, **kwargs):
    # PROTECTED REGION ID(MidCspMasterBase.main) ENABLED START #
    return run((MidCspMasterBase,), args=args, **kwargs)
    # PROTECTED REGION END #    //  MidCspMasterBase.main

if __name__ == '__main__':
    main()
+349 −0

File added.

Preview size limit exceeded, changes collapsed.

+667 −0

File added.

Preview size limit exceeded, changes collapsed.