Commit 10dca534 authored by Elisabetta Giani's avatar Elisabetta Giani
Browse files

CT-57: Added AddReceptors command.

Still to test the state machine model on it.
parent 7d1e6c5c
Loading
Loading
Loading
Loading
Loading
+194 −125
Original line number Diff line number Diff line
@@ -38,16 +38,42 @@ from tango import AttrWriteType, DeviceProxy
# Additional import
# PROTECTED REGION ID(MidCspSubarray.additional_import) ENABLED START #
#from ska.base import SKAMaster
from ska.base import utils
from ska.base.commands import ResponseCommand, ResultCode
from ska.base.faults import CapabilityValidationError
from ska.base.control_model import HealthState, AdminMode, ObsState
# import CSP.LMC Common package
from csp_lmc_common.utils.cspcommons import CmdExecState
from csp_lmc_common.utils.decorators import AdminModeCheck, ObsStateCheck, SubarrayRejectCmd
from csp_lmc_common.CspSubarray import CspSubarray
from csp_lmc_common.CspSubarray import CspSubarray, CspSubarrayStateModel
# PROTECTED REGION END #    //  MidCspSubarrayBase.additionnal_import

__all__ = ["MidCspSubarrayBase", "main"]

class MidCspSubarrayStateModel(CspSubarrayStateModel):
    _subarray_transitions = {
            ('EMPTY', 'add_receptors_succeeded'): (
        "IDLE",
        lambda self: self._set_dev_state(ObsState.IDLE)
    ),
     ('EMPTY', 'add_receptors_started'): (
        "RESOURCING",
        lambda self: self._set_dev_state(ObsState.RESOURCING)
    ),
    ('EMPTY', 'add_receptor_failed'): (
        "OBSFAULT",
        lambda self: self._set_dev_state(DevState.FAULT)
    ),
    }

    def __init__(self, dev_state_callback=None):
        """
        Initialises the model. Note that this does not imply moving to
        INIT state. The INIT state is managed by the model itself.
        """
        super().__init__(
            dev_state_callback=dev_state_callback,
        )
        self.update_transitions(self._subarray_transitions)

class MidCspSubarrayBase(CspSubarray):
    """
@@ -66,6 +92,145 @@ class MidCspSubarrayBase(CspSubarray):
    # PROTECTED REGION ID(MidCspSubarrayBase.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  MidCspSubarrayBase.class_variable
    # PROTECTED REGION ID(MidCspSubarrayBase.private_methods) ENABLED START #
    class InitCommand(CspSubarray.InitCommand):
        """
        A class for the SKASubarray's init_device() "command".
        """
        def do(self):
            """
            Stateless hook for device initialisation.

            :return: A tuple containing a return code and a string
                message indicating status. The message is for
                information purpose only.
            :rtype: (ResultCode, str)
            """
            super().do()
            device = self.target
            self.logger.info("Initial state is:{}".format(device.get_state()))
            device._assigned_vcc = []
            device._assigned_fsp = []
            device._receptor_to_vcc_map = {}
            device._receptor_id_list = []
            message = "MidCspSubarray Init command completed OK"
            self.logger.info(message)
            return (ResultCode.OK, message)

    class OnCommand(CspSubarray.OnCommand):
        # NOTE: To remove when CBF Subarray implements the correct state
        def do(self):
            super().do()
            self.logger.info("On eseguito nel MID")
            return (ResultCode.OK, "On exeguito correttamente")

    class AddReceptorsCommand(ResponseCommand):
        def do(self, argin):
            device = self.target
            # PROTECTED REGION ID(CspSubarray.AddReceptors) ENABLED START #
            # Each vcc_id map to a vcc_fqdn inside CbfMaster, for example:
            # vcc_id = 1 -> mid_csp_cbf/vcc/vcc_001
            # vcc_id = 2 -> mid_csp_cbf/vcc/vcc_002
            # .....
            # vcc_id = 17 -> mid_csp_cbf/vcc/vcc_017
            # vcc_id and receptor_id is not the same. The map between vcc_id and receptor_id
            # is built by CbfMaster and exported as attribute.
            # The max number of VCC allocated is defined by the VCC property of the CBF Master.

            # the list of available receptor IDs. This number is mantained by the CspMaster
            # and reported on request.
            available_receptors = []
            # the list of receptor to assign to the subarray
            receptor_to_assign = []
            try:
                # access to CspMaster to get information about the list of available receptors
                # and the receptors affiliation to subarrays.
                csp_master_proxy = DeviceProxy(device.CspMaster)
                csp_master_proxy.ping()
                available_receptors = csp_master_proxy.unassignedReceptorIDs
                if not device._receptor_to_vcc_map:
                    cbf_master_addr = csp_master_proxy.cbfMasterAddress
                    cbf_master_proxy = tango.DeviceProxy(cbf_master_addr)
                    cbf_master_proxy.ping()
                    # build the list of receptor ids
                    receptor_to_vcc = cbf_master_proxy.receptorToVcc
                    device._receptor_to_vcc_map = dict([int(ID) for ID in pair.split(":")]
                                                     for pair in receptor_to_vcc)
                    # build the list of the installed receptors
                    device._receptor_id_list = list(device._receptor_to_vcc_map.keys())
                if not any(available_receptors):
                    log_msg = "No available receptor to add to subarray {}".format(
                        device.SubID)
                    self.logger.warning(log_msg)
                    return
                receptor_membership = csp_master_proxy.receptorMembership
            except tango.DevFailed as df:
                msg = "Failure in getting receptors information:" + \
                    str(df.args[0].reason)
                tango.Except.throw_exception("Command failed", msg,
                                             "AddReceptors", tango.ErrSeverity.ERR)
            except AttributeError as attr_err:
                msg = "Failure in reading {}: {}".format(
                    str(attr_err.args[0]), attr_err.__doc__)
                tango.Except.throw_exception("Command failed", msg,
                                             "AddReceptors", tango.ErrSeverity.ERR)
            for receptorId in argin:
                # check if the specified receptor id is a valid number (that is, belongs to the list
                # of provided receptors)
                if receptorId in device._receptor_id_list:
                    # check if the receptor id is one of the available receptor Ids
                    if receptorId in available_receptors:
                        receptor_to_assign.append(receptorId)
                    else:
                        # retrieve the subarray owner
                        sub_id = receptor_membership[receptorId - 1]
                        log_msg = "Receptor {} already assigned to subarray {}".format(str(receptorId),
                                                                                       str(sub_id))
                        self.logger.info(log_msg)
                else:
                    log_msg = "Invalid receptor id: {}".format(str(receptorId))
                    self.logger.warning(log_msg)

            # check if the list of receptors to assign is empty
            if not receptor_to_assign:
                log_msg = "No receptors to assign to the subarray"
                self.logger.info(log_msg)
                return

            # check if the CbfSubarray TANGO device is already running
            # and the proxy registered
            if not device._is_sc_subarray_running(device.CbfSubarray):
                log_msg = "Device {} is not running!".format(str(device.CbfSubarray))
                self.logger.error(log_msg)
                tango.Except.throw_exception("Command failed",
                                             log_msg,
                                             "AddReceptors",
                                             tango.ErrSeverity.ERR)
            proxy = device._sc_subarray_proxies[device.CbfSubarray]
            # remove possible receptor repetition
            tmp = set(receptor_to_assign)
            receptor_to_assign = list(tmp)
            # forward the command to the CbfSubarray
            try: 
                proxy.command_inout_asynch("AddReceptors", receptor_to_assign, device._cmd_ended_cb)
                
                device._command_thread['addreceptors'] = threading.Thread(target=device._monitor_add_receptors,
                                                                        name="Thread-AddReceptors",
                                                                        args=(receptor_to_assign,))
                device._sc_subarray_cmd_starting_time[device.CbfSubarray] = time.time()
                if device._cmd_execution_state['addreceptors'] != CmdExecState.FAILED:
                    device._cmd_execution_state['addreceptors'] = CmdExecState.RUNNING
                device._command_thread['addreceptors'].start()
                self.logger.info("AddReceptors obsState::{}".format(device._obs_state))
                return (ResultCode.STARTED, "AddReceptors Started")
            except tango.DevFailed as tango_err:
                tango.Except.throw_exception("Command failed",
                                             tango_err.args[0].desc,
                                             "AddReceptors",
                                             tango.ErrSeverity.ERR)
                return (ResultCode.FAILED, "Failure in AddReceptors")

            # PROTECTED REGION END #    //  MidCspSubarrayBase.AddReceptors

    def _get_cbfsubarray_assigned_receptors(self, device_proxy):
        """

@@ -81,7 +246,7 @@ class MidCspSubarrayBase(CspSubarray):
            self.logger.warning("__monitor_add_receptors:{}".format(tango_err.args[0].desc))
        return receptors

    def __monitor_add_receptors(self, receptors_to_be_added, args_dict=None):
    def _monitor_add_receptors(self, receptors_to_be_added, args_dict=None):
        cmd_name = 'addreceptors'
        device = self.CbfSubarray
        self._num_dev_completed_task[cmd_name] = 0
@@ -138,11 +303,15 @@ class MidCspSubarrayBase(CspSubarray):
            self.logger.warning(msg)
        if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT:
            self._timeout_expired = True
            self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE
            self._cmd_execution_state[cmd_name] = CmdExecState.IDLE
            return (ResultCode.FAILED, "Timeout in receptor assignment!!")
        self.logger.info("CspSubarray failure flag:{}".format(self._failure_raised))
        self.logger.info("CspSubarray timeout flag:{}".format(self._timeout_expired))
        # reset the command execution state
        self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE
        self._cmd_execution_state[cmd_name] = CmdExecState.IDLE
        return (ResultCode.OK, "All receptor assigned!!")

     # PROTECTED REGION END #    //  MidCspSubarrayBase.private_methods

@@ -290,18 +459,32 @@ class MidCspSubarrayBase(CspSubarray):
        self._sc_subarray_assigned_fqdn.append(self.CbfSubarray)
        self.logger.debug("Validate scan: {}".format(self._sc_subarray_assigned_fqdn))


    @command(
        dtype_in='DevString',
        doc_in="A Json-encoded string with the scan configuration.",
    )
    @DebugIt()
    @ObsStateCheck('configscan')
    @SubarrayRejectCmd('AddReceptors',
                       'RemoveReceptors',
                       'RemoveAllReceptors')
    def Configure(self, argin):
        CspSubarray.Configure(self, argin)

    def _init_state_model(self):
        """
        Sets up the state model for the device
        """
        self.state_model = MidCspSubarrayStateModel(
            dev_state_callback=self._update_state,
        )

    def init_command_objects(self):
        """
        Sets up the command objects
        """
        super().init_command_objects()
        self.logger.info("MID call to init_commands")
        args = (self, self.state_model, self.logger)
        self.register_command_object("AddReceptors", self.AddReceptorsCommand(*args))

    
    # PROTECTED REGION END #    //  MidCspSubarrayBase.private_methods
    # ----------------
@@ -398,17 +581,6 @@ class MidCspSubarrayBase(CspSubarray):
    # General methods
    # ---------------

    def init_device(self):
        """Initialises the attributes and properties of the MidCspSubarrayBase."""
        CspSubarray.init_device(self)
        # PROTECTED REGION ID(MidCspSubarrayBase.init_device) ENABLED START #
        self._assigned_vcc = []
        self._assigned_fsp = []
        self._receptor_to_vcc_map = {}
        self._receptor_id_list = []

        # PROTECTED REGION END #    //  MidCspSubarrayBase.init_device

    def always_executed_hook(self):
        """Method always executed before any TANGO command is executed."""
        # PROTECTED REGION ID(MidCspSubarrayBase.always_executed_hook) ENABLED START #
@@ -497,17 +669,12 @@ class MidCspSubarrayBase(CspSubarray):
    # --------
    # Commands
    # --------
    @AdminModeCheck('AddReceptors')
    def is_AddReceptors_allowed(self):
        return self._is_subarray_composition_allowed()

    @command(
        dtype_in='DevVarUShortArray',
        doc_in="List of the receptor IDs to add to the subarray.",
        dtype_out='DevVarLongStringArray',
    )
    @DebugIt()
    @ObsStateCheck('addresources')
    @SubarrayRejectCmd(['RemoveReceptors', 'Configure'])
    def AddReceptors(self, argin):
        # PROTECTED REGION ID(MidCspSubarrayBase.AddReceptors) ENABLED START #
        """
@@ -525,107 +692,9 @@ class MidCspSubarrayBase(CspSubarray):
            tango.DevFailed: if the CbfSubarray is not available or if an exception\
            is caught during command execution.
        """
        # PROTECTED REGION ID(CspSubarray.AddReceptors) ENABLED START #
        # Each vcc_id map to a vcc_fqdn inside CbfMaster, for example:
        # vcc_id = 1 -> mid_csp_cbf/vcc/vcc_001
        # vcc_id = 2 -> mid_csp_cbf/vcc/vcc_002
        # .....
        # vcc_id = 17 -> mid_csp_cbf/vcc/vcc_017
        # vcc_id and receptor_id is not the same. The map between vcc_id and receptor_id
        # is built by CbfMaster and exported as attribute.
        # The max number of VCC allocated is defined by the VCC property of the CBF Master.

        # the list of available receptor IDs. This number is mantained by the CspMaster
        # and reported on request.
        available_receptors = []
        # the list of receptor to assign to the subarray
        receptor_to_assign = []
        try:
            # access to CspMaster to get information about the list of available receptors
            # and the receptors affiliation to subarrays.
            csp_master_proxy = tango.DeviceProxy(self.CspMaster)
            csp_master_proxy.ping()
            available_receptors = csp_master_proxy.unassignedReceptorIDs
            if not self._receptor_to_vcc_map:
                cbf_master_addr = csp_master_proxy.cbfMasterAddress
                cbf_master_proxy = tango.DeviceProxy(cbf_master_addr)
                cbf_master_proxy.ping()
                # build the list of receptor ids
                receptor_to_vcc = cbf_master_proxy.receptorToVcc
                self._receptor_to_vcc_map = dict([int(ID) for ID in pair.split(":")]
                                                 for pair in receptor_to_vcc)
                # build the list of the installed receptors
                self._receptor_id_list = list(self._receptor_to_vcc_map.keys())
            if not any(available_receptors):
                log_msg = "No available receptor to add to subarray {}".format(
                    self.SubID)
                self.logger.warning(log_msg)
                return
            receptor_membership = csp_master_proxy.receptorMembership
        except tango.DevFailed as df:
            msg = "Failure in getting receptors information:" + \
                str(df.args[0].reason)
            tango.Except.throw_exception("Command failed", msg,
                                         "AddReceptors", tango.ErrSeverity.ERR)
        except AttributeError as attr_err:
            msg = "Failure in reading {}: {}".format(
                str(attr_err.args[0]), attr_err.__doc__)
            tango.Except.throw_exception("Command failed", msg,
                                         "AddReceptors", tango.ErrSeverity.ERR)
        for receptorId in argin:
            # check if the specified receptor id is a valid number (that is, belongs to the list
            # of provided receptors)
            if receptorId in self._receptor_id_list:
                # check if the receptor id is one of the available receptor Ids
                if receptorId in available_receptors:
                    receptor_to_assign.append(receptorId)
                else:
                    # retrieve the subarray owner
                    sub_id = receptor_membership[receptorId - 1]
                    log_msg = "Receptor {} already assigned to subarray {}".format(str(receptorId),
                                                                                   str(sub_id))
                    self.logger.info(log_msg)
            else:
                log_msg = "Invalid receptor id: {}".format(str(receptorId))
                self.logger.warning(log_msg)

        # check if the list of receptors to assign is empty
        if not receptor_to_assign:
            log_msg = "No receptors to assign to the subarray"
            self.logger.info(log_msg)
            return

        # check if the CbfSubarray TANGO device is already running
        # and the proxy registered
        if not self._is_sc_subarray_running(self.CbfSubarray):
            log_msg = "Device {} is not running!".format(str(self.CbfSubarray))
            self.logger.error(log_msg)
            tango.Except.throw_exception("Command failed",
                                         log_msg,
                                         "AddReceptors",
                                         tango.ErrSeverity.ERR)
        proxy = self._sc_subarray_proxies[self.CbfSubarray]
        # remove possible receptor repetition
        tmp = set(receptor_to_assign)
        receptor_to_assign = list(tmp)
        # forward the command to the CbfSubarray
        try: 
            proxy.command_inout_asynch("AddReceptors", receptor_to_assign, self._cmd_ended_cb)
            
            self._command_thread['addreceptors'] = threading.Thread(target=self.__monitor_add_receptors,
                                                                    name="Thread-AddReceptors",
                                                                    args=(receptor_to_assign,))
            self._sc_subarray_cmd_starting_time[self.CbfSubarray] = time.time()
            if self._cmd_execution_state['addreceptors'] != CmdExecState.FAILED:
                self._cmd_execution_state['addreceptors'] = CmdExecState.RUNNING
            self._command_thread['addreceptors'].start()
        except tango.DevFailed as tango_err:
            tango.Except.throw_exception("Command failed",
                                         tango_err.args[0].desc,
                                         "AddReceptors",
                                         tango.ErrSeverity.ERR)

        # PROTECTED REGION END #    //  MidCspSubarrayBase.AddReceptors
        handler = self.get_command_object("AddReceptors")
        (result_code, message) = handler(argin)
        return [[result_code], [message]]

    @AdminModeCheck('RemoveReceptors')
    def is_RemoveReceptors_allowed(self):