Skip to content
Snippets Groups Projects
Commit 29dd72ae authored by Thomas Juerges's avatar Thomas Juerges
Browse files

Merge branch 'L2SS-183-Observation_device' into 'master'

L2SS-183: Observation device

Closes L2SS-183

See merge request !40
parents 624fc1a6 96422862
Branches
Tags
1 merge request!40L2SS-183: Observation device
......@@ -7,6 +7,13 @@
}
}
},
"observation_control": {
"LTS": {
"ObservationControl": {
"LTS/ObservationControl/1": {}
}
}
},
"PCC": {
"LTS": {
"PCC": {
......
......@@ -35,13 +35,13 @@ class TangoLoggingHandler(logging.Handler):
class LogAnnotator(logging.Formatter):
""" Annotates log records with:
record.tango_device: the Tango Device that is executing. """
@staticmethod
def get_current_tango_device() -> Device:
""" Return the tango Device we're currently executing for, or None if it can't be detected.
""" Return the tango Device we're currently executing for, or None if it can't be detected.
This is derived by traversing the stack and find a Device as 'self'. In some cases,
this fails, for example if a separate Thread is started for a certain Device. """
......@@ -130,7 +130,7 @@ def device_logging_to_python():
""" Decorator. Call this on a Tango Device instance or class to have your Tango Device log to python instead. """
def inner(cls):
# we'll be doing very weird things if this class isnt
# we'll be doing very weird things if this class isnt
if not issubclass(cls, Device):
raise ValueError("device_logging_to_python decorator is to be used on Tango Device classes only.")
......
# -*- coding: utf-8 -*-
#
# This file is part of the LOFAR2.0 Station Control project.
#
# Distributed under the terms of the APACHE license.
# See LICENSE.txt for more info.
# TODO(Corne): Remove sys.path.append hack once packaging is in place!
import os, sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
# PyTango imports
from tango import server, Except, DevState, AttrWriteType, DevString, DebugIt
from tango.server import Device, run, command, attribute
import numpy
from time import time
from devices.device_decorators import *
from common.lofar_logging import device_logging_to_python, log_exceptions
from common.lofar_git import get_version
from json import loads
__all__ = ["Observation", "main"]
@device_logging_to_python()
class Observation(Device):
""" Observation Device for LOFAR2.0
This Tango device is responsible for the set-up of hardware for a specific observation. It will, if necessary keep tabs on HW MPs to signal issues that are not caught by MPs being outside their nominal range.
The lifecycle of instances of this device is controlled by ObservationControl
"""
# Attributes
version_R = attribute(dtype = str, access = AttrWriteType.READ, fget = lambda self: get_version())
observation_running_R = attribute(dtype = numpy.float, access = AttrWriteType.READ, polling_period = 1000, period = 1000, rel_change = "1.0")
observation_id_R = attribute(dtype = numpy.int64, access = AttrWriteType.READ)
stop_time_R = attribute(dtype = numpy.float, access = AttrWriteType.READ)
# Core functions
@log_exceptions()
def init_device(self):
Device.init_device(self)
self.set_state(DevState.OFF)
self._observation_id = -1
self._stop_time = 0.0
@log_exceptions()
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 (a Tango built-in).
"""
self.debug_stream("Shutting down...")
if self.get_state() != DevState.OFF:
self.Off()
self.debug_stream("Shut down. Good bye.")
# Lifecycle functions
@command(dtype_in = DevString)
@only_in_states([DevState.FAULT, DevState.OFF])
@log_exceptions()
def Initialise(self, parameters: DevString = None):
self.set_state(DevState.INIT)
# ObservationControl takes already good care of checking that the
# parameters are in order and sufficient. It is therefore unnecessary
# at the moment to check the parameters here again.
# This could change when the parameter check becomes depending on
# certain aspects that only an Observation device can know.
self.observation_parameters = loads(parameters)
self._observation_id = int(self.observation_parameters.get("id"))
self._stop_time = float(self.observation_parameters.get("stop_time"))
self.set_state(DevState.STANDBY)
self.info_stream("The observation with ID={} is configured. It will begin as soon as On() is called and it is supposed to stop at {}.".format(self._observation_id, self._stop_time))
@command()
@only_in_states([DevState.STANDBY])
@log_exceptions()
def On(self):
self.set_state(DevState.ON)
self.info_stream("Started the observation with ID={}.".format(self._observation_id))
@command()
@log_exceptions()
def Off(self):
self.stop_polling(True)
self.set_state(DevState.OFF)
self.info_stream("Stopped the observation with ID={}.".format(self._observation_id))
@only_when_on()
@fault_on_error()
@log_exceptions()
def read_observation_id_R(self):
"""Return the observation_id_R attribute."""
return self._observation_id
@only_when_on()
@fault_on_error()
@log_exceptions()
def read_stop_time_R(self):
"""Return the stop_time_R attribute."""
return self._stop_time
@only_when_on()
@fault_on_error()
@log_exceptions()
def read_observation_running_R(self):
"""Return the observation_running_R attribute."""
return time()
# ----------
# Run server
# ----------
def main(args = None, **kwargs):
"""Main function of the ObservationControl module."""
return run((Observation,), args = args, **kwargs)
if __name__ == '__main__':
main()
This diff is collapsed.
#
# Docker compose file that launches a LOFAR2.0 station's
# ObservationControl device. It also runs the dynamically
# created Observation devices.
#
# Defines:
# - device-observation_control: LOFAR2.0 station ObvservationControl
#
# Requires:
# - lofar-device-base.yml
#
version: '2'
services:
device-observation_control:
image: device-observation_control
# build explicitly, as docker-compose does not understand a local image
# being shared among services.
build:
context: lofar-device-base
args:
SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION}
container_name: ${CONTAINER_NAME_PREFIX}device-observation_control
networks:
- control
ports:
- "5703:5703" # unique port for this DS
volumes:
- ${TANGO_LOFAR_CONTAINER_MOUNT}
environment:
- TANGO_HOST=${TANGO_HOST}
entrypoint:
- /usr/local/bin/wait-for-it.sh
- ${TANGO_HOST}
- --timeout=30
- --strict
- --
# configure CORBA to _listen_ on 0:port, but tell others we're _reachable_ through ${HOSTNAME}:port, since CORBA
# can't know about our Docker port forwarding
- python3 -u ${TANGO_LOFAR_CONTAINER_DIR}/devices/devices/observation_control.py LTS -v -ORBendPoint giop:tcp:0:5703 -ORBendPointPublish giop:tcp:${HOSTNAME}:5703
restart: on-failure
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment