Skip to content
Snippets Groups Projects

Resolve CT-215

Merged Gianluca Marotta requested to merge CT-215 into master
2 files
+ 202
117
Compare changes
  • Side-by-side
  • Inline
Files
2
@@ -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,38 +374,31 @@ 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 (ResultCode.STARTED, "CSP Subarray Init STARTED")
return (result_code, message)
def obs_state_alignment(self):
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}')
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
allowed_coupled = {'RESOURCING': 'IDLE',
def initialize_thread(self):
try:
with EnsureOmniThread():
self.logger.info("Init thread started")
device = self.target
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_state of cbf_subarray
#cbf_obs_state = device._sc_subarray_obs_state[self.CbfSubarray].name
# allowed coupled states for different sub-elements
allowed_coupled = {'RESOURCING': 'IDLE',
'RESOURCING': 'EMPTY',
'CONFIGURING': 'READY',
'SCANNING': 'READY',
@@ -347,44 +406,72 @@ class CspSubarray(SKASubarray):
'RESETTING': 'IDLE',
'RESTARTING': 'EMPTY'
}
transitional_states = allowed_coupled.keys()
timeout = 10 # seconds
# CASE B: CBF is ON
if device._sc_subarray_state[self.CbfSubarray] == DevState.ON:
# start a loop in case of transitional states (CASE 2)
starting_time = time.time()
exit_loop = False
while time.time() - starting_time < timeout or exit_loop:
# first creates an intersection list
transitional_present = set(transitional_states) & set(obs_states_list)
# CASE 1: Transitional states NOT present
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])
exit_loop = True
# CASE 1.1: obsStates are DIFFERENT
else:
self.state_model._update_obs_state('FAULT')
exit_loop = True
# CASE 2: Transitional states ARE present
else:
state = transitional_present[0]
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')
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
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:
# first creates an intersection list
transitional_present = set(transitional_states) & set(obs_states_list)
# CASE 1: Transitional states NOT present
if not transitional_present:
# CASE 1.1: All obsStates are EQUAL
if len(set(obs_states_list)) == 1:
self.set_csp_obs_state(obs_states_list[0])
exit_loop = True
break
# CASE 2.2: Other obs_states are ALLOWED
# CASE 1.1: obsStates are DIFFERENT
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('FAULT')
exit_loop = True
# CASE 2: Transitional states ARE present
else:
state = transitional_present[0]
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.set_csp_obs_state('FAULT')
exit_loop = True
break
# CASE 2.2: Other obs_states are ALLOWED
else:
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:
@@ -1644,7 +1732,7 @@ class CspSubarray(SKASubarray):
# Class protected methods
# ---------------
def update_subarray_state(self):
"""
Class protected method.
@@ -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))
Loading