diff --git a/.gitignore b/.gitignore index 87548b3ad86ee868d9327c95f35fbdc2839f08c7..4009e563f2b2a7416f5525a8c7446c12aca73aa3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.sav +*.swp *.py[cod] *.egg-info *.eggs diff --git a/csp-lmc-common/Pipfile b/csp-lmc-common/Pipfile new file mode 100644 index 0000000000000000000000000000000000000000..358cd266445ede675d8f390885f68467214b6eb7 --- /dev/null +++ b/csp-lmc-common/Pipfile @@ -0,0 +1,35 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +# numpy and pytango versions must match those in the ska-python-builder image, +# otherwise pytango will be recompiled. +numpy = "==1.17.2" +pytango = "==9.3.1" +# itango is added to make it easier to exercise the device in a CLI session, +# but it's not mandatory. If you remove itango, you should also remove the +# 'RUN ipython profile create' line from Dockerfile. +itango = "*" +# If you want to debug devices running in containers, add pydevd to the dependencies +# pydevd = "*" + +[dev-packages] +docutils = "*" +MarkupSafe = "*" +Pygments = "*" +pylint = "*" +pytest = "*" +pytest-cov = "*" +pytest-pylint = "*" +pytest-json-report = "*" +python-dotenv = ">=0.5.1" +ptvsd = "*" +Sphinx = "*" +sphinx_rtd_theme = "*" +sphinx-autobuild = "*" +sphinxcontrib-websupport = "*" + +[requires] +python_version = "3" diff --git a/csp-lmc-common/csp-lmc-common/CspMaster.py b/csp-lmc-common/csp-lmc-common/CspMaster.py deleted file mode 100644 index 38130dbe3b81984af3c5e54560f66ca34b594756..0000000000000000000000000000000000000000 --- a/csp-lmc-common/csp-lmc-common/CspMaster.py +++ /dev/null @@ -1,1021 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of the CspMaster project -# -# INAF - SKA Telescope -# -# Distributed under the terms of the GPL license. -# See LICENSE.txt for more info. - -""" CSP.LMC Common CspMaster - -CSP.LMC Common Class for the CSPMaster TANGO Device. -""" - -# tango imports -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, DispLevel, DevState -from tango import AttrWriteType, PipeWriteType -from skabase.SKAMaster import SKAMaster -# Additional import -# PROTECTED REGION ID(CspMaster.additionnal_import) ENABLED START # -# PROTECTED REGION END # // CspMaster.additionnal_import - -__all__ = ["CspMaster", "main"] - - -class CspMaster(SKAMaster): - """ - CSP.LMC Common Class for the CSPMaster TANGO Device. - - **Properties:** - - - Device Property - - CspCbf - - FQDN of the CBF Sub-element Master - - Type:'DevString' - - CspPss - - TANGO FQDN of the PSS Sub-element Master - - Type:'DevString' - - CspPst - - TANGO FQDN of the PST Sub-element Master - - Type:'DevString' - - CspSubarrays - - TANGO FQDN of the CSP.LMC Subarrays - - Type:'DevVarStringArray' - - SearchBeams - - TANGO FQDN of the CSP.LMC SearchBeam Capabilities - - Type:'DevVarStringArray' - - TimingBeams - - TANGO FQDN of the CSP.LMC TimingBeam Capabilities - - Type:'DevVarStringArray' - - VlbiBeams - - TANGO FQDN of the CSP.LMC Vlbi Capabilities - - Type:'DevVarStringArray' - - """ - __metaclass__ = DeviceMeta - # PROTECTED REGION ID(CspMaster.class_variable) ENABLED START # - # PROTECTED REGION END # // CspMaster.class_variable - - # ----------------- - # Device Properties - # ----------------- - - CspCbf = device_property( - dtype='DevString', - ) - - CspPss = device_property( - dtype='DevString', - ) - - CspPst = device_property( - dtype='DevString', - ) - - CspSubarrays = device_property( - dtype='DevVarStringArray', - ) - - SearchBeams = device_property( - dtype='DevVarStringArray', - ) - - TimingBeams = device_property( - dtype='DevVarStringArray', - ) - - VlbiBeams = device_property( - dtype='DevVarStringArray', - ) - - # ---------- - # Attributes - # ---------- - - adminMode = attribute( - dtype='DevEnum', - access=AttrWriteType.READ_WRITE, - polling_period=1000, - memorized=True, - doc= ("The admin mode reported for this device. It may interpret the" - "current device condition and condition of all managed devices" - "to set this. Most possibly an aggregate attribute."), - ) - - onCommandProgress = attribute( - dtype='DevUShort', - label="Progress percentage for the On command", - polling_period=3000, - abs_change=10, - max_value=100, - min_value=0, - doc=("Percentage progress implemented for commands that result in state/mode" - "transitions for a large \nnumber of components and/or are executed in " - "stages (e.g power up, power down)"), - ) - - offCommandProgress = attribute( - dtype='DevUShort', - label="Progress percentage for the Off command", - polling_period=3000, - abs_change=10, - max_value=100, - min_value=0, - doc=("Percentage progress implemented for commands that result in state/mode" - " transitions for a large \nnumber of components and/or are executed in " - "stages (e.g power up, power down)"), - ) - - standbyCommandProgress = attribute( - dtype='DevUShort', - label="Progress percentage for the Standby command", - polling_period=3000, - abs_change=10, - max_value=100, - min_value=0, - doc=("Percentage progress implemented for commands that result in state/mode " - "transitions for a large \nnumber of components and/or are executed in " - "stages (e.g power up, power down)"), - ) - - onCmdDurationExpected = attribute( - dtype='DevUShort', - access=AttrWriteType.READ_WRITE, - label="Expected duration (sec) of the On command execution", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - memorized=True, - doc=("Set/Report the duration expected (in sec.) for the On command execution"), - ) - - offCmdDurationExpected = attribute( - dtype='DevUShort', - access=AttrWriteType.READ_WRITE, - label="Expected duration (sec) of the Off command", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - memorized=True, - doc=("Set/Report the duration expected (in sec.) for the Off command execution"), - ) - - standbyCmdDurationExpected = attribute( - dtype='DevUShort', - access=AttrWriteType.READ_WRITE, - label="Expected duration (sec) of the Standby command", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - memorized=True, - doc=("Set/Report the duration expected (in sec.) for the Standby command"), - ) - - onCmdDurationMeasured = attribute( - dtype='DevUShort', - label="Measured duration (sec) of the On command execution", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - doc=("Report the measured duration (in sec.) of the On command execution"), - ) - - offCmdDurationMeasured = attribute( - dtype='DevUShort', - label="Measured duration (sec) of the Off command", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - doc=("Report the measured duration (in sec.) of the Off command execution"), - ) - - standbyCmdDurationMeasured = attribute( - dtype='DevUShort', - label="Measured duration (sec) of the Standby command", - polling_period=3000, - abs_change=0, - max_value=100, - min_value=0, - doc=("Report the measured duration (in sec.) of the Standby command"), - ) - - cbfOnCmdTimeoutExpired = attribute( - dtype='DevBoolean', - label="CBF command timeout flag", - polling_period=2000, - abs_change=1, - doc=("Signal the occurence of a timeout during the execution of commands on" - " CBF Sub-element"), - ) - - pssOnCmdTimeoutExpired = attribute( - dtype='DevBoolean', - label="PSS command timeout flag", - polling_period=2000, - abs_change=1, - doc=("Signal the occurence of a timeout during the execution of commands on " - "PSS Sub-element"), - ) - - pstOnCmdTimeoutExpired = attribute( - dtype='DevBoolean', - label="PST command timeout flag", - polling_period=2000, - abs_change=1, - doc=("Signal the occurence of a timeout during the execution of commands on" - " PST Sub-element"), - ) - - cspCbfState = attribute( - dtype='DevState', - label="CBF status", - polling_period=3000, - abs_change=1, - doc=("The CBF sub-element Device State. Allowed values are ON, STANDBY, OFF, " - "DISABLED, ALARM, FAULT, UNKNOWN"), - ) - - cspPssState = attribute( - dtype='DevState', - label="PSS status", - polling_period=3000, - abs_change=1, - doc=("The PSS sub-element Device State. Allowed values are ON, STANDBY, OFF," - " DISABLED, ALARM, FAULT, UNKNOWN"), - ) - - cspPstState = attribute( - dtype='DevState', - label="PST status", - polling_period=3000, - doc=("The PST sub-element Device State. Allowed values are ON, STANDBY,OFF," - " DISABLED, ALARM, FAULT, UNKNOWN"), - ) - - cspCbfHealthState = attribute( - dtype='DevEnum', - label="CBF Health status", - polling_period=3000, - abs_change=1, - doc="The CBF sub-element healthState.", - enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], - ) - - cspPssHealthState = attribute( - dtype='DevEnum', - label="PSS Health status", - polling_period=3000, - abs_change=1, - doc="The PSS sub-element healthState", - enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], - ) - - cspPstHealthState = attribute( - dtype='DevEnum', - label="PST health status", - polling_period=3000, - abs_change=1, - doc="The PST sub-element healthState.", - enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], - ) - - cbfMasterAddress = attribute( - dtype='DevString', - doc="TANGO FQDN of the CBF sub-element Master", - ) - - pssMasterAddress = attribute( - dtype='DevString', - doc="TANGO FQDN of the PSS sub-element Master", - ) - - pstMasterAddress = attribute( - dtype='DevString', - doc="TANGO FQDN of the PST sub-element Master", - ) - - cspCbfAdminMode = attribute( - dtype='DevEnum', - access=AttrWriteType.READ_WRITE, - label="CBF administrative Mode", - polling_period=3000, - abs_change=1, - doc=("The CBF sub-lement adminMode. Allowed values are ON-LINE, " - "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED") - ) - - cspPssAdminMode = attribute( - dtype='DevEnum', - access=AttrWriteType.READ_WRITE, - label="PSS administrative mode", - polling_period=3000, - abs_change=1, - doc=("The PSS sub-lement adminMode. Allowed values are ON-LINE, " - "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED") - ) - - cspPstAdminMode = attribute( - dtype='DevEnum', - access=AttrWriteType.READ_WRITE, - label="PST administrative mode", - polling_period=3000, - abs_change=1, - doc=("The PST sub-lement adminMode. Allowed values are ON-LINE, " - "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED") - ) - - unassignedSearchBeamsNum = attribute( - dtype='DevUShort', - label="Number of unassigned SearchBeam Capabilities", - doc=("Report the number of unassigned SearchBeam Capabilities." - " This number does not take in account the number of *reserved*" - " SearchBeams."), - ) - - - 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`."), - ) - - reportSearchBeamState = attribute( - dtype=('DevState',), - max_dim_x=1500, - label="SearchBeam Capabilities State", - doc="Report the state of the SearchBeam Capabilities as an array of DevState.", - ) - - reportSearchBeamHealthState = attribute( - dtype=('DevUShort',), - max_dim_x=1500, - label="SearchBeam Capabilities healthState", - abs_change=1, - doc=("Report the health state of the SearchBeam Capabilities as an array" - " of unsigned short. For ex`: [0,0,...,1..]`"), - ) - - reportSearchBeamAdminMode = attribute( - dtype=('DevUShort',), - access=AttrWriteType.READ_WRITE, - max_dim_x=1500, - label="SearchBeam Capabilities adminMode", - abs_change=1, - doc=("Report the administrative mode of the SearchBeam Capabilities as an" - " array of unsigned short. For ex `:[0,0,0,...2..]`"), - ) - - reportTimingBeamState = attribute( - dtype=('DevState',), - max_dim_x=16, - label="TimingBeam Capabilities State", - doc="Report the state of the TimingBeam Capabilities as an array of DevState.", - ) - - reportTimingBeamHealthState = attribute( - dtype=('DevUShort',), - max_dim_x=16, - label="TimingBeam Capabilities healthState", - abs_change=1, - doc=("Report the health state of the TimingBeam Capabilities as an array of" - " unsigned short. For ex [0,0,...,1..]"), - ) - - reportTimingBeamAdminMode = attribute( - dtype=('DevUShort',), - access=AttrWriteType.READ_WRITE, - max_dim_x=16, - label="TimingBeam Capabilities adminMode", - abs_change=1, - doc=("Report the administrativw mode of the TimingBeam Capabilities as an" - " array of unsigned short. For ex [0,0,0,...2..]"), - ) - - reportVlbiBeamState = attribute( - dtype=('DevState',), - max_dim_x=20, - label="VlbiBeam Capabilities State", - doc="Report the state of the VLBIBeam Capabilities as an array of DevState.", - ) - - reportVlbiBeamHealthState = attribute( - dtype=('DevUShort',), - max_dim_x=20, - label="VlbiBeam Capabilities healthState", - abs_change=1, - doc=("Report the health state of the VlbiBeam Capabilities as an array of" - " unsigned short. For ex [0,0,...,1..]"), - ) - - reportVlbiBeamAdminMode = attribute( - dtype=('DevUShort',), - access=AttrWriteType.READ_WRITE, - max_dim_x=20, - label="VlbiBeam Capabilities adminMode", - abs_change=1, - doc=("Report the administrative mode of the VlbiBeam Capabilities as an" - " array of unsigned short. For ex -[0,0,0,...2..]"), - ) - - cspSubarrayAddresses = attribute( - dtype=('DevString',), - max_dim_x=16, - doc="CSPSubarrays FQDN", - ) - - searchBeamAddresses = attribute( - dtype=('DevString',), - max_dim_x=1500, - label="SearchBeamCapabilities FQDNs", - doc="TANGO FQDNs of the CSP.LMC SearchBeam Capabilities", - ) - - timingBeamAddresses = attribute( - dtype=('DevString',), - max_dim_x=16, - label="TimingBeam Capabilities FQDN", - doc="TANGO FQDNs of the CSP.LMC TimingBeam Capabilities", - ) - - vlbiBeamAddresses = attribute( - dtype=('DevString',), - max_dim_x=20, - label="VLBIBeam Capabilities FQDNs", - doc="TANGO FQDNs of the CSP.LMC VlbiBeam Capabilities", - ) - - searchBeamMembership = attribute( - dtype=('DevUShort',), - max_dim_x=1500, - label="SearchBeam Memebership", - doc="Reports the sub-array affiliation for each SearchBeam Capabiity.", - ) - - timingBeamMembership = attribute( - dtype=('DevUShort',), - max_dim_x=16, - label="TimingBeam Membership", - doc="Report the sub-array affiliation for each TimingBeam Capability.", - ) - - vlbiBeamMembership = attribute( - dtype=('DevUShort',), - max_dim_x=20, - label="VLBI Beam membership", - doc="Report the sub-array affiliation for each VlbiBbeam Capability.", - ) - - unassignedSearchBeamIDs = attribute( - dtype=('DevUShort',), - max_dim_x=1500, - label="Unassigned SeachBeam Capabilities IDs", - doc=("Report the list of SearchBeam Capability IDs that are not assigned to any sub-array." - "SearchBeams are assigned to a sub-array in groups of three because each PSS LRU " - "can process up to three SearchBeams at time. A SearchBeam is marked as *reserved* to" - " a sub-array if the other SearchBeams of the group are already assigned to that sub-array." - " The IDs of the SearchBeams marked as *reserved*, are not included in this list." - " The SCM values of a unassigned SearchBeam Capabiity are " - " State = OFF adminMode = ONLINE or MAINTENACE obsState = IDLE healthState = OK " - "obsMode = IDLE (reserved flag = False)"), - ) - - reservedSearchBeamIDs = attribute( - dtype=('DevUShort',), - max_dim_x=16, - label="IDs of reserved SeachBeam Capabilities", - doc="Report the list of SearchBeam Capability IDs reserved for each sub-array", - ) - - reservedSearchBeamNum = attribute( - dtype=('DevUShort',), - max_dim_x=16, - label="Number of reserved SeachBeam Capabilities", - doc="Report the number of SearchBeam Capabilities reserved for each sub-array", - ) - - unassignedTimingBeamIDs = attribute( - dtype=('DevUShort',), - max_dim_x=16, - label="Unassigned TimingBeam Capabilities IDs", - doc="Report the list of TimingBeam Capability IDs that are not assigned to any sub-array. The SCM values of a unassigned VlbiBeam Capabiity are:\nState = OFF\nadminMode = ONLINE or MAINTENACE\nobsState = IDLE\nhealthState = OK \nobsMode = IDLE\n", - ) - - unassignedVlbiBeamIDs = attribute( - dtype=('DevUShort',), - max_dim_x=20, - label="Unassigned VlbiBeam Capabilities IDs", - doc="Report the list of VlbiBeam Capability IDs that are not assigned to any sub-array. The SCM values of a unassigned VlbiBeam Capabiity are:\nState = OFF\nadminMode = ONLINE or MAINTENACE\nobsState = IDLE\nhealthState = OK \nobsMode = IDLE\n", - ) - - # --------------- - # General methods - # --------------- - - def init_device(self): - """Initialises the attributes and properties of the CspMaster.""" - SKAMaster.init_device(self) - # PROTECTED REGION ID(CspMaster.init_device) ENABLED START # - # PROTECTED REGION END # // CspMaster.init_device - - def always_executed_hook(self): - """Method always executed before any TANGO command is executed.""" - # PROTECTED REGION ID(CspMaster.always_executed_hook) ENABLED START # - # PROTECTED REGION END # // CspMaster.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(CspMaster.delete_device) ENABLED START # - # PROTECTED REGION END # // CspMaster.delete_device - # ------------------ - # Attributes methods - # ------------------ - - def read_adminMode(self): - # PROTECTED REGION ID(CspMaster.adminMode_read) ENABLED START # - """Return the adminMode attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.adminMode_read - - def write_adminMode(self, value): - # PROTECTED REGION ID(CspMaster.adminMode_write) ENABLED START # - """Set the adminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.adminMode_write - - def read_onCommandProgress(self): - # PROTECTED REGION ID(CspMaster.onCommandProgress_read) ENABLED START # - """Return the onCommandProgress attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.onCommandProgress_read - - def read_offCommandProgress(self): - # PROTECTED REGION ID(CspMaster.offCommandProgress_read) ENABLED START # - """Return the offCommandProgress attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.offCommandProgress_read - - def read_standbyCommandProgress(self): - # PROTECTED REGION ID(CspMaster.standbyCommandProgress_read) ENABLED START # - """Return the standbyCommandProgress attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.standbyCommandProgress_read - - def read_onCmdDurationExpected(self): - # PROTECTED REGION ID(CspMaster.onCmdDurationExpected_read) ENABLED START # - """Return the onCmdDurationExpected attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.onCmdDurationExpected_read - - def write_onCmdDurationExpected(self, value): - # PROTECTED REGION ID(CspMaster.onCmdDurationExpected_write) ENABLED START # - """Set the onCmdDurationExpected attribute.""" - pass - # PROTECTED REGION END # // CspMaster.onCmdDurationExpected_write - - def read_offCmdDurationExpected(self): - # PROTECTED REGION ID(CspMaster.offCmdDurationExpected_read) ENABLED START # - """Return the offCmdDurationExpected attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.offCmdDurationExpected_read - - def write_offCmdDurationExpected(self, value): - # PROTECTED REGION ID(CspMaster.offCmdDurationExpected_write) ENABLED START # - """Set the offCmdDurationExpected attribute.""" - pass - # PROTECTED REGION END # // CspMaster.offCmdDurationExpected_write - - def read_standbyCmdDurationExpected(self): - # PROTECTED REGION ID(CspMaster.standbyCmdDurationExpected_read) ENABLED START # - """Return the standbyCmdDurationExpected attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.standbyCmdDurationExpected_read - - def write_standbyCmdDurationExpected(self, value): - # PROTECTED REGION ID(CspMaster.standbyCmdDurationExpected_write) ENABLED START # - """Set the standbyCmdDurationExpected attribute.""" - pass - # PROTECTED REGION END # // CspMaster.standbyCmdDurationExpected_write - - def read_onCmdDurationMeasured(self): - # PROTECTED REGION ID(CspMaster.onCmdDurationMeasured_read) ENABLED START # - """Return the onCmdDurationMeasured attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.onCmdDurationMeasured_read - - def read_offCmdDurationMeasured(self): - # PROTECTED REGION ID(CspMaster.offCmdDurationMeasured_read) ENABLED START # - """Return the offCmdDurationMeasured attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.offCmdDurationMeasured_read - - def read_standbyCmdDurationMeasured(self): - # PROTECTED REGION ID(CspMaster.standbyCmdDurationMeasured_read) ENABLED START # - """Return the standbyCmdDurationMeasured attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.standbyCmdDurationMeasured_read - - def read_cbfOnCmdTimeoutExpired(self): - # PROTECTED REGION ID(CspMaster.cbfOnCmdTimeoutExpired_read) ENABLED START # - """Return the cbfOnCmdTimeoutExpired attribute.""" - return False - # PROTECTED REGION END # // CspMaster.cbfOnCmdTimeoutExpired_read - - def read_pssOnCmdTimeoutExpired(self): - # PROTECTED REGION ID(CspMaster.pssOnCmdTimeoutExpired_read) ENABLED START # - """Return the pssOnCmdTimeoutExpired attribute.""" - return False - # PROTECTED REGION END # // CspMaster.pssOnCmdTimeoutExpired_read - - def read_pstOnCmdTimeoutExpired(self): - # PROTECTED REGION ID(CspMaster.pstOnCmdTimeoutExpired_read) ENABLED START # - """Return the pstOnCmdTimeoutExpired attribute.""" - return False - # PROTECTED REGION END # // CspMaster.pstOnCmdTimeoutExpired_read - - def read_cspCbfState(self): - # PROTECTED REGION ID(CspMaster.cspCbfState_read) ENABLED START # - """Return the cspCbfState attribute.""" - return tango.DevState.UNKNOWN - # PROTECTED REGION END # // CspMaster.cspCbfState_read - - def read_cspPssState(self): - # PROTECTED REGION ID(CspMaster.cspPssState_read) ENABLED START # - """Return the cspPssState attribute.""" - return tango.DevState.UNKNOWN - # PROTECTED REGION END # // CspMaster.cspPssState_read - - def read_cspPstState(self): - # PROTECTED REGION ID(CspMaster.cspPstState_read) ENABLED START # - """Return the cspPstState attribute.""" - return tango.DevState.UNKNOWN - # PROTECTED REGION END # // CspMaster.cspPstState_read - - def read_cspCbfHealthState(self): - # PROTECTED REGION ID(CspMaster.cspCbfHealthState_read) ENABLED START # - """Return the cspCbfHealthState attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspCbfHealthState_read - - def read_cspPssHealthState(self): - # PROTECTED REGION ID(CspMaster.cspPssHealthState_read) ENABLED START # - """Return the cspPssHealthState attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspPssHealthState_read - - def read_cspPstHealthState(self): - # PROTECTED REGION ID(CspMaster.cspPstHealthState_read) ENABLED START # - """Return the cspPstHealthState attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspPstHealthState_read - - def read_cbfMasterAddress(self): - # PROTECTED REGION ID(CspMaster.cbfMasterAddress_read) ENABLED START # - """Return the cbfMasterAddress attribute.""" - return '' - # PROTECTED REGION END # // CspMaster.cbfMasterAddress_read - - def read_pssMasterAddress(self): - # PROTECTED REGION ID(CspMaster.pssMasterAddress_read) ENABLED START # - """Return the pssMasterAddress attribute.""" - return '' - # PROTECTED REGION END # // CspMaster.pssMasterAddress_read - - def read_pstMasterAddress(self): - # PROTECTED REGION ID(CspMaster.pstMasterAddress_read) ENABLED START # - """Return the pstMasterAddress attribute.""" - return '' - # PROTECTED REGION END # // CspMaster.pstMasterAddress_read - - def read_cspCbfAdminMode(self): - # PROTECTED REGION ID(CspMaster.cspCbfAdminMode_read) ENABLED START # - """Return the cspCbfAdminMode attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspCbfAdminMode_read - - def write_cspCbfAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.cspCbfAdminMode_write) ENABLED START # - """Set the cspCbfAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.cspCbfAdminMode_write - - def read_cspPssAdminMode(self): - # PROTECTED REGION ID(CspMaster.cspPssAdminMode_read) ENABLED START # - """Return the cspPssAdminMode attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspPssAdminMode_read - - def write_cspPssAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.cspPssAdminMode_write) ENABLED START # - """Set the cspPssAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.cspPssAdminMode_write - - def read_cspPstAdminMode(self): - # PROTECTED REGION ID(CspMaster.cspPstAdminMode_read) ENABLED START # - """Return the cspPstAdminMode attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.cspPstAdminMode_read - - def write_cspPstAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.cspPstAdminMode_write) ENABLED START # - """Set the cspPstAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.cspPstAdminMode_write - - def read_unassignedSearchBeamsNum(self): - # PROTECTED REGION ID(CspMaster.unassignedSearchBeamsNum_read) ENABLED START # - """Return the unassignedSearchBeamsNum attribute.""" - return 0 - # PROTECTED REGION END # // CspMaster.unassignedSearchBeamsNum_read - - def read_availableCapabilities(self): - # PROTECTED REGION ID(CspMaster.availableCapabilities_read) ENABLED START # - """Return the availableCapabilities attribute.""" - return ('',) - # PROTECTED REGION END # // CspMaster.availableCapabilities_read - - def read_reportSearchBeamState(self): - # PROTECTED REGION ID(CspMaster.reportSearchBeamState_read) ENABLED START # - """Return the reportSearchBeamState attribute.""" - return (tango.DevState.UNKNOWN,) - # PROTECTED REGION END # // CspMaster.reportSearchBeamState_read - - def read_reportSearchBeamHealthState(self): - # PROTECTED REGION ID(CspMaster.reportSearchBeamHealthState_read) ENABLED START # - """Return the reportSearchBeamHealthState attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportSearchBeamHealthState_read - - def read_reportSearchBeamAdminMode(self): - # PROTECTED REGION ID(CspMaster.reportSearchBeamAdminMode_read) ENABLED START # - """Return the reportSearchBeamAdminMode attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportSearchBeamAdminMode_read - - def write_reportSearchBeamAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.reportSearchBeamAdminMode_write) ENABLED START # - """Set the reportSearchBeamAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.reportSearchBeamAdminMode_write - - def read_reportTimingBeamState(self): - # PROTECTED REGION ID(CspMaster.reportTimingBeamState_read) ENABLED START # - """Return the reportTimingBeamState attribute.""" - return (tango.DevState.UNKNOWN,) - # PROTECTED REGION END # // CspMaster.reportTimingBeamState_read - - def read_reportTimingBeamHealthState(self): - # PROTECTED REGION ID(CspMaster.reportTimingBeamHealthState_read) ENABLED START # - """Return the reportTimingBeamHealthState attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportTimingBeamHealthState_read - - def read_reportTimingBeamAdminMode(self): - # PROTECTED REGION ID(CspMaster.reportTimingBeamAdminMode_read) ENABLED START # - """Return the reportTimingBeamAdminMode attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportTimingBeamAdminMode_read - - def write_reportTimingBeamAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.reportTimingBeamAdminMode_write) ENABLED START # - """Set the reportTimingBeamAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.reportTimingBeamAdminMode_write - - def read_reportVlbiBeamState(self): - # PROTECTED REGION ID(CspMaster.reportVlbiBeamState_read) ENABLED START # - """Return the reportVlbiBeamState attribute.""" - return (tango.DevState.UNKNOWN,) - # PROTECTED REGION END # // CspMaster.reportVlbiBeamState_read - - def read_reportVlbiBeamHealthState(self): - # PROTECTED REGION ID(CspMaster.reportVlbiBeamHealthState_read) ENABLED START # - """Return the reportVlbiBeamHealthState attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportVlbiBeamHealthState_read - - def read_reportVlbiBeamAdminMode(self): - # PROTECTED REGION ID(CspMaster.reportVlbiBeamAdminMode_read) ENABLED START # - """Return the reportVlbiBeamAdminMode attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reportVlbiBeamAdminMode_read - - def write_reportVlbiBeamAdminMode(self, value): - # PROTECTED REGION ID(CspMaster.reportVlbiBeamAdminMode_write) ENABLED START # - """Set the reportVlbiBeamAdminMode attribute.""" - pass - # PROTECTED REGION END # // CspMaster.reportVlbiBeamAdminMode_write - - def read_cspSubarrayAddresses(self): - # PROTECTED REGION ID(CspMaster.cspSubarrayAddresses_read) ENABLED START # - """Return the cspSubarrayAddresses attribute.""" - return ('',) - # PROTECTED REGION END # // CspMaster.cspSubarrayAddresses_read - - def read_searchBeamAddresses(self): - # PROTECTED REGION ID(CspMaster.searchBeamAddresses_read) ENABLED START # - """Return the searchBeamAddresses attribute.""" - return ('',) - # PROTECTED REGION END # // CspMaster.searchBeamAddresses_read - - def read_timingBeamAddresses(self): - # PROTECTED REGION ID(CspMaster.timingBeamAddresses_read) ENABLED START # - """Return the timingBeamAddresses attribute.""" - return ('',) - # PROTECTED REGION END # // CspMaster.timingBeamAddresses_read - - def read_vlbiBeamAddresses(self): - # PROTECTED REGION ID(CspMaster.vlbiBeamAddresses_read) ENABLED START # - """Return the vlbiBeamAddresses attribute.""" - return ('',) - # PROTECTED REGION END # // CspMaster.vlbiBeamAddresses_read - - def read_searchBeamMembership(self): - # PROTECTED REGION ID(CspMaster.searchBeamMembership_read) ENABLED START # - """Return the searchBeamMembership attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.searchBeamMembership_read - - def read_timingBeamMembership(self): - # PROTECTED REGION ID(CspMaster.timingBeamMembership_read) ENABLED START # - """Return the timingBeamMembership attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.timingBeamMembership_read - - def read_vlbiBeamMembership(self): - # PROTECTED REGION ID(CspMaster.vlbiBeamMembership_read) ENABLED START # - """Return the vlbiBeamMembership attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.vlbiBeamMembership_read - - def read_unassignedSearchBeamIDs(self): - # PROTECTED REGION ID(CspMaster.unassignedSearchBeamIDs_read) ENABLED START # - """Return the unassignedSearchBeamIDs attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.unassignedSearchBeamIDs_read - - def read_reservedSearchBeamIDs(self): - # PROTECTED REGION ID(CspMaster.reservedSearchBeamIDs_read) ENABLED START # - """Return the reservedSearchBeamIDs attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reservedSearchBeamIDs_read - - def read_reservedSearchBeamNum(self): - # PROTECTED REGION ID(CspMaster.reservedSearchBeamNum_read) ENABLED START # - """Return the reservedSearchBeamNum attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.reservedSearchBeamNum_read - - def read_unassignedTimingBeamIDs(self): - # PROTECTED REGION ID(CspMaster.unassignedTimingBeamIDs_read) ENABLED START # - """Return the unassignedTimingBeamIDs attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.unassignedTimingBeamIDs_read - - def read_unassignedVlbiBeamIDs(self): - # PROTECTED REGION ID(CspMaster.unassignedVlbiBeamIDs_read) ENABLED START # - """Return the unassignedVlbiBeamIDs attribute.""" - return (0,) - # PROTECTED REGION END # // CspMaster.unassignedVlbiBeamIDs_read - - - # -------- - # Commands - # -------- - - @command( - dtype_in='DevVarStringArray', - doc_in=("If the array length is 0, the command applies to the whole CSP Element." - " If the array length is > 1, each array element specifies the FQDN of " - "the CSP SubElement to switch ON."), - ) - @DebugIt() - def On(self, argin): - # PROTECTED REGION ID(CspMaster.On) ENABLED START # - """ - *Class TANGO method* - - Switch-on the CSP sub-elements specified by the input argument. If no argument is - specified, the command is issued on all the CSP sub-elements. - The command is executed if the *AdminMode* is ONLINE or *MAINTENANCE*. - If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an - exception. - - :param argin: - The list of sub-element FQDNs to switch-on or an empty list to switch-on the whole - CSP Element. - - If the array length is 0, the command applies to the whole CSP Element. If the - array length is > 1, each array element specifies the FQDN of the - CSP SubElement to switch ON. - :type: 'DevVarStringArray' - :return: None - :raises: *tango.DevFailed* exception.\n - The exception is thrown when the *On* command fails - for CBF sub-element or there are no DeviceProxy providing interface - to the CSP sub-elements or the AdminMode is not correct. - """ - pass - # PROTECTED REGION END # // CspMaster.On - - @command( - dtype_in='DevVarStringArray', - doc_in=("If the array length is 0, the command applies to the whole CSP Element." - "If the array length is > 1, each array element specifies the FQDN of the" - " CSP SubElement to switch OFF."), - ) - @DebugIt() - def Off(self, argin): - # PROTECTED REGION ID(CspMaster.Off) ENABLED START # - """ - Switch-off the CSP sub-elements specified by the input argument. - If no argument is specified, the command is issued to all the CSP - sub-elements. - - :param argin: - - If the array length is 0, the command applies to the whole CSP Element. - If the array length is > 1, each array element specifies the FQDN of the - CSP SubElement to switch OFF. - :type: 'DevVarStringArray' - - :return: None - """ - pass - # PROTECTED REGION END # // CspMaster.Off - - @command( - dtype_in='DevVarStringArray', - doc_in=("If the array length is 0, the command applies to the whole CSP Element. " - "If the array length is > 1, each array element specifies the FQDN of the" - "CSP SubElement to put in STANDBY mode."), - ) - @DebugIt() - def Standby(self, argin): - # PROTECTED REGION ID(CspMaster.Standby) ENABLED START # - """ - - Transit CSP or one or more CSP SubElements from ON/OFF to - STANDBY. - - :param argin: 'DevVarStringArray' - - If the array length is 0, the command applies to the whole - CSP Element. - If the array length is > 1, each array element specifies the FQDN of the - CSP SubElement to put in STANDBY mode. - - :return: None - """ - pass - # PROTECTED REGION END # // CspMaster.Standby - - @command( - ) - @DebugIt() - def Upgrade(self): - # PROTECTED REGION ID(CspMaster.Upgrade) ENABLED START # - """ - - :return: None - """ - pass - # PROTECTED REGION END # // CspMaster.Upgrade - -# ---------- -# Run server -# ---------- - - -def main(args=None, **kwargs): - # PROTECTED REGION ID(CspMaster.main) ENABLED START # - return run((CspMaster,), args=args, **kwargs) - # PROTECTED REGION END # // CspMaster.main - -if __name__ == '__main__': - main() diff --git a/csp-lmc-common/csp_lmc_common/CspCapabilityMonitor.py b/csp-lmc-common/csp_lmc_common/CspCapabilityMonitor.py new file mode 100644 index 0000000000000000000000000000000000000000..62d99312ea226f936c2ba565f2b40f7afb7ac45b --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/CspCapabilityMonitor.py @@ -0,0 +1,362 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspCapabilityMonitor project +# +# INAF, SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC Common Class + +CSP.LMC Common Class designed to monitoring the SCM +attributes of the CSP Capabilities: SearchBeams, TimingBeams, +VlbiBeams, Receptors/Stations. +""" +# 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 +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +# Additional import +# PROTECTED REGION ID(CspCapabilityMonitor.additionnal_import) ENABLED START # + +from skabase.SKABaseDevice import SKABaseDevice +from skabase.auxiliary import utils +from .utils.cspcommons import HealthState, AdminMode, ObsState + +# PROTECTED REGION END # // CspCapabilityMonitor.additionnal_import + +__all__ = ["CspCapabilityMonitor", "main"] + +class CspCapabilityMonitor(with_metaclass(DeviceMeta,SKABaseDevice)): + """ + CSP.LMC Common Class designed to monitoring the SCM + attributes of the CSP Capabilities: SearchBeams, TimingBeams, + VlbiBeams, Receptors/Stations. + + **Properties:** + + - Device Property + + CapabilityDevices + - The list of the CSP Capability devices FQDNs monitored\nby the instance. + - Type:'DevVarStringArray' + + + """ + # PROTECTED REGION ID(CspCapabilityMonitor.class_variable) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.class_variable + + # ----------------- + # Device Properties + # ----------------- + + CapabilityDevices = device_property( + dtype='DevVarStringArray', + ) + + # ---------- + # Attributes + # ---------- + + numOfUnassignedIDs = attribute( + dtype='DevUShort', + ) + + capabilityState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Capability State", + doc="Report the State of the capabilities.", + ) + + capabilityHealthState = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + capabilityAdminMode = attribute( + dtype=('DevUShort',), + access=AttrWriteType.READ_WRITE, + max_dim_x=1500, + ) + + capabilityObsState = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + unassignedIDs = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + cspCapabilityAddresses = attribute( + dtype=('DevString',), + max_dim_x=1500, + label="CSP.LMC Capability devices FQDNs", + doc="The FQDNs of the CSP.LMC Capability devices: SearchBeams, TimingBeams, VlbiBeams,\nReceptors (MID instance), Stations (LOW instance)", + ) + + capabilityMembership = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + label="Capability sub-array affiliation", + ) + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspCapabilityMonitor.""" + SKABaseDevice.init_device(self) + # PROTECTED REGION ID(CspCapabilityMonitor.init_device) ENABLED START # + self.set_state(tango.DevState.INIT) + self._capability_fqdn = self.CapabilityDevices + print("self._capability_fqdn:", self._capability_fqdn) + self._capability_proxies = {} + self._event_id = defaultdict(lambda: defaultdict(lambda: 0)) + self._capability_state = {} + self._capability_health_state = {} + self._capability_admin_mode = {} + self._capability_obs_state = {} + self._capability_membership = {} + self._capability_proxies = {} + self._unassigned_ids = [0]* len(self._capability_fqdn) + self._capability_state = {fqdn:tango.DevState.DISABLE for fqdn in self._capability_fqdn} + self._capability_health_state = {fqdn:HealthState.UNKNOWN for fqdn in self._capability_fqdn} + self._capability_admin_mode = {fqdn:AdminMode.NOTFITTED for fqdn in self._capability_fqdn} + self._capability_obs_state = {fqdn:ObsState.IDLE for fqdn in self._capability_fqdn} + self._capability_membership = {fqdn:0 for fqdn in self._capability_fqdn} + self._csp_tango_db = 0 + + # establish connection with the CSP.LMC TANGO DB + self._csp_tango_db = tango.Database() + attribute_properties = self._csp_tango_db.get_device_attribute_property(self.get_name(), + {'adminMode': ['__value']}) + try: + admin_mode_memorized = attribute_properties['adminMode']['__value'] + self._admin_mode = int(admin_mode_memorized[0]) + except KeyError as key_err: + self.logger.info("No {} key found".format(str(key_err))) + self._connect_to_capability() + self._healthState = HealthState.OK + self.set_state(tango.DevState.ON) + + def _connect_to_capability(self): + # connect to DB and read the adminMode of each capability + + for fqdn in self.CapabilityDevices: + attribute_properties = self._csp_tango_db.get_device_attribute_property(fqdn, {'adminMode': ['__value'],}) + try: + admin_mode_memorized = attribute_properties['adminMode']['__value'] + self._capability_admin_mode[fqdn] = int(admin_mode_memorized[0]) + except KeyError as key_err: + print(key_err) + try: + device_proxy = tango.DeviceProxy(fqdn) + self._capability_proxies[fqdn] = device_proxy + ev_id = device_proxy.subscribe_event("adminMode", + EventType.CHANGE_EVENT, + self._attributes_change_event_cb, + stateless=True) + self._event_id[fqdn] = ev_id + + ev_id = device_proxy.subscribe_event("State", + EventType.CHANGE_EVENT, + self._attributes_change_event_cb, + stateless=True) + self._event_id[fqdn] = ev_id + + ev_id = device_proxy.subscribe_event("healthState", + EventType.CHANGE_EVENT, + self._attributes_change_event_cb, + stateless=True) + self._event_id[fqdn] = ev_id + + ev_id = device_proxy.subscribe_event("obsState", + EventType.CHANGE_EVENT, + self._attributes_change_event_cb, + stateless=True) + self._event_id[fqdn]= ev_id + + ev_id = device_proxy.subscribe_event("subarrayMemebership", + EventType.CHANGE_EVENT, + self._attributes_change_event_cb, + stateless=True) + self._event_id[fqdn]['subarrayMembership'] = ev_id + except tango.DevFailed as tango_err: + print(tango_err.args[0].desc) + + def _attributes_change_event_cb(self, evt): + dev_name = evt.device.dev_name() + if not evt.err: + try: + if dev_name in self.CapabilityDevices: + if evt.attr_value.name.lower() == "state": + print("{}: received event on {} value {}".format(dev_name, + evt.attr_value.name, + evt.attr_value.value)) + self._capability_state[dev_name] = evt.attr_value.value + + elif evt.attr_value.name.lower() == "healthstate": + self._capability_health_state[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "adminmode": + print("device: {} adminMode value {}".format(dev_name,evt.attr_value.value )) + self._capability_admin_mode[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "obsstate": + print("device: {} adminMode value {}".format(dev_name,evt.attr_value.value )) + self._capability_obsstate[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "subarrayMembershp": + self._capability_membership[dev_name] = evt.attr_value.value + else: + print("Attribute {} not still " + "handled".format(evt.attr_name)) + else: + print("Unexpected change event for" + " attribute: {}".format(str(evt.attr_name))) + return + log_msg = "New value for {} is {}".format(str(evt.attr_name), + str(evt.attr_value.value)) + except tango.DevFailed as df: + self.logger.error(str(df.args[0].desc)) + except Exception as except_occurred: + self.logger.error(str(except_occurred)) + else: + for item in evt.errors: + # API_EventTimeout: if sub-element device not reachable it transitions + # to UNKNOWN state. + if item.reason == "API_EventTimeout": + self._capability_state[dev_name] = tango.DevState.DISABLED + self._capability_health_state[dev_name] = HealthState.UNKNOWN + self._capability_admin_mode[dev_name] = AdminMode.NOTFITTED + self._capability_health_state[dev_name] = ObsState.IDLE + log_msg = item.reason + ": on attribute " + str(evt.attr_name) + print(log_msg) + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspCapabilityMonitor.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.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(CspCapabilityMonitor.delete_device) ENABLED START # + event_to_remove = [] + for fqdn in self._capability_fqdn: + try: + self._capability_proxies[fqdn].unsubscribe_event(self._event_id[fqdn]) + event_to_remove.append(fqdn) + except KeyError as key_err: + msg = ("Failure unsubscribing event {} " + "on device {}. Reason: {}".format(event_id, + fqdn, + key_err)) + self.logger.error(msg) + # remove the events id from the list + for k in _event_id[fqdn].remove(k): + if self._event_id[fqdn]: + msg = "Still subscribed events: {}".format(self._event_id) + self.logger.warn(msg) + else: + # remove the dictionary element + self._event_id.pop(fqdn) + + self._capability_fqdn.clear() + self._capability_state.clear() + self._capability_health_state.clear() + self._capability_admin_mode.clear() + self._capability_obs_state.clear() + self._capability_membership.clear() + # PROTECTED REGION END # // CspCapabilityMonitor.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_numOfUnassignedIDs(self): + # PROTECTED REGION ID(CspCapabilityMonitor.numOfUnassignedIDs_read) ENABLED START # + """Return the numOfUnassignedIDs attribute.""" + return len(self._unassigned_ids) + # PROTECTED REGION END # // CspCapabilityMonitor.numOfUnassignedIDs_read + + def read_capabilityState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityState_read) ENABLED START # + """Return the capabilityState attribute.""" + return list(self._capability_state.values()) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityState_read + + def read_capabilityHealthState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityHealthState_read) ENABLED START # + """Return the capabilityHealthState attribute.""" + return list(self._capability_health_state.values()) + + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityHealthState_read + + def read_capabilityAdminMode(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAdminMode_read) ENABLED START # + """Return the capabilityAdminMode attribute.""" + return list(self._capability_admin_mode.values()) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAdminMode_read + + def write_capabilityAdminMode(self, value): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAdminMode_write) ENABLED START # + """Set the capabilityAdminMode attribute.""" + pass + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAdminMode_write + + def read_capabilityObsState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityObsState_read) ENABLED START # + """Return the capabilityObsState attribute.""" + return list(self._capability_obs_state.values()) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityObsState_read + + def read_unassignedIDs(self): + # PROTECTED REGION ID(CspCapabilityMonitor.unassignedIDs_read) ENABLED START # + """Return the unassignedIDs attribute.""" + return self._unassigned_ids + # PROTECTED REGION END # // CspCapabilityMonitor.unassignedIDs_read + + def read_cspCapabilityAddresses(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAddresses_read) ENABLED START # + return self.CapabilityDevices + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAddresses_read + + def read_capabilityMembership(self): + # PROTECTED REGION ID(CspCapabilityMonitor.membership_read) ENABLED START # + """Return the membership attribute.""" + return list(self._capability_membership.values()) + # PROTECTED REGION END # // CspCapabilityMonitor.membership_read + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + +def main(args=None, **kwargs): + # PROTECTED REGION ID(CspCapabilityMonitor.main) ENABLED START # + return run((CspCapabilityMonitor,), args=args, **kwargs) + # PROTECTED REGION END # // CspCapabilityMonitor.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/csp_lmc_common/CspMaster.py b/csp-lmc-common/csp_lmc_common/CspMaster.py new file mode 100644 index 0000000000000000000000000000000000000000..acaa175f6957cb9a31e891c76623cf3b2aff7a15 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/CspMaster.py @@ -0,0 +1,1931 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspMaster project +# +# INAF - SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC Common CspMaster + +CSP.LMC Common Class for the CSPMaster TANGO Device. +""" +# PROTECTED REGION ID (CspMaster.standardlibray_import) ENABLED START # +# Python standard library +import sys +import os +from future.utils import with_metaclass +from collections import defaultdict +import threading +import time +# PROTECTED REGION END# //CspMaster.standardlibray_import + +# tango imports +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.additional_import) ENABLED START # +# +from skabase.SKAMaster import SKAMaster +from skabase.auxiliary import utils + +from .utils.decorators import AdminModeCheck, CmdInputArgsCheck +from .utils.cspcommons import HealthState, AdminMode, ObsState, CmdExecState +from . import release +# PROTECTED REGION END# //CspMaster.additional_import + + +__all__ = ["CspMaster", "main"] + +class CspMaster(with_metaclass(DeviceMeta, SKAMaster)): + """ + CSP.LMC Common Class for the CSPMaster TANGO Device. + + **Properties:** + + - Device Property + + CspCbf + - FQDN of the CBF Sub-element Master + - Type:'DevString' + + CspPss + - TANGO FQDN of the PSS Sub-element Master + - Type:'DevString' + + CspPst + - TANGO FQDN of the PST Sub-element Master + - Type:'DevString' + + CspSubarrays + - TANGO FQDN of the CSP.LMC Subarrays + - Type:'DevVarStringArray' + + SearchBeams + - TANGO FQDN of the CSP.LMC SearchBeam Capabilities + - Type:'DevVarStringArray' + + TimingBeams + - TANGO FQDN of the CSP.LMC TimingBeam Capabilities + - Type:'DevVarStringArray' + + VlbiBeams + - TANGO FQDN of the CSP.LMC Vlbi Capabilities + - Type:'DevVarStringArray' + + SearchBeamsMonitor + - TANGO Device to monitor the CSP SearchBeams Capability\ndevices. + - Type:'DevString' + + TimingBeamsMonitor + - TANGO Device to monitor the CSP TimingBeams Capability\ndevices. + - Type:'DevString' + + VlbiBeamsMonitor + - TANGO Device to monitor the CSP VlbiBeams Capability\ndevices. + - Type:'DevString' + + """ + # PROTECTED REGION ID(CspMaster.class_variable) ENABLED START # + + # PROTECTED REGION END # // CspMaster.class_variable + # PROTECTED REGION ID(CspMaster.class_protected_methods) ENABLED START # + + # !! NOTE !!: + # In methods and attributes of the class: + # 'se' prefix stands for 'sub-element + # 'cb' suffix stands for 'callback' + #---------------- + # Event Callback functions + # --------------- + def _se_scm_change_event_cb(self, evt): + """ + Class callback function. + Retrieve the values of the sub-element SCM attributes subscribed + for change event at device initialization. + + :param evt: The event data + + :return: None + """ + dev_name = evt.device.dev_name() + if not evt.err: + try: + if dev_name in self._se_fqdn: + if evt.attr_value.name.lower() == "state": + self.logger.debug("{}: received event on {} value {}".format(dev_name, + evt.attr_value.name, + evt.attr_value.value)) + self._se_state[dev_name] = evt.attr_value.value + + elif evt.attr_value.name.lower() == "healthstate": + self.logger.debug("{}: received event on {} value {}".format(dev_name, + evt.attr_value.name, + evt.attr_value.value)) + self._se_health_state[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "adminmode": + self.logger.debug("device: {} adminMode value {}".format(dev_name,evt.attr_value.value )) + self._se_admin_mode[dev_name] = evt.attr_value.value + else: + log_msg = ("Attribute {} not still " + "handled".format(evt.attr_name)) + self.logger.warn(log_msg) + else: + log_msg = ("Unexpected change event for" + " attribute: {}".format(str(evt.attr_name))) + self.logger.warn(log_msg) + return + + log_msg = "New value for {} is {}".format(str(evt.attr_name), + str(evt.attr_value.value)) + self.logger.info(log_msg) + # update CSP global state + # healthState and State are updated accordingly to the updated values of + # sub-elements healthState, State and adminMode + if evt.attr_value.name.lower() in ["state", "healthstate", "adminmode"]: + self._update_csp_state() + except tango.DevFailed as df: + self.logger.error(str(df.args[0].desc)) + except Exception as except_occurred: + self.logger.error(str(except_occurred)) + else: + for item in evt.errors: + # API_EventTimeout: if sub-element device not reachable it transitions + # to UNKNOWN state. + if item.reason == "API_EventTimeout": + # only if the device is ONLINE/MAINTENANCE, its State is set to + # UNKNOWN when there is a timeout on connection, otherwise its + # State should be reported always as DISABLE + if self._se_admin_mode[dev_name] in [AdminMode.ONLINE, + AdminMode.MAINTENANCE]: + self._se_state[dev_name] = tango.DevState.UNKNOWN + self._se_health_state[dev_name] = HealthState.UNKNOWN + # if the device is executing the shutdown the state is set to + # OFF + if self._se_cmd_execution_state[dev_name]['off'] == CmdExecState.RUNNING: + self._se_state[dev_name] = tango.DevState.OFF + # update the State and healthState of the CSP Element + self._update_csp_state() + log_msg = item.reason + ": on attribute " + str(evt.attr_name) + self.logger.warn(log_msg) + + def _attributes_change_evt_cb(self, evt): + """ + Class callback function. + Retrieve the value of the sub-element xxxCommandProgress and xxxcmdTimeoutExpired + attributes subscribed for change event when a long-running command is issued + on the sub-element device. + + :param evt: The event data + + :return: None + """ + dev_name = evt.device.dev_name() + if not evt.err: + try: + if "commandprogress" == evt.attr_value.name.lower()[-15:]: + if dev_name in self._se_fqdn: + # get the command name (on/off/standby) from the attribute name + # (onCommandProgress/offCommandProgress/standbyCommandProgress)) + # removing the last 15 chars + cmd_name = evt.attr_value.name[:-15] + self._se_cmd_progress[dev_name][cmd_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "oncmdtimeoutexpired": + self._se_timeout_expired[dev_name]['on'] = True + elif evt.attr_value.name.lower() == "offcmdtimeoutexpired": + self._se_timeout_expired[dev_name]['off'] = True + elif evt.attr_value.name.lower() == "standbycmdtimeoutexpired": + self._se_timeout_expired[dev_name]['standby'] = True + else: + log_msg = ("Unexpected change event for" + " attribute: {}".format(str(evt.attr_name))) + self.logger.warn(log_msg) + return + + log_msg = "New value for {} is {}".format(str(evt.attr_name), + str(evt.attr_value.value)) + self.logger.info(log_msg) + except tango.DevFailed as df: + self.logger.error(str(df.args[0].desc)) + except Exception as except_occurred: + self.logger.error(str(except_occurred)) + else: + for item in evt.errors: + log_msg = item.reason + ": on attribute " + str(evt.attr_name) + self.logger.warn(log_msg) + + def _cmd_ended_cb(self, evt): + """ + Callback function immediately executed when the asynchronous invoked + command returns. + + :param evt: a CmdDoneEvent object. This class is used to pass data + to the callback method in asynchronous callback model for command + execution. + :type: CmdDoneEvent object + It has the following members: + - device : (DeviceProxy) The DeviceProxy object on which the + call was executed. + - cmd_name : (str) The command name + - argout_raw : (DeviceData) The command argout + - argout : The command argout + - err : (bool) A boolean flag set to true if the command + failed. False otherwise + - errors : (sequence) The error stack + - ext + :return: none + """ + # NOTE:if we try to access to evt.cmd_name or other paramters, sometime + # the callback crashes with this error: + # terminate called after throwing an instance of 'boost::python::error_already_set' + try: + # Can happen evt empty?? + if evt: + if not evt.err: + msg = "Device {} is processing command {}".format(evt.device, + evt.cmd_name) + self.logger.info(msg) + else: + msg = "Error!!Command {} ended on device {}.\n".format(evt.cmd_name, + evt.device.dev_name()) + msg += " Desc: {}".format(evt.errors[0].desc) + self.logger.error(msg) + self._se_cmd_execution_state[evt.device.dev_name()][evt.cmd_name.lower()] = CmdExecState.FAILED + self._alarm_message[evt.cmd_name] = msg + # obsState and obsMode values take on the CbfSubarray's values via + # the subscribe/publish mechanism + else: + self.logger.error("cmd_ended callback: evt is empty!!") + except tango.DevFailed as df: + msg = ("CommandCallback cmd_ended failure - desc: {}" + " reason: {}".format(df.args[0].desc, df.args[0].reason)) + self.logger.error(msg) + except Exception as ex: + msg = "CommandCallBack cmd_ended general exception: {}".format(str(ex)) + self.logger.error(msg) + + # --------------- + # Class methods + # --------------- + + def _update_csp_state(self): + """ + Class method. + Retrieve the *State* attribute value of the CBF sub-element and build up + the CSP global state: only if CBF sub-element is present CSP can work. + The *State* of of PSS and PST sub-elements (if ONLINE/MAINTENANCE) only + contributes to determine the CSP *healthState* + + :param: None + + :return: None + """ + self._update_csp_health_state() + self.set_state(self._se_state[self.CspCbf]) + if self._admin_mode in [AdminMode.OFFLINE, AdminMode.NOTFITTED, AdminMode.RESERVED]: + self.set_state(tango.DevState.DISABLE) + + def _update_csp_health_state(self): + """ + Class method. + Retrieve the *healthState* and *adminMode* attributes of the CSP + sub-elements and aggregate them to build up the CSP *healthState*. + + :param: None + + :return: None + """ + + # The whole CSP HealthState is OK only if: + # - all sub-elements with adminMode ON-LINE or MAINTENACE are ON AND + # - each sub-element HealthState is OK + + # default value to DEGRADED + self._health_state = HealthState.DEGRADED + # build the list of all the sub-elements ONLINE/MAINTENANCE + admin_fqdn = [fqdn for fqdn, admin_value in self._se_admin_mode.items() + if admin_value in [AdminMode.ONLINE, AdminMode.MAINTENANCE]] + # build the list of sub-elements with State ON/STANDBY and ONLINE/MAINTENANCE + state_fqdn = [fqdn for fqdn in admin_fqdn if self._se_state[fqdn] in [tango.DevState.ON, + tango.DevState.STANDBY]] + # build the list with the healthState of ONLINE/MAINTENANCE devices + health_list = [self._se_health_state[fqdn] for fqdn in state_fqdn] + + if self.CspCbf in admin_fqdn: + if all(value == HealthState.OK for value in health_list): + self._health_state = HealthState.OK + elif self._se_health_state[self.CspCbf] in [HealthState.FAILED, + HealthState.UNKNOWN, + HealthState.DEGRADED]: + self._health_state = self._se_health_state[self.CspCbf] + else: + # if CBF is not ONLINE/MAINTENANCE .... + self._health_state = self._se_health_state[self.CspCbf] + return + + def _connect_to_subelements (self): + """ + Class method. + Establish a *stateless* connection with each CSP sub-element and + subscribe for the sub-element SCM attributes. + + :return: None + """ + for fqdn in self._se_fqdn: + try: + # DeviceProxy to sub-elements + log_msg = "Trying connection to" + str(fqdn) + " device" + self.logger.info(log_msg) + device_proxy = DeviceProxy(fqdn) + #device_proxy.ping() + # Note: ping() method is not called. The DeviceProxy is initialized even if the + # sub-element is not running (but defined into the TANGO DB!). + # The connection with a sub-element is establish as soon as the corresponding + # Master device starts. + + # store the sub-element proxies + self._se_proxies[fqdn] = device_proxy + # subscription of SCM attributes (State, healthState and adminMode). + # Note: subscription is performed also for devices not ONLINE/MAINTENANCE. + # In this way the CspMaster is able to detect a change in the admin value. + + + ev_id = device_proxy.subscribe_event("adminMode", + EventType.CHANGE_EVENT, + self._se_scm_change_event_cb, + stateless=True) + self._se_event_id[fqdn]['adminMode'] = ev_id + + ev_id = device_proxy.subscribe_event("State", + EventType.CHANGE_EVENT, + self._se_scm_change_event_cb, + stateless=True) + self._se_event_id[fqdn]['state'] = ev_id + + ev_id = device_proxy.subscribe_event("healthState", + EventType.CHANGE_EVENT, + self._se_scm_change_event_cb, + stateless=True) + self._se_event_id[fqdn]['healthState'] = ev_id + except KeyError as key_err: + log_msg = ("No key {} found".format(str(key_err))) + self.logger.warn(log_msg) + except tango.DevFailed as df: + #for item in df.args: + log_msg = ("Failure in connection to {}" + " device: {}".format(str(fqdn), str(df.args[0].desc))) + self.logger.error(log_msg) + + def _is_device_running(self, device_fqdn, proxy_list=None): + """ + *Class method.* + + Check if a TANGO device is exported in the TANGO DB (i.e its TANGO + device server is running). + + :param: device_fqdn : the FQDN of the sub-element + :type: `DevString` + :param proxy_list: the list with the proxies for the device + :type: list of TANGO proxies + :return: True if the connection with the subarray is established, + False otherwise + """ + if not proxy_list: + return False + try: + proxy = proxy_list[device_fqdn] + # ping the device to control if is alive + proxy.ping() + except KeyError as key_err: + # Raised when a mapping (dictionary) key is not found in the set + # of existing keys. + # no proxy registered for the subelement device + msg = "Can't retrieve the information of key {}".format(key_err) + self.logger.error(msg) + return False + except tango.DevFailed: + return False + return True + + def _issue_power_command(self, device_list, **args_dict): + """ + Target function called when the power command threads start. + The *On*, *Standby* and *Off* methods issue the command on the sub-element + devices in a separate thread. + The target function accepts as input arguments the command to execute and + the list of devices to command. + + :param device_list: tuple with the FQDN of the sub-element devices + args_dict: dictionary with information about the command to execute. + The dictionary keys are: + - cmd_name : the TANGO command name to execute + - attr_name: the corresponding command progress attribute to subscribe + - dev_state: the expected end state for the device transition + """ + #TODO: order the list alphabetically so that the CBF is always the first element to start + # the TANGO command to execute + tango_cmd_name = 0 + # the sub-element device state after successful transition + dev_successful_state = 0 + try: + tango_cmd_name = args_dict['cmd_name'] + dev_successful_state = args_dict['dev_state'] + except KeyError as key_err: + self.logger.warn("No key: {}".format(str(key_err))) + # reset the CSP and sub-element running flags + self._cmd_execution_state = CmdExecState.IDLE + for device in device_list: + for k, _ in self._se_cmd_execution_state[device].values(): + self._se_cmd_execution_state[device][k] = CmdExecState.IDLE + return + # tango_cmd_name: is the TANGO command name with the capital letter + # In the dictionary keys, is generally used the command name in lower letters + cmd_name = tango_cmd_name.lower() + self.logger.debug("cmd_name: {} dev_state: {}".format(cmd_name, + dev_successful_state)) + num_of_failed_device = 0 + self._num_dev_completed_task[cmd_name] = 0 + self._list_dev_completed_task[cmd_name] = [] + self._cmd_progress[cmd_name] = 0 + self._cmd_duration_measured[cmd_name] = 0 + self._alarm_message[cmd_name] = '' + # sub-element command execution measured time + se_cmd_duration_measured = defaultdict(lambda:defaultdict(lambda:0)) + # loop on the devices and power-on them sequentially + for device in device_list: + # set the sub-element command execution flag + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.RUNNING + se_cmd_duration_measured[device][cmd_name] = 0 + self._se_cmd_progress[device][cmd_name] = 0 + + try: + device_proxy = self._se_proxies[device] + self.logger.debug("Issue asynch command {} on device {}:".format(cmd_name, device)) + + # Note: when the command ends on the sub-element, the _cmd_ended_cb callback + # is called. This callback sets the sub-element execution state to FAULT if + # an exception is caught during the execution on the sub-element. + # + # !!Note!!: + # If the command is issued while the same command is already running on a + # sub-element, the sub-element should return without throwing any exception + # (see "SKA System Control Guidelines"). + # In this case the current method enters the while loop and the execution of the + # sub-element command is tracked in the right way. + device_proxy.command_inout_asynch(tango_cmd_name, self._cmd_ended_cb) + # register the starting time for the command + self._se_cmd_starting_time[device] = time.time() + # loop on the device until the State changes to ON or a timeout occurred + self.logger.debug("Device {} State {} expected value {}".format(device, self._se_state[device], dev_successful_state)) + command_progress = self._cmd_progress[cmd_name] + while True: + if self._se_state[device] == dev_successful_state: + self.logger.info("Command {} ended with success on device {}.".format(cmd_name, + device)) + self.logger.info("Command {} executed on device {}.".format(cmd_name,device)) + # update the list and number of device that completed the task + self._num_dev_completed_task[cmd_name] += 1 + self._list_dev_completed_task[cmd_name].append(device) + # reset the value of the attribute reporting the execution state of + # the command + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.IDLE + + self._se_cmd_progress[device][cmd_name] = 100 + # command success: exit from the wait loop and issue the command + # on the next device in the list + break + # check for other sub-element FAULT values + if self._se_state[device] == tango.DevState.FAULT: + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.FAILED + self._alarm_message[cmd_name] += ("Device {} is {}".format(device, self.get_status())) + self.logger.warn(self._alarm_message[cmd_name]) + num_of_failed_device += 1 + break + # check if sub-element command ended throwing an exception: in this case the + # 'cmd_ended_cb' callback is invoked. The callback log the exception and + # sets the sub-element execution state to FAILED. + # NOTE: as per the "SKA Control Guidelines", a sub-element shall not throw an + # exception if the sub-element is already in the requested final state or if the + # command is already running. + # A different implementation could cause a wrong behavior of the current function. + if self._se_cmd_execution_state[device][cmd_name] == CmdExecState.FAILED: + # execution ended for this sub-element, skip to the next one + num_of_failed_device += 1 + # skip to next device + break + # check for timeout event. A timeout event can be detected in two ways: + # 1- the sub-element implements the 'onTimeoutExpired' attribute configured + # for change event + # 2- the CspMaster periodically checks the time elapsed from the start + # of the command: if the value is greater than the sub-element expected time + # for command execution, the sub-element command execution state is set + # to TIMEOUT + # Note: the second check, can be useful if the timeout event is not received + # (for example for a temporary connection timeout) + elapsed_time = time.time() - self._se_cmd_starting_time[device] + if (elapsed_time > self._se_cmd_duration_expected[device][cmd_name] or + self._se_cmd_execution_state[device][cmd_name] == CmdExecState.TIMEOUT): + msg = ("Timeout executing {} command on device {}".format(cmd_name, device)) + self.logger.warn(msg) + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.TIMEOUT + num_of_failed_device += 1 + # if the CBF command timeout expires, the CSP power-on is stopped + # TODO: verify if this behavior conflicts with ICD + self.logger.debug("elapsed_time:{} device {}".format(elapsed_time, device)) + if device == self.CspCbf: + self.logger.error("CBF Timeout during power-on!!! Exit") + self._timeout_expired[cmd_name] = True + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.IDLE + self._timeout_expired[cmd_name] = True + self._cmd_execution_state[cmd_name] = CmdExecState.IDLE + return + # timeout on the sub-element, skip to the next device + break + time.sleep(1) + # update the progress counter inside the loop taking into account the number of devices + # executing the command + self._cmd_progress[cmd_name] = command_progress + self._se_cmd_progress[device][cmd_name]/len(device_list) + # end of the while loop + # calculate the real execution time for the command + se_cmd_duration_measured[device][cmd_name] = (time.time() + - self._se_cmd_starting_time[device]) + self.logger.info("measured duration:{}".format(se_cmd_duration_measured[device][cmd_name])) + self._cmd_duration_measured[cmd_name] += se_cmd_duration_measured[device][cmd_name] + # update the progress counter at the end of the loop + self._cmd_progress[cmd_name] = command_progress + (self._se_cmd_progress[device][cmd_name]/len(device_list)) + if len(device_list) == self._num_dev_completed_task[cmd_name] + num_of_failed_device: + self.logger.info("All devices have been handled!") + # end of the command: the command has been issued on all the sub-element devices + # reset the execution flag for the CSP + break + except KeyError as key_err: + msg = "No key {} found".format(str(key_err)) + self.logger.warn(msg) + except tango.DevFailed as df: + # It should not happen! Verify + msg = "Failure reason: {} Desc: {}".format(str(df.args[0].reason), str(df.args[0].desc)) + self.logger.warn(msg) + # out of the for loop + # reset the CSP command execution flag + self._cmd_execution_state[cmd_name] = CmdExecState.IDLE + self._last_executed_command = cmd_name + # if one or more sub-elements goes in timeout or alarm, set the CSP + # corresponding attribute + for device in device_list: + # reset the CSP sub-element command execution flag + if self._se_cmd_execution_state[device][cmd_name] == CmdExecState.TIMEOUT: + # set the CSP timeout flag + self._timeout_expired[cmd_name] = True + if self._se_cmd_execution_state[device][cmd_name] == CmdExecState.FAILED: + # set the CSP timeout flag + self._alarm_raised[cmd_name] = True + # reset the CSP sub-element command execution flag + self._se_cmd_execution_state[device][cmd_name] = CmdExecState.IDLE + + def _se_write_adminMode(self, value, device_fqdn): + """ + *Class method.* + + Set the administrative mode of the specified device. + :param: subelement_name : the FQDN of the sub-element + :type: `DevString` + :return: True if the connection with the subarray is established, + False otherwise + """ + # check if the device is exported in the TANGO DB (that is the server is running) + if value not in [AdminMode.ONLINE, AdminMode.MAINTENANCE, AdminMode.OFFLINE, + AdminMode.NOTFITTED, AdminMode.RESERVED]: + msg = "Invalid {} value for adminMode attribute".format(value) + tango.Except.throw_exception("Command failed", + msg, + "write_adminMode", + tango.ErrSeverity.ERR) + # check if the sub-element administrative mode has already the requested value + if value == self._se_admin_mode[device_fqdn]: + return + if self._is_device_running(device_fqdn, self._se_proxies): + try: + proxy = self._se_proxies[device_fqdn] + proxy.write_attribute_asynch('adminMode', value) + # TODO: add checks for timeout/errors + except KeyError as key_err: + msg = "Can't retrieve the information of key {}".format(key_err) + self.logger.error(msg) + tango.Except.throw_exception("DevFailed excpetion", msg, + "write adminMode", tango.ErrSeverity.ERR) + def _connect_capabilities_monitor(self): + """ + """ + # build the list with the Capability monitor devices + self._capability_fqdn = [self.SearchBeamsMonitor, + self.TimingBeamsMonitor, + self.VlbiBeamsMonitor] + for fqdn in self._capability_fqdn: + try: + self._capability_proxy[fqdn] = tango.DeviceProxy(fqdn) + except tango.Except as tango_err: + self.logger.warn(tango_err.args[0].desc) + + +# PROTECTED REGION END # // CspMaster.class_protected_methods + # ----------------- + # Device Properties + # ----------------- + + CspCbf = device_property( + dtype='DevString', + ) + + CspPss = device_property( + dtype='DevString', + ) + + CspPst = device_property( + dtype='DevString', + ) + + CspSubarrays = device_property( + dtype='DevVarStringArray', + ) + + SearchBeams = device_property( + dtype='DevVarStringArray', + ) + + TimingBeams = device_property( + dtype='DevVarStringArray', + ) + + VlbiBeams = device_property( + dtype='DevVarStringArray', + ) + + SearchBeamsMonitor = device_property( + dtype='DevString', + ) + + TimingBeamsMonitor = device_property( + dtype='DevString', + ) + + VlbiBeamsMonitor = device_property( + dtype='DevString', + ) + + # ---------- + # Attributes + # ---------- + + adminMode = attribute( + dtype='DevEnum', + access=AttrWriteType.READ_WRITE, + polling_period=1000, + memorized=True, + doc= ("The admin mode reported for this device. It may interpret the" + "current device condition and condition of all managed devices" + "to set this. Most possibly an aggregate attribute."), + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED", ], + + ) + + onCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the On command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc=("Percentage progress implemented for commands that result in state/mode" + "transitions for a large \nnumber of components and/or are executed in " + "stages (e.g power up, power down)"), + ) + + offCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the Off command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc=("Percentage progress implemented for commands that result in state/mode" + " transitions for a large \nnumber of components and/or are executed in " + "stages (e.g power up, power down)"), + ) + + standbyCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the Standby command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc=("Percentage progress implemented for commands that result in state/mode " + "transitions for a large \nnumber of components and/or are executed in " + "stages (e.g power up, power down)"), + ) + + onCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the On command execution", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc=("Set/Report the duration expected (in sec.) for the On command execution"), + ) + + offCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the Off command", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc=("Set/Report the duration expected (in sec.) for the Off command execution"), + ) + + standbyCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the Standby command", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc=("Set/Report the duration expected (in sec.) for the Standby command"), + ) + + onCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the On command execution", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + doc=("Report the measured duration (in sec.) of the On command execution"), + ) + + offCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the Off command", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + doc=("Report the measured duration (in sec.) of the Off command execution"), + ) + + standbyCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the Standby command", + polling_period=3000, + abs_change=0, + max_value=100, + min_value=0, + doc=("Report the measured duration (in sec.) of the Standby command"), + ) + + onCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="CBF command timeout flag", + polling_period=2000, + doc=("Signal the occurence of a timeout during the execution of commands on" + " CBF Sub-element"), + ) + + offCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="PSS command timeout flag", + polling_period=2000, + doc=("Signal the occurence of a timeout during the execution of commands on " + "PSS Sub-element"), + ) + + standbyCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="PST command timeout flag", + polling_period=2000, + doc=("Signal the occurence of a timeout during the execution of commands on" + " PST Sub-element"), + ) + + cspCbfState = attribute( + dtype='DevState', + label="CBF status", + polling_period=3000, + doc=("The CBF sub-element Device State. Allowed values are ON, STANDBY, OFF, " + "DISABLE, ALARM, FAULT, UNKNOWN"), + ) + + cspPssState = attribute( + dtype='DevState', + label="PSS status", + polling_period=3000, + doc=("The PSS sub-element Device State. Allowed values are ON, STANDBY, OFF," + " DISABLE, ALARM, FAULT, UNKNOWN"), + ) + + cspPstState = attribute( + dtype='DevState', + label="PST status", + polling_period=3000, + doc=("The PST sub-element Device State. Allowed values are ON, STANDBY,OFF," + " DISABLE, ALARM, FAULT, UNKNOWN"), + ) + + cspCbfHealthState = attribute( + dtype='DevEnum', + label="CBF Health status", + polling_period=3000, + abs_change=1, + doc="The CBF sub-element healthState.", + enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], + ) + + cspPssHealthState = attribute( + dtype='DevEnum', + label="PSS Health status", + polling_period=3000, + abs_change=1, + doc="The PSS sub-element healthState", + enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], + ) + + cspPstHealthState = attribute( + dtype='DevEnum', + label="PST health status", + polling_period=3000, + abs_change=1, + doc="The PST sub-element healthState.", + enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], + ) + + cbfMasterAddress = attribute( + dtype='DevString', + doc="TANGO FQDN of the CBF sub-element Master", + ) + + pssMasterAddress = attribute( + dtype='DevString', + doc="TANGO FQDN of the PSS sub-element Master", + ) + + pstMasterAddress = attribute( + dtype='DevString', + doc="TANGO FQDN of the PST sub-element Master", + ) + + cspCbfAdminMode = attribute( + dtype='DevEnum', + access=AttrWriteType.READ_WRITE, + label="CBF administrative Mode", + polling_period=3000, + abs_change=1, + doc=("The CBF sub-lement adminMode. Allowed values are ON-LINE, " + "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED"), + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED", ], + ) + + cspPssAdminMode = attribute( + dtype='DevEnum', + access=AttrWriteType.READ_WRITE, + label="PSS administrative mode", + polling_period=3000, + abs_change=1, + doc=("The PSS sub-lement adminMode. Allowed values are ON-LINE, " + "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED"), + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED", ], + ) + + cspPstAdminMode = attribute( + dtype='DevEnum', + access=AttrWriteType.READ_WRITE, + label="PST administrative mode", + polling_period=3000, + abs_change=1, + doc=("The PST sub-lement adminMode. Allowed values are ON-LINE, " + "MAINTENANCE, OFF-LINE, NOT-FITTED, RESERVED"), + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED", ], + ) + + numOfDevCompletedTask = attribute( + dtype='DevUShort', + label="Number of devices that completed the task", + doc="Number of devices that completed the task", + ) + + onCmdAlarm = attribute( + dtype='DevBoolean', + label="CBF command alarm flag", + polling_period=1000, + doc="Alarm flag set when the On command fails with error(s).", + ) + + onAlarmMessage = attribute( + dtype='DevString', + label="On execution alarm message", + doc="Alarm message when the On command fails with error(s).", + ) + + offCmdAlarm = attribute( + dtype='DevBoolean', + label="Off execution alarm flag", + polling_period=1000, + doc="Alarm flag set when the Off command fails with error(s).", + ) + + offAlarmMessage = attribute( + dtype='DevString', + label="Off execution alarm message", + doc="Alarm message when the Off command fails with error(s).", + ) + + standbyCmdAlarm = attribute( + dtype='DevBoolean', + label="Standby execution alarm message", + polling_period=1000, + doc="Alarm flag set when the Standby command fails with error(s).", + ) + + standbyAlarmMessage = attribute( + dtype='DevString', + label="Standby execution alarm message", + doc="Alarm message when the Standby command fails with error(s).", + ) + + reportSearchBeamState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="SearchBeam Capabilities State", + doc="Report the state of the SearchBeam Capabilities as an array of DevState.", + ) + + reportSearchBeamHealthState = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + label="SearchBeam Capabilities healthState", + abs_change=1, + doc=("Report the health state of the SearchBeam Capabilities as an array" + " of unsigned short. For ex`: [0,0,...,1..]`"), + ) + + reportSearchBeamAdminMode = attribute( + dtype=('DevUShort',), + access=AttrWriteType.READ_WRITE, + max_dim_x=1500, + label="SearchBeam Capabilities adminMode", + abs_change=1, + doc=("Report the administrative mode of the SearchBeam Capabilities as an" + " array of unsigned short. For ex `:[0,0,0,...2..]`"), + ) + + reportTimingBeamState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="TimingBeam Capabilities State", + doc="Report the state of the TimingBeam Capabilities as an array of DevState.", + ) + + reportTimingBeamHealthState = attribute( + dtype=('DevUShort',), + max_dim_x=16, + label="TimingBeam Capabilities healthState", + abs_change=1, + doc=("Report the health state of the TimingBeam Capabilities as an array of" + " unsigned short. For ex [0,0,...,1..]"), + ) + + reportTimingBeamAdminMode = attribute( + dtype=('DevUShort',), + access=AttrWriteType.READ_WRITE, + max_dim_x=16, + label="TimingBeam Capabilities adminMode", + abs_change=1, + doc=("Report the administrativw mode of the TimingBeam Capabilities as an" + " array of unsigned short. For ex [0,0,0,...2..]"), + ) + + reportVlbiBeamState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="VlbiBeam Capabilities State", + doc="Report the state of the VLBIBeam Capabilities as an array of DevState.", + ) + + reportVlbiBeamHealthState = attribute( + dtype=('DevUShort',), + max_dim_x=20, + label="VlbiBeam Capabilities healthState", + abs_change=1, + doc=("Report the health state of the VlbiBeam Capabilities as an array of" + " unsigned short. For ex [0,0,...,1..]"), + ) + + reportVlbiBeamAdminMode = attribute( + dtype=('DevUShort',), + access=AttrWriteType.READ_WRITE, + max_dim_x=20, + label="VlbiBeam Capabilities adminMode", + abs_change=1, + doc=("Report the administrative mode of the VlbiBeam Capabilities as an" + " array of unsigned short. For ex -[0,0,0,...2..]"), + ) + + cspSubarrayAddresses = attribute( + dtype=('DevString',), + max_dim_x=16, + doc="CSPSubarrays FQDN", + ) + + listOfDevCompletedTask = attribute( + dtype=('DevString',), + max_dim_x=100, + label="List of devices that completed the task", + doc="List of devices that completed the task", + ) + 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 + ) + + 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 + ) + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspMaster.""" + SKAMaster.init_device(self) + # PROTECTED REGION ID(CspMaster.init_device) ENABLED START # + self._build_state = '{}, {}, {}'.format(release.name, release.version, release.description) + self._version_id = release.version + # connect to TANGO DB + csp_tango_db = tango.Database() + # read the CSP memorized attributes from the TANGO DB. + # Note: a memorized attribute has defined the attribute + # property '__value' + attribute_properties = csp_tango_db.get_device_attribute_property(self.get_name(), + {'adminMode': ['__value']}) + # set init values for the CSP Element and Sub-element SCM states + self.set_state(tango.DevState.INIT) + self._health_state = HealthState.OK + self._admin_mode = AdminMode.ONLINE + # use defaultdict to initialize the sub-element State,healthState + # and adminMode. The dictionary uses as keys the sub-element + # fqdn, for example + # self._se_state[self.CspCbf] + # return the State value of the Mid Cbf sub-element. + self._se_state = defaultdict(lambda: tango.DevState.DISABLE) + self._se_health_state = defaultdict(lambda: HealthState.UNKNOWN) + self._se_admin_mode = defaultdict(lambda: AdminMode.NOTFITTED) + + # build a dictionary with the (attr_name, value) of the memorized attributes + # use memorized atrtibute if present, otherwise the default one + memorized_attr_dict = {attr_name : int(value[0]) for attr_name, db_key in attribute_properties.items() + for key, value in db_key.items() + if key == '__value'} + try: + self._admin_mode = memorized_attr_dict['adminMode'] + if self._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]: + self._health_state = HealthState.UNKNOWN + self.set_state(tango.DevState.DISABLE) + except KeyError as key_err: + self.logger.info("Key {} not found".format(key_err)) + + # initialize list with CSP sub-element FQDNs + self._se_fqdn = [] + # NOTE: + # The normal behavior when a Device Property is created is: + # - a self.Property attribute is created in the Dev_Impl object + # - it takes a value from the Database if it has been defined. + # - if not, it takes the default value assigned in Pogo. + # - if no value is specified nowhere, the attribute is created + # with [] value. + self._se_fqdn.append(self.CspCbf) + self._se_fqdn.append(self.CspPss) + self._se_fqdn.append(self.CspPst) + + # read the sub-elements adminMode (memorized) attributes from + # the TANGO DB. + # Note: a memorized attribute has defined the attribute property '__value' + for fqdn in self._se_fqdn: + attribute_properties = csp_tango_db.get_device_attribute_property(fqdn, + {'adminMode': ['__value']}) + self.logger.debug("fqdn: {} attribute_properties: {}".format(fqdn, attribute_properties)) + try: + admin_mode_memorized = attribute_properties['adminMode']['__value'] + self._se_admin_mode[fqdn] = int(admin_mode_memorized[0]) + except KeyError as key_err: + msg = ("No key {} found for sub-element {}" + " adminMode attribute".format(key_err, fqdn)) + self.logger.info(msg) + + # _se_proxies: the sub-element proxies + # implemented as dictionary: + # keys: sub-element FQDN + # values: device proxy + self._se_proxies = {} + + # Nested default dictionary with list of event ids/sub-element. Need to + # store the event ids for each sub-element and attribute to un-subscribe + # them at sub-element disconnection. + # keys: sub-element FQDN + # values: dictionary (keys: attribute name, values: event id) + self._se_event_id = defaultdict(lambda: defaultdict(lambda: 0)) + + # _se_cmd_execution_state: implement the execution state of a long-running + # command for each sub-element. + # implemented as a nested default dictionary: + # keys: sub-element FQDN + # values: defaut dictionary (keys: command name, values: command state) + self._se_cmd_execution_state = defaultdict(lambda: defaultdict(lambda: CmdExecState.IDLE)) + + # _cmd_execution_state: implement the execution state of a long-running + # command for the whole CSP. Setting this attribute prevent the execution + # of the same command while it is already running. + # implemented as a default dictionary: + # keys: command name + # values:command state + self._cmd_execution_state = defaultdict(lambda: CmdExecState.IDLE) + + # _se_cmd_starting_time: for each sub-element report the long-running command + # starting time + # Implemented as dictionary: + # keys: the sub-element FQDN + # values: starting time + self._se_cmd_starting_time = defaultdict(lambda: 0.0) + + # _command_thread: thread for the command execution + # keys: the command name('on, 'off'...) + # values: thread instance + self._command_thread = {} + + # _se_cmd_progress: for each sub-element report the execution progress + # of a long-running command + # implemented as a default nested dictionary: + # keys: sub-element FQDN + # values: default dictionary (keys: command name, values: the execution percentage) + self._se_cmd_progress = defaultdict(lambda: defaultdict(lambda: 0)) + + # _cmd_progress: report the execution progress of a long-running command + # implemented as a dictionary: + # keys: command name ('on', 'off'..) + # values: the percentage + self._cmd_progress = defaultdict(lambda: 0) + + # _se_cmd_duration_expected: for each sub-element, store the duration (in sec.) + # configured for a long-running command + # Implemented as a nested default dictionary + # keys: FQDN + # values: default dictionary (keys: command name, values: the duration (in sec)) + self._se_cmd_duration_expected = defaultdict(lambda: defaultdict(lambda: 20)) + + # _cmd_duration_expected: store the duration (in sec.) configured for + # a long-running command + # Implemented asdefault dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_expected = defaultdict(lambda: 30) + + # _cmd_duration_measured: report the measured duration (in sec.) for + # a long-running command + # Implemented as default dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_measured = defaultdict(lambda: 0) + + # _timeout_expired: report the timeout flag + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: True/False + self._timeout_expired = defaultdict(lambda: False) + + # _alarm_raised: report the alarm flag + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: True/False + self._alarm_raised = defaultdict(lambda: False) + + # _alarm_message: report the alarm message + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: the message + self._alarm_message = defaultdict(lambda: '') + + # _list_dev_completed_task: for each long-running command report the list of subordinate + # components that completed the task + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the list of components + self._list_dev_completed_task = defaultdict(lambda: []) + # the last executed command + self._last_executed_command = "" + + # _num_dev_completed_task: for each long-running command report the number + # of subordinate components that completed the task + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the number of components + self._num_dev_completed_task = defaultdict(lambda:0) + + # _capability_proxy: dictionary + # keys: the Capability Monitor devices FQDNs + # values: DeviceProxy proxies + self._capability_proxy = {} + # Try connection with sub-elements + self._connect_to_subelements() + # start CSP Capbilities monitoring + self._connect_capabilities_monitor() + + # 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) + # PROTECTED REGION END # // CspMaster.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspMaster.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspMaster.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(CspMaster.delete_device) ENABLED START # + event_to_remove = {} + for fqdn in self._se_fqdn: + try: + event_to_remove[fqdn] = [] + for attr_name, event_id in self._se_event_id[fqdn].items(): + try: + # need to check the event_id value because with the use of defaultdict + # it may happen that a dictionary entry is = 0 (default ditionary value) + if event_id: + self._se_proxies[fqdn].unsubscribe_event(event_id) + event_to_remove[fqdn].append(attr_name) + # NOTE: in tango unsubscription of not-existing event + # id raises a KeyError exception not a DevFailed !! + except KeyError as key_err: + msg = ("Failure unsubscribing event {} " + "on device {}. Reason: {}".format(event_id, + fqdn, + key_err)) + self.logger.error(msg) + # remove the attribute entry from the fqdn dictionary + for attr_name in event_to_remove[fqdn]: + del self._se_event_id[fqdn][attr_name] + # check if there are still some registered events. + if not self._se_event_id[fqdn]: + # remove the dictionary element when the fqdn dictionary is + # empty + self._se_event_id.pop(fqdn) + else: + # What to do in this case??. Only log (for the moment) + msg = "Still subscribed events: {}".format(self._se_event_id) + self.logger.warn(msg) + except KeyError as key_err: + msg = " Can't retrieve the information of key {}".format(key_err) + self.logger.error(msg) + continue + # clear any list and dict + self._se_fqdn.clear() + self._se_proxies.clear() + # PROTECTED REGION END # // CspMaster.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_adminMode(self): + # PROTECTED REGION ID(CspMaster.adminMode_read) ENABLED START # + """Return the adminMode attribute.""" + return self._admin_mode + # PROTECTED REGION END # // CspMaster.adminMode_read + + def write_adminMode(self, value): + # PROTECTED REGION ID(CspMaster.adminMode_write) ENABLED START # + """ + Write attribute method. + + Set the administration mode for the whole CSP element. + + :param argin: + value: one of the administration mode value (ON-LINE,\ + OFF-LINE, MAINTENANCE, NOT-FITTED, RESERVED). + :type: DevEnum + :return: None + """ + # PROTECTED REGION ID(CspMaster.adminMode_write) ENABLED START # + for fqdn in self._se_fqdn: + try: + self._se_write_adminMode(value, fqdn) + except tango.DevFailed as df: + + log_msg = (("Failure in setting adminMode " + "for device {}: {}".format(str(fqdn), + str(df.args[0].reason)))) + self.logger.error(log_msg) + #TODO: what happens if one sub-element fails? + # add check on timeout command execution + self._admin_mode = value + if self._admin_mode in [AdminMode.OFFLINE, AdminMode.NOTFITTED, AdminMode.RESERVED]: + self.set_state(tango.DevState.DISABLE) + else: + if self.get_state() == tango.DevState.DISABLE: + #STANDBY or ON how can be determined?? + self.set_state(tango.DevState.STANDBY) + # PROTECTED REGION END # // CspMaster.adminMode_write + + def read_onCommandProgress(self): + # PROTECTED REGION ID(CspMaster.onCommandProgress_read) ENABLED START # + """Return the onCommandProgress attribute.""" + return int(self._cmd_progress['on']) + # PROTECTED REGION END # // CspMaster.onCommandProgress_read + + def read_offCommandProgress(self): + # PROTECTED REGION ID(CspMaster.offCommandProgress_read) ENABLED START # + """Return the offCommandProgress attribute.""" + return int(self._cmd_progress['off']) + # PROTECTED REGION END # // CspMaster.offCommandProgress_read + + def read_standbyCommandProgress(self): + # PROTECTED REGION ID(CspMaster.standbyCommandProgress_read) ENABLED START # + """Return the standbyCommandProgress attribute.""" + return int(self._cmd_progress['standby']) + # PROTECTED REGION END # // CspMaster.standbyCommandProgress_read + + def read_onCmdDurationExpected(self): + # PROTECTED REGION ID(CspMaster.onCmdDurationExpected_read) ENABLED START # + """Return the onCmdDurationExpected attribute.""" + return self._cmd_duration_expected['on'] + # PROTECTED REGION END # // CspMaster.onCmdDurationExpected_read + + def write_onCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspMaster.onCmdDurationExpected_write) ENABLED START # + """Set the onCmdDurationExpected attribute.""" + self._cmd_duration_expected['on'] = value + # PROTECTED REGION END # // CspMaster.onCmdDurationExpected_write + + def read_offCmdDurationExpected(self): + # PROTECTED REGION ID(CspMaster.offCmdDurationExpected_read) ENABLED START # + """Return the offCmdDurationExpected attribute.""" + return self._cmd_duration_expected['off'] + # PROTECTED REGION END # // CspMaster.offCmdDurationExpected_read + + def write_offCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspMaster.offCmdDurationExpected_write) ENABLED START # + """Set the offCmdDurationExpected attribute.""" + self._cmd_duration_expected['off'] = value + # PROTECTED REGION END # // CspMaster.offCmdDurationExpected_write + + def read_standbyCmdDurationExpected(self): + # PROTECTED REGION ID(CspMaster.standbyCmdDurationExpected_read) ENABLED START # + """Return the standbyCmdDurationExpected attribute.""" + return self._cmd_duration_expected['standby'] + # PROTECTED REGION END # // CspMaster.standbyCmdDurationExpected_read + + def write_standbyCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspMaster.standbyCmdDurationExpected_write) ENABLED START # + """Set the standbyCmdDurationExpected attribute.""" + self._cmd_duration_expected['standby'] = value + # PROTECTED REGION END # // CspMaster.standbyCmdDurationExpected_write + + def read_onCmdDurationMeasured(self): + # PROTECTED REGION ID(CspMaster.onCmdDurationMeasured_read) ENABLED START # + """Return the onCmdDurationMeasured attribute.""" + return int(self._cmd_duration_measured['on']) + # PROTECTED REGION END # // CspMaster.onCmdDurationMeasured_read + + def read_offCmdDurationMeasured(self): + # PROTECTED REGION ID(CspMaster.offCmdDurationMeasured_read) ENABLED START # + """Return the offCmdDurationMeasured attribute.""" + return int(self._cmd_duration_measured['off']) + # PROTECTED REGION END # // CspMaster.offCmdDurationMeasured_read + + def read_standbyCmdDurationMeasured(self): + # PROTECTED REGION ID(CspMaster.standbyCmdDurationMeasured_read) ENABLED START # + """Return the standbyCmdDurationMeasured attribute.""" + return int(self._cmd_duration_measured['standby']) + # PROTECTED REGION END # // CspMaster.standbyCmdDurationMeasured_read + + def read_onCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspMaster.onCmdTimeoutExpired_read) ENABLED START # + """Return the onCmdTimeoutExpired attribute.""" + return self._timeout_expired['on'] + # PROTECTED REGION END # // CspMaster.cbfOnCmdTimeoutExpired_read + + def read_offCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspMaster.pssOnCmdTimeoutExpired_read) ENABLED START # + """Return the offCmdTimeoutExpired attribute.""" + return self._timeout_expired['off'] + # PROTECTED REGION END # // CspMaster.pssOnCmdTimeoutExpired_read + + def read_standbyCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspMaster.standbyCmdTimeoutExpired_read) ENABLED START # + """Return the standbyCmdTimeoutExpired attribute.""" + return self._timeout_expired['standby'] + # PROTECTED REGION END # // CspMaster.standbyCmdTimeoutExpired_read + + def read_cspCbfState(self): + # PROTECTED REGION ID(CspMaster.cspCbfState_read) ENABLED START # + """Return the cspCbfState attribute.""" + return self._se_state[self.CspCbf] + # PROTECTED REGION END # // CspMaster.cspCbfState_read + + def read_cspPssState(self): + # PROTECTED REGION ID(CspMaster.cspPssState_read) ENABLED START # + """Return the cspPssState attribute.""" + return self._se_state[self.CspPss] + # PROTECTED REGION END # // CspMaster.cspPssState_read + + def read_cspPstState(self): + # PROTECTED REGION ID(CspMaster.cspPstState_read) ENABLED START # + """Return the cspPstState attribute.""" + return self._se_state[self.CspPst] + # PROTECTED REGION END # // CspMaster.cspPstState_read + + def read_cspCbfHealthState(self): + # PROTECTED REGION ID(CspMaster.cspCbfHealthState_read) ENABLED START # + """Return the cspCbfHealthState attribute.""" + return self._se_health_state[self.CspCbf] + # PROTECTED REGION END # // CspMaster.cspCbfHealthState_read + + def read_cspPssHealthState(self): + # PROTECTED REGION ID(CspMaster.cspPssHealthState_read) ENABLED START # + """Return the cspPssHealthState attribute.""" + return self._se_health_state[self.CspPss] + # PROTECTED REGION END # // CspMaster.cspPssHealthState_read + + def read_cspPstHealthState(self): + # PROTECTED REGION ID(CspMaster.cspPstHealthState_read) ENABLED START # + """Return the cspPstHealthState attribute.""" + return self._se_health_state[self.CspPst] + # PROTECTED REGION END # // CspMaster.cspPstHealthState_read + + def read_cbfMasterAddress(self): + # PROTECTED REGION ID(CspMaster.cbfMasterAddress_read) ENABLED START # + """Return the cbfMasterAddress attribute.""" + return self.CspCbf + # PROTECTED REGION END # // CspMaster.cbfMasterAddress_read + + def read_pssMasterAddress(self): + # PROTECTED REGION ID(CspMaster.pssMasterAddress_read) ENABLED START # + """Return the pssMasterAddress attribute.""" + return self.CspPss + # PROTECTED REGION END # // CspMaster.pssMasterAddress_read + + def read_pstMasterAddress(self): + # PROTECTED REGION ID(CspMaster.pstMasterAddress_read) ENABLED START # + """Return the pstMasterAddress attribute.""" + return self.CspPst + # PROTECTED REGION END # // CspMaster.pstMasterAddress_read + + def read_cspCbfAdminMode(self): + # PROTECTED REGION ID(CspMaster.cspCbfAdminMode_read) ENABLED START # + """Return the cspCbfAdminMode attribute.""" + return self._se_admin_mode[self.CspCbf] + # PROTECTED REGION END # // CspMaster.cspCbfAdminMode_read + + def write_cspCbfAdminMode(self, value): + # PROTECTED REGION ID(CspMaster.cspCbfAdminMode_write) ENABLED START # + """ + Write attribute method + + Set the CBF sub-element *adminMode* attribute value. + + :parameter:value: one of the administration mode value (ON-LINE,\ + OFF-LINE, MAINTENANCE, NOT-FITTED, RESERVED). + :return: None + :raises: tango.DevFailed: raised when there is no DeviceProxy providing interface \ + to the CBF sub-element Master, or an exception is caught in command execution. + """ + self._se_write_adminMode(value, self.CspCbf) + # PROTECTED REGION END # // CspMaster.cspCbfAdminMode_write + + def read_cspPssAdminMode(self): + # PROTECTED REGION ID(CspMaster.cspPssAdminMode_read) ENABLED START # + """Return the cspPssAdminMode attribute.""" + return self._se_admin_mode[self.CspPss] + # PROTECTED REGION END # // CspMaster.cspPssAdminMode_read + + def write_cspPssAdminMode(self, value): + # PROTECTED REGION ID(CspMaster.cspPssAdminMode_write) ENABLED START # + """Set the cspPssAdminMode attribute.""" + self._se_write_adminMode(value, self.CspPss) + # PROTECTED REGION END # // CspMaster.cspPssAdminMode_write + + def read_cspPstAdminMode(self): + # PROTECTED REGION ID(CspMaster.cspPstAdminMode_read) ENABLED START # + """Return the cspPstAdminMode attribute.""" + return self._se_admin_mode[self.CspPst] + # PROTECTED REGION END # // CspMaster.cspPstAdminMode_read + + def write_cspPstAdminMode(self, value): + # PROTECTED REGION ID(CspMaster.cspPstAdminMode_write) ENABLED START # + """Set the cspPstAdminMode attribute.""" + self._se_write_adminMode(value, self.CspPst) + # PROTECTED REGION END # // CspMaster.cspPstAdminMode_write + + def read_numOfDevCompletedTask(self): + # PROTECTED REGION ID(CspMaster.numOfDevCompletedTask_read) ENABLED START # + """Return the numOfDevCompletedTask attribute.""" + if not self._last_executed_command: + return 0 + return self._num_dev_completed_task[self._last_executed_command] + + # PROTECTED REGION END # // CspMaster.numOfDevCompletedTask_read + def read_onCmdAlarm(self): + # PROTECTED REGION ID(CspMaster.onCmdAlarm_read) ENABLED START # + """Return the onCmdAlarm attribute.""" + return self._alarm_raised['on'] + # PROTECTED REGION END # // CspMaster.onCmdAlarm_read + + def read_onAlarmMessage(self): + # PROTECTED REGION ID(CspMaster.onAlarmMessage_read) ENABLED START # + """Return the onAlarmMessage attribute.""" + return self._alarm_message['on'] + # PROTECTED REGION END # // CspMaster.onAlarmMessage_read + + def read_offCmdAlarm(self): + # PROTECTED REGION ID(CspMaster.offCmdAlarm_read) ENABLED START # + """Return the offCmdAlarm attribute.""" + return self._alarm_raised['off'] + # PROTECTED REGION END # // CspMaster.offCmdAlarm_read + + def read_offAlarmMessage(self): + # PROTECTED REGION ID(CspMaster.offAlarmMessage_read) ENABLED START # + """Return the offAlarmMessage attribute.""" + return self._alarm_message['off'] + # PROTECTED REGION END # // CspMaster.offAlarmMessage_read + + def read_standbyCmdAlarm(self): + # PROTECTED REGION ID(CspMaster.standbyCmdAlarm_read) ENABLED START # + """Return the standbyCmdAlarm attribute.""" + return self._alarm_raised['standby'] + # PROTECTED REGION END # // CspMaster.standbyCmdAlarm_read + + def read_standbyAlarmMessage(self): + # PROTECTED REGION ID(CspMaster.standbyAlarmMessage_read) ENABLED START # + """Return the standbyAlarmMessage attribute.""" + return self._alarm_message['standby'] + # PROTECTED REGION END # // CspMaster.standbyAlarmMessage_read + + def read_cspSubarrayAddresses(self): + # PROTECTED REGION ID(CspMaster.cspSubarrayAddresses_read) ENABLED START # + """Return the cspSubarrayAddresses attribute.""" + return self.CspSubarrays + # PROTECTED REGION END # // CspMaster.cspSubarrayAddresses_read + def read_listOfDevCompletedTask(self): + # PROTECTED REGION ID(CspMaster.listOfDevCompletedTask_read) ENABLED START # + """Return the listOfDevCompletedTask attribute.""" + #TO IMPLEMENT + # report the list of the devices that completed the last executed task + if not self._last_executed_command: + return ('',) + return self._list_dev_completed_task[self._last_executed_command] + # PROTECTED REGION END # // CspMaster.listOfDevCompletedTask_read + + # -------- + # Commands + # -------- + @AdminModeCheck('On') + def is_On_allowed(self): + """ + *TANGO is_allowed method* + + Command *On* is allowed when the device *State* is STANDBY. + + Returns: + True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in=("If the array length is 0, the command applies to the whole CSP Element." + " If the array length is > 1, each array element specifies the FQDN of " + "the CSP SubElement to switch ON."), + ) + @DebugIt() + @CmdInputArgsCheck("onCommandProgress", "onCmdTimeoutExpired", cmd_name = "on") + def On(self, argin): + # PROTECTED REGION ID(CspMaster.On) ENABLED START # + """ + *Class TANGO method* + + Switch-on the CSP sub-elements specified by the input argument. If no argument is + specified, the command is issued on all the CSP sub-elements. + The command is executed if the *AdminMode* is ONLINE or *MAINTENANCE*. + If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an + exception. + The CSP.LMC commands sub-element transition from STANDBY to ON sequentially. It + waits for the first sub-element (CBF) to complete the transition, then issues the + command to the second sub-element (e.g. PST), waits for PST to complete and then + issues command for PSS. + Command is forwarded to the sub-element devices specified in the input list, + only if their adminMode is ONLINE or MAINTENANCE. + + :param argin: + The list of sub-element FQDNs to switch-on or an empty list to switch-on the whole + CSP Element. + + If the array length is 0, the command applies to the whole CSP Element. If the + array length is > 1, each array element specifies the FQDN of the + CSP SubElement to switch ON. + :type: 'DevVarStringArray' + :return: None + :raises: *tango.DevFailed* exception when: + - the CSP adminMode is not correct + - one or more sub-element devices are already running a power command + - there is no DeviceProxy providing interface to the CBF sub-element + """ + # the input list after decorator examination + device_list = argin + # invoke the constructor for the command thread. + # The target thread function is common to all the invoked commands. Specifc information + # are passed as arguments of the function + # args: the list of sub-element FQDNS + # args_dict: dictionary with the specific command information + args_dict = {'cmd_name':'On', 'dev_state': tango.DevState.ON} + self._command_thread['on'] = threading.Thread(target=self._issue_power_command, name="Thread-On", + args=(device_list,), + kwargs=args_dict) + # set the CSP command execution running flag + self._cmd_execution_state['on'] = CmdExecState.RUNNING + # start the thread + self._command_thread['on'].start() + # sleep for a while to let the thread start + time.sleep(0.2) + # PROTECTED REGION END # // CspMaster.On + + @AdminModeCheck('Off') + def is_Off_allowed(self): + """ + *TANGO is_allowed method* + + Command *Off* is allowed when the device *State* is STANDBY. + + Returns: + True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.OFF]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in=("If the array length is 0, the command applies to the whole CSP Element." + "If the array length is > 1, each array element specifies the FQDN of the" + " CSP SubElement to switch OFF."), + ) + @DebugIt() + @CmdInputArgsCheck("offCommandProgress", "offCmdTimeoutExpired", cmd_name = "off") + def Off(self, argin): + # PROTECTED REGION ID(CspMaster.Off) ENABLED START # + """ + *Class TANGO method* + + Power-down the CSP sub-elements specified by the input argument. If no argument is + specified, the command is issued on all the CSP sub-elements. + The command is executed if the *AdminMode* is ONLINE or *MAINTENANCE*. + If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an + exception. + The CSP.LMC commands sub-element transition from STANDBY to OFF sequentially.It + waits for the first sub-element (CBF) to complete the transition, then issues the + command to the second sub-element (e.g. PST), waits for PST to complete and then + issues command for PSS. + Command is forwarded to the sub-element devices specified in the input list, + only if their adminMode is ONLINE or MAINTENANCE. + + :param argin: + The list of sub-element FQDNs to power-down or an empty list to + power-off the whole CSP Element. + If the array length is 0, the command applies to the whole CSP + Element. If the array length is > 1, each array element specifies + the FQDN of the CSP SubElement to power-off. + :type: 'DevVarStringArray' + :return: None + :raises: *tango.DevFailed* exception when: + - the CSP adminMode is not correct + - one or more sub-element devices are already running a power command + - there is no DeviceProxy providing interface to the CBF sub-element + """ + # the input list after decorator examination + device_list = argin + # invoke the constructor for the command thread. + # The target thread function is common to all the invoked commands. Specifc information + # are passed as arguments of the function + # args: the list of sub-element FQDNS + # args_dict: dictionary with the specific command information + args_dict = {'cmd_name':'Off', + 'dev_state': tango.DevState.ON} + + self._command_thread['off'] = threading.Thread(target=self._issue_power_command, name="Thread-Off", + args=(device_list,), + kwargs=args_dict) + # set the CSP command execution running flag + self._cmd_execution_state['off'] = CmdExecState.RUNNING + # start the thread + self._command_thread['off'].start() + # sleep for a while to let the thread start + time.sleep(0.2) + + # PROTECTED REGION END # // CspMaster.Off + + @AdminModeCheck('Standby') + def is_Standby_allowed(self): + """ + *TANGO is_allowed method* + + Command *Standby* is allowed when the device *State* is ON. + + Returns: + True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in=("If the array length is 0, the command applies to the whole CSP Element. " + "If the array length is > 1, each array element specifies the FQDN of the" + "CSP SubElement to put in STANDBY mode."), + ) + @DebugIt() + @CmdInputArgsCheck("standbyCommandProgress", + "standbyCmdTimeoutExpired", cmd_name = "standby") + def Standby(self, argin): + # PROTECTED REGION ID(CspMaster.Standby) ENABLED START # + """ + Transit CSP or one or more CSP SubElements from ON to *STANDBY*. + The command is executed only if the *AdminMode* is ONLINE or *MAINTENANCE*. + If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an + exception. + The CSP.LMC commands sub-element transition from ON to STANDBY sequentially. It + waits for the first sub-element (CBF) to complete the transition, then issues the + command to the second sub-element (e.g. PST), waits for PST to complete and then + issues command for PSS. + Command is forwarded to the sub-element devices specified in the input list, + only if their adminMode is ONLINE or MAINTENANCE. + + :param argin: A list with the FQDN of the sub-elements to set in low-power. + If the array length is 0, the command applies to the whole + CSP Element. If the array length is > 1, each array element + specifies the FQDN of the CSP SubElement to put in STANDBY mode. + :type: 'DevVarStringArray' + :return: None + :raises: *tango.DevFailed* exception when: + - the CSP adminMode is not correct + - one or more sub-element devices are already running a power command + - there is no DeviceProxy providing interface to the CBF sub-element + """ + device_list = argin + # build the dictionary to pass as argument of the thread target function + # The dictionary keys are: + # cmd_name : the TANGO command name to execute + # attr_name: the corresponding command progress attribute to subscribe + # dev_state: the expected finale state for the device transition + args_dict = {'cmd_name':'Standby', + 'dev_state':tango.DevState.STANDBY} + # invoke the constructor for the command thread + self._command_thread['standby'] = threading.Thread(target=self._issue_power_command, + name="Thread-Standby", + args=(device_list,), + kwargs=args_dict) + # start the thread + self._cmd_execution_state['standby'] = CmdExecState.RUNNING + self._command_thread['standby'].start() + # sleep for a while to let the thread start + time.sleep(0.2) + # PROTECTED REGION END # // CspMaster.Standby + + @command( + ) + @DebugIt() + def Upgrade(self): + # PROTECTED REGION ID(CspMaster.Upgrade) ENABLED START # + """ + + :return: None + """ + pass + # PROTECTED REGION END # // CspMaster.Upgrade + +# ---------- +# Run server +# ---------- + +def main(args=None, **kwargs): + # PROTECTED REGION ID(CspMaster.main) ENABLED START # + return run((CspMaster,), args=args, **kwargs) + # PROTECTED REGION END # // CspMaster.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/csp_lmc_common/CspSubarray.py b/csp-lmc-common/csp_lmc_common/CspSubarray.py new file mode 100644 index 0000000000000000000000000000000000000000..b5b966d5a40204d138f84ab60b7191fc8404dd74 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/CspSubarray.py @@ -0,0 +1,2079 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspSubarray project +# +# INAF - SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC Common CspSubarray + +CSP subarray functionality is modeled via a TANGCSP.LMC Common Class for the CSPSubarray TANGO Device. +""" +# PROTECTED REGION ID (CspSubarray.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 +from enum import IntEnum, unique +import threading +import time +import json +# PROTECTED REGION END# //CspSubarray.standardlibray_import + +# tango imports +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 class_property, device_property +from tango import AttrQuality, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType + +# Additional import +# PROTECTED REGION ID(CspSubarray.additionnal_import) ENABLED START # +from skabase.SKASubarray import SKASubarray +from skabase.auxiliary import utils +# PROTECTED REGION END # // CspSubarray.additionnal_import + +# PROTECTED REGION ID (CspSubarray.add_path) ENABLED START # +# add the path to import global_enum package. + +from .utils.decorators import AdminModeCheck, StateAndObsStateCheck +from .utils.cspcommons import HealthState, AdminMode, ObsState, ObsMode, CmdExecState +from . import release +# PROTECTED REGION END# //CspSubarray.add_path + +__all__ = ["CspSubarray", "main"] + + +class CspSubarray(with_metaclass(DeviceMeta,SKASubarray)): + """ + CSP subarray functionality is modeled via a TANGCSP.LMC Common Class for the CSPSubarray TANGO Device. + + **Properties:** + + - Class Property + PSTBeams + - PST sub-element PSTBeams TANGO devices FQDNs + - Type:'DevVarStringArray' + + - Device Property + + CspMaster + - The TANGO address of the CspMaster. + - Type:'DevString' + + CbfSubarray + - CBF sub-element sub-array TANGO device FQDN + - Type:'DevString' + + PssSubarray + - PST sub-element sub-array TANGO device FQDN. + - Type:'DevString' + + SubarrayProcModeCorrelation + - CSP Subarray *Correlation Inherent Capability*\nTANGO device FQDN + - Type:'DevString' + + SubarrayProcModePss + - CSP Subarray *Pss Inherent Capability*\nTANGO device FQDN + - Type:'DevString' + + SubarrayProcModePst + - CSP Subarray *PST Inherent Capability*\nTANGO device FQDN + - Type:'DevString' + + SubarrayProcModeVlbi + - CSP Subarray *VLBI Inherent Capability*\nTANGO device FQDN + - Type:'DevString' + + """ + # PROTECTED REGION ID(CspSubarray.class_variable) ENABLED START # + # PROTECTED REGION END # // CspSubarray.class_variable + # !! NOTE !!: + # In methods and attributes of the class: + # 'sc' prefix stands for 'sub-component' + # 'cb' suffix stands for 'callback' + #---------------- + # Event Callback functions + # --------------- + def _sc_scm_change_event_cb(self, evt): + """ + Class protected callback function. + Retrieve the values of the sub-array sub-component SCM attributes subscribed + at device connection. + Sub-array sub-components are: + - the CBF sub-array (assigned at initialization!) + - the PSS sub-array if SearchBeams are assigned to the sub-array + - the PSTBeams if TimingBeams are assigned to the sub-array + These values are used to report the whole Csp Subarray State and healthState. + + :param evt: The event data + + :return: None + """ + dev_name = evt.device.dev_name() + if not evt.err: + try: + if dev_name in self._sc_subarray_fqdn: + if evt.attr_value.name.lower() == "state": + self._sc_subarray_state[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "healthstate": + self._sc_subarray_health_state[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "adminmode": + self.logger.debug("device: {} adminMode value {}".format(dev_name,evt.attr_value.value)) + self._sc_subarray_admin_mode[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "obsstate": + self.logger.debug("device: {} obsState value {}".format(dev_name,evt.attr_value.value )) + self._sc_subarray_obs_state[dev_name] = evt.attr_value.value + elif evt.attr_value.name.lower() == "obsmode": + self.logger.debug("device: {} obsMode value {}".format(dev_name, evt.attr_value.value )) + self._sc_subarray_obs_mode[dev_name] = evt.attr_value.value + else: + log_msg = ("Attribute {} not still " + "handled".format(evt.attr_name)) + self.logger.warn(log_msg) + else: + log_msg = ("Unexpected change event for" + " attribute: {}".format(str(evt.attr_name))) + self.logger.warn(log_msg) + return + + log_msg = "New value for {} is {}".format(str(evt.attr_name), + str(evt.attr_value.value)) + self.logger.info(log_msg) + # update CSP sub-array SCM + if evt.attr_value.name.lower() in ["state", "healthstate", "adminmode"]: + self._update_subarray_state() + if evt.attr_value.name.lower() == "obsstate": + self._update_subarray_obs_state() + except tango.DevFailed as df: + self.logger.error(str(df.args[0].desc)) + except Exception as except_occurred: + self.logger.error(str(except_occurred)) + else: + for item in evt.errors: + # API_EventTimeout: if sub-element device not reachable it transitions + # to UNKNOWN state. + if item.reason == "API_EventTimeout": + # only if the device is ONLINE/MAINTENANCE, its State is set to + # UNKNOWN when there is a timeout on connection, otherwise its + # State should be reported always as DISABLE + if self._sc_subarray_admin_mode[dev_name] in [AdminMode.ONLINE, + AdminMode.MAINTENANCE]: + self._sc_subarray_state[dev_name] = tango.DevState.UNKNOWN + self._sc_subarray_health_state[dev_name] = HealthState.UNKNOWN + # TODO how report obsState? + # adminMode can't be change otherwise the State and healthState + # are note updated + # update the State and healthState of the CSP sub-array + self._update_subarray_state() + log_msg = item.reason + ": on attribute " + str(evt.attr_name) + self.logger.warn(log_msg) + + def _attributes_change_evt_cb(self, evt): + """ + *Class callback function.* + Retrieve the value of the sub-element xxxCommandProgress attribute + subscribed for change event when a long-running command is issued + on the sub-element device. + + :param evt: The event data + + :return: None + """ + dev_name = evt.device.dev_name() + if not evt.err: + try: + if "commandprogress" == evt.attr_value.name.lower()[-15:]: + if dev_name in self._sc_subarray_fqdn: + cmd_name = evt.attr_value.name[:-15] + self._sc_subarray_cmd_progress[dev_name][cmd_name] = evt.attr_value.value + elif "cmdtimeoutexpired" == evt.attr_value.name.lower()[-17:]: + if dev_name in self._sc_subarray_fqdn: + cmd_name = evt.attr_value.name[:-17] + self._sc_subarray__timeout_expired[dev_name][cmd] = True + else: + log_msg = ("Unexpected change event for" + " attribute: {}".format(str(evt.attr_name))) + self.logger.warn(log_msg) + return + + log_msg = "New value for {} is {}".format(str(evt.attr_name), + str(evt.attr_value.value)) + self.logger.info(log_msg) + except tango.DevFailed as df: + self.logger.error(str(df.args[0].desc)) + except Exception as except_occurred: + self.logger.error(str(except_occurred)) + else: + for item in evt.errors: + log_msg = item.reason + ": on attribute " + str(evt.attr_name) + self.logger.warn(log_msg) + + def _cmd_ended_cb(self, evt): + """ + Callback function immediately executed when the asynchronous invoked + command returns. + + :param evt: a CmdDoneEvent object. This class is used to pass data + to the callback method in asynchronous callback model for command + execution. + :type: CmdDoneEvent object + It has the following members: + - device : (DeviceProxy) The DeviceProxy object on which the + call was executed. + - cmd_name : (str) The command name + - argout_raw : (DeviceData) The command argout + - argout : The command argout + - err : (bool) A boolean flag set to true if the command + failed. False otherwise + - errors : (sequence) The error stack + - ext + :return: none + """ + # NOTE:if we try to access to evt.cmd_name or other paramters, sometime + # the callback crashes withthis error: + # terminate called after throwing an instance of 'boost::python::error_already_set' + try: + # Can happen evt empty?? + if evt: + if not evt.err: + if self._sc_subarray_cmd_exec_state[evt.device.dev_name()][evt.cmd_name.lower()] == CmdExecState.RUNNING: + msg = "Device {} is processing command {}".format(evt.device, + evt.cmd_name) + if self._sc_subarray_cmd_exec_state[evt.device.dev_name()][evt.cmd_name.lower()] == CmdExecState.IDLE: + msg = "Device {} ended command {} execution".format(evt.device, evt.cmd_name) + self.logger.info(msg) + else: + msg = "Error!!Command {} ended on device {}.\n".format(evt.cmd_name, + evt.device.dev_name()) + msg += " Desc: {}".format(evt.errors[0].desc) + self.logger.info(msg) + self._sc_subarray_cmd_exec_state[evt.device.dev_name()][evt.cmd_name.lower()] = CmdExecState.FAILED + self._alarm_message[evt.cmd_name.lower()] += msg + # obsState and obsMode values take on the CbfSubarray's values via + # the subscribe/publish mechanism + else: + self.logger.error("cmd_ended callback: evt is empty!!") + except tango.DevFailed as df: + msg = ("CommandCallback cmd_ended failure - desc: {}" + " reason: {}".format(df.args[0].desc, df.args[0].reason)) + self.logger.error(msg) + except Exception as ex: + msg = "CommandCallBack cmd_ended general exception: {}".format(str(ex)) + self.logger.error(msg) + + # Class protected methods + # --------------- + + def _update_subarray_state(self): + """ + Class protected method. + Retrieve the State attribute values of the CSP sub-elements and aggregate + them to build up the CSP global state. + + :param: None + + :return: None + """ + self._update_subarray_health_state() + # 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. + self.set_state(self._sc_subarray_state[self.CbfSubarray]) + if self._sc_subarray_admin_mode[self.CbfSubarray] not in [AdminMode.ONLINE, + AdminMode.MAINTENANCE]: + self.set_state(tango.DevState.DISABLE) + if self._admin_mode not in [AdminMode.ONLINE, + AdminMode.MAINTENANCE]: + self.set_state[tango.DevState.DISABLE] + + def _update_subarray_health_state(self): + """ + Class protected method. + Retrieve the healthState attribute of the CSP sub-elements and + aggregate them to build up the CSP health state + + :param: None + + :return: None + """ + # if the Subarray is OFF (no assigned resources) or DISABLE, + # its health state is UNKNOWN. + # Note: when the Subarray adminMode is set OFFLINE/RESERVED/NOTFITTED + # all its allocated resources are released and its State moves to DISABLE. + # + if self.get_state() in [tango.DevState.OFF, tango.DevState.DISABLE]: + self._health_state = HealthState.UNKNOWN + + # The whole CspSubarray HealthState is OK if is ON and all its assigned sub-components + # (CBF and PSS subarrays as well PST Beams) are OK. + # - CbfSubarray ON (receptors/stations assigned) + # - PssSubarray ON + + # default value to DEGRADED + self._health_state = HealthState.DEGRADED + + # build the list of all the Csp Subarray sub-components ONLINE/MAINTENANCE + admin_fqdn = [fqdn for fqdn, admin_value in self._sc_subarray_admin_mode.items() + if admin_value in [AdminMode.ONLINE, AdminMode.MAINTENANCE]] + # build the list of sub-elements with State ON + state_fqdn = [fqdn for fqdn in admin_fqdn if self._sc_subarray_state[fqdn] == tango.DevState.ON] + # build the list with the healthState of ONLINE/MAINTENANCE devices + health_list = [self._sc_subarray_health_state[fqdn] for fqdn in state_fqdn] + + if self.CbfSubarray in admin_fqdn: + if all(value == HealthState.OK for value in health_list): + self._health_state = HealthState.OK + elif self._sc_subarray_health_state[self.CbfSubarray] in [HealthState.FAILED, + HealthState.UNKNOWN, + HealthState.DEGRADED]: + self._health_state = self._sc_subarray_health_state[self.CbfSubarray] + else: + # if CBF Subarray is not ONLINE/MAINTENANCE .... + self._health_state = self._sc_subarray_health_state[self.CbfSubarray] + return + + def _update_subarray_obs_state(self): + """ + Class protected method. + Retrieve the State attribute values of the CSP sub-elements and aggregate + them to build up the CSP global state. + + :param: None + + :return: None + """ + # update the CspSubarray ObsMode only when no command is running on sub-array + # sub-components + exec_state_list = [] + for fqdn in self._sc_subarray_assigned_fqdn: + device_exec_state_list = [value for value in self._sc_subarray_cmd_exec_state[fqdn].values()] + exec_state_list.extend(device_exec_state_list) + # when command are not running, the CbfSubarray osbState reflects the + # CSP Subarray obsState. + # If CbfSubarray obsState is READY and PssSubarray IDLE, the CspSubarray + # onsState is READY (it can performs IMAGING!) + if all(value == CmdExecState.IDLE for value in exec_state_list): + self._obs_state = self._sc_subarray_obs_state[self.CbfSubarray] + self.logger.debug("All sub-array sub-component are IDLE." + "Subarray obsState:", self._obs_state) + + def _connect_to_subarray_subcomponent(self, fqdn): + """ + Class method. + Establish a *stateless* connection with a CSP Subarray sub-component + device (CBF Subarray, PSS Subarray , PST Beams). + Exceptions are logged. + :param fqdn: + the CspSubarray sub-component FQDN + :return: None + """ + + # check if the device has already been addedd + if fqdn in self._sc_subarray_fqdn: + return + # read the sub-componet adminMode (memorized) attribute from + # the CSP.LMC TANGO DB. + attribute_properties = self._csp_tango_db.get_device_attribute_property(fqdn, + {'adminMode': ['__value']}) + self.logger.info("fqdn: {} attribute_properties: {}".format(fqdn, attribute_properties)) + try: + admin_mode_memorized = attribute_properties['adminMode']['__value'] + self._sc_subarray_admin_mode[fqdn] = int(admin_mode_memorized[0]) + except KeyError: + self.logger.warn("No key {} found".format(str(key_error))) + try: + log_msg = "Trying connection to " + str(fqdn) + " device" + self.logger.info(log_msg) + device_proxy = tango.DeviceProxy(fqdn) + # Note: The DeviceProxy is initialized even if the sub-component + # device is not running (but defined into the TANGO DB! If not defined in the + # TANGO DB a exception is throw). + # The connection with a sub-element is establish as soon as the corresponding + # device starts. + # append the FQDN to the list and store the sub-element proxies + self._sc_subarray_fqdn.append(fqdn) + self._sc_subarray_proxies[fqdn] = device_proxy + + # subscription of SCM attributes (State, healthState and adminMode). + # Note: subscription is performed also for devices not ONLINE or MAINTENANCE. + # In this way the CspMaster is able to detect a change in the admin value. + + ev_id = device_proxy.subscribe_event("adminMode", + tango.EventType.CHANGE_EVENT, + self._sc_scm_change_event_cb, + stateless=True) + self._sc_subarray_event_id[fqdn]['adminMode'] = ev_id + + ev_id = device_proxy.subscribe_event("State", + tango.EventType.CHANGE_EVENT, + self._sc_scm_change_event_cb, + stateless=True) + self._sc_subarray_event_id[fqdn]['state'] = ev_id + + ev_id = device_proxy.subscribe_event("healthState", + tango.EventType.CHANGE_EVENT, + self._sc_scm_change_event_cb, + stateless=True) + self._sc_subarray_event_id[fqdn]['healthState'] = ev_id + + ev_id = device_proxy.subscribe_event("obsState", + tango.EventType.CHANGE_EVENT, + self._sc_scm_change_event_cb, + stateless=True) + self._sc_subarray_event_id[fqdn]['obsState'] = ev_id + + ev_id = device_proxy.subscribe_event("obsMode", + tango.EventType.CHANGE_EVENT, + self._sc_scm_change_event_cb, + stateless=True) + self._sc_subarray_event_id[fqdn]['obsMode'] = ev_id + + except KeyError as key_err: + log_msg = ("No key {} found".format(str(key_err))) + self.logger.warn(log_msg) + except tango.DevFailed as df: + log_msg = ("Failure in connection to {}" + " device: {}".format(str(fqdn), str(df.args[0].desc))) + self.logger.error(log_msg) + + def _is_sc_subarray_running (self, device_name): + """ + *Class protected method.* + + Check if a sub-element is exported in the TANGO DB (i.e its TANGO + device server is running). + If the device is not in the list of the connected sub-elements, + a connection with the device is performed. + + :param: subelement_name : the FQDN of the sub-element + :type: `DevString` + :return: True if the connection with the subarray is established, + False otherwise + """ + try: + proxy = self._sc_subarray_proxies[device_name] + proxy.ping() + except KeyError as key_err: + # Raised when a mapping (dictionary) key is not found in the set + # of existing keys. + # no proxy registered for the subelement device + msg = "Can't retrieve the information of key {}".format(key_err) + self.logger.warn(msg) + try: + proxy = tango.DeviceProxy(device_name) + # execute a ping to detect if the device is actually running + proxy.ping() + self._sc_subarray_proxies[device_name] = proxy + except tango.DevFailed as df: + return False + except tango.DevFailed as df: + msg = "Failure reason: {} Desc: {}".format(str(df.args[0].reason), str(df.args[0].desc)) + self.logger.warn(msg) + return False + return True + + def _is_subarray_composition_allowed(self): + if self.get_state() in [tango.DevState.ON, tango.DevState.OFF]: + return True + return False + + def _is_subarray_configuring_allowed(self): + if self.get_state() == tango.DevState.ON: + return True + return False + + # ---------------- + # Class private methods + # ---------------- + + def __configure_scan(self, device_list, **args_dict): + tango_cmd_name = 0 + # the sub-element device state after successful transition + dev_successful_state = 0 + try: + tango_cmd_name = args_dict['cmd_name'] + dev_successful_state = args_dict['obs_state'] + except KeyError as key_err: + self.logger.warn("No key: {}".format(str(key_err))) + return + # tango_cmd_name: is the TANGO command name with the capital letter + # In the dictionary keys, is generally used the command name in lower letters + cmd_name = tango_cmd_name.lower() + self.logger.info("cmd_name: {} dev_state: {}".format(cmd_name, + dev_successful_state)) + self._num_dev_completed_task[cmd_name] = 0 + self._list_dev_completed_task[cmd_name] = [] + self._cmd_progress[cmd_name] = 0 + self._cmd_duration_measured[cmd_name] = 0 + # sub-component command execution measured time + sc_cmd_duration_measured = defaultdict(lambda:defaultdict(lambda:0)) + # loop on the devices and issue asynchrnously the ConfigureScan command + for device in device_list: + proxy = self._sc_subarray_proxies[device] + sc_cmd_duration_measured[device][cmd_name] = 0 + self._sc_subarray_cmd_progress[device][cmd_name] = 0 + self._alarm_message[cmd_name] = '' + # 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 + proxy.command_inout_asynch("ConfigureScan", self._sc_subarray_scan_configuration[device], self._cmd_ended_cb) + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.RUNNING + self._obs_state = ObsState.CONFIGURING + # register the starting time for the command + self._sc_subarray_cmd_starting_time[device] = time.time() + self.logger.info("Device {} State {} expected value {}".format(device, + self._sc_subarray_state[device], + dev_successful_state)) + command_progress = self._cmd_progress[cmd_name] + # flag to signal when configuration ends on a sub-array sub-component + device_done = defaultdict(lambda:False) + # inside the end-less lop check the obsState of each sub-component + while True: + for device in device_list: + print("__configure_scan obs_state:", self._sc_subarray_obs_state[device]) + if device_done[device] == True: + continue + # if the sub-component execution flag is no more RUNNING, the command has + # ended with or without success. Go to check next device state. + if self._sc_subarray_obs_state[device] == dev_successful_state: + self.logger.info("Command {} ended with success on device {}.".format(cmd_name, + device)) + # update the list and number of device that completed the task + self._num_dev_completed_task[cmd_name] += 1 + self._list_dev_completed_task[cmd_name].append(device) + # reset the value of the attribute reporting the execution state of + # the command + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE + self._sc_subarray_cmd_progress[device][cmd_name] = 100 + # calculate the real execution time for the command + self._cmd_duration_measured[cmd_name] += sc_cmd_duration_measured[device][cmd_name] + # command success: step to next device + device_done[device] = True + # check if sub-element command ended throwing an exception: in this case the + # 'cmd_ended_cb' callback is invoked. + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.FAILED: + # execution ended for this sub-element, skip to the next one + device_done[device] = True + #if self._sc_subarray_obs_state[device] in [ObsState.ABORTED, ObsState.FAULT]: + # num_of_failed_device += 1 + # continue + # check for timeout event. A timeout event can be detected in two ways: + # 1- the sub-element implements the 'onTimeoutExpired' attribute configured + # for change event + # 2- the CspMaster periodically checks the time elapsed from the start + # of the command: if the value is greater than the sub-element expected time + # for command execution, the sub-element command execution state is set + # to TIMEOUT + # Note: the second check, can be useful if the timeout event is not received + # (for example for a temporary connection timeout) + elapsed_time = time.time() - self._sc_subarray_cmd_starting_time[device] + if (elapsed_time > self._sc_subarray_cmd_duration_expected[device][cmd_name] or + self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT): + msg = ("Timeout executing {} command on device {}".format(cmd_name, device)) + self.logger.warn(msg) + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.TIMEOUT + device_done[device] = True + self.logger.info("elapsed_time:{} device {}".format(elapsed_time, device)) + # update the progress counter inside the loop taking into account the number of devices + # executing the command + self._cmd_progress[cmd_name] = command_progress + self._sc_subarray_cmd_progress[device][cmd_name]/len(device_list) + print("__configure_scan:", self._sc_subarray_cmd_exec_state[device][cmd_name]) + if all(value == True for value in device_done.values()): + self.logger.info("All devices have been handled!") + if (all(self._sc_subarray_obs_state[device] == ObsState.READY for device in device_list)): + self._obs_state = ObsState.READY + # end of the command: the command has been issued on all the sub-element devices + # reset the execution flag for the CSP + break + time.sleep(1) + # end of the while loop + # check for timeout/alarm conditions on each sub-component + for device in device_list: + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT: + self._timeout_expired = True + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.FAILED: + self._alarm_raised = True + # reset sub-component execution flag + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE + # update the progress counter at the end of the loop + self._cmd_progress[cmd_name] = command_progress + self._sc_subarray_cmd_progress[device][cmd_name]/len(device_list) + if all(self._sc_subarray_obs_state[fqdn] == dev_successful_state for fqdn in device_list): + self._obs_state = dev_successful_state + self._last_executed_command = cmd_name + # reset the CSP Subarray command execution flag + self._cmd_execution_state[cmd_name] = CmdExecState.IDLE + + # ---------------- + # Class Properties + # ---------------- + + PSTBeams = class_property( + dtype='DevVarStringArray', + ) + + # ----------------- + # Device Properties + # ----------------- + + CspMaster = device_property( + dtype='DevString', + ) + + CbfSubarray = device_property( + dtype='DevString', + ) + + PssSubarray = device_property( + dtype='DevString', + ) + + SubarrayProcModeCorrelation = device_property( + dtype='DevString', + ) + + SubarrayProcModePss = device_property( + dtype='DevString', + ) + + SubarrayProcModePst = device_property( + dtype='DevString', + ) + + SubarrayProcModeVlbi = device_property( + dtype='DevString', + ) + + # ---------- + # Attributes + # ---------- + + scanID = attribute( + dtype='DevULong64', + access=AttrWriteType.READ_WRITE, + ) + + procModeCorrelationAddr = attribute( + dtype='DevString', + label="Correlation Inherent Capability Address", + doc="The CSP sub-array Correlation Inherent Capability FQDN.", + ) + + procModePssAddr = attribute( + dtype='DevString', + label="PSS Inherent Capability address", + doc="The CSP sub-array PSS Inherent Capability FQDN.", + ) + + procModePstAddr = attribute( + dtype='DevString', + label="PST Inherent Capability address", + doc="The CSP sub-array PST Inherent Capability FQDN.", + ) + + procModeVlbiAddr = attribute( + dtype='DevString', + label="VLBI Inhernt Capabilityaddress", + doc="The CSP sub-array VLBI Inherent Capability FQDN.", + ) + + cbfSubarrayState = attribute( + dtype='DevState', + ) + + pssSubarrayState = attribute( + dtype='DevState', + ) + + cbfSubarrayHealthState = attribute( + dtype='DevEnum', + label="CBF Subarray Health State", + doc="CBF Subarray Health State", + enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], + ) + + pssSubarrayHealthState = attribute( + dtype='DevEnum', + label="PSS Subarray Health State", + doc="PSS Subarray Health State", + enum_labels=["OK", "DEGRADED", "FAILED", "UNKNOWN", ], + ) + + cbfSubarrayAdminMode = attribute( + dtype='DevEnum', + label="CBF Subarray Admin Mode", + doc="CBF Subarray Admin Mode", + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED",], + ) + + pssSubarrayAdminMode = attribute( + dtype='DevEnum', + label="PSS Subarray Admin Mode", + doc="PSS Subarray Admin Mode", + enum_labels=["ON-LINE", "OFF-LINE", "MAINTENANCE", "NOT-FITTED", "RESERVED",], + ) + cbfSubarrayObsState = attribute( + dtype='DevEnum', + label="CBF Subarray Observing State", + doc="The CBF subarray observing state.", + enum_labels=["IDLE", "CONFIGURING", "READY", "SCANNING", "PAUSED", "ABORTED", "FAULT",], + ) + + pssSubarrayObsState = attribute( + dtype='DevEnum', + label="PSS Subarray Observing State", + doc="The PSS subarray observing state.", + enum_labels=["IDLE", "CONFIGURING", "READY", "SCANNING", "PAUSED", "ABORTED", "FAULT",], + ) + + pssSubarrayAddr = attribute( + dtype='DevString', + label="PSS sub-array address", + doc="The PSS sub-element sub-array FQDN.", + ) + + cbfSubarrayAddr = attribute( + dtype='DevString', + label="CBF sub-array address", + doc="The CBF sub-element sub-array FQDN.", + ) + + validScanConfiguration = attribute( + dtype='DevString', + label="Valid Scan Configuration", + doc="Store the last valid scan configuration.", + ) + + addSearchBeamDurationExpected = attribute( + dtype='DevUShort', + label="AddSearchBeams command duration expected", + doc="The duration expected (in sec) for the AddSearchBeams command.", + ) + + remSearchBeamsDurationExpected = attribute( + dtype='DevUShort', + label="RemoveSearchBeams command duration expected", + doc="The duration expected (in sec) for the RemoveSearchBeams command.", + ) + + addSearchBeamDurationMeasured = attribute( + dtype='DevUShort', + label="AddSearchBeams command duration measured", + doc="The duration measured (in sec) for the AddSearchBeams command.", + ) + + remSearchBeamsDurationMeasured = attribute( + dtype='DevUShort', + label="RemoveSearchBeams command duration measured", + doc="The duration measured (in sec) for the RemoveSearchBeams command.", + ) + + + addTimingBeamDurationExpected = attribute( + dtype='DevUShort', + label="AddTimingBeams command duration expected", + doc="The duration expected (in sec) for the AddTimingBeams command.", + ) + + remTimingBeamsDurationExpected = attribute( + dtype='DevUShort', + label="RemoveTimingBeams command duration expected", + doc="The duration expected (in sec) for the RemoveTimingBeams command.", + ) + + addTimingBeamDurationMeasured = attribute( + dtype='DevUShort', + label="AddTimingBeams command duration measured", + doc="The duration measured (in sec) for the AddTimingBeams command.", + ) + + remTimingBeamsDurationMeasured = attribute( + dtype='DevUShort', + label="EndSB command duration measured", + doc="The duration measured (in sec) for the RemoveTimingBeams command.", + ) + + endSBDurationExpected = attribute( + dtype='DevUShort', + label="EndSB command duration expected", + doc="The duration expected (in sec) for the EndSB command.", + ) + + endSBDurationMeasured = attribute( + dtype='DevUShort', + label="EndSB command duration measured", + doc="The duration measured (in sec) for the EndSB command.", + ) + + endSBCmdProgress = attribute( + dtype='DevUShort', + label="EndSB command progress percentage", + polling_period=1500, + abs_change=5, + doc="The progress percentage for the EndSB command.", + ) + + endScanDurationExpected = attribute( + dtype='DevUShort', + label="EndScan command duration expected", + doc="The duration expected (in sec) for the EndScan command.", + ) + + endScanDurationMeasured = attribute( + dtype='DevUShort', + label="EndScan command duration measured", + doc="The duration measured (in sec) for the EndScan command.", + ) + + endScanCmdProgress = attribute( + dtype='DevUShort', + label="EndScan command progress percentage", + polling_period=1500, + abs_change=5, + doc="The progress percentage for the EndScan command.", + ) + + + addResourcesCmdProgress = attribute( + dtype='DevUShort', + label="Add resources command progress percentage", + polling_period=1500, + abs_change=5, + doc="The progress percentage for the Add resources command.", + ) + + removeResourcesCmdProgress = attribute( + dtype='DevUShort', + label="Remove resources command progress percentage", + polling_period=1500, + abs_change=5, + doc="The progress percentage for the Add/SearchBeams command.", + ) + + scanCmdProgress = attribute( + dtype='DevUShort', + label="Scan command progress percentage", + polling_period=1500, + abs_change=5, + doc="The progress percentage for the Scan command.", + ) + + reservedSearchBeamNum = attribute( + dtype='DevUShort', + label="Number of reserved SearchBeam IDs", + doc="Number of SearchBeam IDs reserved for the CSP sub-array", + ) + + numOfDevCompletedTask = attribute( + dtype='DevUShort', + label="Number of devices that completed the task", + doc="Number of devices that completed the task", + ) + + cmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="CspSubarray command execution timeout flag", + polling_period=1000, + doc="The timeout flag for a CspSubarray command.", + ) + + cmdAlarmRaised = attribute( + dtype='DevBoolean', + label="CspSubarray alarm flag", + polling_period=1000, + doc="The alarm flag for a CspSubarray command.", + ) + + + pstOutputLink = attribute( + dtype='DevString', + label="PST output link", + doc="The output link for PST products.", + ) + + assignedSearchBeamIDs = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + label="List of assigned Search Beams", + doc="List of assigned Search Beams", + ) + + reservedSearchBeamIDs = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + label="List of reserved SearchBeam IDs", + doc="List of SearchBeam IDs reserved for the CSP sub-array", + ) + + assignedTimingBeamIDs = attribute( + dtype=('DevUShort',), + max_dim_x=16, + label="List of assigned TimingBeam IDs", + doc="List of TimingBeam IDs assigned to the CSP sub-array", + ) + + assignedVlbiBeamIDs = attribute( + dtype=('DevUShort',), + max_dim_x=20, + label="List of assigned VlbiBeam IDs", + doc="List of VlbiBeam IDs assigned to the CSP sub-array", + ) + + assignedSearchBeamsState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams State", + doc="State of the assigned SearchBeams", + ) + + assignedTimingBeamsState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams State", + doc="State of the assigned TimingBeams", + ) + + assignedVlbiBeamsState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams State", + doc="State of the assigned VlbiBeams", + ) + + assignedSearchBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams HealthState", + doc="HealthState of the assigned SearchBeams", + ) + + assignedTimingBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams HealthState", + doc="HealthState of the assigned TimingBeams", + ) + + assignedVlbiBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams HealthState", + doc="HealthState of the assigned VlbiBeams", + ) + + assignedSearchBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams ObsState", + doc="ObsState of the assigned SearchBeams", + ) + + assignedTimingBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams ObsState", + doc="ObsState of the assigned TimingBeams", + ) + + assignedVlbiBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams ObsState", + doc="ObsState of the assigned VlbiBeams", + ) + + assignedSearchBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams AdminMode", + doc="AdminMode of the assigned SearchBeams", + ) + + assignedTimingBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams AdminMode", + doc="AdminMode of the assigned TimingBeams", + ) + + assignedVlbiBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams AdminMode", + doc="AdminMode of the assigned VlbiBeams", + ) + + pstBeams = attribute( + dtype=('DevString',), + max_dim_x=16, + label="PSTBeams addresses", + doc="PST sub-element PSTBeam TANGO device FQDNs.", + ) + + listOfDevCompletedTask = attribute( + dtype=('DevString',), + max_dim_x=100, + label="List of devices that completed the task", + doc="List of devices that completed the task", + ) + + cbfOutputLink = attribute(name="cbfOutputLink", + label="cbfOutputLink", + forwarded=True + ) + #pssOutputLink = attribute(name="pssOutputLink", + # label="cbfOutputLink", + # forwarded=True + #) + + #vlbiOutputLink = attribute(name="vlbiOutputLink", + # label="cbfOutputLink", + # forwarded=True + #) + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspSubarray.""" + SKASubarray.init_device(self) + # PROTECTED REGION ID(CspSubarray.init_device) ENABLED START # + self._build_state = '{}, {}, {}'.format(release.name, release.version, release.description) + self._version_id = release.version + # connect to CSP.LMC TANGO DB + self.set_state(tango.DevState.INIT) + self._health_state = HealthState.UNKNOWN + self._admin_mode = AdminMode.ONLINE + self._obs_mode = ObsMode.IDLE + self._obs_state = ObsState.IDLE + # connect to TANGO DB + + # use defaultdict to initialize the sub-element State,healthState + # and adminMode. The dictionary uses as keys the sub-element + # fqdn, for example + # self._sc_subarray_state[self.CspCbf] + # return the State value of the Mid Cbf sub-element. + self._sc_subarray_state = defaultdict(lambda: tango.DevState.DISABLE) + self._sc_subarray_health_state = defaultdict(lambda: HealthState.UNKNOWN) + self._sc_subarray_admin_mode = defaultdict(lambda: AdminMode.NOTFITTED) + self._sc_subarray_obs_state = defaultdict(lambda: ObsState.IDLE) + self._sc_subarray_obs_mode = defaultdict(lambda: ObsMode.IDLE) + self._csp_tango_db = tango.Database() + # read the CSP memorized attributes from the TANGO DB. + # Note: a memorized attribute has defined the attribute + # property '__value' + attribute_properties = self._csp_tango_db.get_device_attribute_property(self.get_name(), + {'adminMode': ['__value']}) + # build a dictionary with the (attr_name, value) of the memorized attributes + # use memorized atrtibute if present, otherwise the default one + memorized_attr_dict = {attr_name : int(value[0]) for attr_name, db_key in attribute_properties.items() + for key, value in db_key.items() + if key == '__value'} + try: + self._admin_mode = memorized_attr_dict['adminMode'] + if self._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]: + self._health_state = HealthState.UNKNOWN + self.set_state(tango.DevState.DISABLE) + + except KeyError as key_err: + self.logger.info("Key {} not found".format(key_err)) + + # list of sub-array sub-component FQDNs + self._sc_subarray_fqdn = [] + + # list of sub-component FQDNs assigned to the sub-array + self._sc_subarray_assigned_fqdn = [] + + # _sc_subarray_proxies: the sub-element sub-array proxies + # implementes as dictionary: + # keys: sub-element sub-arrayFQDN + # values: device proxy + self._sc_subarray_proxies = {} + + # Nested default dictionary with list of event ids/CSP sub-array sub-component. Need to + # store the event ids for each CSP sub-array component and attribute to un-subscribe + # them at disconnection. + # keys: sub-component FQDN + # values: dictionary (keys: attribute name, values: event id) + self._sc_subarray_event_id = defaultdict(lambda: defaultdict(lambda: 0)) + + # _sc_subarray_cmd_exec_state: implement the execution state of a long-running + # command for each sub-array sub-component. + # implemented as a nested default dictionary: + # keys: sub-element FQDN + # values: defaut dictionary (keys: command name, values: command state) + self._sc_subarray_cmd_exec_state = defaultdict(lambda: defaultdict(lambda: CmdExecState.IDLE)) + + # _sc_subarray_cmd_starting_time: for each sub-element report the long-running command + # starting time + # Implemented as dictionary: + # keys: the sub-element sub-array FQDN + # values: starting time + self._sc_subarray_cmd_starting_time = defaultdict(lambda: 0.0) + + # _command_thread: thread for the command execution + # keys: the command name('on, 'off'...) + # values: thread instance + self._command_thread = {} + + # of a long-running command + # implemented as a default nested dictionary: + # keys: sub-element sub-array FQDN + # values: default dictionary (keys: command name, values: the execution percentage) + self._sc_subarray_cmd_progress = defaultdict(lambda: defaultdict(lambda: 0)) + + # _sc_subarray_cmd_duration_expected: for each sub-element, store the duration (in sec.) + # configured for a long-running command + # Implemented as a nested default dictionary + # keys: FQDN + # values: default dictionary (keys: command name, values: the duration (in sec)) + self._sc_subarray_cmd_duration_expected = defaultdict(lambda: defaultdict(lambda: 20)) + + # _sc_subarray_scan_configuration: report the scan configuration + # for each sub-array sub-component (CBF, PSS subarray, PSTBeams) + # Implemented as default dictionary + # keys: FQDN + # values: the scan confiration as JSON formatted string + + self._sc_subarray_scan_configuration = defaultdict(lambda:'') + + # _cmd_execution_state: implement the execution state of a long-running + # command for the whole CSP sub-array Setting this attribute prevent the execution + # of the same command while it is already running. + # implemented as a default dictionary: + # keys: command name + # values:command state + self._cmd_execution_state = defaultdict(lambda: CmdExecState.IDLE) + + # _cmd_progress: report the execution progress of a long-running command + # implemented as a dictionary: + # keys: command name ('addbeams', 'removebeams', 'configure') + # values: the percentage + self._cmd_progress = defaultdict(lambda: 0) + + # _cmd_duration_expected: store the duration (in sec.) configured for + # a long-running command + # Implemented asdefault dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_expected = defaultdict(lambda: 30) + + # _cmd_duration_measured: report the measured duration (in sec.) for + # a long-running command + # Implemented as default dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_measured = defaultdict(lambda: 0) + + # _timeout_expired: report the timeout flag + self._timeout_expired = False + + # _alarm_raised: report the alarm flag + self._alarm_raised = False + + # _alarm_message: report the alarm message + # Implemented as a dictionary + # keys: command name ('addserachbeams', 'configurescan'..) + # values: the message + self._alarm_message = defaultdict(lambda: '') + + # _list_dev_completed_task: for each long-running command report the list of subordinate + # components that completed the task + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the list of components + self._list_dev_completed_task = defaultdict(lambda: []) + # the last executed command + self._last_executed_command = "" + + # _num_dev_completed_task: for each long-running command report the number + # of subordinate components that completed the task + # Implemented as a dictionary + # keys: the command name ('addbeams, 'configurescan',...) + # values: the number of components + self._num_dev_completed_task = defaultdict(lambda:0) + + # _valid_scan_configuration: the last programmed scan configuration + self._valid_scan_configuration = '' + + # unassigned CSP SearchBeam, TimingBeam, VlbiBeam Capability IDs + self._assigned_search_beams = [] + #self._unassigned_search_beam_num = 0 + self._reserved_search_beams = [] + #self._reserved_search_beam_num = 0 + self._assigned_timing_beams= [] + self._assigned_vlbi_beams = [] + + # Try connection with the CBF sub-array + self._connect_to_subarray_subcomponent(self.CbfSubarray) + # Try connection with the PSS sub-array + self._connect_to_subarray_subcomponent(self.PssSubarray) + + # 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) + # PROTECTED REGION END # // CspSubarray.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspSubarray.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspSubarray.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(CspSubarray.delete_device) ENABLED START # + #release the allocated event resources + for fqdn in self._sc_subarray_fqdn: + event_to_remove = [] + try: + for event_id in self._sc_subarray_event_id[fqdn]: + try: + self._sc_subarrays_proxies[fqdn].unsubscribe_event(event_id) + # self._se_subarray_event_id[fqdn].remove(event_id) + # in Pyton3 can't remove the element from the list while looping on it. + # Store the unsubscribed events in a temporary list and remove them later. + event_to_remove.append(event_id) + except tango.DevFailed as df: + msg = ("Unsubscribe event failure.Reason: {}. " + "Desc: {}".format(df.args[0].reason, df.args[0].desc)) + self.logger.error(msg) + except KeyError as key_err: + # NOTE: in PyTango unsubscription of a not-existing event id raises a + # KeyError exception not a DevFailed!! + msg = "Unsubscribe event failure. Reason: {}".format(str(key_err)) + self.dev_logging(msg, tango.LogLevel.LOG_ERROR) + # remove the events from the list + for k in event_to_remove: + self._se_subarray_event_id[fqdn].remove(k) + # check if there are still some registered events. What to do in this case?? + if self._se_subarray_event_id[fqdn]: + msg = "Still subscribed events: {}".format(self._se_subarray_event_id) + self.dev_logging(msg, tango.LogLevel.LOG_WARN) + else: + # delete the dictionary entry + self._se_subarray_event_id.pop(fqdn) + except KeyError as key_err: + msg = " Can't retrieve the information of key {}".format(key_err) + self.dev_logging(msg, tango.LogLevel.LOG_ERROR) + # clear the subarrays list and dictionary + self._se_subarrays_fqdn.clear() + self._se_subarrays_proxies.clear() + + # PROTECTED REGION END # // CspSubarray.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_scanID(self): + # PROTECTED REGION ID(CspSubarray.scanID_read) ENABLED START # + """Return the scanID attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.scanID_read + + def write_scanID(self, value): + # PROTECTED REGION ID(CspSubarray.scanID_write) ENABLED START # + """Set the scanID attribute.""" + pass + # PROTECTED REGION END # // CspSubarray.scanID_write + + def read_procModeCorrelationAddr(self): + # PROTECTED REGION ID(CspSubarray.corrInherentCapAddr_read) ENABLED START # + """Return the procModeCorrelationAddr attribute.""" + return self.SubarrayProcModeCorrelation + # PROTECTED REGION END # // CspSubarray.corrInherentCapAddr_read + + def read_procModePssAddr(self): + # PROTECTED REGION ID(CspSubarray.pssInherentCapAddr_read) ENABLED START # + """Return the procModePssAddr attribute.""" + return self.SubarrayProcModePss + # PROTECTED REGION END # // CspSubarray.pssInherentCapAddr_read + + def read_procModePstAddr(self): + # PROTECTED REGION ID(CspSubarray.pstInherentCap_read) ENABLED START # + """Return the procModePstAddr( attribute.""" + return self.SubarrayProcModePst + # PROTECTED REGION END # // CspSubarray.pstInherentCap_read + + def read_procModeVlbiAddr(self): + # PROTECTED REGION ID(CspSubarray.vlbiInherentCap_read) ENABLED START # + """Return the procModeVlbiAddr attribute.""" + return self.SubarrayProcModeVlbi + # PROTECTED REGION END # // CspSubarray.vlbiInherentCap_read + + def read_cbfSubarrayState(self): + # PROTECTED REGION ID(CspSubarray.cbfSubarrayState_read) ENABLED START # + """Return the cbfSubarrayState attribute.""" + return self._sc_subarray_state[self.CbfSubarray] + # PROTECTED REGION END # // CspSubarray.cbfSubarrayState_read + + def read_pssSubarrayState(self): + # PROTECTED REGION ID(CspSubarray.pssSubarrayState_read) ENABLED START # + """Return the pssSubarrayState attribute.""" + return self._sc_subarray_state[selPssSubarray] + # PROTECTED REGION END # // CspSubarray.pssSubarrayState_read + + def read_cbfSubarrayHealthState(self): + # PROTECTED REGION ID(CspSubarray.cbfSubarrayHealthState_read) ENABLED START # + """Return the cbfSubarrayHealthState attribute.""" + return self._sc_subarray_health_state[self.CbfSubarray] + # PROTECTED REGION END # // CspSubarray.cbfSubarrayHealthState_read + + def read_pssSubarrayHealthState(self): + # PROTECTED REGION ID(CspSubarray.pssSubarrayHealthState_read) ENABLED START # + """Return the pssSubarrayHealthState attribute.""" + return self._sc_subarray_health_state[self.PssSubarray] + # PROTECTED REGION END # // CspSubarray.pssSubarrayHealthState_read + + def read_cbfSubarrayAdminMode(self): + # PROTECTED REGION ID(CspSubarray.cbfSubarrayHealthState_read) ENABLED START # + """Return the cbfSubarrayHealthState attribute.""" + return self._sc_subarray_admin_mode[self.CbfSubarray] + # PROTECTED REGION END # // CspSubarray.cbfSubarrayHealthState_read + + def read_pssSubarrayAdminMode(self): + # PROTECTED REGION ID(CspSubarray.pssSubarrayHealthState_read) ENABLED START # + """Return the pssSubarrayHealthState attribute.""" + return self._sc_subarray_admin_mode[self.PssSubarray] + # PROTECTED REGION END # // CspSubarray.pssSubarrayHealthState_read + + def read_cbfSubarrayObsState(self): + # PROTECTED REGION ID(CspSubarray.cbfSubarrayObsState_read) ENABLED START # + """Return the cbfSubarrayObsState attribute.""" + return self._sc_subarray_obs_state[self.CbfSubarray] + # PROTECTED REGION END # // CspSubarray.cbfSubarrayObsState_read + + def read_pssSubarrayObsState(self): + # PROTECTED REGION ID(CspSubarray.pssSubarrayObsState_read) ENABLED START # + """Return the pssSubarrayObsState attribute.""" + return self._sc_subarray_obs_state[self.PssSubarray] + # PROTECTED REGION END # // CspSubarray.pssSubarrayObsState_read + + def read_pssSubarrayAddr(self): + # PROTECTED REGION ID(CspSubarray.pssSubarrayAddr_read) ENABLED START # + """Return the pssSubarrayAddr attribute.""" + return self.PssSubarray + # PROTECTED REGION END # // CspSubarray.pssSubarrayAddr_read + + def read_cbfSubarrayAddr(self): + # PROTECTED REGION ID(CspSubarray.cbfSubarrayAddr_read) ENABLED START # + """Return the cbfSubarrayAddr attribute.""" + return self.CbfSubarray + # PROTECTED REGION END # // CspSubarray.cbfSubarrayAddr_read + + def read_validScanConfiguration(self): + # PROTECTED REGION ID(CspSubarray.validScanConfiguration_read) ENABLED START # + """Return the validScanConfiguration attribute.""" + return self._valid_scan_configuration + # PROTECTED REGION END # // CspSubarray.validScanConfiguration_read + + def read_addSearchBeamDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.addSearchBeamDurationExpected_read) ENABLED START # + """Return the addSearchBeamDurationExpected attribute.""" + return self._cmd_duration_expected['addsearchbeam'] + # PROTECTED REGION END # // CspSubarray.addSearchBeamDurationExpected_read + + def read_remSearchBeamsDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.remSearchBeamsDurationExpected_read) ENABLED START # + """Return the remSearchBeamsDurationExpected attribute.""" + return self._cmd_duration_expected['rmsearchbeam'] + # PROTECTED REGION END # // CspSubarray.remSearchBeamsDurationExpected_read + + def read_addSearchBeamDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.addSearchBeamDurationMeasured_read) ENABLED START # + """Return the addSearchBeamDurationMeasured attribute.""" + return self._cmd_duration_measured['addsearchbeam'] + # PROTECTED REGION END # // CspSubarray.addSearchBeamDurationMeasured_read + + def read_remSearchBeamsDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.remSearchBeamsDurationMeasured_read) ENABLED START # + """Return the remSearchBeamsDurationMeasured attribute.""" + return self._cmd_duration_measured['rmsearchbeam'] + # PROTECTED REGION END # // CspSubarray.remSearchBeamsDurationMeasured_read + + def read_addTimingBeamDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.addTimingBeamDurationExpected_read) ENABLED START # + """Return the addTimingBeamDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.addTimingBeamDurationExpected_read + + def read_remTimingBeamsDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.remTimingBeamsDurationExpected_read) ENABLED START # + """Return the remTimingBeamsDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.remTimingBeamsDurationExpected_read + + def read_addTimingBeamDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.addTimingBeamDurationMeasured_read) ENABLED START # + """Return the addTimingBeamDurationMeasured attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.addTimingBeamDurationMeasured_read + + def read_remTimingBeamsDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.remTimingBeamsDurationMeasured_read) ENABLED START # + """Return the remTimingBeamsDurationMeasured attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.remTimingBeamsDurationMeasured_read + + def read_addResourcesCmdProgress(self): + # PROTECTED REGION ID(CspSubarray.searchBeamsCmdProgress_read) ENABLED START # + """Return the assResourcesCmdProgress attribute.""" + return self._cmd_progress['addbeam'] + # PROTECTED REGION END # // CspSubarray.searchBeamsCmdProgress_read + + def read_removeResourcesCmdProgress(self): + # PROTECTED REGION ID(CspSubarray.timingBeamsCmdProgress_read) ENABLED START # + """Return the removeResourcesCmdProgress attribute.""" + return self._cmd_progress['removebeams'] + # PROTECTED REGION END # // CspSubarray.timingBeamsCmdProgress_read + + def read_scanCmdProgress(self): + # PROTECTED REGION ID(CspSubarray.endSBCmdProgress_read) ENABLED START # + """Return the ScanCmdProgress attribute.""" + return self._cmd_progress['scan'] + # PROTECTED REGION END # // CspSubarray.endSBCmdProgress_read + + def read_endSBDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.endSBDurationExpected_read) ENABLED START # + """Return the endSBDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.endSBDurationExpected_read + + def read_endSBDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.endSBDurationMeasured_read) ENABLED START # + """Return the endSBDurationMeasured attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.endSBDurationMeasured_read + + def read_endSBCmdProgress(self): + # PROTECTED REGION ID(CspSubarray.endSBCmdProgress_read) ENABLED START # + """Return the endSBCmdProgress attribute.""" + return self._cmd_progress['endsb'] + # PROTECTED REGION END # // CspSubarray.endSBCmdProgress_read + + def read_endScanDurationExpected(self): + # PROTECTED REGION ID(CspSubarray.endScanDurationExpected_read) ENABLED START # + """Return the endScanDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.endScanDurationExpected_read + + def read_endScanDurationMeasured(self): + # PROTECTED REGION ID(CspSubarray.endScanDurationMeasured_read) ENABLED START # + """Return the endScanDurationMeasured attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.endScanDurationMeasured_read + + def read_endScanCmdProgress(self): + # PROTECTED REGION ID(CspSubarray.endScanCmdProgress_read) ENABLED START # + """Return the endScanCmdProgress attribute.""" + return self._cmd_progress['endscan'] + # PROTECTED REGION END # // CspSubarray.endScanCmdProgress_read + + def read_reservedSearchBeamNum(self): + # PROTECTED REGION ID(CspSubarray.reservedSearchBeamNum_read) ENABLED START # + """Return the reservedSearchBeamNum attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.reservedSearchBeamNum_read + + def read_numOfDevCompletedTask(self): + # PROTECTED REGION ID(CspSubarray.numOfDevCompletedTask_read) ENABLED START # + """Return the numOfDevCompletedTask attribute.""" + return 0 + # PROTECTED REGION END # // CspSubarray.numOfDevCompletedTask_read + + def read_assignedSearchBeamIDs(self): + # PROTECTED REGION ID(CspSubarray.assignedSearchBeamIDs_read) ENABLED START # + """Return the assignedSearchBeamIDs attribute.""" + return _assigned_search_beams + # PROTECTED REGION END # // CspSubarray.assignedSearchBeamIDs_read + + def read_reservedSearchBeamIDs(self): + # PROTECTED REGION ID(CspSubarray.reservedSearchBeamIDs_read) ENABLED START # + """Return the reservedSearchBeamIDs attribute.""" + return _reserved_search_beams + # PROTECTED REGION END # // CspSubarray.reservedSearchBeamIDs_read + + def read_assignedTimingBeamIDs(self): + # PROTECTED REGION ID(CspSubarray.assignedTimingBeamIDs_read) ENABLED START # + """Return the assignedTimingBeamIDs attribute.""" + return _assigned_timing_beams + # PROTECTED REGION END # // CspSubarray.assignedTimingBeamIDs_read + + def read_assignedVlbiBeamIDs(self): + # PROTECTED REGION ID(CspSubarray.assignedVlbiBeam IDs_read) ENABLED START # + """Return the assignedVlbiBeam IDs attribute.""" + return _assigned_vlbi_beams + # PROTECTED REGION END # // CspSubarray.assignedVlbiBeam IDs_read + + def read_assignedSearchBeamsState(self): + # PROTECTED REGION ID(CspSubarray.assignedSearchBeamsState_read) ENABLED START # + """Return the assignedSearchBeamsState attribute.""" + self._search_beams_state = {key:value for key,value in self._subarray_resources_state.items() + if key.find("search") > -1} + return self._search_beams_state.values() + # PROTECTED REGION END # // CspSubarray.assignedSearchBeamsState_read + + def read_assignedTimingBeamsState(self): + # PROTECTED REGION ID(CspSubarray.assignedTimingBeamsState_read) ENABLED START # + """Return the assignedTimingBeamsState attribute.""" + self._timing_beams_state = {key:value for key,value in self._subarray_resources_state.items() + if key.find("timing") > -1} + return self._timing_beams_state.values() + # PROTECTED REGION END # // CspSubarray.assignedTimingBeamsState_read + + def read_assignedVlbiBeamsState(self): + # PROTECTED REGION ID(CspSubarray.assignedVlbiBeamsState_read) ENABLED START # + """Return the assignedVlbiBeamsState attribute.""" + self._vlbi_beams_state = {key:value for key,value in self._subarray_resources_state.items() + if key.find("vlbi") > -1} + return self._vlbi_beams_state.values() + # PROTECTED REGION END # // CspSubarray.assignedVlbiBeamsState_read + + def read_assignedSearchBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarray.assignedSearchBeamsHealthState_read) ENABLED START # + """Return the assignedSearchBeamsHealthState attribute.""" + self._search_beams_health_state = {key:value for key,value in + self._subarray_resources_health_state.item() + if key.find("search") > -1} + return self._search_beams_health_state.values() + # PROTECTED REGION END # // CspSubarray.assignedSearchBeamsHealthState_read + + def read_assignedTimingBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarray.assignedTimingBeamsHealthState_read) ENABLED START # + """Return the assignedTimingBeamsHealthState attribute.""" + self._timing_beams_health_state = {key:value for key,value in + self._subarray_resources_state.items() + if key.find("timing") > -1} + return self._timing_beams_health_state.values() + # PROTECTED REGION END # // CspSubarray.assignedTimingBeamsHealthState_read + + def read_assignedVlbiBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarray.assignedVlbiBeamsHealthState_read) ENABLED START # + """Return the assignedVlbiBeamsHealthState attribute.""" + self._vlbi_beams_health_state = {key:value for key,value + in self._subarray_resources_state.items() + if key.find("vlbi") > -1} + return self._vlbi_beams_health_state.values() + # PROTECTED REGION END # // CspSubarray.assignedVlbiBeamsHealthState_read + + def read_assignedSearchBeamsObsState(self): + # PROTECTED REGION ID(CspSubarray.assignedSearchBeamsObsState_read) ENABLED START # + """Return the assignedSearchBeamsObsState attribute.""" + self._search_beams_obs_state = {key:value for key,value in + self._subarray_resources_health_state.items() + if key.find("search") > -1} + return self._search_beams_obs_state.values() + # PROTECTED REGION END # // CspSubarray.assignedSearchBeamsObsState_read + + def read_assignedTimingBeamsObsState(self): + # PROTECTED REGION ID(CspSubarray.assignedTimingBeamsObsState_read) ENABLED START # + """Return the assignedTimingBeamsObsState attribute.""" + self._timing_beams_obs_state = {key:value for key,value in + self._subarray_resources_state.items() + if key.find("timing") > -1} + return self._timing_beams_obs_state.values() + # PROTECTED REGION END # // CspSubarray.assignedTimingBeamsObsState_read + + def read_assignedVlbiBeamsObsState(self): + # PROTECTED REGION ID(CspSubarray.assignedVlbiBeamsObsState_read) ENABLED START # + """Return the assignedVlbiBeamsObsState attribute.""" + self._vlbi_beams_obs_state = {key:value for key,value in + self._subarray_resources_state.items() + if key.find("vlbi") > -1} + return self._vlbi_beams_obs_state.values() + # PROTECTED REGION END # // CspSubarray.assignedVlbiBeamsObsState_read + + def read_assignedSearchBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarray.assignedSearchBeamsAdminMode_read) ENABLED START # + """Return the assignedSearchBeamsAdminMode attribute.""" + self._search_beams_admin_mode = {key:value for key,value in + self._subarray_resources_health_state.items() + if key.find("search") > -1} + return self._search_beams_admin_mode.values() + # PROTECTED REGION END # // CspSubarray.assignedSearchBeamsAdminMode_read + + def read_assignedTimingBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarray.assignedTimingBeamsAdminMode_read) ENABLED START # + """Return the assignedTimingBeamsAdminMode attribute.""" + self._timing_beams_admin_mode = {key:value for key,value in + self._subarray_resources_state.items() + if key.find("timing") > -1} + return self._timing_beams_admin_mode.values() + # PROTECTED REGION END # // CspSubarray.assignedTimingBeamsAdminMode_read + + def read_assignedVlbiBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarray.assignedVlbiBeamsAdminMode_read) ENABLED START # + """Return the assignedVlbiBeamsAdminMode attribute.""" + self._vlbi_beams_admin_mode = {key:value for key,value in + self._subarray_resources_state.items() + if key.find("vlbi") > -1} + return self._vlbi_beams_admin_mode.values() + # PROTECTED REGION END # // CspSubarray.assignedVlbiBeamsAdminMode_read + + def read_pstBeams(self): + # PROTECTED REGION ID(CspSubarray.pstBeams_read) ENABLED START # + """Return the pstBeams attribute.""" + return self.PstBeams + # PROTECTED REGION END # // CspSubarray.pstBeams_read + + def read_cmdTimeoutExpired(self): + # PROTECTED REGION ID(CspSubarray.cmdTimeoutExpired_read) ENABLED START # + """Return the cmdTimeoutExpired attribute.""" + return False + # PROTECTED REGION END # // CspSubarray.cmdTimeoutExpired_read + + def read_cmdAlarmRaised(self): + # PROTECTED REGION ID(CspSubarray.cmdAlarmRaised_read) ENABLED START # + """Return the cmdAlarmRaised attribute.""" + return False + # PROTECTED REGION END # // CspSubarray.cmdAlarmRaised_read + + def read_pstOutputLink(self): + # PROTECTED REGION ID(CspSubarray.pstOutputLink_read) ENABLED START # + """Return the pstOutputLink attribute.""" + return '' + # PROTECTED REGION END # // CspSubarray.pstOutputLink_read + def read_listOfDevCompletedTask(self): + # PROTECTED REGION ID(CspSubarray.listOfDevCompletedTask_read) ENABLED START # + """Return the listOfDevCompletedTask attribute.""" + return ('',) + # PROTECTED REGION END # // CspSubarray.listOfDevCompletedTask_read + + + # -------- + # Commands + # -------- + + @AdminModeCheck('EndScan') + @ObsStateCheck('endscan') + def is_EndScan_allowed(self): + return self._is_subarray_configuring_allowed() + + @command( + ) + @DebugIt() + def EndScan(self): + # PROTECTED REGION ID(CspSubarray.EndScan) ENABLED START # + """ + *Class method* + End the execution of a running scan. After successful execution, the CspSubarray \ + *ObsState* is IDLE. + + raises: + tango.DevFailed: if the subarray *obsState* is not SCANNING or if an exception + is caught during the command execution. + Note: + Still to implement the check on AdminMode values: the command can be processed \ + only when the CspSubarray is *ONLINE* or *MAINTENANCE* + """ + for device in self._sc_subarray_fqdn: + try: + proxy = self._sc_subarray_proxies[device] + except KeyError as key_err: + self.logger.warn("No key {} found".format(key_err)) + proxy.command_inout_asynch("EndScan", self._cmd_ended_cb) + # PROTECTED REGION END # // CspSubarray.EndScan + + @AdminModeCheck('Scan') + @ObsStateCheck('scan') + def is_Scan_allowed(self): + return self._is_subarray_configuring_allowed() + + @command( + dtype_in='DevVarStringArray', + ) + @DebugIt() + def Scan(self, argin): + # PROTECTED REGION ID(CspSubarray.Scan) ENABLED START # + """ + Starts the scan. + + :param argin: 'DevVarStringArray' + + :return:None + """ + # invoke the constructor for the command thread + self._cmd_progress['scan'] = 0 + for device in self._sc_subarray_fqdn: + try: + proxy = self._sc_subarray_proxies[device] + if not self._sc_subarray_event_id[device]['scancmdprogress']: + evt_id = proxy.subscribe_event("scanCmdProgress", + tango.EventType.CHANGE_EVENT, + self._sc_attributes_change_event_cb, + stateless=False) + self._sc_subarray_event_id[device]['scancmdprogress'] = evt_id + except KeyError as key_err: + self.logger.warn("No key {} found".format(key_err)) + except tango.DevFailed as tango_err: + self.logger.info(tango_err.args[0].desc) + proxy.command_inout_asynch("Scan", self._cmd_ended_cb) + + # PROTECTED REGION END # // CspSubarray.Scan + def __validate_scan_configuration(self, json_config): + """ + here is done a preliminary validation of the configuraito: + - look for the sub-element entries + - add eventual information to the sub-element blocks (for example for PSS add the + addresses of the PSS pipelines or the IDs of the SearchBeams) + - set the observing mode for each sub-element sub-array/PSTBeam + + if "cbf" in json_config: + self._sc_subarray_obs_mode[self.CbfSubarray] = ObsMode.CORRELATION + scan_configutation[self.CbfSubarray] = json_config["cbf"] + if "pss" in json_config: + scan_configutation[self.PssSubarray] = json_config["pss"] + if "pst" in json_config: + scan_configuration[self.PssSubarray] = json_config["pst"] + return scan_configuration_dict + + Customize the function for each instance + """ + if "cbf" in json_config: + if self._sc_subarray_state[self.CbfSubarray] != tango.DevState.ON: + pass + # throw exception + self._sc_subarray_obs_mode[self.CbfSubarray] = ObsMode.CORRELATION + self._sc_scan_configuration[self.CbfSubarray] = json_config["cbf"] + self._sc_subarray_assigned_fqdn.append(self.CbfSubarray) + if "pss" in json_config: + if self._sc_subarray_state[self.PssSubarray] != tango.DevState.ON: + pass + # throw exception + #self._sc_subarray_obs_mode[self.PssSubarray] = ?? + self._sc_subarray_assigned_fqdn.append(self.PssSubarray) + self._sc_scan_configuration[self.PssSubarray] = json_config["pss"] + if "searchbeams" not in self._sc_scan_configuration[self.PssSubarray]: + self._sc_scan_configuration[self.PssSubarray]["searchbeams"] = self._assigned_search_beams + if "pst" in json_config: + + pass + + @AdminModeCheck('ConfigureScan') + def is_ConfigureScan_allowed(self): + return self._is_subarray_configuring_allowed() + + @command( + dtype_in='DevString', + doc_in="A Json-encoded string with the scan configuration.", + ) + @DebugIt() + @ObsStateCheck('configscan') + @SubarrayRejectCmd(['AddSearchBeams', + 'RemoveSearchBeams', + 'AddTimingBeams', + 'RemoveTimingBeams' + 'AddNumOfSearchBeams', + 'RemoveNumOfSearchBeams']) + def ConfigureScan(self, argin): + """ + *TANGO Class method* + + Configure a scan for the subarray.\n + The command can be execuced when the CspSubarray State is *ON* and the \ + ObsState is *IDLE* or *READY*.\n + If the configuration for the scan is not correct (invalid parameters or invalid JSON)\ + the configuration is not applied and the ObsState of the CspSubarray remains IDLE. + + :param argin: a JSON-encoded string with the parameters to configure a scan. + :return: None + :raises: + tango.DevFailed exception if the CspSubarray ObsState is not valid or if an exception\ + is caught during command execution. + Note: + Still to implement the check on AdminMode values: the command can be processed \ + only when the CspSubarray is *ONLINE* or *MAINTENANCE* + """ + # PROTECTED REGION ID(CspSubarray.ConfigureScan) ENABLED START # + + # checks on Stae, adminMode and obsState values are performed inside the + # python decorators + + # the dictionary with the scan configuration + argin_dict = {} + try: + # for test purpose we load the json configuration from an + # external file. + if "load" in argin: + # skip the 'load' chars and remove spaces from the filename + fn = (argin[4:]).strip() + # !!!Note!! set the path to the data file + filename = os.path.join(commons_pkg_path, fn) + with open(filename) as json_file: + # load the file into a dictionary + argin_dict = json.load(json_file) + # dump the dictionary into the input string to forward + # to CbfSubarray + argin = json.dumps(argin_dict) + else: + argin_dict = json.loads(argin) + except FileNotFoundError as file_err: + self.logger.error(file_err) + tango.Except.throw_exception("Command failed", + str(file_err), + "ConfigureScan execution", + tango.ErrSeverity.ERR) + except json.JSONDecodeError as e: # argument not a valid JSON object + # this is a fatal error + msg = ("Scan configuration object is not a valid JSON object." + "Aborting configuration:{}".format(str(e))) + self.logger.error(msg) + tango.Except.throw_exception("Command failed", + msg, + "ConfigureScan execution", + tango.ErrSeverity.ERR) + self._validate_scan_configuration(argin) + + # Forward the ConfigureScan command to CbfSubarray. + #self._timeout_expired = False + #self._alarm_raised = False + for device in self._sc_subarray_assigned_fqdn: + #json_config = json.dumps(self._sc_subarray_scan_configuration[device]) + #print("json_config:", json_config) + proxy = self._sc_subarray_proxies[device] + attributes = ['configureCmdProgress', 'configureCmdTimeoutExpired'] + 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) + args_dict = {'cmd_name':"ConfigureScan", + 'obs_state':ObsState.READY} + # invoke the constructor for the command thread + self._command_thread['configurescan'] = threading.Thread(target=self.__configure_scan, + name="Thread-ConfigureScan", + args=(self._sc_subarray_assigned_fqdn,), + kwargs=args_dict) + self._command_thread['configurescan'].start() + # sleep for a while to let the thread start + time.sleep(0.2) + # PROTECTED REGION END # // CspSubarray.ConfigureScan + + @AdminModeCheck('AddNumOfSearchBeams') + @ObsStateCheck('addresources') + def is_AddNumOfSearchBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevUShort', + doc_in="The number of SearchBeams Capabilities to assign to the subarray.", + ) + @DebugIt() + @SubarrayRejectCmd(['RemoveSearchBeams', + 'RemoveNumOfSearchBeams', + 'ConfigureScan']) + def AddNumOfSearchBeams(self, argin): + # PROTECTED REGION ID(CspSubarray.AddNumOfSearchBeams) ENABLED START # + self._cmd_execution_state['addsearchbeams'] = CmdExecState.RUNNING + # connect to CspMaster and check if enough beams are available + # forward the command to PSS + # wait for PSS number of assigned pipelines == number of required beams + # get the PSS beams IDs + # if map exists, retrieve the SearchBeam IDs + # get the corresponding SearchBeams FQDNs + # open proxies to devices + # subscribe SearchBeams attributes + # PROTECTED REGION END # // CspSubarray.AddNumOfSearchBeams + pass + + @AdminModeCheck('RemoveNumOfSearchBeams') + @ObsStateCheck('removeresources') + def is_RemoveNumOfSearchBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevUShort', + doc_in="The number of SearchBeam Capabilities to remove from the \nCSP sub-array.\nAll the assigned SearcBbeams are removed from the CSP sub-array if the\ninput number is equal to the max number of SearchBeam \nCapabilities for the specified Csp sub-array instance (1500 for MID,\n500 for LOW)", + ) + @DebugIt() + @SubarrayRejectCmd(['AddSearchBeams', 'ConfigureScan']) + def RemoveNumOfSearchBeams(self, argin): + # PROTECTED REGION ID(CspSubarray.RemoveNumOfSearchBeams) ENABLED START # + """ + + Remove the specified number of SearchBeam Capabilities + from the subarray. + + :param argin: 'DevUShort' + + The number of SearchBeam Capabilities to remove from the + CSP sub-array. + All the assigned SearcBbeams are removed from the CSP sub-array if the + input number is equal to the max number of SearchBeam + Capabilities for the specified Csp sub-array instance (1500 for MID, + 500 for LOW) + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubarray.RemoveNumOfSearchBeams + + + @AdminModeCheck('AddTimingBeams') + @ObsStateCheck('addresources') + def is_AddTimingBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevVarUShortArray', + doc_in="The list of TimingBeam Capability IDs to assign to the CSP sub-array.", + ) + @DebugIt() + @SubarrayRejectCmd(['RemoveTimingBeams', 'ConfigureScan']) + def AddTimingBeams(self, argin): + # PROTECTED REGION ID(CspSubarray.AddTimingBeams) ENABLED START # + """ + + Add the specified TimingBeam Capability IDs to the CSP + sub-array. + + :param argin: 'DevVarUShortArray' + The list of TimingBeam Capability IDs to assign to the CSP sub-array. + + :return:None + """ + # read the CSP Master list of CSP TimingBeams addresses + # get the CSP TimingBeams addresses from IDs + # map timing beams ids to PST Beams ids + # write the CSP TimingBeams membership + # get the PSTBeams addresses + + pass + # PROTECTED REGION END # // CspSubarray.AddTimingBeams + + @AdminModeCheck('AddSearchBeams') + @ObsStateCheck('addresources') + def is_AddSearchBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevVarUShortArray', + doc_in="The list of SearchBeam Capability IDs to assign to the CSP sub-array.", + ) + @DebugIt() + @SubarrayRejectCmd(['RemoveSearchBeams', 'ConfigureScan']) + def AddSearchBeams(self, argin): + # PROTECTED REGION ID(CspSubarray.AddSearchBeams) ENABLED START # + """ + + Add the specified SeachBeam Capability IDs o the CSP + sub-array. + + :param argin: 'DevVarUShortArray' + The list of SearchBeam Capability IDs to assign to the CSP sub-array. + + :return:None + """ + # read the CSP Master list of CSP SearchBeams addresses + # get the CSP SearchBeams addresses from IDs + # map search beams ids to PSS beams IDs + # issue the AddSearchBeams command on PSS sub-array + # wait until PSS list of beams is equal to the sent one + self._cmd_execution_state['addsearchbeams'] = CmdExecState.RUNNING + pass + # PROTECTED REGION END # // CspSubarray.AddSearchBeams + + @AdminModeCheck('RemoveSearchBeamsID') + @ObsStateCheck('removeresources') + def is_RemoveSearchBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevVarUShortArray', + doc_in="The list of SearchBeam Capability IDs to remove from the CSP sub-array.", + ) + @DebugIt() + @SubarrayRejectCmd(['AddSearchBeams', 'ConfigureScan']) + def RemoveSearchBeamsID(self, argin): + # PROTECTED REGION ID(CspSubarray.RemoveSearchBeamsID) ENABLED START # + """ + + Remove the specified Search Beam Capability IDs from the + CSP sub-array. + + :param argin: 'DevVarUShortArray' + The list of SearchBeam Capability IDs to remove from the CSP sub-array. + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubarray.RemoveSearchBeamsID + + @AdminModeCheck('RemoveTimingBeams') + @ObsStateCheck('removeresources') + def is_RemoveTimingBeams_allowed(self): + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevVarUShortArray', + doc_in="The list of Timing Beams IDs to remove from the sub-array.", + ) + @DebugIt() + @SubarrayRejectCmd(['AddTimingBeams', 'ConfigureScan']) + def RemoveTimingBeams(self, argin): + # PROTECTED REGION ID(CspSubarray.RemoveTimingBeams) ENABLED START # + """ + Remove the specified Timing Beams from the sub-array. + + :param argin: 'DevVarUShortArray' + The list of Timing Beams IDs to remove from the sub-array. + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubarray.RemoveTimingBeams + + @AdminModeCheck('EndSB') + @ObsStateCheck('endsb') + def is_EndSB_allowed(self): + return self._is_subarray_configuring_allowed() + + @command( + ) + @DebugIt() + @SubarrayRejectCmd(['ConfigureScan']) + def EndSB(self): + # PROTECTED REGION ID(CspSubarray.EndSB) ENABLED START # + """ + Set the subarray obsState to IDLE. + + :return:None + """ + device_list = self._sc_subarray_assigned_fqdn + if not any(self._sc_subarray_assigned_fqdn): + print("Assigne list is empty") + device_list = self._sc_subarray_fqdn + for fqdn in device_list: + proxy = self._sc_subarray_proxies[fqdn] + proxy.command_inout_asynch("EndSB", self._cmd_ended_cb) + # PROTECTED REGION END # // CspSubarray.EndSB + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(CspSubarray.main) ENABLED START # + return run((CspSubarray,), args=args, **kwargs) + # PROTECTED REGION END # // CspSubarray.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/csp_lmc_common/CspSubarrayResourcesMonitor.py b/csp-lmc-common/csp_lmc_common/CspSubarrayResourcesMonitor.py new file mode 100644 index 0000000000000000000000000000000000000000..c5e2e468ac6bee64591d3beb63d1b11019455790 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/CspSubarrayResourcesMonitor.py @@ -0,0 +1,283 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspSubarrayResourcesMonitor project +# +# INAF, SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP Subarray Resource Monitor + +The class implementes the monitoring of all the resources +allocated to the CSP Subarray. +""" + +# tango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from SKABaseDevice import SKABaseDevice +# Additional import +# PROTECTED REGION ID(CspSubarrayResourcesMonitor.additionnal_import) ENABLED START # +# PROTECTED REGION END # // CspSubarrayResourcesMonitor.additionnal_import + +__all__ = ["CspSubarrayResourcesMonitor", "main"] + + +class CspSubarrayResourcesMonitor(SKABaseDevice): + """ + The class implementes the monitoring of all the resources + allocated to the CSP Subarray. + + **Properties:** + + - Device Property + + + + + """ + __metaclass__ = DeviceMeta + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.class_variable) ENABLED START # + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.class_variable + + # ----------------- + # Device Properties + # ----------------- + + + + + + # ---------- + # Attributes + # ---------- + + + + + + + + + + + assignedSearchBeamsState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams State", + polling_period=3000, + doc="State of the assigned SearchBeams", + ) + + assignedTimingBeamsState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams State", + polling_period=3000, + doc="State of the assigned TimingBeams", + ) + + assignedVlbiBeamsState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams State", + polling_period=3000, + doc="State of the assigned VlbiBeams", + ) + + assignedSearchBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams HealthState", + polling_period=3000, + doc="HealthState of the assigned SearchBeams", + ) + + assignedTimingBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams HealthState", + polling_period=3000, + doc="HealthState of the assigned TimingBeams", + ) + + assignedVlbiBeamsHealthState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams HealthState", + polling_period=3000, + doc="HealthState of the assigned VlbiBeams", + ) + + assignedSearchBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams ObsState", + polling_period=3000, + doc="ObsState of the assigned SearchBeams", + ) + + assignedTimingBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams ObsState", + polling_period=3000, + doc="ObsState of the assigned TimingBeams", + ) + + assignedVlbiBeamsObsState = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams ObsState", + polling_period=3000, + doc="ObsState of the assigned VlbiBeams", + ) + + assignedSearchBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Assigned SearchBeams AdminMode", + polling_period=3000, + doc="AdminMode of the assigned SearchBeams", + ) + + assignedTimingBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=16, + label="Assigned TimingBeams AdminMode", + polling_period=3000, + doc="AdminMode of the assigned TimingBeams", + ) + + assignedVlbiBeamsAdminMode = attribute( + dtype=('DevState',), + max_dim_x=20, + label="Assigned VlbiBeams AdminMode", + polling_period=3000, + doc="AdminMode of the assigned VlbiBeams", + ) + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspSubarrayResourcesMonitor.""" + SKABaseDevice.init_device(self) + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.init_device) ENABLED START # + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.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(CspSubarrayResourcesMonitor.delete_device) ENABLED START # + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_assignedSearchBeamsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedSearchBeamsState_read) ENABLED START # + """Return the assignedSearchBeamsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedSearchBeamsState_read + + def read_assignedTimingBeamsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedTimingBeamsState_read) ENABLED START # + """Return the assignedTimingBeamsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedTimingBeamsState_read + + def read_assignedVlbiBeamsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedVlbiBeamsState_read) ENABLED START # + """Return the assignedVlbiBeamsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedVlbiBeamsState_read + + def read_assignedSearchBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedSearchBeamsHealthState_read) ENABLED START # + """Return the assignedSearchBeamsHealthState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedSearchBeamsHealthState_read + + def read_assignedTimingBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedTimingBeamsHealthState_read) ENABLED START # + """Return the assignedTimingBeamsHealthState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedTimingBeamsHealthState_read + + def read_assignedVlbiBeamsHealthState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedVlbiBeamsHealthState_read) ENABLED START # + """Return the assignedVlbiBeamsHealthState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedVlbiBeamsHealthState_read + + def read_assignedSearchBeamsObsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedSearchBeamsObsState_read) ENABLED START # + """Return the assignedSearchBeamsObsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedSearchBeamsObsState_read + + def read_assignedTimingBeamsObsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedTimingBeamsObsState_read) ENABLED START # + """Return the assignedTimingBeamsObsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedTimingBeamsObsState_read + + def read_assignedVlbiBeamsObsState(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedVlbiBeamsObsState_read) ENABLED START # + """Return the assignedVlbiBeamsObsState attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedVlbiBeamsObsState_read + + def read_assignedSearchBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedSearchBeamsAdminMode_read) ENABLED START # + """Return the assignedSearchBeamsAdminMode attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedSearchBeamsAdminMode_read + + def read_assignedTimingBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedTimingBeamsAdminMode_read) ENABLED START # + """Return the assignedTimingBeamsAdminMode attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedTimingBeamsAdminMode_read + + def read_assignedVlbiBeamsAdminMode(self): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.assignedVlbiBeamsAdminMode_read) ENABLED START # + """Return the assignedVlbiBeamsAdminMode attribute.""" + return (tango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.assignedVlbiBeamsAdminMode_read + + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(CspSubarrayResourcesMonitor.main) ENABLED START # + return run((CspSubarrayResourcesMonitor,), args=args, **kwargs) + # PROTECTED REGION END # // CspSubarrayResourcesMonitor.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/csp-lmc-common/__init__.py b/csp-lmc-common/csp_lmc_common/__init__.py similarity index 100% rename from csp-lmc-common/csp-lmc-common/__init__.py rename to csp-lmc-common/csp_lmc_common/__init__.py diff --git a/csp-lmc-common/csp_lmc_common/release.py b/csp-lmc-common/csp_lmc_common/release.py new file mode 100755 index 0000000000000000000000000000000000000000..bf07f0aa8237ceeb6a7bb546d8209b1e55d6f8b4 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/release.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CentralNode project +# +# +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +"""Release information for Python Package""" + +name = """csp-lmc-common""" +version = "0.3.0" +version_info = version.split(".") +description = """SKA CSP.LMC Common Software""" +author = "INAF-OAA" +author_email = "elisabetta.giani@inaf.it" +license = """BSD-3-Clause""" +url = """https://gitlab.com/ska-telescope/csp-lmc.git""" +copyright = """INAF, SKA Telescope""" diff --git a/csp-lmc-common/csp_lmc_common/utils/__init__.py b/csp-lmc-common/csp_lmc_common/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/csp-lmc-common/csp_lmc_common/utils/cspcommons.py b/csp-lmc-common/csp_lmc_common/utils/cspcommons.py new file mode 100644 index 0000000000000000000000000000000000000000..0c8243e2d6fc5065d02d4cafac79246776827f92 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/utils/cspcommons.py @@ -0,0 +1,51 @@ +from enum import IntEnum, unique + +@unique +class HealthState(IntEnum): + OK = 0 + DEGRADED = 1 + FAILED = 2 + UNKNOWN = 3 + +@unique +class AdminMode(IntEnum): + ONLINE = 0 + OFFLINE = 1 + MAINTENANCE = 2 + NOTFITTED = 3 + RESERVED = 4 + +@unique +class ControlMode(IntEnum): + REMOTE = 0 + LOCAL = 1 + +@unique +class ObsMode(IntEnum): + IDLE = 0 + IMAGING = 1 + PULSARSEARCH = 2 + PULSARTIMING = 3 + DYNAMICSPECTRUM = 4 + TRANSIENTSEARCH = 5 + VLBI = 6 + CALIBRATION = 7 + +@unique +class ObsState(IntEnum): + IDLE = 0 + CONFIGURING = 1 + READY = 2 + SCANNING = 3 + PAUSED = 4 + ABORTED = 5 + FAULT = 6 + +@unique +class CmdExecState(IntEnum): + IDLE = 0 + RUNNING = 1 + QUEUED = 2 + TIMEOUT = 3 + FAILED = 4 + diff --git a/csp-lmc-common/csp_lmc_common/utils/decorators.py b/csp-lmc-common/csp_lmc_common/utils/decorators.py new file mode 100644 index 0000000000000000000000000000000000000000..45e5507c9739c246b39579f7f2c253267268c3b0 --- /dev/null +++ b/csp-lmc-common/csp_lmc_common/utils/decorators.py @@ -0,0 +1,297 @@ +import sys +import os + +import tango +from .cspcommons import AdminMode, ObsState, CmdExecState +import functools + +class AdminModeCheck(object): + """ + Class designed to be a decorator for the CspMaster methods. + It checks the adminMode attribute value: if not ONLINE or + MAINTENANCE it throws an exception. + """ + def __init__(self, cmd_to_execute): + self._cmd_to_execute = cmd_to_execute + def __call__(self, f): + @functools.wraps(f) + def admin_mode_check(*args, **kwargs): + # get the device instance + dev_instance = args[0] + dev_instance.logger.debug("AdminModeCheck command to execute:", self._cmd_to_execute) + # Check the AdminMode value: the command is callable only if the + # the administration mode is ONLINE or MAINTENACE + + if dev_instance._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]: + # NOTE: when adminMode is not ONLINE/MAINTENANCE the device State has to be + # DISABLE + # Add only a check on State value to log a warning message if it + # is different from DISABLE + msg_args = (self._cmd_to_execute, dev_instance.get_state(), AdminMode(dev_instance._admin_mode).name) + if dev_instance.get_state() != tango.DevState.DISABLE: + dev_instance.logger.warn("Command {}: incoherent device State {} " + " with adminMode {}".format(*msg_args)) + err_msg = ("{} command can't be issued when State is {} and" + " adminMode is {} ".format(*msg_args)) + + tango.Except.throw_exception("Invalid adminMode value", + err_msg, + "AdminModeCheck decorator", + tango.ErrSeverity.ERR) + return f(*args, **kwargs) + return admin_mode_check + +VALID_OBS_STATE = {'abort' : [ObsState.CONFIGURING, ObsState.SCANNING], + 'reset' : [ObsState.ABORTED], + 'configscan' : [ObsState.IDLE, ObsState.READY], + 'scan' : [ObsState.READY], + 'endscan' : [ObsState.SCANNING], + 'endsb' : [ObsState.READY, ObsState.IDLE], + 'addresources' : [ObsState.IDLE], + 'removeresources' : [ObsState.IDLE] + } +class ObsStateCheck(object): + """ + Class designed to be a decorator for the CspMaster methods. + It checks the obsMode attribute value + """ + def __init__(self, args=False, kwargs=False): + self._args = args + self._kwargs = kwargs + def __call__(self, f): + @functools.wraps(f) + def obs_state_check(*args, **kwargs): + # get the device instance + dev_instance = args[0] + cmd_type = self._args + + # Check the obsState attribute value: valid values for the command to + # execute are defined by VALID_OBS_STATE dictionary + if dev_instance._obs_state not in VALID_OBS_STATE[cmd_type]: + msg_args = (f.__name__, ObsState(dev_instance._obs_state).name) + err_msg = ("{} command can't be issued when the" + " obsState is {} ".format(*msg_args)) + + tango.Except.throw_exception("Command not executable", + err_msg, + "ObsStateCheck decorator", + tango.ErrSeverity.ERR) + return f(*args, **kwargs) + return obs_state_check + +class CmdInputArgsCheck(object): + """ + Class designed to be a decorator for the CspMaster methods. + The *decorator function* performs a check on the function input argument, + detecting if the corresponding servers are running and the + administrative mode of the devices has the right value to execute a command (i.e + ONLINE/MAINTENACE) + The *decorator function* accepts some parameters as input to customize + its functionality + """ + def __init__(self, *args, **kwargs): + # store the decorators parameters: + # args: the list of sub-element attributes to subscribe, to track the + # sub-element command progress and detect a command timeout + # kwargs: a dictionary: key ="cmd_name", + # value = command to execute ('on', 'off'...) + # + self._args = args + self._kwargs = kwargs + def __call__(self, f): + @functools.wraps(f) + def input_args_check(*args, **kwargs): + # the CspMaster device instance + dev_instance = args[0] + # get the information passed as arguments to the decorator + attrs_to_subscribe = self._args + try: + cmd_to_exec = self._kwargs['cmd_name'] + except KeyError as key_err: + msg =("No key found for {}".format(str(key_err))) + dev_instance.logger.warn(msg) + tango.Except.throw_exception("Command failure", + "Error in input decorator args", + "CmdInputArgsCheck decorator", + tango.ErrSeverity.ERR) + input_arg = args[1] + device_list = input_arg + # Note: device list is a reference to args[1]: changing + # device_list content, args[1] changes accordingly! + num_of_devices = len(input_arg) + if num_of_devices == 0: + # no input argument -> switch on all sub-elements + num_of_devices = len(dev_instance._se_fqdn) + # !!Note!!: + # need to copy inside device_list to maintain the reference to args[1] + # if we do + # device_list = dev_instance._se_fqdn + # we get a new variable address and we lose the reference to args[1] + for fqdn in dev_instance._se_fqdn: + device_list.append(fqdn) + else: + if num_of_devices > len(dev_instance._se_fqdn): + # too many devices specified-> log the warning but go on + # with command execution + dev_instance.logger.warn("Too many input parameters") + dev_instance.logger.debug("CmdInputArgsCheck: devices {} to check:".format(device_list)) + # If a sub-element device is already executing a power command, an exception is + # thown only when the requested command is different from the one + # already running (power commands have to be executed sequentially). + # TODO: + # What to do if the required device is performing a software upgrade or is changing its + # adminMode? How can CSP.LMC detect this condition? + list_of_running_cmd = [cmd_name for cmd_name, cmd_state in dev_instance._cmd_execution_state.items() + if cmd_state == CmdExecState.RUNNING] + if list_of_running_cmd: + # if a command is running, check if its the requested one + if len(list_of_running_cmd) > 1: + # should not happen!! throw an exception + err_msg = "{} power commands are running. Something strange!".format(len(list_of_running_cmd)) + tango.Except.throw_exception("Command failure", + err_msg, + "CmdInputArgsCheck decorator", + tango.ErrSeverity.ERR) + if list_of_running_cmd[0] == cmd_to_exec: + # the requested command is already running + # return with no exception (see SKA Guidelines) + msg = ("Command {} is already running".format(cmd_to_exec)) + dev_instance.logger.info(msg) + return + else: + # another power command is already running + err_msg = ("Can't execute command {}:" + " power command {} is already running".format(cmd_to_exec, list_of_running_cmd[0])) + tango.Except.throw_exception("Command failure", + err_msg, + "CmdInputArgsCheck decorator", + tango.ErrSeverity.ERR) + # check for devices that are not ONLINE/MAINTENANCE + device_to_remove = [] + for device in device_list: + dev_instance.logger.debug("CmdInputArgsCheack-processing device:", device) + # if the sub-element device server is not running or the adminMode + # attribute is not ONLINE or MAINTENANCE: + # - schedule the device for removing from the input arg list + # - skip to next device and + if (not dev_instance._is_device_running(device, dev_instance._se_proxies) or + dev_instance._se_admin_mode[device] not in [AdminMode.ONLINE, + AdminMode.MAINTENANCE]): + if device == dev_instance.CspCbf: + msg = ("Can't execute command {} with " + "device {} {}".format(cmd_to_exec, + device, + AdminMode(dev_instance._se_admin_mode[device]).name)) + tango.Except.throw_exception("Command failure", + msg, + "CmdInputArgsCheck decorator", + tango.ErrSeverity.ERR) + device_to_remove.append(device) + dev_instance.logger.debug("Devices to remove from the list:", device_to_remove) + continue + for device in device_to_remove: + device_list.remove(device) + if not device_list: + dev_instance.logger.info("No device to power on") + return + command_timeout = 0 + # build the sub-element attribute name storing the command duration + # expected value. + cmd_time_attr_name = cmd_to_exec + "DurationExpected" + for device in device_list: + dev_instance.logger.debug("Processing device:", device) + # set to QUEUED. This state can be useful in case of command abort. + dev_instance._se_cmd_execution_state[device][cmd_to_exec] = CmdExecState.QUEUED + # reset the timeout and alarm attribute content + dev_instance._timeout_expired[cmd_to_exec] = False + # TODO: how check if the alarm condition has been reset by AlarmHandler? + dev_instance._alarm_raised[cmd_to_exec] = False + device_proxy = dev_instance._se_proxies[device] + try: + # get the sub-element value for the onCommandDurationExpected attribute. + # If this attribute is not implemented at sub-element level, + # the default value is used. + # Note: if onCmdDurationExpected attribute is not implemented, the + # call device_proxy.onCmdDurationExpected throws an AttributeError exception + # (not tango.DevFailed) + #dev_instance._se_cmd_duration_expected[device][cmd_to_exec] = device_proxy.onCmdDurationExpected + # read_Attribute returns a DeviceAttribute object + device_attr = device_proxy.read_attribute(cmd_time_attr_name) + dev_instance._se_cmd_duration_expected[device][cmd_to_exec] = device_attr.value + except tango.DevFailed as tango_err: + # we get here if the attribute is not implemented + dev_instance.logger.info(tango_err.args[0].desc) + for attr in attrs_to_subscribe: + try: + if dev_instance._se_event_id[device][attr.lower()] == 0: + evt_id = device_proxy.subscribe_event(attr, tango.EventType.CHANGE_EVENT, + dev_instance._attributes_change_evt_cb, stateless=False) + dev_instance._se_event_id[device][attr.lower()] = evt_id + except tango.DevFailed as tango_err: + dev_instance.logger.info(tango_err.args[0].desc) + # evaluate the total timeout value to execute the whole command + # note: if the xxxDurationExpected attribute read fails, it is used the default value + # (xxxDurationExpected initialized as defaultdict) + command_timeout += dev_instance._se_cmd_duration_expected[device][cmd_to_exec] + # device loop end + # use the greatest value for the onCommand duration expected. + if command_timeout > dev_instance._cmd_duration_expected[cmd_to_exec]: + dev_instance._cmd_duration_expected[cmd_to_exec] = command_timeout + dev_instance.logger.info("Modified the {} command Duration Expected value!!".format(cmd_to_exec)) + return f(*args, **kwargs) + return input_args_check + +class SubarrayRejectCmd(object): + """ + Class designed to be a decorator for the CspSubarray methods. + The *decorator function* control if the execution of a sub-array + command to assign/remove resources conflicts with a command already + running. + The *decorator function* accepts some parameters as input to customize + its functionality + """ + def __init__(self, *args, **kwargs): + # store the decorators parameters: + # args: the list of command to reject + # + self._args = args + self._kwargs = kwargs + print(args) + def __call__(self, f): + @functools.wraps(f) + def input_args_check(*args, **kwargs): + # the CspSubarray device instance + dev_instance = args[0] + cmd_to_exec = f.__name__ + commands_to_reject = self._args + dev_instance.logger.debug("SubarrayRejectCmd: function {}".format(f.__name__)) + # If a sub-array is executing an AddXXX (RemoveXX) command, an exception is + # thown only when the requested command is RemoveXXX (AddXXX)remove/add resources or ConfigureScan. + # If the requested command is already running, the decorator returns. + + list_of_running_cmd = [cmd_name for cmd_name, cmd_state in dev_instance._cmd_execution_state.items() + if cmd_state == CmdExecState.RUNNING] + print(list_of_running_cmd) + if cmd_to_exec.lower() in list_of_running_cmd: + # the requested command is already running + # return with no exception (see SKA Guidelines) + msg = ("Command {} is already running".format(cmd_to_exec)) + dev_instance.logger.info(msg) + return + if any (cmd_name in commands_to_reject for cmd_name in list_of_running_cmd): + err_msg = ("Can't execute command {}:" + " command {} is already running".format(cmd_to_exec, list_of_running_cmd)) + tango.Except.throw_exception("Command failure", + err_msg, + "SubarrayRejectCmd decorator", + tango.ErrSeverity.ERR) + # reset alarm/timeout condition + if dev_instance._alarm_raised: + dev_instance.logger.info("A previous alarm condition is present") + dev_instance._alarm_raised = False + if dev_instance._timeout_expired: + dev_instance.logger.info("A previous timeout condition is present") + dev_instance._timeout_expired = False + # TODO: how check if the alarm condition has been reset by AlarmHandler? + return f(*args, **kwargs) + return input_args_check diff --git a/csp-lmc-common/docker/.make/.make-release-support b/csp-lmc-common/docker/.make/.make-release-support new file mode 100644 index 0000000000000000000000000000000000000000..f1f3a2cb9fb3ea0ce3a173a35c3c9fe316d75156 --- /dev/null +++ b/csp-lmc-common/docker/.make/.make-release-support @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Copyright 2015 Xebia Nederland B.V. +# Modifications copyright 2019 SKA Organisation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +function hasChanges() { + test -n "$(git status -s .)" +} + +function getRelease() { + awk -F= '/^release=/{print $2}' .release +} + +function getBaseTag() { + sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release +} + +function getTag() { + if [ -z "$1" ] ; then + awk -F= '/^tag/{print $2}' .release + else + echo "$(getBaseTag)$1" + fi +} + +function setRelease() { + if [ -n "$1" ] ; then + sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release + sed -i.x -e "s/^release=.*/release=$1/g" .release + rm -f .release.x + runPreTagCommand "$1" + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function runPreTagCommand() { + if [ -n "$1" ] ; then + COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release) + if [ -n "$COMMAND" ] ; then + if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi + fi + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function tagExists() { + tag=${1:-$(getTag)} + test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" +} + +function differsFromRelease() { + tag=$(getTag) + ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" +} + +function getVersion() { + result=$(getRelease) + + if differsFromRelease; then + result="$result-$(git log -n 1 --format=%h .)" + fi + + if hasChanges ; then + result="$result-dirty" + fi + echo $result +} + +function nextPatchLevel() { + version=${1:-$(getRelease)} + major_and_minor=$(echo $version | cut -d. -f1,2) + patch=$(echo $version | cut -d. -f3) + version=$(printf "%s.%d" $major_and_minor $(($patch + 1))) + echo $version +} + +function nextMinorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + minor=$(echo $version | cut -d. -f2); + version=$(printf "%d.%d.0" $major $(($minor + 1))) ; + echo $version +} + +function nextMajorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + version=$(printf "%d.0.0" $(($major + 1))) + echo $version +} diff --git a/csp-lmc-common/docker/.make/Makefile.mk b/csp-lmc-common/docker/.make/Makefile.mk new file mode 100644 index 0000000000000000000000000000000000000000..c8196593ee69d4cdb75be9779299b1955cd6025c --- /dev/null +++ b/csp-lmc-common/docker/.make/Makefile.mk @@ -0,0 +1,137 @@ +# +# Copyright 2015 Xebia Nederland B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifeq ($(strip $(PROJECT)),) + NAME=$(shell basename $(CURDIR)) +else + NAME=$(PROJECT) +endif + +RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support + +ifeq ($(strip $(DOCKER_REGISTRY_HOST)),) + DOCKER_REGISTRY_HOST = nexus.engageska-portugal.pt +endif + +ifeq ($(strip $(DOCKER_REGISTRY_USER)),) + DOCKER_REGISTRY_USER = ska-docker +endif + +IMAGE=$(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(NAME) + +#VERSION = release version + git sha +VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion) + +#BASE_VERSION +BASE_VERSION=$(shell . $(RELEASE_SUPPORT) ; getRelease) + +#TAG = project name + release version +TAG=$(shell . $(RELEASE_SUPPORT); getTag) + +#DEFAULT_TAG = image name + BASE_VERSION +DEFAULT_TAG=$(IMAGE):$(BASE_VERSION) + + +SHELL=/bin/bash + +DOCKER_BUILD_CONTEXT=.. +DOCKER_FILE_PATH=Dockerfile + +.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ + push pre-push do-push post-push + +build: pre-build docker-build post-build ## build the application image + +pre-build: + +post-build: + +pre-push: + +post-push: + +docker-build: .release + @echo "Building image: $(IMAGE):$(VERSION)" + @echo "NAME: $(NAME)" + docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) --build-arg DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) --build-arg DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) + @DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \ + DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \ + if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \ + echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + else \ + echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \ + fi + +release: check-status check-release build push + +push: pre-push do-push post-push ## push the image to the Docker registry + +do-push: ## Push the image tagged as $(IMAGE):$(VERSION) and $(DEFAULT_TAG) + @echo -e "Tagging: $(IMAGE):$(VERSION) -> $(DEFAULT_TAG)" + docker tag $(IMAGE):$(VERSION) $(DEFAULT_TAG) + @echo -e "Pushing: $(IMAGE):$(VERSION)" + docker push $(IMAGE):$(VERSION) + @echo -e "Pushing: $(DEFAULT_TAG)" + docker push $(DEFAULT_TAG) + +tag_latest: do-push ## Tag the images as latest + @echo "Tagging: $(DEFAULT_TAG) -> $(IMAGE):latest" + @docker tag $(DEFAULT_TAG) $(IMAGE):latest + +push_latest: tag_latest ## Push the image tagged as :latest + @echo "Pushing: $(IMAGE):latest" + @docker push $(IMAGE):latest + +snapshot: build push + +showver: .release + @. $(RELEASE_SUPPORT); getVersion + +bump-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel) +bump-patch-release: .release tag + +bump-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel) +bump-minor-release: .release tag + +bump-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel) +bump-major-release: .release tag + +patch-release: tag-patch-release release + @echo $(VERSION) + +minor-release: tag-minor-release release + @echo $(VERSION) + +major-release: tag-major-release release + @echo $(VERSION) + +tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION)) +tag: check-status +# @. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; setRelease $(VERSION) +# git add . +# git commit -m "bumped to version $(VERSION)" ; +# git tag $(TAG) ; +# @ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi + +check-status: + @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ; + +check-release: .release + @. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1) diff --git a/csp-lmc-common/docker/.release b/csp-lmc-common/docker/.release new file mode 100644 index 0000000000000000000000000000000000000000..83148a001c33c45cac1b8cb0185ed0a81490e6c5 --- /dev/null +++ b/csp-lmc-common/docker/.release @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CSP.LMC prototype project +# +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +"""Release information for Python Package""" + +name = """tangods-cspmaster""" +version = "0.3.0" +version_info = version.split(".") +description = """SKA CSP.LMC Common Classe""" +author = "E.G" +author_email = "elisabetta.giani@inaf.it" +license = """BSD-3-Clause""" +url = """www.tango-controls.org""" +copyright = """""" + +release=0.3.0 +tag=csp-lmc-common-0.3.0 diff --git a/csp-lmc-common/docker/Dockerfile b/csp-lmc-common/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..429d8ad4ab58422c4638c12f90711f337669edbe --- /dev/null +++ b/csp-lmc-common/docker/Dockerfile @@ -0,0 +1,10 @@ +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:0.2.2 AS buildenv +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:0.2.2 AS runtime + +# create ipython profile to so that itango doesn't fail if ipython hasn't run yet +RUN ipython profile create +#install lmc-base-classes +USER root +RUN DEBIAN_FRONTEND=noninteractive pip3 install https://nexus.engageska-portugal.pt/repository/pypi/packages/lmcbaseclasses/0.2.0+6bb55a6e/lmcbaseclasses-0.2.0+6bb55a6e.tar.gz + +CMD ["/venv/bin/python", "-m"," csp_lmc_common.CspMaster" ] diff --git a/csp-lmc-common/docker/Makefile b/csp-lmc-common/docker/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..142895a0b41ee048577639ba957bfc9e2f5728b4 --- /dev/null +++ b/csp-lmc-common/docker/Makefile @@ -0,0 +1,198 @@ +# +# Project makefile for a Tango project. You should normally only need to modify +# DOCKER_REGISTRY_USER and PROJECT below. +# + +# +# DOCKER_REGISTRY_HOST, DOCKER_REGISTRY_USER and PROJECT are combined to define +# the Docker tag for this project. The definition below inherits the standard +# value for DOCKER_REGISTRY_HOST (=rnexus.engageska-portugal.pt) and overwrites +# DOCKER_REGISTRY_USER and PROJECT to give a final Docker tag of +# nexus.engageska-portugal.pt/tango-example/csplmc +# + +DOCKER_REGISTRY_USER:=ska-docker +PROJECT = csp-lmc-common + +# +# include makefile to pick up the standard Make targets, e.g., 'make build' +# build, 'make push' docker push procedure, etc. The other Make targets +# ('make interactive', 'make test', etc.) are defined in this file. +# +include .make/Makefile.mk + +# +# IMAGE_TO_TEST defines the tag of the Docker image to test +# +IMAGE_TO_TEST = $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(PROJECT):latest + +# +# CACHE_VOLUME is the name of the Docker volume used to cache eggs and wheels +# used during the test procedure. The volume is not used during the build +# procedure +# +CACHE_VOLUME = $(PROJECT)-test-cache + +# optional docker run-time arguments +DOCKER_RUN_ARGS = + +# +# Never use the network=host mode when running CI jobs, and add extra +# distinguishing identifiers to the network name and container names to +# prevent collisions with jobs from the same project running at the same +# time. +# +ifneq ($(CI_JOB_ID),) +NETWORK_MODE := tangonet-$(CI_JOB_ID) +CONTAINER_NAME_PREFIX := $(PROJECT)-$(CI_JOB_ID)- +else +CONTAINER_NAME_PREFIX := $(PROJECT)- +endif + +COMPOSE_FILES := $(wildcard *.yml) +COMPOSE_FILE_ARGS := $(foreach yml,$(COMPOSE_FILES),-f $(yml)) + +ifeq ($(OS),Windows_NT) + $(error Sorry, Windows is not supported yet) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + DISPLAY ?= :0.0 + NETWORK_MODE ?= host + XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix + XAUTHORITY ?= /hosthome/.Xauthority + # /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly + SHELL := /bin/bash + endif + ifeq ($(UNAME_S),Darwin) + IF_INTERFACE := $(shell netstat -nr | awk '{ if ($$1 ~/default/) { print $$6} }') + DISPLAY := $(shell ifconfig $(IF_INTERFACE) | awk '{ if ($$1 ~/inet$$/) { print $$2} }'):0 + # network_mode = host doesn't work on MacOS, so fix to the internal network + NETWORK_MODE := tangonet + XAUTHORITY_MOUNT := $(HOME):/hosthome:ro + XAUTHORITY := /hosthome/.Xauthority + endif +endif + +# +# When running in network=host mode, point devices at a port on the host +# machine rather than at the container. +# +ifeq ($(NETWORK_MODE),host) +TANGO_HOST := $(shell hostname):10000 +MYSQL_HOST := $(shell hostname):3306 +else +# distinguish the bridge network from others by adding the project name +NETWORK_MODE := $(NETWORK_MODE)-$(PROJECT) +TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds:10000 +MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306 +endif + + +DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) XAUTHORITY=$(XAUTHORITY) TANGO_HOST=$(TANGO_HOST) \ + NETWORK_MODE=$(NETWORK_MODE) XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) MYSQL_HOST=$(MYSQL_HOST) \ + DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) \ + CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) COMPOSE_IGNORE_ORPHANS=true + +# +# Defines a default make target so that help is printed if make is called +# without a target +# +.DEFAULT_GOAL := help + +# +# defines a function to copy the ./test-harness directory into the container +# and then runs the requested make target in the container. The container is: +# +# 1. attached to the network of the docker-compose test system +# 2. uses a persistent volume to cache Python eggs and wheels so that fewer +# downloads are required +# 3. uses a transient volume as a working directory, in which untarred files +# and test output can be written in the container and subsequently copied +# to the host +# +make = tar -c test-harness/ | \ + docker run -i --rm --network=$(NETWORK_MODE) \ + -e TANGO_HOST=$(TANGO_HOST) \ + -v $(CACHE_VOLUME):/home/tango/.cache \ + --volumes-from=$(CONTAINER_NAME_PREFIX)rsyslog-csplmc:rw \ + -v /build -w /build -u tango $(DOCKER_RUN_ARGS) $(IMAGE_TO_TEST) \ + bash -c "sudo chown -R tango:tango /build && \ + tar x --strip-components 1 --warning=all && \ + make TANGO_HOST=$(TANGO_HOST) $1" + +test: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +test: build up ## test the application + @echo "BUILD: $(BUILD)" + $(INIT_CACHE) + $(call make,test); \ + status=$$?; \ + rm -fr build; \ + #docker-compose $(COMPOSE_FILE_ARGS) logs; + docker cp $(BUILD):/build .; \ + docker rm -f -v $(BUILD); \ + $(MAKE) down; \ + exit $$status + +lint: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +lint: build up ## lint the application (static code analysis) + $(INIT_CACHE) + $(call make,lint); \ + status=$$?; \ + docker cp $(BUILD):/build .; \ + $(MAKE) down; \ + exit $$status + +pull: ## download the application image + docker pull $(IMAGE_TO_TEST) + +up: build ## start develop/test environment +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE)) +endif + #$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull + #to pull only the mid-cbf-mcs image remove comment on row below. + #docker pull $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/mid-cbf-mcs:latest + $(DOCKER_COMPOSE_ARGS) docker-compose -f csp-tangodb.yml up -d + # put a sleep to wait TANGO DB + @sleep 10 + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up + +piplock: build ## overwrite Pipfile.lock with the image version + docker run $(IMAGE_TO_TEST) cat /app/Pipfile.lock > $(CURDIR)/Pipfile.lock + +interactive: up +interactive: ## start an interactive session using the project image (caution: R/W mounts source directory to /app) + docker run --rm -it -p 3000:3000 --name=$(CONTAINER_NAME_PREFIX)dev -e TANGO_HOST=$(TANGO_HOST) --network=$(NETWORK_MODE) \ + -v $(CURDIR):/app $(IMAGE_TO_TEST) /bin/bash + +down: ## stop develop/test environment and any interactive session + docker ps | grep $(CONTAINER_NAME_PREFIX)dev && docker stop $(PROJECT)-dev || true + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true +endif + +dsconfigdump: up ## dump the entire configuration to the file dsconfig.json + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump > dsconfig.json + +dsconfigadd: up ## Add a configuration json file (environment variable DSCONFIG_JSON_FILE) to the database + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -u -w -a $(DSCONFIG_JSON_FILE) + +dsconfigcheck: up ## check a json file (environment variable DSCONFIG_JSON_FILE) according to the project lib-maxiv-dsconfig json schema + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -a $(DSCONFIG_JSON_FILE) + +help: ## show this help. + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: all test up down help + +# Creates Docker volume for use as a cache, if it doesn't exist already +INIT_CACHE = \ + docker volume ls | grep $(CACHE_VOLUME) || \ + docker create --name $(CACHE_VOLUME) -v $(CACHE_VOLUME):/cache $(IMAGE_TO_TEST) + +# http://cakoose.com/wiki/gnu_make_thunks +BUILD_GEN = $(shell docker create -v /build $(IMAGE_TO_TEST)) +BUILD = $(eval BUILD := $(BUILD_GEN))$(BUILD) diff --git a/csp-lmc-common/docker/config/csplmc_dsconfig.json b/csp-lmc-common/docker/config/csplmc_dsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..d448c1bbd1bb3a7673e513bf0867ac9d8f67247f --- /dev/null +++ b/csp-lmc-common/docker/config/csplmc_dsconfig.json @@ -0,0 +1,494 @@ +{ + "classes": { + "CspSubarray": { + "properties": { + "PstBeam": [ + "mid_csp_pst/sub_elt/beam_01" + ] + } + } + }, + "servers": { + "CspMaster": { + "commaster": { + "CspMaster": { + "common/elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "reportSearchBeamState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityState" + ] + }, + "reportTimingBeamState": { + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityState" + ] + }, + "reportVlbiBeamState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityState" + ] + }, + "reportSearchBeamHealthState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityHealthState" + ] + }, + "reportTimingBeamHealthState":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityHealthState" + ] + }, + "reportVlbiBeamHealthState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityHealthState" + ] + }, + "reportSearchBeamObsState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityObsState" + ] + }, + "reportTimingBeamObsState":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityObsState" + ] + }, + "reportVlbiBeamObsState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityObsState" + ] + }, + "reportSearchBeamAdminMode": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityAdminMode" + ] + }, + "reportTimingBeamAdminMode":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityAdminMode" + ] + }, + "reportVlbiBeamAdminMode": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityAdminMode" + ] + }, + "searchBeamAddresses": { + "__root_att": [ + "common/elt/search_beams_monitor/cspCapabilityAddresses" + ] + }, + "timingBeamAddresses": { + "__root_att": [ + "common/elt/timing_beams_monitor/cspCapabilityAddresses" + ] + }, + "vlbiBeamAddresses": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/cspCapabilityAddresses" + ] + }, + "reservedSearchBeamIDs": { + "__root_att": [ + "common/elt/search_beams_monitor/reservedIDs" + ] + }, + "unassignedSearchBeamIDs": { + "__root_att": [ + "common/elt/search_beams_monitor/unassignedIDs" + ] + }, + "unassignedTimingBeamIDs": { + "__root_att": [ + "common/elt/timing_beams_monitor/unassignedIDs" + ] + }, + "unassignedVlbiBeamIDs": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/unassignedIDs" + ] + }, + "unassignedSearchBeamNum": { + "__root_att": [ + "common/elt/search_beams_monitor/numOfUnassignedIDs" + ] + }, + "unassignedTimingBeamNum": { + "__root_att": [ + "common/elt/timing_beams_monitor/numOfUnassignedIDs" + ] + }, + "unassignedVlbiBeamNum": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/numOfUnassignedIDs" + ] + }, + "searchBeamMembership": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityMembership" + ] + }, + "timingBeamMembership": { + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityMembership" + ] + }, + "vlbiBeamMembership": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityMembership" + ] + } + }, + "properties": { + "CspCbf": [ + "mid_csp_cbf/sub_elt/master" + ], + "CspPss": [ + "mid_csp_pss/sub_elt/master" + ], + "CspPst": [ + "mid_csp_pst/sub_elt/master" + ], + "SearchBeamsMonitor":[ + "common/elt/search_beams_monitor" + ], + "TimingBeamsMonitor":[ + "common/elt/timing_beams_monitor" + ], + "VlbiBeamsMonitor":[ + "common/elt/vlbi_beams_monitor" + ], + "CspSubarrays": [ + "common/elt/subarray_01", + "common/elt/subarray_02" + ], + "MaxCapabilities": [ + "Subarray:16", + "VlbiBeam:20", + "TimingBeam:16", + "SearchBeam:1500" + ], + "polled_attr": [ + "healthstate", + "1000", + "adminmode", + "1000", + "state", + "1000", + "csppststate", + "1000", + "cspcbfstate", + "1000", + "csppsthealthstate", + "1000", + "pssadminmode", + "1000", + "cbfadminmode", + "1000", + "csppssstate", + "1000", + "pstadminmode", + "1000", + "commandprogress", + "3000", + "cspcbfhealthstate", + "1000", + "csppsshealthstate", + "1000" + ] + } + } + } + } + }, + "PssMasterSimulator": { + "pss": { + "PssMasterSimulator": { + "mid_csp_pss/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "onDurationExpected": { + "__value": [ + "10" + ] + }, + "offDurationExpected": { + "__value": [ + "12" + ] + }, + "standbyDurationExpected": { + "__value": [ + "5" + ] + }, + "onCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "offCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "standbyCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + } + }, + "properties": { + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "onCommandProgress", + "1000", + "offCommandProgress", + "1000", + "standbyCommandProgress", + "1000" + ] + } + } + } + } + }, + "CspCapabilityMonitor": { + "searchbeams": { + "CspCapabilityMonitor": { + "common/elt/search_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "common/search_beams/0001", + "common/search_beams/0002", + "common/search_beams/0003" + ] + } + } + } + }, + "timingbeams": { + "CspCapabilityMonitor": { + "common/elt/timing_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "common/timing_beams/01", + "common/timing_beams/02", + "common/timing_beams/03" + ] + } + } + } + }, + "vlbibeams": { + "CspCapabilityMonitor": { + "common/elt/vlbi_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "common/vlbi_beams/01", + "common/vlbi_beams/02", + "common/vlbi_beams/03" + ] + } + } + } + } + }, + "CspSubarray": { + "comsub1": { + "CspSubarray": { + "common/elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_01/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_01" + ], + "SubID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + }, + "comsub2": { + "CspSubarray": { + "common/elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_02/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "SubID": [ + "2" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_02" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + } + } +} diff --git a/csp-lmc-common/docker/config/csplmc_dsconfig.json.sav b/csp-lmc-common/docker/config/csplmc_dsconfig.json.sav new file mode 100644 index 0000000000000000000000000000000000000000..0cf8becab488d936da938f03697fb3d41a15319d --- /dev/null +++ b/csp-lmc-common/docker/config/csplmc_dsconfig.json.sav @@ -0,0 +1,406 @@ +{ + "classes": { + "CspSubarray": { + "properties": { + "PstBeam": [ + "mid_csp_pst/sub_elt/beam_01" + ] + } + } + }, + "servers": { + "CspMaster": { + "commaster": { + "CspMaster": { + "common/elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "reportSearchBeamState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityState" + ] + }, + "reportTimingBeamState": { + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityState" + ] + }, + "reportVlbiBeamState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityState" + ] + }, + "reportSearchBeamHealthState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityHealthState" + ] + }, + "reportTimingBeamHealthState":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityHealthState" + ] + }, + "reportVlbiBeamHealthState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityHealthState" + ] + }, + "reportSearchBeamObsState": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityObsState" + ] + }, + "reportTimingBeamObsState":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityObsState" + ] + }, + "reportVlbiBeamObsState": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityObsState" + ] + }, + "reportSearchBeamAdminMode": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityAdminMode" + ] + }, + "reportTimingBeamAdminMode":{ + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityAdminMode" + ] + }, + "reportVlbiBeamAdminMode": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityAdminMode" + ] + }, + "searchBeamAddresses": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityAddresses" + ] + }, + "timingBeamAddresses": { + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityAddresses" + ] + }, + "vlbiBeamAddresses": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityAddresses" + ] + }, + "reservedSearchBeamIDs": { + "__root_att": [ + "common/elt/search_beams_monitor/reservedIDs" + ] + }, + "unassignedSearchBeamIDs": { + "__root_att": [ + "common/elt/search_beams_monitor/unassignedIDs" + ] + }, + "unassignedTimingBeamIDs": { + "__root_att": [ + "common/elt/timing_beams_monitor/unassignedIDs" + ] + }, + "unassignedVlbiBeamIDs": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/unassignedIDs" + ] + }, + "searchBeamMembership": { + "__root_att": [ + "common/elt/search_beams_monitor/capabilityMembership" + ] + }, + "timingBeamMembership": { + "__root_att": [ + "common/elt/timing_beams_monitor/capabilityMembership" + ] + }, + "vlbiBeamMembership": { + "__root_att": [ + "common/elt/vlbi_beams_monitor/capabilityMembership" + ] + } + }, + "properties": { + "CspCbf": [ + "mid_csp_cbf/sub_elt/master" + ], + "CspPss": [ + "mid_csp_pss/sub_elt/master" + ], + "CspPst": [ + "mid_csp_pst/sub_elt/master" + ], + "SearchBeamsMonitor":[ + "common/elt/search_beams_monitor" + ], + "TimingBeamsMonitor":[ + "common/elt/timing_beams_monitor" + ], + "VlbiBeamsMonitor":[ + "common/elt/vlbi_beams_monitor" + ], + "CspSubarrays": [ + "common/elt/subarray_01", + "common/elt/subarray_02" + ], + "MaxCapabilities": [ + "Subarray:16", + "VlbiBeam:20", + "TimingBeam:16", + "SearchBeam:1500" + ], + "polled_attr": [ + "healthstate", + "1000", + "adminmode", + "1000", + "state", + "1000", + "csppststate", + "1000", + "cspcbfstate", + "1000", + "csppsthealthstate", + "1000", + "pssadminmode", + "1000", + "cbfadminmode", + "1000", + "csppssstate", + "1000", + "pstadminmode", + "1000", + "commandprogress", + "3000", + "cspcbfhealthstate", + "1000", + "csppsshealthstate", + "1000" + ] + } + } + } + } + }, + "CspCapabilityMonitor": { + "searchbeams": { + "CspCapabilityMonitor": { + "common/elt/search_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "common/search_beams/0001", + "common/search_beams/0002", + "common/search_beams/0003" + ] + } + } + } + }, + "timingbeams": { + "CspCapabilityMonitor": { + "common/elt/timing_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "common/timing_beams/01", + "common/timing_beams/02", + "common/timing_beams/03" + ] + } + } + } + }, + "vlbibeams": { + "CspCapabilityMonitor": { + "common/elt/vlbi_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "VlbiBeams": [ + "common/vlbi_beams/01", + "common/vlbi_beams/02", + "common/vlbi_beams/03" + ] + } + } + } + } + }, + "CspSubarray": { + "comsub1": { + "CspSubarray": { + "common/elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_01/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_01" + ], + "SubID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + }, + "comsub2": { + "CspSubarray": { + "common/elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_02/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "SubID": [ + "2" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_02" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + } + } +} diff --git a/csp-lmc-common/docker/config/midcbf_dsconfig.json b/csp-lmc-common/docker/config/midcbf_dsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..1b7632630e0a3f13aa6109fd0ea029f3ec6adfe9 --- /dev/null +++ b/csp-lmc-common/docker/config/midcbf_dsconfig.json @@ -0,0 +1,1121 @@ +{ + "servers": { + "CbfMaster": { + "master": { + "CbfMaster": { + "mid_csp_cbf/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value":[ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_01", + "mid_csp_cbf/sub_elt/subarray_02" + ], + "FSP": [ + "mid_csp_cbf/fsp/01", + "mid_csp_cbf/fsp/02", + "mid_csp_cbf/fsp/03", + "mid_csp_cbf/fsp/04" + ], + "MaxCapabilities": [ + "VCC:4", + "FSP:4", + "Subarray:2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ], + "polled_attr": [ + "reportfspstate", + "1000", + "reportvccadminmode", + "1000", + "reportvcchealthstate", + "1000", + "receptortovcc", + "1000", + "reportvccsubarraymembership", + "1000", + "reportfspsubarraymembership", + "1000", + "reportfsphealthstate", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "subarrayscanid", + "1000", + "reportfspadminmode", + "1000", + "commandprogress", + "2000", + "reportsubarrayhealthstate", + "1000", + "reportvccstate", + "1000", + "reportsubarrayadminmode", + "1000", + "vcctoreceptor", + "3000", + "reportsubarraystate", + "3000", + "state", + "1000" + ] + } + } + } + } + }, + "CbfSubarrayMulti": { + "cbfSubarray-01": { + "CbfSubarray": { + "mid_csp_cbf/sub_elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "scanID": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "FSP": [ + "mid_csp_cbf/fsp/01", + "mid_csp_cbf/fsp/02", + "mid_csp_cbf/fsp/03", + "mid_csp_cbf/fsp/04" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/01_01", + "mid_csp_cbf/fspSubarray/02_01", + "mid_csp_cbf/fspSubarray/03_01", + "mid_csp_cbf/fspSubarray/04_01" + ], + "SW1Address": [ + "mid_csp_cbf/sw1/01" + ], + "SW2Address": [ + "mid_csp_cbf/sw2/01" + ], + "SubID": [ + "1" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "fsphealthstate", + "1000", + "fspstate", + "1000", + "vccstate", + "1000", + "vcchealthstate", + "1000", + "obsstate", + "1000", + "scanid", + "1000", + "outputLinksDistribution", + "1000" + ] + } + } + }, + "SearchWindow": { + "mid_csp_cbf/sw1/01": {}, + "mid_csp_cbf/sw2/01": {} + } + }, + "cbfSubarray-02": { + "CbfSubarray": { + "mid_csp_cbf/sub_elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "scanID": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "FSP": [ + "mid_csp_cbf/fsp/01", + "mid_csp_cbf/fsp/02", + "mid_csp_cbf/fsp/03", + "mid_csp_cbf/fsp/04" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/01_02", + "mid_csp_cbf/fspSubarray/02_02", + "mid_csp_cbf/fspSubarray/03_02", + "mid_csp_cbf/fspSubarray/04_02" + ], + "SW1Address": [ + "mid_csp_cbf/sw1/02" + ], + "SW2Address": [ + "mid_csp_cbf/sw2/02" + ], + "SubID": [ + "2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ], + "polled_attr": [ + "scanid", + "1000", + "healthstate", + "1000", + "state", + "1000", + "obsstate", + "1000", + "vcchealthstate", + "1000", + "adminmode", + "1000", + "fspstate", + "1000", + "fsphealthstate", + "1000", + "vccstate", + "1000", + "outputLinksDistribution", + "1000" + ] + } + } + }, + "SearchWindow": { + "mid_csp_cbf/sw1/02": {}, + "mid_csp_cbf/sw2/02": {} + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "FspMulti": { + "fsp-01": { + "Fsp": { + "mid_csp_cbf/fsp/01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CorrelationAddress": [ + "mid_csp_cbf/fsp_corr/01" + ], + "FspID": [ + "1" + ], + "PSSAddress": [ + "mid_csp_cbf/fsp_pss/01" + ], + "PSTAddress": [ + "mid_csp_cbf/fsp_pst/01" + ], + "VLBIAddress": [ + "mid_csp_cbf/fsp_vlbi/01" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/01_01", + "mid_csp_cbf/fspSubarray/01_02" + ], + "polled_attr": [ + "adminmode", + "1000", + "healthstate", + "1000", + "state", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "FspCorr": { + "mid_csp_cbf/fsp_corr/01": {} + }, + "FspPss": { + "mid_csp_cbf/fsp_pss/01": {} + }, + "FspPst": { + "mid_csp_cbf/fsp_pst/01": {} + }, + "FspSubarray": { + "mid_csp_cbf/fspSubarray/01_01": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "FspID": [ + "1" + ], + "SubID": [ + "1" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + }, + "mid_csp_cbf/fspSubarray/01_02": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "FspID": [ + "1" + ], + "SubID": [ + "2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + } + }, + "FspVlbi": { + "mid_csp_cbf/fsp_vlbi/01": {} + } + }, + "fsp-02": { + "Fsp": { + "mid_csp_cbf/fsp/02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CorrelationAddress": [ + "mid_csp_cbf/fsp_corr/02" + ], + "FspID": [ + "2" + ], + "PSSAddress": [ + "mid_csp_cbf/fsp_pss/02" + ], + "PSTAddress": [ + "mid_csp_cbf/fsp_pst/02" + ], + "VLBIAddress": [ + "mid_csp_cbf/fsp_vlbi/02" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/02_01", + "mid_csp_cbf/fspSubarray/02_02" + ], + "polled_attr": [ + "adminmode", + "1000", + "healthstate", + "1000", + "state", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "FspCorr": { + "mid_csp_cbf/fsp_corr/02": {} + }, + "FspPss": { + "mid_csp_cbf/fsp_pss/02": {} + }, + "FspPst": { + "mid_csp_cbf/fsp_pst/02": {} + }, + "FspSubarray": { + "mid_csp_cbf/fspSubarray/02_01": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "FspID": [ + "2" + ], + "SubID": [ + "1" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + }, + "mid_csp_cbf/fspSubarray/02_02": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "FspID": [ + "2" + ], + "SubID": [ + "2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + } + }, + "FspVlbi": { + "mid_csp_cbf/fsp_vlbi/02": {} + } + }, + "fsp-03": { + "Fsp": { + "mid_csp_cbf/fsp/03": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CorrelationAddress": [ + "mid_csp_cbf/fsp_corr/03" + ], + "FspID": [ + "3" + ], + "PSSAddress": [ + "mid_csp_cbf/fsp_pss/03" + ], + "PSTAddress": [ + "mid_csp_cbf/fsp_pst/03" + ], + "VLBIAddress": [ + "mid_csp_cbf/fsp_vlbi/03" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/03_01", + "mid_csp_cbf/fspSubarray/03_02" + ], + "polled_attr": [ + "adminmode", + "1000", + "healthstate", + "1000", + "state", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "FspCorr": { + "mid_csp_cbf/fsp_corr/03": {} + }, + "FspPss": { + "mid_csp_cbf/fsp_pss/03": {} + }, + "FspPst": { + "mid_csp_cbf/fsp_pst/03": {} + }, + "FspSubarray": { + "mid_csp_cbf/fspSubarray/03_01": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "FspID": [ + "3" + ], + "SubID": [ + "1" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + }, + "mid_csp_cbf/fspSubarray/03_02": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "FspID": [ + "3" + ], + "SubID": [ + "2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + } + }, + "FspVlbi": { + "mid_csp_cbf/fsp_vlbi/03": {} + } + }, + "fsp-04": { + "Fsp": { + "mid_csp_cbf/fsp/04": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CorrelationAddress": [ + "mid_csp_cbf/fsp_corr/04" + ], + "FspID": [ + "4" + ], + "PSSAddress": [ + "mid_csp_cbf/fsp_pss/04" + ], + "PSTAddress": [ + "mid_csp_cbf/fsp_pst/04" + ], + "VLBIAddress": [ + "mid_csp_cbf/fsp_vlbi/04" + ], + "FspSubarray": [ + "mid_csp_cbf/fspSubarray/04_01", + "mid_csp_cbf/fspSubarray/04_02" + ], + "polled_attr": [ + "adminmode", + "1000", + "healthstate", + "1000", + "state", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "FspCorr": { + "mid_csp_cbf/fsp_corr/04": {} + }, + "FspPss": { + "mid_csp_cbf/fsp_pss/04": {} + }, + "FspPst": { + "mid_csp_cbf/fsp_pst/04": {} + }, + "FspSubarray": { + "mid_csp_cbf/fspSubarray/04_01": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "FspID": [ + "4" + ], + "SubID": [ + "1" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + }, + "mid_csp_cbf/fspSubarray/04_02": { + "properties": { + "CbfMasterAddress": [ + "mid_csp_cbf/sub_elt/master" + ], + "CbfSubarrayAddress": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "FspID": [ + "4" + ], + "SubID": [ + "2" + ], + "VCC": [ + "mid_csp_cbf/vcc/001", + "mid_csp_cbf/vcc/002", + "mid_csp_cbf/vcc/003", + "mid_csp_cbf/vcc/004" + ] + } + } + }, + "FspVlbi": { + "mid_csp_cbf/fsp_vlbi/04": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + }, + "VccMulti": { + "vcc-001": { + "Vcc": { + "mid_csp_cbf/vcc/001": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Band1And2Address": [ + "mid_csp_cbf/vcc_band12/001" + ], + "Band3Address": [ + "mid_csp_cbf/vcc_band3/001" + ], + "Band4Address": [ + "mid_csp_cbf/vcc_band4/001" + ], + "Band5Address": [ + "mid_csp_cbf/vcc_band5/001" + ], + "SW1Address": [ + "mid_csp_cbf/vcc_sw1/001" + ], + "SW2Address": [ + "mid_csp_cbf/vcc_sw2/001" + ], + "VccID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "VccBand1And2": { + "mid_csp_cbf/vcc_band12/001": {} + }, + "VccBand3": { + "mid_csp_cbf/vcc_band3/001": {} + }, + "VccBand4": { + "mid_csp_cbf/vcc_band4/001": {} + }, + "VccBand5": { + "mid_csp_cbf/vcc_band5/001": {} + }, + "VccSearchWindow": { + "mid_csp_cbf/vcc_sw1/001": {}, + "mid_csp_cbf/vcc_sw2/001": {} + } + }, + "vcc-002": { + "Vcc": { + "mid_csp_cbf/vcc/002": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Band1And2Address": [ + "mid_csp_cbf/vcc_band12/002" + ], + "Band3Address": [ + "mid_csp_cbf/vcc_band3/002" + ], + "Band4Address": [ + "mid_csp_cbf/vcc_band4/002" + ], + "Band5Address": [ + "mid_csp_cbf/vcc_band5/002" + ], + "SW1Address": [ + "mid_csp_cbf/vcc_sw1/002" + ], + "SW2Address": [ + "mid_csp_cbf/vcc_sw2/002" + ], + "VccID": [ + "2" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "VccBand1And2": { + "mid_csp_cbf/vcc_band12/002": {} + }, + "VccBand3": { + "mid_csp_cbf/vcc_band3/002": {} + }, + "VccBand4": { + "mid_csp_cbf/vcc_band4/002": {} + }, + "VccBand5": { + "mid_csp_cbf/vcc_band5/002": {} + }, + "VccSearchWindow": { + "mid_csp_cbf/vcc_sw1/002": {}, + "mid_csp_cbf/vcc_sw2/002": {} + } + }, + "vcc-003": { + "Vcc": { + "mid_csp_cbf/vcc/003": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Band1And2Address": [ + "mid_csp_cbf/vcc_band12/003" + ], + "Band3Address": [ + "mid_csp_cbf/vcc_band3/003" + ], + "Band4Address": [ + "mid_csp_cbf/vcc_band4/003" + ], + "Band5Address": [ + "mid_csp_cbf/vcc_band5/003" + ], + "SW1Address": [ + "mid_csp_cbf/vcc_sw1/003" + ], + "SW2Address": [ + "mid_csp_cbf/vcc_sw2/003" + ], + "VccID": [ + "3" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "VccBand1And2": { + "mid_csp_cbf/vcc_band12/003": {} + }, + "VccBand3": { + "mid_csp_cbf/vcc_band3/003": {} + }, + "VccBand4": { + "mid_csp_cbf/vcc_band4/003": {} + }, + "VccBand5": { + "mid_csp_cbf/vcc_band5/003": {} + }, + "VccSearchWindow": { + "mid_csp_cbf/vcc_sw1/003": {}, + "mid_csp_cbf/vcc_sw2/003": {} + } + }, + "vcc-004": { + "Vcc": { + "mid_csp_cbf/vcc/004": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "subarrayMembership": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Band1And2Address": [ + "mid_csp_cbf/vcc_band12/004" + ], + "Band3Address": [ + "mid_csp_cbf/vcc_band3/004" + ], + "Band4Address": [ + "mid_csp_cbf/vcc_band4/004" + ], + "Band5Address": [ + "mid_csp_cbf/vcc_band5/004" + ], + "SW1Address": [ + "mid_csp_cbf/vcc_sw1/004" + ], + "SW2Address": [ + "mid_csp_cbf/vcc_sw2/004" + ], + "VccID": [ + "4" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "subarraymembership", + "1000" + ] + } + } + }, + "VccBand1And2": { + "mid_csp_cbf/vcc_band12/004": {} + }, + "VccBand3": { + "mid_csp_cbf/vcc_band3/004": {} + }, + "VccBand4": { + "mid_csp_cbf/vcc_band4/004": {} + }, + "VccBand5": { + "mid_csp_cbf/vcc_band5/004": {} + }, + "VccSearchWindow": { + "mid_csp_cbf/vcc_sw1/004": {}, + "mid_csp_cbf/vcc_sw2/004": {} + } + } + }, + "TmCspSubarrayLeafNodeTest": { + "tm": { + "TmCspSubarrayLeafNodeTest": { + "ska_mid/tm_leaf_node/csp_subarray_01": { + "attribute_properties": { + "dopplerPhaseCorrection": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CspMasterAddress": [ + "mid_csp/elt/master" + ], + "CspSubarrayAddress": [ + "mid_csp/elt/subarray_01" + ], + + "polled_attr": [ + "delaymodel", + "1000", + "visdestinationaddress", + "1000", + "dopplerphasecorrection", + "1000" + ] + } + } + } + }, + "tm2": { + "TmCspSubarrayLeafNodeTest": { + "ska_mid/tm_leaf_node/csp_subarray_02": { + "attribute_properties": { + "dopplerPhaseCorrection": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "CspMasterAddress": [ + "mid_csp/elt/master" + ], + "CspSubarrayAddress": [ + "mid_csp/elt/subarray_02" + ], + + "polled_attr": [ + "delaymodel", + "1000", + "visdestinationaddress", + "1000", + "dopplerphasecorrection", + "1000" + ] + } + } + } + } + } + } +} diff --git a/csp-lmc-common/docker/csp-lmc.yml b/csp-lmc-common/docker/csp-lmc.yml new file mode 100644 index 0000000000000000000000000000000000000000..7908280e8fa3080c12e47d485ecd768b6b00456e --- /dev/null +++ b/csp-lmc-common/docker/csp-lmc.yml @@ -0,0 +1,144 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-csplmc: rsyslog service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + csp_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}csp_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u csplmc/config/csplmc_dsconfig.json && sleep infinity" + volumes: + - .:/csplmc + + cspsubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspsubarray01 + depends_on: + - csp_dsconfig + - cspmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device common/elt/master &&\ + /venv/bin/python /app/csp_lmc_common/CspSubarray.py comsub1" + volumes_from: + - rsyslog-csplmc:rw + + cspsubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspsubarray02 + depends_on: + - csp_dsconfig + - cspmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device common/elt/master &&\ + /venv/bin/python /app/csp_lmc_common/CspSubarray.py comsub2" + volumes_from: + - rsyslog-csplmc:rw + + cspmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspmaster + depends_on: + - csp_dsconfig + - cbfmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python -m csp_lmc_common.CspMaster commaster" + volumes_from: + - rsyslog-csplmc:rw + + searchbeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}searchbeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor searchbeams" + volumes_from: + - rsyslog-csplmc:rw + + timingbeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}timingbeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor timingbeams" + volumes_from: + - rsyslog-csplmc:rw + + vlbibeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vlbibeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor vlbibeams" + volumes_from: + - rsyslog-csplmc:rw + + pssmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}pssmaster + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python /app/simulators/DeviceTestMaster/PssMasterSimulator.py pss" + volumes_from: + - rsyslog-csplmc:rw + + rsyslog-csplmc: + image: jumanjiman/rsyslog + container_name: ${CONTAINER_NAME_PREFIX}rsyslog-csplmc + network_mode: ${NETWORK_MODE} diff --git a/csp-lmc-common/docker/csp-tangodb.yml b/csp-lmc-common/docker/csp-tangodb.yml new file mode 100644 index 0000000000000000000000000000000000000000..64a6922bb979d5b19e26369fdd1a788fd44adb6d --- /dev/null +++ b/csp-lmc-common/docker/csp-tangodb.yml @@ -0,0 +1,50 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# +# Requires: +# - None +# +version: '2.2' +volumes: + tangodb: {} + +services: + tangodb: + image: nexus.engageska-portugal.pt/ska-docker/tango-db:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tangodb + environment: + - MYSQL_ROOT_PASSWORD=secret + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + volumes: + - tangodb:/var/lib/mysql + + databaseds: + image: nexus.engageska-portugal.pt/ska-docker/tango-cpp:latest + depends_on: + - tangodb + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}databaseds + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + - TANGO_HOST=${TANGO_HOST} + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${MYSQL_HOST} + - --timeout=70 + - --strict + - -- + - /usr/local/bin/DataBaseds + - "2" + - -ORBendPoint + - giop:tcp::10000 + diff --git a/csp-lmc-common/docker/mid-cbf-mcs.yml b/csp-lmc-common/docker/mid-cbf-mcs.yml new file mode 100644 index 0000000000000000000000000000000000000000..490c97ea649590a9b0610120d07aa4a8340c884e --- /dev/null +++ b/csp-lmc-common/docker/mid-cbf-mcs.yml @@ -0,0 +1,288 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-cbf-csplmc: rsyslog-cbf service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + cbf_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbf_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u csplmc/config/midcbf_dsconfig.json && sleep infinity" + volumes: + - .:/csplmc + + cbfmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfmaster + depends_on: + - databaseds + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/001 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/002 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/003 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/004 &&\ + /venv/bin/python /app/tangods/CbfMaster/CbfMaster/CbfMaster.py master" + volumes_from: + - rsyslog-cbf:rw + + + cbfsubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfsubarray01 + depends_on: + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - cbfmaster + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python /app/tangods/CbfSubarray/CbfSubarrayMulti/CbfSubarrayMulti.py cbfSubarray-01" + volumes_from: + - rsyslog-cbf:rw + + + cbfsubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfsubarray02 + depends_on: + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - cbfmaster + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python /app/tangods/CbfSubarray/CbfSubarrayMulti/CbfSubarrayMulti.py cbfSubarray-02" + volumes_from: + - rsyslog-cbf:rw + + + vcc001: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc001 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-001" + volumes_from: + - rsyslog-cbf:rw + + + vcc002: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc002 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-002" + volumes_from: + - rsyslog-cbf:rw + + + vcc003: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc003 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-003" + volumes_from: + - rsyslog-cbf:rw + + + vcc004: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc004 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-004" + volumes_from: + - rsyslog-cbf:rw + + + fsp01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp01 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-01" + volumes_from: + - rsyslog-cbf:rw + + fsp02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp02 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-02" + volumes_from: + - rsyslog-cbf:rw + + fsp03: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp03 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-03" + volumes_from: + - rsyslog-cbf:rw + + + fsp04: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp04 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-04" + volumes_from: + - rsyslog-cbf:rw + + + tmcspsubarrayleafnodetest: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tmcspsubarrayleafnodetest + depends_on: + - cspmaster + - databaseds + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=10 -- tango_admin --ping-device mid_csp/elt/subarray_01 && + /venv/bin/python /app/tangods/TmCspSubarrayLeafNodeTest/TmCspSubarrayLeafNodeTest.py tm" + volumes_from: + - rsyslog-cbf:rw + + tmcspsubarrayleafnodetest2: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tmcspsubarrayleafnodetest2 + depends_on: + - cspmaster + - databaseds + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=10 -- tango_admin --ping-device mid_csp/elt/subarray_02 && + /venv/bin/python /app/tangods/TmCspSubarrayLeafNodeTest/TmCspSubarrayLeafNodeTest.py tm2" + volumes_from: + - rsyslog-cbf:rw + + rsyslog-cbf: + image: jumanjiman/rsyslog + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}rsyslog-cbf + + diff --git a/csp-lmc-common/pogo/CspCapabilityMonitor.py b/csp-lmc-common/pogo/CspCapabilityMonitor.py new file mode 100644 index 0000000000000000000000000000000000000000..5d93858f2b642c79b9a63c1663aece8e17606f8c --- /dev/null +++ b/csp-lmc-common/pogo/CspCapabilityMonitor.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspCapabilityMonitor project +# +# INAF, SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC Common Class + +CSP.LMC Common Class designed to monitoring the SCM +attributes of the CSP Capabilities: SearchBeams, TimingBeams, +VlbiBeams, Receptors/Stations. +""" + +# PyTango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from SKABaseDevice import SKABaseDevice +# Additional import +# PROTECTED REGION ID(CspCapabilityMonitor.additionnal_import) ENABLED START # +# PROTECTED REGION END # // CspCapabilityMonitor.additionnal_import + +__all__ = ["CspCapabilityMonitor", "main"] + + +class CspCapabilityMonitor(SKABaseDevice): + """ + CSP.LMC Common Class designed to monitoring the SCM + attributes of the CSP Capabilities: SearchBeams, TimingBeams, + VlbiBeams, Receptors/Stations. + + **Properties:** + + - Device Property + + + + + + CapabilityDevices + - The list of the CSP Capability devices FQDNs monitored\nby the instance. + - Type:'DevVarStringArray' + + """ + __metaclass__ = DeviceMeta + # PROTECTED REGION ID(CspCapabilityMonitor.class_variable) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.class_variable + + # ----------------- + # Device Properties + # ----------------- + + + + + + + CapabilityDevices = device_property( + dtype='DevVarStringArray', + ) + + # ---------- + # Attributes + # ---------- + + + + + + + + + + + + numOfUnassignedIDs = attribute( + dtype='DevUShort', + ) + + capabilityState = attribute( + dtype=('DevState',), + max_dim_x=1500, + label="Capability State", + doc="Report the State of the capabilities.", + ) + + capabilityHealthState = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + capabilityAdminMode = attribute( + dtype=('DevUShort',), + access=AttrWriteType.READ_WRITE, + max_dim_x=1500, + ) + + capabilityObsState = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + unassignedIDs = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + ) + + capabilityAddresses = attribute( + dtype=('DevString',), + max_dim_x=1500, + label="CSP.LMC Capability devices FQDNs", + doc="The FQDNs of the CSP.LMC Capability devices: SearchBeams, TimingBeams, VlbiBeams,\nReceptors (MID instance), Stations (LOW instance)", + ) + + membership = attribute( + dtype=('DevUShort',), + max_dim_x=1500, + label="Capabiity sub-array affilitiation", + ) + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspCapabilityMonitor.""" + SKABaseDevice.init_device(self) + # PROTECTED REGION ID(CspCapabilityMonitor.init_device) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspCapabilityMonitor.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.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(CspCapabilityMonitor.delete_device) ENABLED START # + # PROTECTED REGION END # // CspCapabilityMonitor.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_numOfUnassignedIDs(self): + # PROTECTED REGION ID(CspCapabilityMonitor.numOfUnassignedIDs_read) ENABLED START # + """Return the numOfUnassignedIDs attribute.""" + return 0 + # PROTECTED REGION END # // CspCapabilityMonitor.numOfUnassignedIDs_read + + def read_capabilityState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityState_read) ENABLED START # + """Return the capabilityState attribute.""" + return (PyTango.DevState.UNKNOWN,) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityState_read + + def read_capabilityHealthState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityHealthState_read) ENABLED START # + """Return the capabilityHealthState attribute.""" + return (0,) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityHealthState_read + + def read_capabilityAdminMode(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAdminMode_read) ENABLED START # + """Return the capabilityAdminMode attribute.""" + return (0,) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAdminMode_read + + def write_capabilityAdminMode(self, value): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAdminMode_write) ENABLED START # + """Set the capabilityAdminMode attribute.""" + pass + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAdminMode_write + + def read_capabilityObsState(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityObsState_read) ENABLED START # + """Return the capabilityObsState attribute.""" + return (0,) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityObsState_read + + def read_unassignedIDs(self): + # PROTECTED REGION ID(CspCapabilityMonitor.unassignedIDs_read) ENABLED START # + """Return the unassignedIDs attribute.""" + return (0,) + # PROTECTED REGION END # // CspCapabilityMonitor.unassignedIDs_read + + def read_capabilityAddresses(self): + # PROTECTED REGION ID(CspCapabilityMonitor.capabilityAddresses_read) ENABLED START # + """Return the capabilityAddresses attribute.""" + return ('',) + # PROTECTED REGION END # // CspCapabilityMonitor.capabilityAddresses_read + + def read_membership(self): + # PROTECTED REGION ID(CspCapabilityMonitor.membership_read) ENABLED START # + """Return the membership attribute.""" + return (0,) + # PROTECTED REGION END # // CspCapabilityMonitor.membership_read + + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(CspCapabilityMonitor.main) ENABLED START # + return run((CspCapabilityMonitor,), args=args, **kwargs) + # PROTECTED REGION END # // CspCapabilityMonitor.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/pogo/CspCapabilityMonitor.xmi b/csp-lmc-common/pogo/CspCapabilityMonitor.xmi new file mode 100644 index 0000000000000000000000000000000000000000..80ebee40a2e75e0dc36d72282d58f1bf4f908c33 --- /dev/null +++ b/csp-lmc-common/pogo/CspCapabilityMonitor.xmi @@ -0,0 +1,218 @@ + + + + + + + + + + + + 4 + + + + + + + + + + + + + 4 + + + + + console::cout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-common/pogo/CspMaster.xmi b/csp-lmc-common/pogo/CspMaster.xmi index 221036e6ab8a80b46cc4f5ae3459ba2a66e87a3b..46ea1fcd36489a44ea06674dbd50f52887301792 100644 --- a/csp-lmc-common/pogo/CspMaster.xmi +++ b/csp-lmc-common/pogo/CspMaster.xmi @@ -4,7 +4,7 @@ - + @@ -12,19 +12,6 @@ 4 - - - - - - - - - - - - localhost - @@ -58,18 +45,28 @@ - - + + - - + + - - + + + + + + 4 + + + + + console::cout + @@ -330,31 +327,31 @@ - + - + - + - + - + - + @@ -481,194 +478,175 @@ - - - - - - - - - - - - - - - - - - - - - - - + - - + - - + + - - + - - + + - + - - + + - - + - - + + - - + - - + + - + - - + + - - + - - + + - - - - + + - + - - - + + - + - - - + + - + - + - + - + - - + + - - - + + - - - - - + - - - - - - - + + - - - - - - - + + - - - - - - - + + - - - - - - - + + - - - - - - - + + - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-common/pogo/CspSubarray.xmi b/csp-lmc-common/pogo/CspSubarray.xmi new file mode 100644 index 0000000000000000000000000000000000000000..57d63aae679b613e16188ad51bd60f11446338a9 --- /dev/null +++ b/csp-lmc-common/pogo/CspSubarray.xmi @@ -0,0 +1,875 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + console::cout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-common/pogo/CspSubarrayResourcesMonitor.xmi b/csp-lmc-common/pogo/CspSubarrayResourcesMonitor.xmi new file mode 100644 index 0000000000000000000000000000000000000000..6aa94cc1bc73e2904c5bfb4f70336bd418d69c51 --- /dev/null +++ b/csp-lmc-common/pogo/CspSubarrayResourcesMonitor.xmi @@ -0,0 +1,231 @@ + + + + + + + + + + + + 4 + + + + + + + + + 4 + + + + + console::cout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-common/setup.py b/csp-lmc-common/setup.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2d66002e5751ae759d0077937c714e81666c3692 100644 --- a/csp-lmc-common/setup.py +++ b/csp-lmc-common/setup.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# This file is part of the CSP.LMC project +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +import os +import sys +from setuptools import setup, find_packages + +setup_dir = os.path.dirname(os.path.abspath(__file__)) + +# make sure we use latest info from local code +sys.path.insert(0, setup_dir) + +INFO = {} +with open("README.md") as file: + long_description = file.read() + +RELEASE_FILENAME = os.path.join(setup_dir, 'csp_lmc_common','release.py') +exec(open(RELEASE_FILENAME).read(), INFO) + +setup( + name=INFO['name'], + version=INFO['version'], + description=INFO['description'], + author=INFO['author'], + author_email=INFO['author_email'], + packages=find_packages(), + license=INFO['license'], + url=INFO['url'], + long_description=long_description, + keywords="csp lmc ska tango", + platforms="All Platforms", + include_package_data=True, + install_requires = [ + 'pytango >=9.3.1', + 'future' + ], + setup_requires=[ + 'pytest-runner', + 'sphinx', + 'recommonmark' + ], + test_suite="test", + entry_points={'console_scripts':['CspMaster = CspMaster:main']}, + classifiers=[ + "Development Status :: 3 - Alpha", + "Programming Language :: Python :: 3", + "Operating System :: POSIX :: Linux", + "Intended Audience :: Developers", + "License :: Other/Proprietary License", + "Topic::Scientific/Enineering :: Astronomy", + ], + tests_require=[ + 'pytest', + 'pytest-cov', + 'pytest-json-report', + 'pycodestyle', + ], + extras_require={ + }) diff --git a/csp-lmc-common/simulators/DeviceTestMaster/DeviceTestMaster.py b/csp-lmc-common/simulators/DeviceTestMaster/DeviceTestMaster.py new file mode 100644 index 0000000000000000000000000000000000000000..90c5d2294db3441671fa0536b210b80431b7393e --- /dev/null +++ b/csp-lmc-common/simulators/DeviceTestMaster/DeviceTestMaster.py @@ -0,0 +1,339 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the DeviceTestMaster project +# +# +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC subelement Test Master Tango device prototype + +Test TANGO device class to test connection with the CSPMaster prototype. +It simulates the CbfMaster sub-element. +""" +from __future__ import absolute_import +import sys +from collections import defaultdict +import os +import time + +file_path = os.path.dirname(os.path.abspath(__file__)) +print(file_path) +module_path = os.path.abspath(os.path.join(file_path, os.pardir)) + "/../utils" +print(module_path) +sys.path.insert(0, module_path) + +# Tango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +# Additional import +# PROTECTED REGION ID(DeviceTestMaster.additionnal_import) ENABLED START # +from future.utils import with_metaclass +import threading +from csp_lmc_common.utils.cspcommons import HealthState, AdminMode +from skabase.SKAMaster.SKAMaster import SKAMaster +# PROTECTED REGION END # // DeviceTestMaster.additionnal_import + +__all__ = ["DeviceTestMaster", "main"] + + +class DeviceTestMaster(with_metaclass(DeviceMeta,SKAMaster)): + """ + DeviceTestMaster TANGO device class to test connection with the CSPMaster prototype + """ + # PROTECTED REGION ID(DeviceTestMaster.class_variable) ENABLED START # + # PROTECTED REGION END # // DeviceTestMaster.class_variable + + # ----------------- + # Device Properties + # ----------------- + + # ---------- + # Attributes + # ---------- + + onCommandProgress = attribute( + dtype='DevUShort', + label="Command progress percentage", + polling_period=1000, + abs_change=5, + max_value=100, + min_value=0, + doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + ) + + offCommandProgress = attribute( + dtype='DevDouble', + polling_period=1000, + abs_change=5, + ) + + standbyCommandProgress = attribute( + dtype='DevDouble', + polling_period=1000, + abs_change=5, + ) + + onDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + offDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + standbyDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + + # --------------- + # General methods + # --------------- + + def init_subelement(self): + """ + Simulate the sub-element device initialization + """ + time.sleep(3) + self.set_state(tango.DevState.STANDBY) + + def on_subelement(self): + """ + Simulate the sub-element transition from STANDBY to ON + """ + print("Executing the On command...wait") + while True: + elapsed_time = time.time() - self._start_time + if elapsed_time > self._duration_expected['on']: + break + if elapsed_time > 1: + self._cmd_progress['on'] = elapsed_time* 100/self._duration_expected['on'] + print(self._cmd_progress['on']) + self.push_change_event("onCommandProgress", int(self._cmd_progress['on'])) + time.sleep(1) + self.set_state(tango.DevState.ON) + self._health_state = HealthState.DEGRADED + self.push_change_event("onCommandProgress", 100) + print("Final state:", self.get_state()) + print("End On command...wait") + + def standby_subelement(self): + """ + Simulate the sub-element transition from ON to STANDBY + """ + print("Executing the Standby command...wait") + while True: + elapsed_time = time.time() - self._start_time + if elapsed_time > self._duration_expected['standby']: + break + if elapsed_time > 1: + self._cmd_progress['standby'] = elapsed_time* 100/self._duration_expected['standby'] + print(self._cmd_progress['standby']) + self.push_change_event("standbyCommandProgress", int(self._cmd_progress['standby'])) + time.sleep(1) + self.set_state(tango.DevState.STANDBY) + self.push_change_event("standbyCommandProgress", 100) + print("End Standby command...wait") + + def off_subelement(self): + """ + Simulate the sub-element transition from STANDBY to OFF + """ + while True: + elapsed_time = time.time() - self._start_time + if elapsed_time > self._duration_expected['off']: + break + if elapsed_time > 1: + self._cmd_progress['off'] = elapsed_time* 100/self._duration_expected['ff'] + self.push_change_event("offCommandProgress", int(self._cmd_progress['off'])) + time.sleep(1) + self._health_state = HealthState.UNKNOWN + self.set_state(tango.DevState.OFF) + self.push_change_event("offCommandProgress", 100) + + def init_device(self): + SKAMaster.init_device(self) + # PROTECTED REGION ID(DeviceTestMaster.init_device) ENABLED START # + + self.set_state(tango.DevState.INIT) + self._health_state = HealthState.UNKNOWN + self._admin_mode = AdminMode.NOTFITTED + self._duration_expected = defaultdict(lambda:10) + self._cmd_progress = defaultdict(lambda:0) + + csp_tango_db = tango.Database() + # read the CSP memorized attributes from the TANGO DB. + # Note: a memorized attribute has defined the attribute + # property '__value' + attribute_properties = csp_tango_db.get_device_attribute_property(self.get_name(), + {'adminMode': ['__value'], + 'on': ['__value'], + 'elementLoggingLevel': ['__value'], + 'centralLoggingLevel': ['__value'],}) + + self._admin_mode = int(attribute_properties['adminMode']['__value'][0]) + # start a timer to simulate device intialization + thread = threading.Timer(1, self.init_subelement) + thread.start() + + # PROTECTED REGION END # // DeviceTestMaster.init_device + + def always_executed_hook(self): + # PROTECTED REGION ID(DeviceTestMaster.always_executed_hook) ENABLED START # + pass + # PROTECTED REGION END # // DeviceTestMaster.always_executed_hook + + def delete_device(self): + # PROTECTED REGION ID(DeviceTestMaster.delete_device) ENABLED START # + pass + # PROTECTED REGION END # // DeviceTestMaster.delete_device + + # ------------------ + # Attributes methods + # ------------------ + + def read_onCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.onCommandProgress_read) ENABLED START # + """Return the onCommandProgress attribute.""" + return int(self._cmd_progress['on']) + # PROTECTED REGION END # // DeviceTestMaster.onCommandProgress_read + + def read_offCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.offCommandProgress_read) ENABLED START # + """Return the offCommandProgress attribute.""" + return int(self._cmd_progress['off']) + # PROTECTED REGION END # // DeviceTestMaster.offCommandProgress_read + + def read_standbyCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.standbyCommandProgress_read) ENABLED START # + """Return the standbyCommandProgress attribute.""" + return int(self._cmd_progress['standby']) + # PROTECTED REGION END # // DeviceTestMaster.standbyCommandProgress_read + + def read_onDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.onDurationExpected_read) ENABLED START # + """Return the onDurationExpected attribute.""" + return self._duration_expected['on'] + # PROTECTED REGION END # // DeviceTestMaster.onDurationExpected_read + + def write_onDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.onDurationExpected_write) ENABLED START # + """Set the onDurationExpected attribute.""" + self._duration_expected['on'] = value + # PROTECTED REGION END # // DeviceTestMaster.onDurationExpected_write + + def read_offDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.offDurationExpected_read) ENABLED START # + """Return the offDurationExpected attribute.""" + return self._duration_expected['off'] + # PROTECTED REGION END # // DeviceTestMaster.offDurationExpected_read + + def write_offDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.offDurationExpected_write) ENABLED START # + """Set the offDurationExpected attribute.""" + self._duration_expected['off'] = value + # PROTECTED REGION END # // DeviceTestMaster.offDurationExpected_write + + def read_standbyDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.standbyDurationExpected_read) ENABLED START # + """Return the standbyDurationExpected attribute.""" + return self._duration_expected['standby'] + # PROTECTED REGION END # // DeviceTestMaster.standbyDurationExpected_read + + def write_standbyDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.standbyDurationExpected_write) ENABLED START # + """Set the standbyDurationExpected attribute.""" + elf._duration_expected['standby'] = value + # PROTECTED REGION END # // DeviceTestMaster.standbyDurationExpected_write + + # -------- + # Commands + # -------- + + @command( + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\nIf the array length is > 1, each array element specifies the FQDN of the\nCSP SubElement to switch ON.", + ) + @DebugIt() + def On(self): + # PROTECTED REGION ID(DeviceTestMaster.On) ENABLED START # + print("Processing On command") + self._cmd_progress['on'] = 0 + self._start_time = time.time() + thread = threading.Timer(2, self.on_subelement) + thread.start() + # PROTECTED REGION END # // DeviceTestMaster.On + + @command( + dtype_in=('str',), + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\nIf the array length is > 1, each array element specifies the FQDN of the\nCSP SubElement to switch OFF.", + ) + @DebugIt() + def Off(self): + # PROTECTED REGION ID(DeviceTestMaster.Off) ENABLED START # + self._cmd_progress['off'] = 0 + self._start_time = time.time() + thread = threading.Timer(1, self.off_subelement) + thread.start() + # PROTECTED REGION END # // DeviceTestMaster.Off + + @command( + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\n\ + If the array length is > 1, each array element specifies the FQDN of the\n\ + CSP SubElement to switch OFF.", + ) + + @DebugIt() + def Standby(self): + # PROTECTED REGION ID(DeviceTestMaster.Standby) ENABLED START # + self._cmd_progress['standby'] = 0 + self._start_time = time.time() + thread = threading.Timer(2, self.standby_subelement) + thread.start() + # PROTECTED REGION END # // DeviceTestMaster.Standby + + def is_Off_allowed(self): + # PROTECTED REGION ID(DeviceTestMaster.is_Off_allowed) ENABLED START # + if self.get_state() not in [DevState.STANDBY]: + return False + return True + # PROTECTED REGION END # // DeviceTestMaster.is_Off_allowed. + + def is_Standby_allowed(self): + # PROTECTED REGION ID(DeviceTestMaster.is_Standby_allowed) ENABLED START # + if self.get_state() not in [DevState.ON, DevState.OFF]: + return False + return True + # PROTECTED REGION END # // DeviceTestMaster.is_Standby_allowed + + def is_On_allowed(self): + # PROTECTED REGION ID(DeviceTestMaster.is_On_allowed) ENABLED START # + if self.get_state() not in [DevState.STANDBY]: + return False + return True + # PROTECTED REGION END # // DeviceTestMaster.is_On_allowed + +# ---------- +# Run server +# ---------- + +def main(args=None, **kwargs): + # PROTECTED REGION ID(DeviceTestMaster.main) ENABLED START # + return run((DeviceTestMaster,), args=args, **kwargs) + # PROTECTED REGION END # // DeviceTestMaster.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/simulators/DeviceTestMaster/PssMasterSimulator.py b/csp-lmc-common/simulators/DeviceTestMaster/PssMasterSimulator.py new file mode 100644 index 0000000000000000000000000000000000000000..407dc38b00a480f99f36eb07b5f28f8ca15e8b6c --- /dev/null +++ b/csp-lmc-common/simulators/DeviceTestMaster/PssMasterSimulator.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the PssMasterSimulator project +# +# INAF-SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" PssMaster Class simulator + +""" + +from __future__ import absolute_import +import sys +from collections import defaultdict +import os +import time + +file_path = os.path.dirname(os.path.abspath(__file__)) +print(file_path) +module_path = os.path.abspath(os.path.join(file_path, os.pardir)) + "/../csp_lmc_common/utils" +print(module_path) +sys.path.insert(0, module_path) + +# Tango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +# Additional import +# PROTECTED REGION ID(DeviceTestMaster.additionnal_import) ENABLED START # +from future.utils import with_metaclass +import threading +from cspcommons import HealthState, AdminMode +#from csp_lmc_common.util.cspcommons import HealthState, AdminMode +from DeviceTestMaster import DeviceTestMaster +# PROTECTED REGION END # // DeviceTestMaster.additionnal_import + +__all__ = ["PssMasterSimulator", "main"] + + +class PssMasterSimulator(with_metaclass(DeviceMeta,DeviceTestMaster)): + """ + + **Properties:** + + - Device Property + """ + # PROTECTED REGION ID(PssMasterSimulator.class_variable) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.class_variable + + # ----------------- + # Device Properties + # ----------------- + + # ---------- + # Attributes + # ---------- + + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the PssMasterSimulator.""" + DeviceTestMaster.init_device(self) + # PROTECTED REGION ID(PssMasterSimulator.init_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(PssMasterSimulator.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.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(PssMasterSimulator.delete_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.delete_device + # ------------------ + # Attributes methods + # ------------------ + + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(PssMasterSimulator.main) ENABLED START # + return run((PssMasterSimulator,), args=args, **kwargs) + # PROTECTED REGION END # // PssMasterSimulator.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/simulators/DeviceTestMaster/PstMasterSimulator.py b/csp-lmc-common/simulators/DeviceTestMaster/PstMasterSimulator.py new file mode 100644 index 0000000000000000000000000000000000000000..84377a5417a4c1cfb9b3ae00b62f7a7e746140b3 --- /dev/null +++ b/csp-lmc-common/simulators/DeviceTestMaster/PstMasterSimulator.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the PssMasterSimulator project +# +# INAF-SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" PssMaster Class simulator + +""" + +from __future__ import absolute_import +import sys +from collections import defaultdict +import os +import time + +file_path = os.path.dirname(os.path.abspath(__file__)) +print(file_path) +module_path = os.path.abspath(os.path.join(file_path, os.pardir)) + "/../utils" +print(module_path) +sys.path.insert(0, module_path) + +# Tango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +# Additional import +# PROTECTED REGION ID(DeviceTestMaster.additionnal_import) ENABLED START # +from future.utils import with_metaclass +import threading +from csp_lmc_common.utils.cspcommons import HealthState, AdminMode +from DeviceTestMaster import DeviceTestMaster +# PROTECTED REGION END # // DeviceTestMaster.additionnal_import + +__all__ = ["PstMasterSimulator", "main"] + + +class PssMasterSimulator(with_metaclass(DeviceMeta,DeviceTestMaster)): + """ + + **Properties:** + + - Device Property + """ + # PROTECTED REGION ID(PssMasterSimulator.class_variable) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.class_variable + + # ----------------- + # Device Properties + # ----------------- + + # ---------- + # Attributes + # ---------- + + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the PssMasterSimulator.""" + DeviceTestMaster.init_device(self) + # PROTECTED REGION ID(PssMasterSimulator.init_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(PssMasterSimulator.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.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(PssMasterSimulator.delete_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.delete_device + # ------------------ + # Attributes methods + # ------------------ + + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(PssMasterSimulator.main) ENABLED START # + return run((PssMasterSimulator,), args=args, **kwargs) + # PROTECTED REGION END # // PssMasterSimulator.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/simulators/DeviceTestMaster/README.md b/csp-lmc-common/simulators/DeviceTestMaster/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d2f084cdd60438fd7cc3e58e4f6e313804408dd8 --- /dev/null +++ b/csp-lmc-common/simulators/DeviceTestMaster/README.md @@ -0,0 +1,6 @@ +This device is no more supported. +It was implemented at the beginning of the project to test the +basic CSP.LMC functionalities. +The mid-csp-mcs project provides the Mid-CBF TANGO Devices that are +now currently used by the CSP.LMC prototype. + diff --git a/csp-lmc-common/simulators/pogo/DeviceTestMaster.py b/csp-lmc-common/simulators/pogo/DeviceTestMaster.py new file mode 100644 index 0000000000000000000000000000000000000000..83f0d747044991ae20e7b750505d9a64067fb654 --- /dev/null +++ b/csp-lmc-common/simulators/pogo/DeviceTestMaster.py @@ -0,0 +1,292 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the DeviceTestMaster project +# +# +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC subelement Test Master Tango device prototype + +Test TANGO device class to test connection with the CSPMaster prototype. +It simulates the CbfMaster sub-element. +""" + +# PyTango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from SKAMaster import SKAMaster +# Additional import +# PROTECTED REGION ID(DeviceTestMaster.additionnal_import) ENABLED START # +# PROTECTED REGION END # // DeviceTestMaster.additionnal_import + +__all__ = ["DeviceTestMaster", "main"] + + +class DeviceTestMaster(SKAMaster): + """ + Test TANGO device class to test connection with the CSPMaster prototype. + It simulates the CbfMaster sub-element. + + **Properties:** + + - Device Property + + + + + + + + + """ + __metaclass__ = DeviceMeta + # PROTECTED REGION ID(DeviceTestMaster.class_variable) ENABLED START # + # PROTECTED REGION END # // DeviceTestMaster.class_variable + + # ----------------- + # Device Properties + # ----------------- + + + + + + + + + + # ---------- + # Attributes + # ---------- + + + + + + + + + + + + + + + + onCommandProgress = attribute( + dtype='DevUShort', + label="Command progress percentage", + polling_period=1000, + abs_change=5, + max_value=100, + min_value=0, + doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + ) + + offCommandProgress = attribute( + dtype='DevDouble', + polling_period=1000, + abs_change=5, + ) + + standbyCommandProgress = attribute( + dtype='DevDouble', + polling_period=1000, + abs_change=5, + ) + + onDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + offDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + standbyDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + memorized=True, + ) + + + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the DeviceTestMaster.""" + SKAMaster.init_device(self) + # PROTECTED REGION ID(DeviceTestMaster.init_device) ENABLED START # + # PROTECTED REGION END # // DeviceTestMaster.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(DeviceTestMaster.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // DeviceTestMaster.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(DeviceTestMaster.delete_device) ENABLED START # + # PROTECTED REGION END # // DeviceTestMaster.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_onCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.onCommandProgress_read) ENABLED START # + """Return the onCommandProgress attribute.""" + return 0 + # PROTECTED REGION END # // DeviceTestMaster.onCommandProgress_read + + def read_offCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.offCommandProgress_read) ENABLED START # + """Return the offCommandProgress attribute.""" + return 0.0 + # PROTECTED REGION END # // DeviceTestMaster.offCommandProgress_read + + def read_standbyCommandProgress(self): + # PROTECTED REGION ID(DeviceTestMaster.standbyCommandProgress_read) ENABLED START # + """Return the standbyCommandProgress attribute.""" + return 0.0 + # PROTECTED REGION END # // DeviceTestMaster.standbyCommandProgress_read + + def read_onDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.onDurationExpected_read) ENABLED START # + """Return the onDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // DeviceTestMaster.onDurationExpected_read + + def write_onDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.onDurationExpected_write) ENABLED START # + """Set the onDurationExpected attribute.""" + pass + # PROTECTED REGION END # // DeviceTestMaster.onDurationExpected_write + + def read_offDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.offDurationExpected_read) ENABLED START # + """Return the offDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // DeviceTestMaster.offDurationExpected_read + + def write_offDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.offDurationExpected_write) ENABLED START # + """Set the offDurationExpected attribute.""" + pass + # PROTECTED REGION END # // DeviceTestMaster.offDurationExpected_write + + def read_standbyDurationExpected(self): + # PROTECTED REGION ID(DeviceTestMaster.standbyDurationExpected_read) ENABLED START # + """Return the standbyDurationExpected attribute.""" + return 0 + # PROTECTED REGION END # // DeviceTestMaster.standbyDurationExpected_read + + def write_standbyDurationExpected(self, value): + # PROTECTED REGION ID(DeviceTestMaster.standbyDurationExpected_write) ENABLED START # + """Set the standbyDurationExpected attribute.""" + pass + # PROTECTED REGION END # // DeviceTestMaster.standbyDurationExpected_write + + + # -------- + # Commands + # -------- + + @command( + dtype_in='DevVarStringArray', + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\nIf the array length is > 1, each array element specifies the FQDN of the\nCSP SubElement to switch ON.", + ) + @DebugIt() + def On(self, argin): + # PROTECTED REGION ID(DeviceTestMaster.On) ENABLED START # + """ + Transit CSP or one or more CSP SubElements fromSTANDBY to ON + + :param argin: 'DevVarStringArray' + + If the array length is0, the command apllies to the whole + CSP Element. + If the array length is > 1, each array element specifies the FQDN of the + CSP SubElement to switch ON. + + :return:None + """ + pass + # PROTECTED REGION END # // DeviceTestMaster.On + + @command( + dtype_in='DevVarStringArray', + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\nIf the array length is > 1, each array element specifies the FQDN of the\nCSP SubElement to switch OFF.", + ) + @DebugIt() + def Off(self, argin): + # PROTECTED REGION ID(DeviceTestMaster.Off) ENABLED START # + """ + Transit CSP or one or more CSP SubElements from ON to OFF. + + :param argin: 'DevVarStringArray' + + If the array length is0, the command apllies to the whole + CSP Element. + If the array length is > 1, each array element specifies the FQDN of the + CSP SubElement to switch OFF. + + :return:None + """ + pass + # PROTECTED REGION END # // DeviceTestMaster.Off + + @command( + dtype_in='DevVarStringArray', + doc_in="If the array length is0, the command apllies to the whole\nCSP Element.\nIf the array length is > 1, each array element specifies the FQDN of the\nCSP SubElement to put in STANDBY mode.", + ) + @DebugIt() + def Standby(self, argin): + # PROTECTED REGION ID(DeviceTestMaster.Standby) ENABLED START # + """ + + Transit CSP or one or more CSP SubElements from ON/OFF to + STANDBY. + + :param argin: 'DevVarStringArray' + + If the array length is0, the command apllies to the whole + CSP Element. + If the array length is > 1, each array element specifies the FQDN of the + CSP SubElement to put in STANDBY mode. + + :return:None + """ + pass + # PROTECTED REGION END # // DeviceTestMaster.Standby + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(DeviceTestMaster.main) ENABLED START # + return run((DeviceTestMaster,), args=args, **kwargs) + # PROTECTED REGION END # // DeviceTestMaster.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/simulators/pogo/DeviceTestMaster.xmi b/csp-lmc-common/simulators/pogo/DeviceTestMaster.xmi new file mode 100644 index 0000000000000000000000000000000000000000..a6e162aa5a71173c68b6c95777aa60907205d24d --- /dev/null +++ b/csp-lmc-common/simulators/pogo/DeviceTestMaster.xmi @@ -0,0 +1,306 @@ + + + + + + + + + + + + + 4 + + + + + + + + + + + + + localhost + + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-common/simulators/pogo/PssMasterSimulator.py b/csp-lmc-common/simulators/pogo/PssMasterSimulator.py new file mode 100644 index 0000000000000000000000000000000000000000..a915d1fefbd867f334664408ce329cceb643d2da --- /dev/null +++ b/csp-lmc-common/simulators/pogo/PssMasterSimulator.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the PssMasterSimulator project +# +# INAF-SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" PssMaster Class simulator + +""" + +# PyTango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from DeviceTestMaster import DeviceTestMaster +# Additional import +# PROTECTED REGION ID(PssMasterSimulator.additionnal_import) ENABLED START # +# PROTECTED REGION END # // PssMasterSimulator.additionnal_import + +__all__ = ["PssMasterSimulator", "main"] + + +class PssMasterSimulator(DeviceTestMaster): + """ + + **Properties:** + + - Device Property + + + + + + + + + """ + __metaclass__ = DeviceMeta + # PROTECTED REGION ID(PssMasterSimulator.class_variable) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.class_variable + + # ----------------- + # Device Properties + # ----------------- + + + + + + + + + + # ---------- + # Attributes + # ---------- + + + + + + + + + + + + + + + + + + + + + + + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the PssMasterSimulator.""" + DeviceTestMaster.init_device(self) + # PROTECTED REGION ID(PssMasterSimulator.init_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(PssMasterSimulator.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.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(PssMasterSimulator.delete_device) ENABLED START # + # PROTECTED REGION END # // PssMasterSimulator.delete_device + # ------------------ + # Attributes methods + # ------------------ + + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(PssMasterSimulator.main) ENABLED START # + return run((PssMasterSimulator,), args=args, **kwargs) + # PROTECTED REGION END # // PssMasterSimulator.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-common/simulators/pogo/PssMasterSimulator.xmi b/csp-lmc-common/simulators/pogo/PssMasterSimulator.xmi new file mode 100644 index 0000000000000000000000000000000000000000..a4a3f0860eac1405ea64e4103e8c3b98a84f9621 --- /dev/null +++ b/csp-lmc-common/simulators/pogo/PssMasterSimulator.xmi @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + localhost + + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-mid/Pipfile b/csp-lmc-mid/Pipfile new file mode 100644 index 0000000000000000000000000000000000000000..358cd266445ede675d8f390885f68467214b6eb7 --- /dev/null +++ b/csp-lmc-mid/Pipfile @@ -0,0 +1,35 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +# numpy and pytango versions must match those in the ska-python-builder image, +# otherwise pytango will be recompiled. +numpy = "==1.17.2" +pytango = "==9.3.1" +# itango is added to make it easier to exercise the device in a CLI session, +# but it's not mandatory. If you remove itango, you should also remove the +# 'RUN ipython profile create' line from Dockerfile. +itango = "*" +# If you want to debug devices running in containers, add pydevd to the dependencies +# pydevd = "*" + +[dev-packages] +docutils = "*" +MarkupSafe = "*" +Pygments = "*" +pylint = "*" +pytest = "*" +pytest-cov = "*" +pytest-pylint = "*" +pytest-json-report = "*" +python-dotenv = ">=0.5.1" +ptvsd = "*" +Sphinx = "*" +sphinx_rtd_theme = "*" +sphinx-autobuild = "*" +sphinxcontrib-websupport = "*" + +[requires] +python_version = "3" diff --git a/csp-lmc-mid/csp-lmc-mid/MidCspMaster.py b/csp-lmc-mid/csp-lmc-mid/MidCspMaster.py new file mode 100644 index 0000000000000000000000000000000000000000..7d776338acdd8a2ae8009f50b05147b929f73f73 --- /dev/null +++ b/csp-lmc-mid/csp-lmc-mid/MidCspMaster.py @@ -0,0 +1,16 @@ +from tango.server import run +import os +import sys +#file_path = os.path.dirname(os.path.abspath(__file__)) +#pkg_path = os.path.abspath(os.path.join(file_path, "./")) +#sys.path.insert(0, pkg_path) + +from MidCspMasterBase import MidCspMasterBase +from csp_lmc_common.CspCapabilityMonitor import CspCapabilityMonitor + +def main(args=None, **kwargs): + return run(classes=(MidCspMasterBase, CspCapabilityMonitor), args=args, **kwargs) + + +if __name__ == '__main__': + main() diff --git a/csp-lmc-mid/csp-lmc-mid/MidCspMasterBase.py b/csp-lmc-mid/csp-lmc-mid/MidCspMasterBase.py new file mode 100644 index 0000000000000000000000000000000000000000..39fa80ba481e99ad8b9679bf327f3737d2e53570 --- /dev/null +++ b/csp-lmc-mid/csp-lmc-mid/MidCspMasterBase.py @@ -0,0 +1,505 @@ +# -*- 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 +import sys +import os +from future.utils import with_metaclass +from collections import defaultdict +# PROTECTED REGION END# //CspMaster.standardlibray_import + +# tango imports + +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(MidCspMaster.additional_import) ENABLED START # +# +from skabase.SKAMaster import SKAMaster +from skabase.auxiliary import utils +# import CSP.LMC Common package +from csp_lmc_common.utils.cspcommons import HealthState, AdminMode +from csp_lmc_common.CspMaster import CspMaster +# PROTECTED REGION END # // MidCspMaster.additionnal_import +__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 + + """ + # 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.logger.error(log_msg) + + except AttributeError as attr_err: + log_msg = "Error reading{}: {}".format(str(attr_err.args[0]), + attr_err.__doc__) + self.logger.error(log_msg) + except tango.DevFailed as df: + log_msg = "Error: " + str(df.args[0].reason) + self.logger.error(log_msg) + + # --------------- + # 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()] + 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: + 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_logger.error(msg) + 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.logger.error(msg) + 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 [0] + #return self._unassigned_receptor_id[0] + 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) + if not len(self._unassigned_receptor_id): + return [0] + 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() diff --git a/csp-lmc-mid/csp-lmc-mid/MidCspSubarrayBase.py b/csp-lmc-mid/csp-lmc-mid/MidCspSubarrayBase.py new file mode 100644 index 0000000000000000000000000000000000000000..7377aff3e032a1f7d20ac518e392b7304fd6e638 --- /dev/null +++ b/csp-lmc-mid/csp-lmc-mid/MidCspSubarrayBase.py @@ -0,0 +1,652 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the MidCspSubarrayBase project +# +# INAF, SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" MidCspSubarrayBase + +The base class for MID CspSubarray. +Fuctionality to monitor assigned CSP.LMC Capabilities, +as well as inherent Capabilities, are implemented in +separate TANGO Devices. +""" +# PROTECTED REGION ID (MidCspSubarrayBase.standardlibray_import) ENABLED START # +# Python standard library +import sys +import os +from future.utils import with_metaclass +from collections import defaultdict +import threading +import time + +import json +# PROTECTED REGION END# //MidCspSubarrayBase.standardlibray_import + +# tango imports +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(MidCspMaster.additional_import) ENABLED START # +from skabase.SKAMaster import SKAMaster +from skabase.auxiliary import utils +# import CSP.LMC Common package +from csp_lmc_common.utils.cspcommons import HealthState, AdminMode +from csp_lmc_common.CspSubarray import CspSubarray +# PROTECTED REGION END # // MidCspSubarrayBase.additionnal_import + +__all__ = ["MidCspSubarrayBase", "main"] + + +class MidCspSubarrayBase(with_metaclass(DeviceMeta, CspSubarray)): + """ + The base class for MID CspSubarray. + Fuctionality to monitor assigned CSP.LMC Capabilities, + as well as inherent Capabilities, are implemented in + separate TANGO Devices. + + **Properties:** + + - Class Property + + - Device Property + """ + + # PROTECTED REGION ID(MidCspSubarrayBase.class_variable) ENABLED START # + # PROTECTED REGION END # // MidCspSubarrayBase.class_variable + # PROTECTED REGION ID(MidCspSubarrayBase.private_methods) ENABLED START # + def __monitor_add_receptors(self, receptor_list, args_dict= None): + cmd_name = 'addreceptors' + device = self.CbfSubarray + self._num_dev_completed_task[cmd_name] = 0 + self._list_dev_completed_task[cmd_name] = [] + self._cmd_progress[cmd_name] = 0 + self._cmd_duration_measured[cmd_name] = 0 + # sub-component command execution measured time + self._sc_subarray_cmd_progress[device][cmd_name] = 0 + self._alarm_message[cmd_name] = '' + device_proxy = self._sc_subarray_proxies[device] + + while True: + # read the list of receptor IDs assigned to the CbfSubarray + try: + # Note: with numpy support in PyTango, receptors is a + # numpy array + receptors = device_proxy.receptors + except tango.DevFailed as tango_err: + self.logger.warn("__monitor_add_receptors:",tango_err.args[0].desc) + if len(receptors): + # get the ids in receptor_list that are also in receptor + receptors_assigned = [value for value in receptor_list if value in receptors] + self._num_dev_completed_task[cmd_name] = len(receptors_assigned) + if len(receptors_assigned) == len(receptor_list): + self.logger.info("All required receptors asigned!!") + self._sc_subarray_cmd_progress[device][cmd_name] = 100 + # calculate the real execution time for the command + self._cmd_duration_measured[cmd_name] = (time.time() - self._sc_subarray_cmd_starting_time[device]) + break + # check if sub-element command ended throwing an exception: in this case the + # 'cmd_ended_cb' callback is invoked. + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.FAILED: + self._alarm_raised = True + break + elapsed_time = time.time() - self._sc_subarray_cmd_starting_time[device] + if (elapsed_time > self._sc_subarray_cmd_duration_expected[device][cmd_name] or + self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT): + msg = ("Timeout executing {} command on device {}".format(cmd_name, device)) + self.logger.warn(msg) + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.TIMEOUT + break + # update the progress counter inside the loop taking into account the number of devices + # executing the command + self._cmd_progress[cmd_name] = self._sc_subarray_cmd_progress[device][cmd_name] + time.sleep(1) + # end of the while loop + + self._last_executed_command = cmd_name + # update the progress counter at the end of the loop + self._cmd_progress[cmd_name] = self._sc_subarray_cmd_progress[device][cmd_name] + # check for error conditions + if self._sc_subarray_state[self.CbfSubarray] != tango.DevState.ON: + msg= ("AddReceptors: device {} is in {}" + " State".format(device,self._sc_subarray_state[self.CbfSubarray])) + self.logger.warn(msg) + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT: + self._timeout_expired = True + # reset the command execution state + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE + self._cmd_execution_state[cmd_name] = CmdExecState.IDLE + # PROTECTED REGION END # // MidCspSubarrayBase.private_methods + + def __monitor_remove_receptors(self, receptor_list, args_dict= None): + cmd_name = 'removereceptors' + device = self.CbfSubarray + self._num_dev_completed_task[cmd_name] = 0 + self._list_dev_completed_task[cmd_name] = [] + self._cmd_progress[cmd_name] = 0 + self._cmd_duration_measured[cmd_name] = 0 + # sub-component command execution measured time + self._sc_subarray_cmd_progress[device][cmd_name] = 0 + self._alarm_message[cmd_name] = '' + device_proxy = self._sc_subarray_proxies[device] + while True: + # read the list of receptor IDs assigned to the CbfSubarray + try: + receptors = device_proxy.receptors + except AttributeError as attr_err: + self.logger.warn("RemoveReceptors:",str(attr_err)) + if len(receptors): + # get the ids in receptor_list that are no more present in receptors + receptors_removed = [value for value in receptor_list if value not in receptors] + self._num_dev_completed_task[cmd_name] = len(receptors) - len(receptor_list) + if len(receptors_removed) == len(receptor_list): + self._sc_subarray_cmd_progress[device][cmd_name] = 100 + # calculate the real execution time for the command + self._cmd_duration_measured[cmd_name] = (time.time() - self._sc_subarray_cmd_starting_time[device]) + self.logger.info("Receptors {} have been successfully removed".format(receptor_list)) + break + # check if sub-element command ended throwing an exception: in this case the + # 'cmd_ended_cb' callback is invoked. + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.FAILED: + break + elapsed_time = time.time() - self._sc_subarray_cmd_starting_time[device] + if (elapsed_time > self._sc_subarray_cmd_duration_expected[device][cmd_name] or + self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT): + msg = ("Timeout executing {} command on device {}".format(cmd_name, device)) + self.logger.warn(msg) + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.TIMEOUT + break + # update the progress counter inside the loop taking into account the number of devices + # executing the command + self._cmd_progress[cmd_name] = self._sc_subarray_cmd_progress[device][cmd_name] + time.sleep(1) + # end of the while loop + self._last_executed_command = cmd_name + # update the progress counter at the end of the loop + self._cmd_progress[cmd_name] = self._sc_subarray_cmd_progress[device][cmd_name] + # check for error conditions + if self._sc_subarray_state[self.CbfSubarray] not in [tango.DevState.OFF, + tango.DevState.ON]: + self._alarm_message[cmd_name] += ("Device {} is in {} State".format(device, + self._sc_subarray_state[self.CbfSubarray])) + self.logger.warn(self._alarm_message[device]) + self._alarm_raised = True + if self._sc_subarray_cmd_exec_state[device][cmd_name] == CmdExecState.TIMEOUT: + self._timeout_expired = True + # reset the command exeuction state + self._sc_subarray_cmd_exec_state[device][cmd_name] = CmdExecState.IDLE + self._cmd_execution_state[cmd_name] = CmdExecState.IDLE + + def _validate_scan_configuration(self, json_config): + """ + Overwritten method. + Validate the MID scan configuration file. + Currently it only copies the received configuration because it does not + still exist any "cbf" block inside the JSON script. + :param json_config: the input JSON formatted string with the configuration + for a scan + """ + self.logger.debug("Validate scan configuration for MID CSP") + #self._sc_subarray_obs_mode[self.CbfSubarray] = ObsMode.IMAGING + #self._sc_scan_configuration[self.CbfSubarray] = json_config["cbf"] + self._sc_subarray_scan_configuration[self.CbfSubarray] = json_config + self._sc_subarray_assigned_fqdn.append(self.CbfSubarray) + + # PROTECTED REGION END # // MidCspSubarrayBase.private_methods + # ---------------- + # Class Properties + # ---------------- + + + # ----------------- + # Device Properties + # ----------------- + # ---------- + # Attributes + # ---------- + assignedFsp = attribute( + dtype=('DevUShort',), + max_dim_x=27, + label="List of assigned FSPs", + doc="List of assigned FSPs.", + ) + + assignedVcc = attribute( + dtype=('DevUShort',), + max_dim_x=197, + label="List of assigned VCCs", + doc="List of assigned VCCs.", + ) + + cbfOutputLink = attribute(name="cbfOutputLink", + label="cbfOutputLink", + forwarded=True + ) + pssOutputLink = attribute(name="pssOutputLink", + label="cbfOutputLink", + forwarded=True + ) + vlbiOutputLink = attribute(name="vlbiOutputLink", + label="cbfOutputLink", + forwarded=True + ) + assignedVccState = attribute(name="assignedVccState", + label="State of the assigned VCC", + forwarded=True + ) + assignedVccHealthState = attribute(name="assignedVccHealthState", + label="HealthState of the assigned VCC", + forwarded=True + ) + assignedFspState = attribute(name="assignedFspState", + label="State of the assigned FSPs", + forwarded=True + ) + assignedFspHealthState = attribute(name="assignedFspHealthState", + label="HealthState of the assigned FSPs.", + forwarded=True + ) + assignedReceptors = attribute(name="assignedReceptors", + label="The list of assigned receptor IDs.", + forwarded=True + ) + assignedVccObsState = attribute(name="assignedVccObsState", + label="ObsState of the assigned VCCs", + forwarded=True + ) + assignedFspObsState = attribute(name="assignedFspObsState", + label="ObsState of the assigned FSPs.", + forwarded=True + ) + assignedVccAdminMode = attribute(name="assignedVccAdminMode", + label="AdminMode of the assigned VCCs.", + forwarded=True + ) + assignedFspAdminMode = attribute(name="assignedFspAdminMode", + label="AdminMode of the assigned FSPs.", + forwarded=True + ) + # --------------- + # 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 # + # PROTECTED REGION END # // MidCspSubarrayBase.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(MidCspSubarrayBase.delete_device) ENABLED START # + # PROTECTED REGION END # // MidCspSubarrayBase.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_assignedFsp(self): + # PROTECTED REGION ID(MidCspSubarrayBase.assignedFsp_read) ENABLED START # + """Return the assignedFsp attribute.""" + return (0,) + # PROTECTED REGION END # // MidCspSubarrayBase.assignedFsp_read + + def read_assignedVcc(self): + # PROTECTED REGION ID(MidCspSubarrayBase.assignedVcc_read) ENABLED START # + """ + *Attribute method* + + :returns: + The list of VCC IDs assigned to the subarray. + + *Type*: array of DevUShort. + """ + # PROTECTED REGION ID(CspSubarray.vcc_read) ENABLED START # + self._assigned_vcc.clear() + # get the map VCC-receptor from CspMaster + if not self._receptor_to_vcc_map: + try: + csp_proxy = tango.DeviceProxy(self.CspMaster) + csp_proxy.ping() + cbf_master_addr = csp_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()) + except tango.DevFailed as tango_err: + self.logger.warn(tango_err.args[0].desc) + try: + assigned_receptors = self._sc_subarray_proxies[self.CbfSubarray].receptors + # NOTE: if receptors attribute is empty, assigned_receptors is an empty numpy array + # and it will just be skipped by the for loop + for receptor_id in assigned_receptors: + vcc_id = self._receptor_to_vcc_map[receptor_id] + self._assigned_vcc.append(vcc_id) + except KeyError as key_err: + msg = "No {} found".format(key_err) + tango.Except.throw_exception("Read attribute failure", + msg, + "read_vcc", + tango.ErrSeverity.ERR) + except tango.DevFailed as df: + tango.Except.throw_exception("Read attribute failure", + df.args[0].desc, + "read_vcc", + tango.ErrSeverity.ERR) + return self._assigned_vcc + # PROTECTED REGION END # // MidCspSubarrayBase.assignedVcc_read + + + # -------- + # Commands + # -------- + @AdminModeCheck('AddReceptors') + @ObsStateCheck('addresources') + 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.", + ) + @DebugIt() + #@SubarrayRejectCmd(['RemoveReceptors', 'Configure']) + def AddReceptors(self, argin): + # PROTECTED REGION ID(MidCspSubarrayBase.AddReceptors) ENABLED START # + """ + *Class method* + + Add the specified receptor IDs to the subarray. + + The command can be executed only if the CspSubarray *ObsState* is *IDLE*. + + :param argin: the list of receptor IDs + :type: array of DevUShort + :return: + None + :raises: + tango.DevFailed: if the CbfSubarray is not available or if an exception\ + is caught during command execution. + Note: + Still to implement the check on AdminMode values: the command can be processed \ + only when the CspSubarray is *ONLINE* or *MAINTENANCE* + """ + # 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()) + print("available_receptors:", available_receptors) + print("available_receptors:", type(available_receptors)) + if not any(available_receptors): + log_msg = "No available receptor to add to subarray {}".format(self.SubID) + self.dev_logging(log_msg, tango.LogLevel.LOG_WARN) + return + receptor_membership = csp_master_proxy.receptorMembership + print("receptor_membership:", receptor_membership) + 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: + print("receptorId:", receptorId) + print("self._receptor_id_list:", self._receptor_id_list) + # 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.warn(log_msg) + + # check if the list of receptors to assign is empty + if not receptor_to_assign: + log_msg = "The required receptors are already assigned to a subarray" + self.logger.info(log_msg) + return + # check if the CspSubarray is already connected to the CbfSubarray + proxy = 0 + if self._is_sc_subarray_running(self.CbfSubarray): + self._cmd_execution_state['addreceptors'] = CmdExecState.RUNNING + 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 + proxy.command_inout_asynch("AddReceptors", receptor_to_assign, self._cmd_ended_cb) + self._sc_subarray_cmd_starting_time['addreceptors'] = time.time() + self._command_thread['addreceptors'] = threading.Thread(target=self.__monitor_add_receptors, + name="Thread-AddReceptors", + args=(receptor_to_assign,)) + self._sc_subarray_cmd_starting_time['addreceptors'] = time.time() + self._command_thread['addreceptors'].start() + else: + log_msg = "Device {} is not running!".format(str(self._cbf_subarray_fqdn)) + self.logger.error(log_msg) + tango.Except.throw_exception("Command failed", + log_msg, + "AddReceptors", + tango.ErrSeverity.ERR) + # PROTECTED REGION END # // MidCspSubarrayBase.AddReceptors + @AdminModeCheck('RemoveReceptors') + @ObsStateCheck('removeresources') + def is_RemoveReceptors_allowed(self): + + return self._is_subarray_composition_allowed() + + @command( + dtype_in='DevVarUShortArray', + doc_in="The list with the receptor IDs to remove", + ) + @DebugIt() + @SubarrayRejectCmd(['AddReceptors', 'Configure']) + def RemoveReceptors(self, argin): + # PROTECTED REGION ID(MidCspSubarrayBase.RemoveReceptors) ENABLED START # + """ + Remove the receptor IDs from the subarray. + + :param argin: The list of the receptor IDs to remove from the subarray. + Type: array of DevUShort + :returns: + None + :raises: + tango.DevFailed: raised if the subarray *obState* attribute is not IDLE, or \ + when an exception is caught during command execution. + """ + # PROTECTED REGION ID(CspSubarray.RemoveReceptors) ENABLED START # + # check if the CspSubarray is already connected to the CbfSubarray + if self._is_sc_subarray_running(self.CbfSubarray): + try: + + proxy = self._sc_subarray_proxies[self.CbfSubarray] + # read from CbfSubarray the list of assigned receptors + # failure in reading attribute raises an AttributeError (not tangoDevFailed!!) + receptors = proxy.receptors + #!!!!!!!!!!!!!!!!! + # 2019-09-20: New images for TANGO and PyTango images has been released. PyTango + # is now compiled with th numpy support. In this case the proxy.receptors call + # does no more return an empty tuple but an empty numpy array. + # Checks on receptors content need to be changed (see below) + # NB: the receptors attribute implemented by the CbfSubarray is declared as RW. + # In this case the read method returns an empty numpy array ([]) whose length is 0. + #!!!!!!!!!!!!!!!!! + + # check if the list of assigned receptors is empty + if len(receptors): + receptors_to_remove = [] + # check if the receptors to remove belong to the subarray + for receptor_id in argin: + if receptor_id in receptors: + receptors_to_remove.append(receptor_id) + if any(receptors_to_remove): + #TODO_ add reading of CbfSubarray removeReceptorsCmdDurationExpected + # attribute, if implemented, otherwise use the default value + + # subscribes attributes to track progress and timeout: if these + # attributes are not implemented at CbfSubarray level, the warning + # is only logged because is not a fatal error. + for attr in ['removeReceptorsCmdProgress', 'cmdTimeoutExpired']: + try: + if self._sc_subarray_event_id[self.CbfSubarray][attr.lower()] == 0: + evt_id = proxy.subscribe_event(attr, tango.EventType.CHANGE_EVENT, + self._attributes_change_evt_cb, stateless=False) + self._sc_subarray_event_id[self.CbfSubarray][attr.lower()] = evt_id + except tango.DevFailed as tango_err: + self.logger.info(tango_err.args[0].desc) + # forward the command to CbfSubarray + proxy.command_inout_asynch("RemoveReceptors", receptors_to_remove, self._cmd_ended_cb) + self._cmd_execution_state['removereceptors'] = CmdExecState.RUNNING + self._sc_subarray_cmd_starting_time['removereceptors'] = time.time() + # Note: rembember to put the comma in args=(receptors_to_remove,) otherwise + # the list is received as a numpy array! + self._command_thread['removereceptors'] = threading.Thread(target=self.__monitor_remove_receptors, + name="Thread-RemoveReceptors", + args=(receptors_to_remove,)) + + self._command_thread['removereceptors'].start() + self.logger.info("No receptor to remove from subarray {}".format(self.get_name())) + self._cmd_execution_state['removereceptors'] = CmdExecState.IDLE + return + except tango.DevFailed as tango_err: + tango.Except.throw_exception("Command failed", + tango_err.args[0].desc, + "RemoveReceptors", + tango.ErrSeverity.ERR) + except AttributeError as attr_err: + print("ATTRERROR") + log_msg = "RemoveReceptors:" + str(attr_err) + self.logger.error(log_msg) + tango.Except.throw_exception("Command failed", + str(attr_err), + "RemoveReceptors", + tango.ErrSeverity.ERR) + else: + log_msg = "Subarray {} not registered!".format(str(self.CbfSubarray)) + self.logger.error(log_msg) + tango.Except.throw_exception("Command failed", + log_msg, + "RemoveReceptors", + tango.ErrSeverity.ERR) + + # PROTECTED REGION END # // MidCspSubarrayBase.RemoveReceptors + + @command( + ) + @DebugIt() + def RemoveAllReceptors(self): + # PROTECTED REGION ID(MidCspSubarrayBase.RemoveAllReceptors) ENABLED START # + """ + *Class method.* + + Remove all the assigned receptors from the subarray. + Returns: + None + Raises: + tango.DevFailed: raised if the subarray *obState* attribute is not IDLE or READY, or \ + when an exception is caught during command execution. + """ + # PROTECTED REGION ID(CspSubarray.RemoveAllReceptors) ENABLED START # + if self._is_sc_subarray_running(self.CbfSubarray): + try: + proxy = self._sc_subarray_proxies[self.CbfSubarray] + # check if the list of assigned receptors is empty + receptors = proxy.receptors + if len(receptors): + self.RemoveReceptors(receptors[:]) + except tango.DevFailed as df: + log_msg = ("RemoveAllReceptors failure. Reason: {} " + "Desc: {}".format(df.args[0].reason, + df.args[0].desc)) + self.dev_logging(log_msg, tango.LogLevel.LOG_ERROR) + tango.Except.re_throw_exception(df, "Command failed", + "CspSubarray RemoveAllReceptors command failed", + "Command()", + tango.ErrSeverity.ERR) + else: + log_msg = "Subarray {} not registered!".format(str(self._cbf_subarray_fqdn)) + self.dev_logging(log_msg, tango.LogLevel.LOG_ERROR) + tango.Except.throw_exception("Command failed", + log_msg, + "RemoveAllReceptors", + tango.ErrSeverity.ERR) + + # PROTECTED REGION END # // MidCspSubarrayBase.RemoveAllReceptors + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + # PROTECTED REGION ID(MidCspSubarrayBase.main) ENABLED START # + return run((MidCspSubarrayBase,), args=args, **kwargs) + # PROTECTED REGION END # // MidCspSubarrayBase.main + +if __name__ == '__main__': + main() diff --git a/csp-lmc-mid/docker/.make/.make-release-support b/csp-lmc-mid/docker/.make/.make-release-support new file mode 100644 index 0000000000000000000000000000000000000000..f1f3a2cb9fb3ea0ce3a173a35c3c9fe316d75156 --- /dev/null +++ b/csp-lmc-mid/docker/.make/.make-release-support @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Copyright 2015 Xebia Nederland B.V. +# Modifications copyright 2019 SKA Organisation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +function hasChanges() { + test -n "$(git status -s .)" +} + +function getRelease() { + awk -F= '/^release=/{print $2}' .release +} + +function getBaseTag() { + sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release +} + +function getTag() { + if [ -z "$1" ] ; then + awk -F= '/^tag/{print $2}' .release + else + echo "$(getBaseTag)$1" + fi +} + +function setRelease() { + if [ -n "$1" ] ; then + sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release + sed -i.x -e "s/^release=.*/release=$1/g" .release + rm -f .release.x + runPreTagCommand "$1" + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function runPreTagCommand() { + if [ -n "$1" ] ; then + COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release) + if [ -n "$COMMAND" ] ; then + if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi + fi + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function tagExists() { + tag=${1:-$(getTag)} + test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" +} + +function differsFromRelease() { + tag=$(getTag) + ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" +} + +function getVersion() { + result=$(getRelease) + + if differsFromRelease; then + result="$result-$(git log -n 1 --format=%h .)" + fi + + if hasChanges ; then + result="$result-dirty" + fi + echo $result +} + +function nextPatchLevel() { + version=${1:-$(getRelease)} + major_and_minor=$(echo $version | cut -d. -f1,2) + patch=$(echo $version | cut -d. -f3) + version=$(printf "%s.%d" $major_and_minor $(($patch + 1))) + echo $version +} + +function nextMinorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + minor=$(echo $version | cut -d. -f2); + version=$(printf "%d.%d.0" $major $(($minor + 1))) ; + echo $version +} + +function nextMajorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + version=$(printf "%d.0.0" $(($major + 1))) + echo $version +} diff --git a/csp-lmc-mid/docker/.make/.make-release-support.katversion b/csp-lmc-mid/docker/.make/.make-release-support.katversion new file mode 100644 index 0000000000000000000000000000000000000000..f1f3a2cb9fb3ea0ce3a173a35c3c9fe316d75156 --- /dev/null +++ b/csp-lmc-mid/docker/.make/.make-release-support.katversion @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Copyright 2015 Xebia Nederland B.V. +# Modifications copyright 2019 SKA Organisation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +function hasChanges() { + test -n "$(git status -s .)" +} + +function getRelease() { + awk -F= '/^release=/{print $2}' .release +} + +function getBaseTag() { + sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release +} + +function getTag() { + if [ -z "$1" ] ; then + awk -F= '/^tag/{print $2}' .release + else + echo "$(getBaseTag)$1" + fi +} + +function setRelease() { + if [ -n "$1" ] ; then + sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release + sed -i.x -e "s/^release=.*/release=$1/g" .release + rm -f .release.x + runPreTagCommand "$1" + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function runPreTagCommand() { + if [ -n "$1" ] ; then + COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release) + if [ -n "$COMMAND" ] ; then + if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi + fi + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function tagExists() { + tag=${1:-$(getTag)} + test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" +} + +function differsFromRelease() { + tag=$(getTag) + ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" +} + +function getVersion() { + result=$(getRelease) + + if differsFromRelease; then + result="$result-$(git log -n 1 --format=%h .)" + fi + + if hasChanges ; then + result="$result-dirty" + fi + echo $result +} + +function nextPatchLevel() { + version=${1:-$(getRelease)} + major_and_minor=$(echo $version | cut -d. -f1,2) + patch=$(echo $version | cut -d. -f3) + version=$(printf "%s.%d" $major_and_minor $(($patch + 1))) + echo $version +} + +function nextMinorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + minor=$(echo $version | cut -d. -f2); + version=$(printf "%d.%d.0" $major $(($minor + 1))) ; + echo $version +} + +function nextMajorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + version=$(printf "%d.0.0" $(($major + 1))) + echo $version +} diff --git a/csp-lmc-mid/docker/.make/Makefile.mk b/csp-lmc-mid/docker/.make/Makefile.mk new file mode 100644 index 0000000000000000000000000000000000000000..d2cb6314fbab45ccc2dd1357139a7260497a25c1 --- /dev/null +++ b/csp-lmc-mid/docker/.make/Makefile.mk @@ -0,0 +1,141 @@ +# +# Copyright 2015 Xebia Nederland B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifeq ($(strip $(PROJECT)),) + NAME=$(shell basename $(CURDIR)) +else + NAME=$(PROJECT) +endif + +RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support + +ifeq ($(strip $(DOCKER_REGISTRY_HOST)),) + DOCKER_REGISTRY_HOST = nexus.engageska-portugal.pt +endif + +ifeq ($(strip $(DOCKER_REGISTRY_USER)),) + DOCKER_REGISTRY_USER = ska-docker +endif + +IMAGE=$(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(NAME) + +#VERSION = release version + git sha +VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion) + +#BASE_VERSION +BASE_VERSION=$(shell . $(RELEASE_SUPPORT) ; getRelease) + +#TAG = project name + release version +TAG=$(shell . $(RELEASE_SUPPORT); getTag) + +#DEFAULT_TAG = image name + BASE_VERSION +DEFAULT_TAG=$(IMAGE):$(BASE_VERSION) + + +SHELL=/bin/bash + +DOCKER_BUILD_CONTEXT=.. +DOCKER_FILE_PATH=Dockerfile + +.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ + push pre-push do-push post-push + +build: pre-build docker-build post-build ## build the application image + +pre-build: + +post-build: + +pre-push: + +post-push: + +#docker-build: .release +docker-build: + @echo "$(PWD)" + rm $(PWD)/.release + $(PWD)/scripts/kat-get-version.py > .release + @echo "Building image: $(IMAGE):$(VERSION)" + @echo "NAME: $(NAME)" + docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) --build-arg DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) --build-arg DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) + @DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \ + DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \ + if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \ + echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + else \ + echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \ + fi + +release: check-status check-release build push + +push: pre-push do-push post-push ## push the image to the Docker registry + +do-push: ## Push the image tagged as $(IMAGE):$(VERSION) and $(DEFAULT_TAG) + @echo -e "Tagging: $(IMAGE):$(VERSION) -> $(DEFAULT_TAG)" + docker tag $(IMAGE):$(VERSION) $(DEFAULT_TAG) + @echo -e "Pushing: $(IMAGE):$(VERSION)" + docker push $(IMAGE):$(VERSION) + @echo -e "Pushing: $(DEFAULT_TAG)" + docker push $(DEFAULT_TAG) + +tag_latest: do-push ## Tag the images as latest + @echo "Tagging: $(DEFAULT_TAG) -> $(IMAGE):latest" + @docker tag $(DEFAULT_TAG) $(IMAGE):latest + +push_latest: tag_latest ## Push the image tagged as :latest + @echo "Pushing: $(IMAGE):latest" + @docker push $(IMAGE):latest + +snapshot: build push + +showver: .release + @. $(RELEASE_SUPPORT); getVersion + +bump-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel) +bump-patch-release: .release tag + +bump-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel) +bump-minor-release: .release tag + +bump-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel) +bump-major-release: .release tag + +patch-release: tag-patch-release release + @echo $(VERSION) + +minor-release: tag-minor-release release + @echo $(VERSION) + +major-release: tag-major-release release + @echo $(VERSION) + +tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION)) +tag: check-status +# @. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; setRelease $(VERSION) +# git add . +# git commit -m "bumped to version $(VERSION)" ; +# git tag $(TAG) ; +# @ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi + +check-status: + @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ; + +check-release: .release + @. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1) diff --git a/csp-lmc-mid/docker/.release b/csp-lmc-mid/docker/.release new file mode 100644 index 0000000000000000000000000000000000000000..f3edec2f5b5669fda5aaa333ab7f1b8d85629a0d --- /dev/null +++ b/csp-lmc-mid/docker/.release @@ -0,0 +1,4 @@ +UFFA +0.1.dev28+at5.262.b2479f2.dirty +AT5.262 +None diff --git a/csp-lmc-mid/docker/Dockerfile b/csp-lmc-mid/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e6f377143b503d3096cc05fa83d1afa4da4528b9 --- /dev/null +++ b/csp-lmc-mid/docker/Dockerfile @@ -0,0 +1,11 @@ +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:0.2.2 AS buildenv +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:0.2.2 AS runtime + +# create ipython profile to so that itango doesn't fail if ipython hasn't run yet +RUN ipython profile create +#install lmc-base-classes +USER root +RUN DEBIAN_FRONTEND=noninteractive pip3 install https://nexus.engageska-portugal.pt/repository/pypi/packages/lmcbaseclasses/0.2.0+6bb55a6e/lmcbaseclasses-0.2.0+6bb55a6e.tar.gz + +#CMD ["/venv/bin/python -m"," csp_lmc_common.CspMaster" ] +CMD ["/bin/bash"] diff --git a/csp-lmc-mid/docker/Makefile b/csp-lmc-mid/docker/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..47075be07263118aefa555298d405802bc9ffc9f --- /dev/null +++ b/csp-lmc-mid/docker/Makefile @@ -0,0 +1,198 @@ +# +# Project makefile for a Tango project. You should normally only need to modify +# DOCKER_REGISTRY_USER and PROJECT below. +# + +# +# DOCKER_REGISTRY_HOST, DOCKER_REGISTRY_USER and PROJECT are combined to define +# the Docker tag for this project. The definition below inherits the standard +# value for DOCKER_REGISTRY_HOST (=rnexus.engageska-portugal.pt) and overwrites +# DOCKER_REGISTRY_USER and PROJECT to give a final Docker tag of +# nexus.engageska-portugal.pt/tango-example/csplmc +# + +DOCKER_REGISTRY_USER:=ska-docker +PROJECT = mid-csp-lmc + +# +# include makefile to pick up the standard Make targets, e.g., 'make build' +# build, 'make push' docker push procedure, etc. The other Make targets +# ('make interactive', 'make test', etc.) are defined in this file. +# +include .make/Makefile.mk + +# +# IMAGE_TO_TEST defines the tag of the Docker image to test +# +IMAGE_TO_TEST = $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(PROJECT):latest + +# +# CACHE_VOLUME is the name of the Docker volume used to cache eggs and wheels +# used during the test procedure. The volume is not used during the build +# procedure +# +CACHE_VOLUME = $(PROJECT)-test-cache + +# optional docker run-time arguments +DOCKER_RUN_ARGS = + +# +# Never use the network=host mode when running CI jobs, and add extra +# distinguishing identifiers to the network name and container names to +# prevent collisions with jobs from the same project running at the same +# time. +# +ifneq ($(CI_JOB_ID),) +NETWORK_MODE := tangonet-$(CI_JOB_ID) +CONTAINER_NAME_PREFIX := $(PROJECT)-$(CI_JOB_ID)- +else +CONTAINER_NAME_PREFIX := $(PROJECT)- +endif + +COMPOSE_FILES := $(wildcard *.yml) +COMPOSE_FILE_ARGS := $(foreach yml,$(COMPOSE_FILES),-f $(yml)) + +ifeq ($(OS),Windows_NT) + $(error Sorry, Windows is not supported yet) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + DISPLAY ?= :0.0 + NETWORK_MODE ?= host + XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix + XAUTHORITY ?= /hosthome/.Xauthority + # /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly + SHELL := /bin/bash + endif + ifeq ($(UNAME_S),Darwin) + IF_INTERFACE := $(shell netstat -nr | awk '{ if ($$1 ~/default/) { print $$6} }') + DISPLAY := $(shell ifconfig $(IF_INTERFACE) | awk '{ if ($$1 ~/inet$$/) { print $$2} }'):0 + # network_mode = host doesn't work on MacOS, so fix to the internal network + NETWORK_MODE := tangonet + XAUTHORITY_MOUNT := $(HOME):/hosthome:ro + XAUTHORITY := /hosthome/.Xauthority + endif +endif + +# +# When running in network=host mode, point devices at a port on the host +# machine rather than at the container. +# +ifeq ($(NETWORK_MODE),host) +TANGO_HOST := $(shell hostname):10000 +MYSQL_HOST := $(shell hostname):3306 +else +# distinguish the bridge network from others by adding the project name +NETWORK_MODE := $(NETWORK_MODE)-$(PROJECT) +TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds:10000 +MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306 +endif + + +DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) XAUTHORITY=$(XAUTHORITY) TANGO_HOST=$(TANGO_HOST) \ + NETWORK_MODE=$(NETWORK_MODE) XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) MYSQL_HOST=$(MYSQL_HOST) \ + DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) \ + CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) COMPOSE_IGNORE_ORPHANS=true + +# +# Defines a default make target so that help is printed if make is called +# without a target +# +.DEFAULT_GOAL := help + +# +# defines a function to copy the ./test-harness directory into the container +# and then runs the requested make target in the container. The container is: +# +# 1. attached to the network of the docker-compose test system +# 2. uses a persistent volume to cache Python eggs and wheels so that fewer +# downloads are required +# 3. uses a transient volume as a working directory, in which untarred files +# and test output can be written in the container and subsequently copied +# to the host +# +make = tar -c test-harness/ | \ + docker run -i --rm --network=$(NETWORK_MODE) \ + -e TANGO_HOST=$(TANGO_HOST) \ + -v $(CACHE_VOLUME):/home/tango/.cache \ + --volumes-from=$(CONTAINER_NAME_PREFIX)rsyslog-csplmc:rw \ + -v /build -w /build -u tango $(DOCKER_RUN_ARGS) $(IMAGE_TO_TEST) \ + bash -c "sudo chown -R tango:tango /build && \ + tar x --strip-components 1 --warning=all && \ + make TANGO_HOST=$(TANGO_HOST) $1" + +test: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +test: build up ## test the application + @echo "BUILD: $(BUILD)" + $(INIT_CACHE) + $(call make,test); \ + status=$$?; \ + rm -fr build; \ + #docker-compose $(COMPOSE_FILE_ARGS) logs; + docker cp $(BUILD):/build .; \ + docker rm -f -v $(BUILD); \ + $(MAKE) down; \ + exit $$status + +lint: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +lint: build up ## lint the application (static code analysis) + $(INIT_CACHE) + $(call make,lint); \ + status=$$?; \ + docker cp $(BUILD):/build .; \ + $(MAKE) down; \ + exit $$status + +pull: ## download the application image + docker pull $(IMAGE_TO_TEST) + +up: build ## start develop/test environment +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE)) +endif + #$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull + #to pull only the mid-cbf-mcs image remove comment on row below. + #docker pull $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/mid-cbf-mcs:latest + $(DOCKER_COMPOSE_ARGS) docker-compose -f csp-tangodb.yml up -d + # put a sleep to wait TANGO DB + @sleep 10 + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up + +piplock: build ## overwrite Pipfile.lock with the image version + docker run $(IMAGE_TO_TEST) cat /app/Pipfile.lock > $(CURDIR)/Pipfile.lock + +interactive: up +interactive: ## start an interactive session using the project image (caution: R/W mounts source directory to /app) + docker run --rm -it -p 3000:3000 --name=$(CONTAINER_NAME_PREFIX)dev -e TANGO_HOST=$(TANGO_HOST) --network=$(NETWORK_MODE) \ + -v $(CURDIR):/app $(IMAGE_TO_TEST) /bin/bash + +down: ## stop develop/test environment and any interactive session + docker ps | grep $(CONTAINER_NAME_PREFIX)dev && docker stop $(PROJECT)-dev || true + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true +endif + +dsconfigdump: up ## dump the entire configuration to the file dsconfig.json + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump > dsconfig.json + +dsconfigadd: up ## Add a configuration json file (environment variable DSCONFIG_JSON_FILE) to the database + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -u -w -a $(DSCONFIG_JSON_FILE) + +dsconfigcheck: up ## check a json file (environment variable DSCONFIG_JSON_FILE) according to the project lib-maxiv-dsconfig json schema + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -a $(DSCONFIG_JSON_FILE) + +help: ## show this help. + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: all test up down help + +# Creates Docker volume for use as a cache, if it doesn't exist already +INIT_CACHE = \ + docker volume ls | grep $(CACHE_VOLUME) || \ + docker create --name $(CACHE_VOLUME) -v $(CACHE_VOLUME):/cache $(IMAGE_TO_TEST) + +# http://cakoose.com/wiki/gnu_make_thunks +BUILD_GEN = $(shell docker create -v /build $(IMAGE_TO_TEST)) +BUILD = $(eval BUILD := $(BUILD_GEN))$(BUILD) diff --git a/csp-lmc-mid/docker/csp-lmc.yml b/csp-lmc-mid/docker/csp-lmc.yml new file mode 100644 index 0000000000000000000000000000000000000000..7908280e8fa3080c12e47d485ecd768b6b00456e --- /dev/null +++ b/csp-lmc-mid/docker/csp-lmc.yml @@ -0,0 +1,144 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-csplmc: rsyslog service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + csp_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}csp_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u csplmc/config/csplmc_dsconfig.json && sleep infinity" + volumes: + - .:/csplmc + + cspsubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspsubarray01 + depends_on: + - csp_dsconfig + - cspmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device common/elt/master &&\ + /venv/bin/python /app/csp_lmc_common/CspSubarray.py comsub1" + volumes_from: + - rsyslog-csplmc:rw + + cspsubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspsubarray02 + depends_on: + - csp_dsconfig + - cspmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device common/elt/master &&\ + /venv/bin/python /app/csp_lmc_common/CspSubarray.py comsub2" + volumes_from: + - rsyslog-csplmc:rw + + cspmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cspmaster + depends_on: + - csp_dsconfig + - cbfmaster + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python -m csp_lmc_common.CspMaster commaster" + volumes_from: + - rsyslog-csplmc:rw + + searchbeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}searchbeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor searchbeams" + volumes_from: + - rsyslog-csplmc:rw + + timingbeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}timingbeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor timingbeams" + volumes_from: + - rsyslog-csplmc:rw + + vlbibeam: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vlbibeam + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python -m csp_lmc_common.CspCapabilityMonitor vlbibeams" + volumes_from: + - rsyslog-csplmc:rw + + pssmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-common:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}pssmaster + depends_on: + - csp_dsconfig + - rsyslog-csplmc + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + /venv/bin/python /app/simulators/DeviceTestMaster/PssMasterSimulator.py pss" + volumes_from: + - rsyslog-csplmc:rw + + rsyslog-csplmc: + image: jumanjiman/rsyslog + container_name: ${CONTAINER_NAME_PREFIX}rsyslog-csplmc + network_mode: ${NETWORK_MODE} diff --git a/csp-lmc-mid/docker/csp-tangodb.yml b/csp-lmc-mid/docker/csp-tangodb.yml new file mode 100644 index 0000000000000000000000000000000000000000..64a6922bb979d5b19e26369fdd1a788fd44adb6d --- /dev/null +++ b/csp-lmc-mid/docker/csp-tangodb.yml @@ -0,0 +1,50 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# +# Requires: +# - None +# +version: '2.2' +volumes: + tangodb: {} + +services: + tangodb: + image: nexus.engageska-portugal.pt/ska-docker/tango-db:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tangodb + environment: + - MYSQL_ROOT_PASSWORD=secret + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + volumes: + - tangodb:/var/lib/mysql + + databaseds: + image: nexus.engageska-portugal.pt/ska-docker/tango-cpp:latest + depends_on: + - tangodb + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}databaseds + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + - TANGO_HOST=${TANGO_HOST} + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${MYSQL_HOST} + - --timeout=70 + - --strict + - -- + - /usr/local/bin/DataBaseds + - "2" + - -ORBendPoint + - giop:tcp::10000 + diff --git a/csp-lmc-mid/docker/csplmc_dsconfig.json b/csp-lmc-mid/docker/csplmc_dsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..257c9dadc3c4caf840260becaa909a5cdbe63e4f --- /dev/null +++ b/csp-lmc-mid/docker/csplmc_dsconfig.json @@ -0,0 +1,645 @@ +{ + "classes": { + "CspSubarray": { + "properties": { + "PstBeam": [ + "mid_csp_pst/sub_elt/beam_01" + ] + } + } + }, + "servers": { + "MidCspMaster": { + "master": { + "CspCapabilityMonitor": { + "mid_csp/capability_monitor/receptors": { + "properties": { + "CapabilityDevices": [ + "mid_csp/receptors/002", + "mid_csp/receptors/003", + "mid_csp/receptors/004", + "mid_csp/receptors/001" + ], + "SkaLevel": [ + "2" + ] + } + }, + "mid_csp/capability_monitor/search_beams": { + "properties": { + "CapabilityDevices": [ + "mid_csp/search_beams/0001", + "mid_csp/search_beams/0004", + "mid_csp/search_beams/0003", + "mid_csp/search_beams/0002" + ], + "SkaLevel": [ + "2" + ] + } + }, + "mid_csp/capability_monitor/timing_beams": { + "properties": { + "CapabilityDevices": [ + "mid_csp/timing_beams/01", + "mid_csp/timing_beams/02", + "mid_csp/timing_beams/03", + "mid_csp/timing_beams/04" + ], + "SkaLevel": [ + "2" + ] + } + }, + "mid_csp/capability_monitor/vlbi_beams": { + "properties": { + "CapabilityDevices": [ + "mid_csp/vlbi_beams/01", + "mid_csp/vlbi_beams/04", + "mid_csp/vlbi_beams/03", + "mid_csp/vlbi_beams/02" + ], + "SkaLevel": [ + "2" + ] + } + } + }, + "MidCspMasterBase": { + "mid_csp/elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "reportSearchBeamState": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/capabilityState" + ] + }, + "reportTimingBeamState": { + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/capabilityState" + ] + }, + "reportVlbiBeamState": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/capabilityState" + ] + }, + "reportSearchBeamHealthState": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/capabilityHealthState" + ] + }, + "reportTimingBeamHealthState":{ + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/capabilityHealthState" + ] + }, + "reportVlbiBeamHealthState": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/capabilityHealthState" + ] + }, + "reportSearchBeamObsState": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/capabilityObsState" + ] + }, + "reportTimingBeamObsState":{ + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/capabilityObsState" + ] + }, + "reportVlbiBeamObsState": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/capabilityObsState" + ] + }, + "reportSearchBeamAdminMode": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/capabilityAdminMode" + ] + }, + "reportTimingBeamAdminMode":{ + "__root_att": [ + "mid_csp/capability_monitor/timig_beams/capabilityAdminMode" + ] + }, + "reportVlbiBeamAdminMode": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/capabilityAdminMode" + ] + }, + "searchBeamAddresses": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/cspCapabilityAddresses" + ] + }, + "timingBeamAddresses": { + "__root_att": [ + "mid_csp/capability_monitor/timig_beams/cspCapabilityAddresses" + ] + }, + "vlbiBeamAddresses": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/cspCapabilityAddresses" + ] + }, + "reservedSearchBeamIDs": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/reservedIDs" + ] + }, + "unassignedSearchBeamIDs": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/unassignedIDs" + ] + }, + "unassignedTimingBeamIDs": { + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/unassignedIDs" + ] + }, + "unassignedVlbiBeamIDs": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/unassignedIDs" + ] + }, + "unassignedSearchBeamNum": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/numOfUnassignedIDs" + ] + }, + "unassignedTimingBeamNum": { + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/numOfUnassignedIDs" + ] + }, + "unassignedVlbiBeamNum": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/numOfUnassignedIDs" + ] + }, + "searchBeamMembership": { + "__root_att": [ + "mid_csp/capability_monitor/search_beams/capabilityMembership" + ] + }, + "timingBeamMembership": { + "__root_att": [ + "mid_csp/capability_monitor/timing_beams/capabilityMembership" + ] + }, + "vlbiBeamMembership": { + "__root_att": [ + "mid_csp/capability_monitor/vlbi_beams/capabilityMembership" + ] + }, + "fspMembership": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportFSPSubarrayMembership" + ] + }, + "reportFSPAdminMode": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportFSPAdminMode" + ] + }, + "reportFSPHealthState": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportFSPHealthState" + ] + }, + "reportFSPState": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportFSPState" + ] + }, + "reportVCCAdminMode": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportVCCAdminMode" + ] + }, + "reportVCCHealthState": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportVCCHealthState" + ] + }, + "reportVCCState": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportVCCState" + ] + }, + "vccMembership": { + "__root_att": [ + "mid_csp_cbf/sub_elt/master/reportVCCSubarrayMembership" + ] + } + }, + "properties": { + "CspCbf": [ + "mid_csp_cbf/sub_elt/master" + ], + "CspPss": [ + "mid_csp_pss/sub_elt/master" + ], + "CspPst": [ + "mid_csp_pst/sub_elt/master" + ], + "CspSubarrays": [ + "mid_csp/elt/subarray_01", + "mid_csp/elt/subarray_02" + ], + "MaxCapabilities": [ + "VlbiBeams:20", + "TimingBeams:16", + "SearchBeams:1500", + "Receptors:197" + ], + "SearchBeams": [ + "mid_csp/search_beams/0001", + "mid_csp/search_beams/0002", + "mid_csp/search_beams/0003", + "mid_csp/search_beams/0004" + ], + "SearchBeamsMonitor": [ + "mid_csp/capability_monitor/search_beams" + ], + "SkaLevel": [ + "1" + ], + "TimingBeams": [ + "mid_csp/timing_beams/01", + "mid_csp/timing_beams/02", + "mid_csp/timing_beams/03", + "mid_csp/timing_beams/04" + ], + "TimingBeamsMonitor": [ + "mid_csp/capability_monitor/timing_beams" + ], + "VlbiBeams": [ + "mid_csp/vlbi_beams/01", + "mid_csp/vlbi_beams/02", + "mid_csp/vlbi_beams/03", + "mid_csp/vlbi_beams/04" + ], + "VlbiBeamsMonitor": [ + "mid_csp/capability_monitor/vlbi_beams" + ], + "polled_attr": [ + "csppssadminmode", + "3000", + "csppstadminmode", + "cspcbfadminmode", + "3000", + "1000", + "standbycmdalarm", + "1000", + "offcmdalarm", + "1000", + "3000", + "oncmdalarm", + "adminmode", + "1000", + "oncommandprogress", + "3000", + "offcommandprogress", + "3000", + "standbycommandprogress", + "3000", + "oncmddurationexpected", + "3000", + "offcmddurationexpected", + "3000", + "standbycmddurationexpected", + "3000", + "oncmddurationmeasured", + "3000", + "offcmddurationmeasured", + "3000", + "standbycmddurationmeasured", + "3000", + "oncmdtimeoutexpired", + "2000", + "offcmdtimeoutexpired", + "2000", + "standbycmdtimeoutexpired", + "2000", + "cspcbfstate", + "3000", + "csppssstate", + "3000", + "csppststate", + "3000", + "cspcbfhealthstate", + "3000", + "csppsshealthstate", + "3000", + "3000", + "csppsthealthstate" + ] + } + } + } + } + }, + "PssMasterSimulator": { + "pss": { + "PssMasterSimulator": { + "mid_csp_pss/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "onDurationExpected": { + "__value": [ + "10" + ] + }, + "offDurationExpected": { + "__value": [ + "12" + ] + }, + "standbyDurationExpected": { + "__value": [ + "5" + ] + }, + "onCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "offCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "standbyCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + } + }, + "properties": { + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "onCommandProgress", + "1000", + "offCommandProgress", + "1000", + "standbyCommandProgress", + "1000" + ] + } + } + } + } + }, + "PstMasterSimulator": { + "pst": { + "PstMasterSimulator": { + "mid_csp_pst/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ], + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "offCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "offDurationExpected": { + "__value": [ + "12" + ] + }, + "onCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "onDurationExpected": { + "__value": [ + "10" + ] + }, + "standbyCommandProgress": { + "abs_change": [ + "-5", + "5" + ] + }, + "standbyDurationExpected": { + "__value": [ + "5" + ] + } + }, + "properties": { + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "onCommandProgress", + "1000", + "offCommandProgress", + "1000", + "standbyCommandProgress", + "1000" + ] + } + } + } + } + }, + "CspSubarray": { + "comsub1": { + "CspSubarray": { + "common/elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_01/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_01" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_01" + ], + "SubID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + }, + "comsub2": { + "CspSubarray": { + "common/elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + }, + "cbfOutputLink": { + "__root_att": [ + "mid_csp_cbf/sub_elt/subarray_02/outputLinksDistribution" + ] + } + }, + "properties": { + "CspMaster": [ + "common/elt/master" + ], + "SubID": [ + "2" + ], + "CbfSubarray": [ + "mid_csp_cbf/sub_elt/subarray_02" + ], + "PssSubarray": [ + "mid_csp_pss/sub_elt/subarray_02" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + } + } +} diff --git a/csp-lmc-mid/docker/mid-cbf-mcs.yml b/csp-lmc-mid/docker/mid-cbf-mcs.yml new file mode 100644 index 0000000000000000000000000000000000000000..490c97ea649590a9b0610120d07aa4a8340c884e --- /dev/null +++ b/csp-lmc-mid/docker/mid-cbf-mcs.yml @@ -0,0 +1,288 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-cbf-csplmc: rsyslog-cbf service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + cbf_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbf_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u csplmc/config/midcbf_dsconfig.json && sleep infinity" + volumes: + - .:/csplmc + + cbfmaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfmaster + depends_on: + - databaseds + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/001 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/002 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/003 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/vcc/004 &&\ + /venv/bin/python /app/tangods/CbfMaster/CbfMaster/CbfMaster.py master" + volumes_from: + - rsyslog-cbf:rw + + + cbfsubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfsubarray01 + depends_on: + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - cbfmaster + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python /app/tangods/CbfSubarray/CbfSubarrayMulti/CbfSubarrayMulti.py cbfSubarray-01" + volumes_from: + - rsyslog-cbf:rw + + + cbfsubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}cbfsubarray02 + depends_on: + - cbf_dsconfig + - vcc001 + - vcc002 + - vcc003 + - vcc004 + - cbfmaster + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/sub_elt/master &&\ + /venv/bin/python /app/tangods/CbfSubarray/CbfSubarrayMulti/CbfSubarrayMulti.py cbfSubarray-02" + volumes_from: + - rsyslog-cbf:rw + + + vcc001: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc001 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-001" + volumes_from: + - rsyslog-cbf:rw + + + vcc002: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc002 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-002" + volumes_from: + - rsyslog-cbf:rw + + + vcc003: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc003 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-003" + volumes_from: + - rsyslog-cbf:rw + + + vcc004: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}vcc004 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/01 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/02 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/03 &&\ + retry --max=5 -- tango_admin --ping-device mid_csp_cbf/fsp/04 &&\ + /venv/bin/python /app/tangods/Vcc/VccMulti/VccMulti.py vcc-004" + volumes_from: + - rsyslog-cbf:rw + + + fsp01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp01 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-01" + volumes_from: + - rsyslog-cbf:rw + + fsp02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp02 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-02" + volumes_from: + - rsyslog-cbf:rw + + fsp03: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp03 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-03" + volumes_from: + - rsyslog-cbf:rw + + + fsp04: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}fsp04 + depends_on: + - databaseds + - cbf_dsconfig + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + /venv/bin/python /app/tangods/Fsp/FspMulti/FspMulti.py fsp-04" + volumes_from: + - rsyslog-cbf:rw + + + tmcspsubarrayleafnodetest: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tmcspsubarrayleafnodetest + depends_on: + - cspmaster + - databaseds + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=10 -- tango_admin --ping-device mid_csp/elt/subarray_01 && + /venv/bin/python /app/tangods/TmCspSubarrayLeafNodeTest/TmCspSubarrayLeafNodeTest.py tm" + volumes_from: + - rsyslog-cbf:rw + + tmcspsubarrayleafnodetest2: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/mid-cbf-mcs:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tmcspsubarrayleafnodetest2 + depends_on: + - cspmaster + - databaseds + - rsyslog-cbf + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + retry --max=10 -- tango_admin --ping-device mid_csp/elt/subarray_02 && + /venv/bin/python /app/tangods/TmCspSubarrayLeafNodeTest/TmCspSubarrayLeafNodeTest.py tm2" + volumes_from: + - rsyslog-cbf:rw + + rsyslog-cbf: + image: jumanjiman/rsyslog + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}rsyslog-cbf + + diff --git a/csp-lmc-mid/docker/scripts/kat-get-version.py b/csp-lmc-mid/docker/scripts/kat-get-version.py new file mode 100755 index 0000000000000000000000000000000000000000..04c0840c2758bcf898fffeeaad36e369fdb2b4bf --- /dev/null +++ b/csp-lmc-mid/docker/scripts/kat-get-version.py @@ -0,0 +1,44 @@ +#!/venv/bin/python + +################################################################################ +# Copyright (c) 2014-2018, National Research Foundation (Square Kilometre Array) +# +# Licensed under the BSD 3-Clause License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy +# of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################ + +"""Script to get the current version string of a Python package.""" + +import os +import argparse + +from katversion.version import get_version_from_file, get_git_cleaned_branch_name, get_version_from_module +from katversion import get_version + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-p', '--path', dest='path', action='store', + help='Path of SCM checkout. If not given the' + ' current directory is used.') + args = parser.parse_args() + + if args.path: + path = args.path + else: + # If path was not given us the current working directory. This is the + # way git smudge uses this file. + path = os.getcwd() + print("UFFA") + print(get_version(path, "mid-csp-lmc")) + print(get_git_cleaned_branch_name(path)) + print(get_version_from_module("csp-lmc")) diff --git a/csp-lmc-mid/pogo/MidCspMasterBase.py b/csp-lmc-mid/pogo/MidCspMasterBase.py new file mode 100644 index 0000000000000000000000000000000000000000..7eeec895bd19e68be172ff3d963f4cdfcb658c87 --- /dev/null +++ b/csp-lmc-mid/pogo/MidCspMasterBase.py @@ -0,0 +1,349 @@ +# -*- 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. +""" + +# PyTango imports +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, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from CspMaster import CspMaster +# Additional import +# PROTECTED REGION ID(MidCspMasterBase.additionnal_import) ENABLED START # +# PROTECTED REGION END # // MidCspMasterBase.additionnal_import + +__all__ = ["MidCspMasterBase", "main"] + + +class MidCspMasterBase(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`.", + ) + + + + 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 + ) + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the MidCspMasterBase.""" + CspMaster.init_device(self) + # PROTECTED REGION ID(MidCspMasterBase.init_device) ENABLED START # + # 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 # + # PROTECTED REGION END # // MidCspMasterBase.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_availableCapabilities(self): + # PROTECTED REGION ID(MidCspMasterBase.availableCapabilities_read) ENABLED START # + """Return the availableCapabilities attribute.""" + return ('',) + # PROTECTED REGION END # // MidCspMasterBase.availableCapabilities_read + + def read_receptorMembership(self): + # PROTECTED REGION ID(MidCspMasterBase.receptorMembership_read) ENABLED START # + """Return the receptorMembership attribute.""" + return (0,) + # PROTECTED REGION END # // MidCspMasterBase.receptorMembership_read + + def read_unassignedReceptorIDs(self): + # PROTECTED REGION ID(MidCspMasterBase.unassignedReceptorIDs_read) ENABLED START # + """Return the unassignedReceptorIDs attribute.""" + return (0,) + # 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() diff --git a/csp-lmc-mid/pogo/MidCspMasterBase.xmi b/csp-lmc-mid/pogo/MidCspMasterBase.xmi new file mode 100644 index 0000000000000000000000000000000000000000..bfbc69eb25c0461b4e04c94819a21e81f689cb6c --- /dev/null +++ b/csp-lmc-mid/pogo/MidCspMasterBase.xmi @@ -0,0 +1,667 @@ + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + localhost + + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csp-lmc-mid/pogo/MidCspSubarrayBase.xmi b/csp-lmc-mid/pogo/MidCspSubarrayBase.xmi new file mode 100644 index 0000000000000000000000000000000000000000..182a7abc8c6416d17a1f1329c146f10eef26578b --- /dev/null +++ b/csp-lmc-mid/pogo/MidCspSubarrayBase.xmi @@ -0,0 +1,919 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + 4 + + + + + console::cout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +