Commit 37c5e218 authored by Gianluca Marotta's avatar Gianluca Marotta
Browse files

CT-215 Further implementation of Init command. In progress

parent 221d47da
Loading
Loading
Loading
Loading
Loading
+188 −117
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import json

# tango imports
import tango
from tango import DebugIt
from tango import DebugIt, EnsureOmniThread
from tango.server import run
from tango.server import Device
from tango.server import attribute, command
@@ -44,6 +44,7 @@ from .utils.cspcommons import CmdExecState
from .utils.decorators import transaction_id
from . import release
from .csp_manage_json import JsonConfiguration
from .csp_subarray_state_model import CspSubarrayStateModel
# PROTECTED REGION END #    //  CspSubarray.additionnal_import

__all__ = ["CspSubarray", "main"]
@@ -115,6 +116,69 @@ class CspSubarray(SKASubarray):
    
    """

    class ForceObsStateTransitionCommand(ActionCommand):

        def __init__(self, target, state_model, logger=None):
            """
            Constructor for ForceObsStateTransition.
            It's not a TANGO command. 
            This command in invoked at CSP.LMC Subarray re-initialization.

            :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: :py:class:`SKASubarrayStateModel`
            :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, "force", start_action=False, logger=logger
            )
            self.action = None

        def __call__(self, argin=None):
            """
            Override the __call__ method to set the action to execute when the succeeded method
            is called.
            """
            self.action = argin
            super().__call__(argin)

        def check_allowed(self):
            """
            check_allowed is invoked before the do() in the command __call__ method.
            The basic behavior is to check for a transition named 'force_succeeded'.
            At re-initialization there are several 'succeeded' transitions, depending on 
            the expected observing state of the CSP Subarray, so it's necessary to modify 
            the succeeded method name with the one stored in the action attribute.
            """
            self.logger.info("check for transition trigger {}".format(self.action))
            self._succeeded_hook = self.action
            return super().check_allowed()

        def do(self, argin):
            self.action = argin
            return (ResultCode.OK, f"Executed {argin}")

        def succeeded(self):
            """
            Action to take on successful completion of device server
            re-initialization.
            """
            self.logger.info("Execute succeeded with arg {}".format(self.action))
            if not self.action:
                self.logger.info("Action not specified!!")
            self.state_model.perform_action(self.action)

        def failed(self):
            self.state_model.perform_action("fatal_error")

    class InitCommand(SKASubarray.InitCommand):
        """
        A class for the SKASubarray's init_device() "command".
@@ -131,6 +195,8 @@ class CspSubarray(SKASubarray):
            (result_code, message) = super().do()

            device = self.target
            self.logger.info("CspSubarray INIT COMMAND STARTED!!")
            self.logger.info("CspSubarray obs_state: {}".format(device._obs_state))
            device._build_state = '{}, {}, {}'.format(release.name, release.version, release.description)
            device._version_id = release.version
            # connect to CSP.LMC TANGO DB
@@ -308,34 +374,27 @@ class CspSubarray(SKASubarray):
            #device._reserved_search_beam_num =  0
            device._assigned_timing_beams= []
            device._assigned_vlbi_beams = []      
                                                               
            # Try connection with the CBF sub-array
            device.connect_to_subarray_subcomponent(device.CbfSubarray)
            # Try connection with the PSS sub-array
            device.connect_to_subarray_subcomponent(device.PssSubarray)
                    
            device.init_thread = threading.Thread(target=self.initialize_thread,name="Thread-Initialization ObsState Alignment",
                                                    args=())
            device.init_thread.start()
            # to use the push model in command_inout_asynch (the one with the callback parameter),
            # change the global TANGO model to PUSH_CALLBACK.
            apiutil = tango.ApiUtil.instance()
            apiutil.set_asynch_cb_sub_model(tango.cb_sub_model.PUSH_CALLBACK)
            self.logger.info(message)

            alignment_thr = threading.Thread(target=self.obs_state_alignment,
                                                    name="Thread-Initialization ObsState Alignment",
                                                    args=())
            alignment_thr.start()

            return (result_code, message)

        def obs_state_alignment(self):
            return (ResultCode.STARTED, "CSP Subarray Init STARTED")

        def initialize_thread(self):
            try:
                with EnsureOmniThread():
                    self.logger.info("Init thread started")
                    device = self.target
            # create a list with all the obs_states of sub-elements
            # !!! delete the logger !!!
            self.logger.info(f'obs state of CBF: {device._sc_subarray_obs_state[self.CbfSubarray].name}')
                    args = (device, device.state_model, self.logger)
                    self.force_cmd_obj = device.ForceObsStateTransitionCommand(*args)
                    device.on_cmd_obj = device.OnCommand(*args)

                    #list of obs_states of sub-elements
                    obs_states_list = [str(device._sc_subarray_obs_state[fqdn]) for fqdn in device._sc_subarray_fqdn]

            obs_states_list = [device._sc_subarray_obs_state[fqdn].name for fqdn in
                               device._sc_subarray_fqdn]
                    # obs_state of cbf_subarray
                    #cbf_obs_state = device._sc_subarray_obs_state[self.CbfSubarray].name
                    # allowed coupled states for different sub-elements
@@ -350,9 +409,24 @@ class CspSubarray(SKASubarray):
                    transitional_states = allowed_coupled.keys()
                    timeout = 10 # seconds

                    
                    # Try connection with the CBF sub-array
                    device.connect_to_subarray_subcomponent(device.CbfSubarray)
                    # Try connection with the PSS sub-array
                    device.connect_to_subarray_subcomponent(device.PssSubarray)
                    # to put the device in OFF/EMPTY
                    self.succeeded()
                    if device._sc_subarray_state[device.CbfSubarray] is not DevState.ON:
                        self.logger.info('devo leggerlo se sono alla prima inizializzazione')
                        return
                    # to put the device in ON/EMPTY
                    self.logger.info('Non devo leggerlo se sono alla prima inizializzazione')  
                    device.on_cmd_obj.succeeded()

                    # CASE B: CBF is ON
            if device._sc_subarray_state[self.CbfSubarray] == DevState.ON:
                    self.logger.info('CSP is already ON. Aligning to Sub-elements...')
                    # start a loop in case of transitional states (CASE 2)
                    timeout = 10
                    starting_time = time.time()
                    exit_loop = False
                    while time.time() - starting_time < timeout or exit_loop:
@@ -362,11 +436,11 @@ class CspSubarray(SKASubarray):
                        if not transitional_present:
                            # CASE 1.1: All obsStates are EQUAL
                            if len(set(obs_states_list)) == 1:
                            self.state_model._update_obs_state(obs_states_list[0])
                                self.set_csp_obs_state(obs_states_list[0])
                                exit_loop = True
                            # CASE 1.1: obsStates are DIFFERENT
                            else:
                            self.state_model._update_obs_state('FAULT')
                                self.set_csp_obs_state('FAULT')
                                exit_loop = True
                        # CASE 2: Transitional states ARE present
                        else:
@@ -374,17 +448,30 @@ class CspSubarray(SKASubarray):
                            for sub_elt_obs_state in obs_states_list:
                                # CASE 2.1: Other obs_states are NOT ALLOWED
                                if sub_elt_obs_state is not (state or allowed_coupled[state]):
                                self.state_model._update_obs_state('FAULT')
                                    self.set_csp_obs_state('FAULT')
                                    exit_loop = True
                                    break
                                # CASE 2.2: Other obs_states are ALLOWED
                                else:
                                self.state_model._update_obs_state(state)
            # CASE A: CBF is OFF
            else:
                self.state_model._update_op_state('OFF')
                self.state_model._update_obs_state('EMPTY')

                                    self.set_csp_obs_state(state)
            except Exception as msg:
                self.logger.info(f'error in thread: {msg}')
        def set_csp_obs_state(self, state):
            self.force_cmd_obj(f"force_to_{state.lower()}")

#                if device._sc_subarray_obs_state[device.CbfSubarray] == ObsState.IDLE:
#                    force_cmd_obj("force_to_idle")
#                    self.logger.info(self.state_model.obs_state)
#                    self.logger.info(self._obs_state)
#                if device._sc_subarray_obs_state[device.CbfSubarray] == ObsState.ABORTED:
#                    force_cmd_obj("force_to_aborted")
#                    self.logger.info(self.state_model.obs_state)
#                    self.logger.info(self._obs_state)
#                if device._sc_subarray_obs_state[device.CbfSubarray] == ObsState.READY:
#                    self.logger.info("force_to_ready")
#                    force_cmd_obj("force_to_ready")
#                    self.logger.info(self.state_model.obs_state)
#                    self.logger.info(self._obs_state)

    class OnCommand(SKASubarray.OnCommand):
        def do(self):
@@ -759,26 +846,26 @@ class CspSubarray(SKASubarray):
                self.logger.info("CspSubarray timeout flag:{}".format(target_device._timeout_expired))
                if target_device._abort_obs_event.is_set():
                    if target_device._timeout_expired or target_device._failure_raised:
                        return target_device._abort_cmd_obj.failed()
                        return self.failed()
                    self.logger.info("Abort configure ends with success!!")
                    if all(target_device._sc_subarray_obs_state[fqdn] == ObsState.ABORTED for fqdn in device_list):
                        return target_device._abort_cmd_obj.succeeded()
                    return target_device._abort_cmd_obj.abort_monitoring(device_list)
                        return self.succeeded()
                    return target_device.abort_cmd_obj.abort_monitoring(device_list)

                if target_device._timeout_expired or target_device._failure_raised:
                    # if failure/timeout found check if the CBF subarray is configured. In
                    # this case the CSP.LMC Subarray obsState is set to READY.
                    if target_device._sc_subarray_obs_state[target_device.CbfSubarray] == ObsState.READY:
                        return target_device._configure_cmd_obj.succeeded()
                        return self.succeeded()
                    self.logger.info("Configure ends with failure")
                    return target_device._configure_cmd_obj.failed()
                    return self.failed()
                if all(target_device._sc_subarray_obs_state[fqdn] == ObsState.READY for fqdn in device_list):
                    target_device._valid_scan_configuration = input_arg[1]
                    target_device._cmd_duration_measured[cmd_name] = time.time() - command_start_time
                    target_device._cmd_progress[cmd_name] = 100
                    target_device._last_executed_command = cmd_name
                    self.logger.info("Configure ends with success!!")
                    return target_device._configure_cmd_obj.succeeded()
                    return self.succeeded()

        def validate_scan_configuration(self, argin):
            """
@@ -913,9 +1000,9 @@ class CspSubarray(SKASubarray):
                return
            if target_device._abort_obs_event.is_set():
                if target_device._failure_raised or target_device._timeout_expired:
                    return target_device._abort_cmd_obj.failed()
                    return target_device.abort_cmd_obj.failed()
                self.logger.info("Abort of scan command ends with success!")
                return target_device._abort_cmd_obj.succeeded()
                return target_device.abort_cmd_obj.succeeded()

    class EndScanCommand(SKASubarray.EndScanCommand):

@@ -967,7 +1054,7 @@ class CspSubarray(SKASubarray):
                    if target_device._sc_subarray_obs_state[device] == ObsState.IDLE:
                        continue
                    if target_device._sc_subarray_obs_state[device] == ObsState.READY:
                        (result_code, msg) = target_device._gotoidle_cmd_obj.do()
                        (result_code, msg) = target_device.gotoidle_cmd_obj.do()
                return (result_code, msg)
            for device in devices_to_reset:
                try:
@@ -1024,13 +1111,13 @@ class CspSubarray(SKASubarray):
            # end of the while loop
            # check for timeout/failure conditions on each sub-component
            if target_device._failure_raised or target_device._timeout_expired:
                return target_device._obsreset_cmd_obj.failed()
                return self.failed()

            if all(target_device._sc_subarray_obs_state[fqdn] == dev_successful_state for fqdn in device_list):
                target_device._cmd_progress[cmd_name] = 100
                target_device._last_executed_command = cmd_name
                self.logger.info("ObsReset ends with success")
                return target_device._obsreset_cmd_obj.succeeded()
                return self.succeeded()

    class AbortCommand(SKASubarray.AbortCommand):

@@ -1105,13 +1192,13 @@ class CspSubarray(SKASubarray):
            # end of the while loop
            # check for timeout/failure conditions on each sub-component
            if target_device._failure_raised or target_device._timeout_expired:
                return target_device._abort_cmd_obj.failed()
                return self.failed()

            if all(target_device._sc_subarray_obs_state[fqdn] == ObsState.ABORTED for fqdn in device_list):
                target_device._cmd_progress[cmd_name] = 100
                target_device._last_executed_command = cmd_name
                self.logger.info("Abort ends with success")
                return target_device._abort_cmd_obj.succeeded()
                return self.succeeded()

    class RestartCommand(SKASubarray.RestartCommand):

@@ -1188,13 +1275,13 @@ class CspSubarray(SKASubarray):
            # end of the while loop
            # check for timeout/failure conditions on each sub-component
            if target_device._failure_raised or target_device._timeout_expired:
                return target_device._restart_cmd_obj.failed()
                return target_device.restart_cmd_obj.failed()

            if all(target_device._sc_subarray_obs_state[fqdn] == ObsState.EMPTY for fqdn in device_list):
                target_device._cmd_progress[cmd_name] = 100
                target_device._last_executed_command = cmd_name
                self.logger.info("Restart ends with success")
                return target_device._restart_cmd_obj.succeeded()
                return target_device.restart_cmd_obj.succeeded()

    '''
    class GoToIdleCommand(ActionCommand):
@@ -1364,14 +1451,14 @@ class CspSubarray(SKASubarray):
            self.logger.info("1")
            target_device._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE
            if target_device._failure_raised or target_device._timeout_expired:
                return target_device._gotoidle_cmd_obj.failed()
                return target_device.gotoidle_cmd_obj.failed()
                
            self.logger.info("2")
            if all(target_device._sc_subarray_obs_state[fqdn] == dev_successful_state for fqdn in device_list):
                target_device._last_executed_command = cmd_name
                # reset the CSP Subarray command execution flag
                target_device._cmd_execution_state[cmd_name] = CmdExecState.IDLE
                return target_device._gotoidle_cmd_obj.succeeded()
                return target_device.gotoidle_cmd_obj.succeeded()

        def check_allowed(self):
            """
@@ -1506,7 +1593,8 @@ class CspSubarray(SKASubarray):
                # update CSP sub-array SCM
                #07-2020: with the new base classes, transitions are handled via actions.
                #if evt.attr_value.name.lower() in ["state", "healthstate", "adminmode", "obsstate"]:
                #   self.update_subarray_state()
                if evt.attr_value.name.lower() in ["obsstate"]:
                    self.update_subarray_state()
                if evt.attr_value.name.lower() == "healthstate":
                    self._update_subarray_health_state()
            except tango.DevFailed as df:
@@ -1655,28 +1743,7 @@ class CspSubarray(SKASubarray):

        :return: None
        """
        self._update_subarray_health_state()

        if self._command_thread:
            a = [self._command_thread[cmd_name].is_alive() for cmd_name in self._command_thread.keys()]
            self.logger.info("list of running threds:{}".format(a))
            if any(self._command_thread[cmd_name].is_alive() for cmd_name in self._command_thread.keys()):
                self.logger.info("A command is already running...the obsState is not updated")
                return False
        # CSP state reflects the status of CBF. Only if CBF is present
        # CSP can work. The state of PSS and PST sub-elements only contributes
        # to determine the CSP health state.
        if self._sc_subarray_state[self.CbfSubarray] == DevState.OFF:
            if self._sc_subarray_obs_state[self.CbfSubarray] == ObsState.EMPTY:
                self._off_cmd_obj.succeeded()
        if self._sc_subarray_state[self.CbfSubarray] == DevState.ON:
            if self._sc_subarray_obs_state[self.CbfSubarray] == ObsState.EMPTY:
                self._on_cmd_obj.succeeded()
            if self._sc_subarray_obs_state[self.CbfSubarray] == ObsState.READY:
                self._configure_cmd_obj.succeeded()
        #self.set_state(self._sc_subarray_state[self.CbfSubarray])
        #self.logger.info("Csp subarray state: {} obsState: {}".format(self.get_state(), self.state_model._obs_state))
        return True
        self.logger.info("update_subarray_state")

    def _update_subarray_health_state(self):
        """
@@ -1903,30 +1970,34 @@ class CspSubarray(SKASubarray):
    # ----------------
    # Class private methods
    # ----------------
    '''    

    def _init_state_model(self):
        """
        Sets up the state model for the device
        """
        self.state_model = CspSubarrayStateModel(
            dev_state_callback=self._update_state,
            logger=self.logger,
            op_state_callback=self._update_state,
            admin_mode_callback=self._update_admin_mode,
            obs_state_callback=self._update_obs_state,
        )
    '''

    def init_command_objects(self):
        """
        Sets up the command objects
        Sets up the command objects.
        The init_command_method is called after InitCommand in the
        SKABaseDevice class. 
        This means that the command object handler has to be defined into
        the InitCommandClass.
        """
        super().init_command_objects()

        args = (self, self.state_model, self.logger)
        self._configure_cmd_obj = self.ConfigureCommand(*args)
        self._off_cmd_obj = self.OffCommand(*args)
        self._on_cmd_obj = self.OnCommand(*args)
        self._scan_cmd_obj = self.ScanCommand(*args)
        self._gotoidle_cmd_obj = self.GoToIdleCommand(*args)
        self._obsreset_cmd_obj = self.ObsResetCommand(*args)
        self._abort_cmd_obj = self.AbortCommand(*args)
        self._restart_cmd_obj = self.RestartCommand(*args)
        #self.configure_cmd_obj = self.ConfigureCommand(*args)
        self.scan_cmd_obj = self.ScanCommand(*args)
        self.gotoidle_cmd_obj = self.GoToIdleCommand(*args)
        self.abort_cmd_obj = self.AbortCommand(*args)
        self.restart_cmd_obj = self.RestartCommand(*args)
        self._assignresources_cmd_obj = self.AssignResourcesCommand(*args)
        self._releaseresources_cmd_obj = self.ReleaseResourcesCommand(*args)
        self.register_command_object("AssignResources", self.AssignResourcesCommand(*args))
+14 −0
Original line number Diff line number Diff line
@@ -450,6 +450,20 @@ class MidCspSubarrayBase(CspSubarray):
        self.logger.debug("len assigned_receptors:{}".format(assigned_receptors))
        return len(assigned_receptors)

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

        args = (self, self.state_model, self.logger)

        self._assignresources_cmd_obj = self.AssignResourcesCommand(*args)
        self._releaseresources_cmd_obj = self.ReleaseResourcesCommand(*args)
        self.register_command_object("AssignResources", self.AssignResourcesCommand(*args))
        self.register_command_object("ReleaseResources", self.ReleaseResourcesCommand(*args))
        self.register_command_object("ReleaseAllResources", self.ReleaseAllResourcesCommand(*args))
   
    def update_subarray_state(self):
        """
        Class protected method.