Commit 7d1e6c5c authored by Elisabetta Giani's avatar Elisabetta Giani
Browse files

CT-57: CspSubarray version passes the uni tests.

parent a85f2ee7
Loading
Loading
Loading
Loading
Loading
+179 −166
Original line number Diff line number Diff line
@@ -37,17 +37,18 @@ from tango import AttrWriteType, DeviceProxy
# PROTECTED REGION ID(CspSubarray.additionnal_import) ENABLED START #
from ska.base import SKASubarray, SKASubarrayStateModel
#from ska.base import utils
from ska.base.commands import ActionCommand, ResultCode
from ska.base.commands import ResponseCommand, ResultCode
from ska.base.faults import CapabilityValidationError
from ska.base.control_model import HealthState, AdminMode, ObsState, ObsMode
from .utils.decorators import AdminModeCheck, ObsStateCheck, SubarrayRejectCmd
from .utils.cspcommons import CmdExecState
from .utils.utils import tango_raise
from . import release
# PROTECTED REGION END #    //  CspSubarray.additionnal_import

__all__ = ["CspSubarray", "main"]


'''
class CspSubarrayStateModel(SKASubarrayStateModel):
    _subarray_transitions = {
            ('READY', 'goto_idle_succeeded'): (
@@ -74,7 +75,7 @@ class CspSubarrayStateModel(SKASubarrayStateModel):
        )
        self.logger.info("Update CspSubarrayStateModel")
        self.update_transitions(self._subarray_transitions)

'''
class CspSubarray(SKASubarray):
    """
    CSP subarray functionality is modeled via a TANGCSP.LMC Common Class for the CSPSubarray TANGO Device.
@@ -331,7 +332,9 @@ class CspSubarray(SKASubarray):

    class OnCommand(SKASubarray.OnCommand):
        def do(self):
            super().do()
            device = self.target
            self.logger.info("Call to OnCommand")
            for fqdn in device._sc_subarray_fqdn:
                try:
                    (result_code, message) = device._sc_subarray_proxies[fqdn].On()
@@ -355,6 +358,22 @@ class CspSubarray(SKASubarray):
    class AbortCommand(SKASubarray.AbortCommand):

        def do(self):
            device = self.target
            device_list = device._sc_subarray_assigned_fqdn
            if not any(device._sc_subarray_assigned_fqdn):
                # beed to add a check also on PSTBeams belonging to subarray
                device_list = device._sc_subarray_fqdn
            for fqdn in device_list:
                try:
                    proxy = device._sc_subarray_proxies[fqdn]
                    proxy.command_inout_asynch("Abort", self._cmd_ended_cb)
                except KeyError as key_err:
                    self.logger.warning("No key {} found".format(key_err))
                    device._sc_subarray_cmd_exec_state[fqdn]['abort'] = CmdExecState.FAILED
                except tango.DevFailed as tango_err:
                    device._sc_subarray_cmd_exec_state[fqdn]['abort'] = CmdExecState.FAILED
                    self.logger.warning(tango_err.args[0].desc)
            device._abort_command_event.set()
            message = "Abort command completed OK"
            self.logger.info(message)
            return (ResultCode.OK, message)
@@ -362,9 +381,124 @@ class CspSubarray(SKASubarray):
    class ConfigureCommand(SKASubarray.ConfigureCommand):

        def do(self):
            message = "Abort command completed OK"
            # checks on State, adminMode and obsState values are performed inside the 
            # python decorators
           
            # the dictionary with the scan configuration

            target_device = self.target
            try:
                # if the stored configuration attribute is not empty, check
                # for the received configuration content
                if target_device._valid_scan_configuration:
                    try:
                        stored_configuration = json.dumps(self._valid_scan_configuration, sort_keys=True)
                        received_configuration = json.dumps(argin, sort_keys=True)
                        # if the received configuration is equal to the last valid configuration and the
                        # state of the subarray is READY than subarray is not re-configured.
                        if (stored_configuration == received_configuration) and (target_device._obs_state == ObsState.READY):
                            self.logger.info("Subarray is going to use the same configuration")
                            return
                    except Exception as e:
                        self.logger.warning(str(e))
                # go ahead and parse the received configuration
                self.validate_scan_configuration(argin)
            except tango.DevFailed as tango_err:
                # validation failure
                msg = "Failure during validation of configuration:{}".format(tango_err.args[0].desc)
                self.logger.error(msg)
                tango.Except.throw_exception("Command failed",
                                             msg,
                                             "Configure",
                                             tango.ErrSeverity.ERR)
            # Forward the Configure command to the sub-elements
            # components (subarrays, pst beams)
            for device in self._sc_subarray_assigned_fqdn:
                # reset the command progress counter for each
                # sub-array component
                target_device._sc_subarray_cmd_progress[device]['configurescan'] = 0
                target_device._failure_message['configurescan'] = ''
                # NOTE: what happens if a sub-element subarray/PSt beam TANGO
                # device is not running? The next calls to proxy should fail
                # with a tango.DevFailed exception.
                if not self._is_sc_subarray_running(device):
                    msg = "Device {} not running".format(device)
                    if device == target_device.CbfSubarray:
                        # throw the exception, configuration can't proceed
                        tango.Except.throw_exception("Command failed",
                                                     msg,
                                                     "Configure",
                                                     tango.ErrSeverity.ERR)
                    target_device._failure_message['configurescan'] += msg
                    target_device._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.FAILED
                    #skip to next device
                    continue
                proxy = target_device._sc_subarray_proxies[device]
                # subscribe sub-elements attributes to track command execution and
                # timeout on subarray sub-components
                attributes = ['configureScanCmdProgress', 'timeoutExpiredFlag']
                for attr in attributes:
                    try:
                        if target_device._sc_subarray_event_id[attr.lower()] == 0:
                            event_id = proxy.subscribe_event(attr,
                                                             tango.EventType.CHANGE_EVENT,
                                                             self._attributes_change_evt_cb,
                                                             stateless=False)
                            target_device._sc_subarray_event_id[device][attr] = event_id
                    except tango.DevFailed as df:
                        self.logger.info(df.args[0].desc)              
                # NOTE: CBF/PSS sub-array checks for the validity of its
                # configuration. Failure in configuration throws an exception that is
                # caught via the _cmd_ended_cb callback

                try:
                    # read the timeout configured for the operation on the device
                    target_device._sc_subarray_duration_expected[device]['configurescan'] = proxy.configureDelayExpected
                except AttributeError as attr_err:
                    self.logger.info("No attribute {} on device {}".format(str(attr_err), device))
                try:
                    proxy.command_inout_asynch("ConfigureScan",
                                               target_device._sc_subarray_scan_configuration[device],
                                               self._cmd_ended_cb)
                    self.logger.info("Exec state command flag is {}".format(target_device._sc_subarray_cmd_exec_state[device]['configurescan']))
                    # Note: check if callaback executed...
                    if target_device._sc_subarray_cmd_exec_state[device]['configurescan'] != CmdExecState.FAILED:
                        target_device._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.RUNNING
                except tango.DevFailed as tango_err:
                    if device == target_device.CbfSubarray:
                        msg = "Failure in configuring CBF: {}".format(tango_err.args[0].desc)
                        # throw the exception, configuration can't proceed
                        tango.Except.throw_exception("Command failed",
                                                     msg,
                                                     "Configure",
                                                     tango.ErrSeverity.ERR)

                    target_device._failure_message['configurescan'] += tango_err.args[0].desc
                    target_device._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.FAILED

                # register the starting time for the command
                target_device._sc_subarray_cmd_starting_time[device] = time.time()
                self.logger.debug("configure starting time: {}".format(target_device._sc_subarray_cmd_starting_time[device]))
            # end for loop on devices

            # TODO: evaluate the global timeout as the max of the single sub-element
            # timeouts
            # configure the timeout for the operation
            if self._config_delay_expected > 0:
                target_device._cmd_duration_expected['configurescan'] = self._config_delay_expected
            self.logger.debug("_config_delay_expected :{}".format(self._config_delay_expected))
            # invoke the constructor for the command thread
            thread_args = [target_device._sc_subarray_assigned_fqdn, argin]
            self._command_thread['configurescan'] = threading.Thread(target=self.__configure_scan,
                                                               name="Thread-Configure",
                                                               args=(thread_args,))
            self._abort_command_event.clear()
            self._cmd_execution_state['configurescan'] = CmdExecState.RUNNING
            self._cmd_duration_measured['configurescan'] = 0
            self._command_thread['configurescan'].start()
            message = "Configure command started"
            self.logger.info(message)
            return (ResultCode.OK, message)
            return (ResultCode.STARTED, message)
    
    class ScanCommand(SKASubarray.ScanCommand):

@@ -380,30 +514,10 @@ class CspSubarray(SKASubarray):
            self.logger.info(message)
            return (ResultCode.OK, message)
    '''
    class GoToIdleCommand(ActionCommand):
    class GoToIdleCommand(ResponseCommand):
        """
        A class for the CSPSubarray's GoToIdle() command.
        """
        def __init__(self, target, state_model, logger=None):
            """
            Constructor for GoToIdle

            :param target: the object that this command acts upon; for
                example, the SKASubarray device for which this class
                implements the command
            :type target: object
            :param state_model: the state model that this command uses
                 to check that it is allowed to run, and that it drives
                 with actions.
            :type state_model: SKABaseClassStateModel or a subclass of
                same
            :param logger: the logger to be used by this Command. If not
                provided, then a default module logger will be used.
            :type logger: a logger that implements the standard library
                logger interface
            """
            super().__init__(target, state_model, "goto_idle", start_action = True, logger=logger)

        def do(self):
            """
            Stateless hook for GoToIdle() command functionality.
@@ -457,6 +571,29 @@ class CspSubarray(SKASubarray):
            self.logger.info(message)
            return (ResultCode.STARTED, message)

        def check_allowed(self):
            """
            Whether this command is allowed to be run in current device
            state

            :return: True if this command is allowed to be run in
                current device state
            :rtype: boolean
            :raises: DevFailed if this command is not allowed to be run
                in current device state
            """
            if not self.state_model.dev_state in [
                DevState.FAULT, DevState.UNKNOWN, DevState.DISABLE,
            ]:
                tango_raise(
                    "GoToIdle() is not allowed in current state"
                )
            if not self.state_model.admin_mode in [AdminMode.READY]:
                tango_raise(
                    "GoToIdle() is not allowed in current "
                )
            return True
    

    # PROTECTED REGION ID(CspSubarray.class_variable) ENABLED START #
    # PROTECTED REGION END #    //  CspSubarray.class_variable
@@ -1188,25 +1325,24 @@ class CspSubarray(SKASubarray):
        self._last_executed_command = cmd_name
        # reset the CSP Subarray command execution flag
        self._cmd_execution_state[cmd_name] = CmdExecState.IDLE

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

    def _init_command_objects(self):
    def init_command_objects(self):
        """
        Sets up the command objects
        """
        super()._init_command_objects()

        device_args = (self, self.state_model, self.logger)
        resource_args = (self.resource_manager, self.state_model, self.logger)
        super().init_command_objects()

        self._goto_idle_command = self.GoToIdleCommand(*device_args)
        args = (self, self.state_model, self.logger)
        self.register_command_object("GoToIdle", self.GoToIdleCommand(*args))


    # ----------------
@@ -2249,119 +2385,6 @@ class CspSubarray(SKASubarray):
        """
        # PROTECTED REGION ID(CspSubarray.Configure) ENABLED START #

        # checks on State, adminMode and obsState values are performed inside the 
        # python decorators
       
        # the dictionary with the scan configuration
        try:
            # if the stored configuration attribute is not empty, check
            # for the received configuration content
            if self._valid_scan_configuration:
                try:
                    stored_configuration = json.dumps(self._valid_scan_configuration, sort_keys=True)
                    received_configuration = json.dumps(argin, sort_keys=True)
                    # if the received configuration is equal to the last valid configuration and the
                    # state of the subarray is READY than subarray is not re-configured.
                    if (stored_configuration == received_configuration) and (self._obs_state == ObsState.READY):
                        self.logger.info("Subarray is going to use the same configuration")
                        return
                except Exception as e:
                    self.logger.warning(str(e))
            # go ahead and parse the received configuration
            self.validate_scan_configuration(argin)
        except tango.DevFailed as tango_err:
            # validation failure
            msg = "Failure during validation of configuration:{}".format(tango_err.args[0].desc)
            self.logger.error(msg)
            tango.Except.throw_exception("Command failed",
                                         msg,
                                         "Configure",
                                         tango.ErrSeverity.ERR)
        # Forward the Configure command to the sub-elements
        # components (subarrays, pst beams)
        for device in self._sc_subarray_assigned_fqdn:
            # reset the command progress counter for each
            # sub-array component
            self._sc_subarray_cmd_progress[device]['configurescan'] = 0
            self._failure_message['configurescan'] = ''
            # NOTE: what happens if a sub-element subarray/PSt beam TANGO
            # device is not running? The next calls to proxy should fail
            # with a tango.DevFailed exception.
            if not self._is_sc_subarray_running(device):
                msg = "Device {} not running".format(device)
                if device == self.CbfSubarray:
                    # throw the exception, configuration can't proceed
                    tango.Except.throw_exception("Command failed",
                                                 msg,
                                                 "Configure",
                                                 tango.ErrSeverity.ERR)
                self._failure_message['configurescan'] += msg
                self._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.FAILED
                #skip to next device
                continue
            proxy = self._sc_subarray_proxies[device]
            # subscribe sub-elements attributes to track command execution and
            # timeout on subarray sub-components
            attributes = ['configureScanCmdProgress', 'timeoutExpiredFlag']
            for attr in attributes:
                try:
                    if self._sc_subarray_event_id[attr.lower()] == 0:
                        event_id = proxy.subscribe_event(attr,
                                                         tango.EventType.CHANGE_EVENT,
                                                         self._attributes_change_evt_cb,
                                                         stateless=False)
                        self._sc_subarray_event_id[device][attr] = event_id
                except tango.DevFailed as df:
                    self.logger.info(df.args[0].desc)              
            # NOTE: CBF/PSS sub-array checks for the validity of its
            # configuration. Failure in configuration throws an exception that is
            # caught via the _cmd_ended_cb callback

            try:
                # read the timeout configured for the operation on the device
                self._sc_subarray_duration_expected[device]['configurescan'] = proxy.configureDelayExpected
            except AttributeError as attr_err:
                self.logger.info("No attribute {} on device {}".format(str(attr_err), device))
            try:
                proxy.command_inout_asynch("ConfigureScan",
                                           self._sc_subarray_scan_configuration[device],
                                           self._cmd_ended_cb)
                self.logger.info("Exec state command flag is {}".format(self._sc_subarray_cmd_exec_state[device]['configurescan']))
                # Note: check if callaback executed...
                if self._sc_subarray_cmd_exec_state[device]['configurescan'] != CmdExecState.FAILED:
                    self._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.RUNNING
            except tango.DevFailed as tango_err:
                if device == self.CbfSubarray:
                    msg = "Failure in configuring CBF: {}".format(tango_err.args[0].desc)
                    # throw the exception, configuration can't proceed
                    tango.Except.throw_exception("Command failed",
                                                 msg,
                                                 "Configure",
                                                 tango.ErrSeverity.ERR)

                self._failure_message['configurescan'] += tango_err.args[0].desc
                self._sc_subarray_cmd_exec_state[device]['configurescan'] = CmdExecState.FAILED

            # register the starting time for the command
            self._sc_subarray_cmd_starting_time[device] = time.time()
            self.logger.debug("configure starting time: {}".format(self._sc_subarray_cmd_starting_time[device]))
        # end for loop on devices

        # TODO: evaluate the global timeout as the max of the single sub-element
        # timeouts
        # configure the timeout for the operation
        if self._config_delay_expected > 0:
            self._cmd_duration_expected['configurescan'] = self._config_delay_expected
        self.logger.debug("_config_delay_expected :{}".format(self._config_delay_expected))
        # invoke the constructor for the command thread
        thread_args = [self._sc_subarray_assigned_fqdn, argin]
        self._command_thread['configurescan'] = threading.Thread(target=self.__configure_scan,
                                                           name="Thread-Configure",
                                                           args=(thread_args,))
        self._abort_command_event.clear()
        self._cmd_execution_state['configurescan'] = CmdExecState.RUNNING
        self._cmd_duration_measured['configurescan'] = 0
        self._command_thread['configurescan'].start()
        # PROTECTED REGION END #    //  CspSubarray.Configure
    
    @AdminModeCheck('AddNumOfSearchBeams')
@@ -2566,7 +2589,8 @@ class CspSubarray(SKASubarray):
        # PROTECTED REGION END #    //  CspSubarray.EndScan
        
    def is_GoToIdle_allowed(self):
        return self._goto_idle_command.check_allowed()
        handler = self.get_command_object("GoToIdle")
        return handler.check_allowed()
    
    @command(
        dtype_out='DevVarLongStringArray',
@@ -2580,8 +2604,9 @@ class CspSubarray(SKASubarray):

        :return: None
        """
        (return_code, message) = self._goto_idle_command()
        return [[return_code], [message]]
        handler = self.get_command_object("GoToIdle")
        (result_code, message) = handler(argin)
        return [[result_code], [message]] 
        # PROTECTED REGION END #    //  CspSubarray.GoToIdle
        
    @command(
@@ -2596,22 +2621,10 @@ class CspSubarray(SKASubarray):

        :return:'DevVarLongStringArray'
        """
        device_list = self._sc_subarray_assigned_fqdn
        if not any(self._sc_subarray_assigned_fqdn):
            # beed to add a check also on PSTBeams belonging to subarray
            device_list = self._sc_subarray_fqdn
        for fqdn in device_list:
            try:
                proxy = self._sc_subarray_proxies[fqdn]
                proxy.command_inout_asynch("Abort", self._cmd_ended_cb)
            except KeyError as key_err:
                self.logger.warning("No key {} found".format(key_err))
                self._sc_subarray_cmd_exec_state[fqdn]['abort'] = CmdExecState.FAILED
            except tango.DevFailed as tango_err:
                self._sc_subarray_cmd_exec_state[fqdn]['abort'] = CmdExecState.FAILED
                self.logger.warning(tango_err.args[0].desc)
        self._abort_command_event.set()
        return [[0], [""]]
        handler = self.get_command_object("GoToIdle")
        (result_code, message) = handler(argin)
        return [[result_code], [message]] 

        # PROTECTED REGION END #    //  CspSubarray.Abort
    
# ----------