diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c222a48dcd223050f203a69d7b4f4b4d99ccdb7..fcecc7c684ba15b7c8437b5c38b92276d70aaf6f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -86,11 +86,13 @@ docker_build_image_all: - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh grafana latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh jupyter latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh apsct-sim latest + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh ccd-sim latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh apspu-sim latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh recv-sim latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh sdptr-sim latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh unb2-sim latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apsct latest + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-ccd latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-tilebeam latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-beamlet latest @@ -191,6 +193,17 @@ docker_build_image_apsct_sim: script: # Do not remove 'bash' or statement will be ignored by primitive docker shell - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh apsct-sim $tag +docker_build_image_ccd_sim: + extends: .base_docker_images_except + only: + refs: + - merge_requests + changes: + - docker-compose/ccd-sim.yml + - docker-compose/pypcc-sim-base/* + script: +# Do not remove 'bash' or statement will be ignored by primitive docker shell + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh ccd-sim $tag docker_build_image_apspu_sim: extends: .base_docker_images_except only: @@ -246,6 +259,17 @@ docker_build_image_device_apsct: script: # Do not remove 'bash' or statement will be ignored by primitive docker shell - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-aspct $tag +docker_build_image_device_ccd: + extends: .base_docker_images_except + only: + refs: + - merge_requests + changes: + - docker-compose/device-ccd.yml + - docker-compose/lofar-device-base/* + script: +# Do not remove 'bash' or statement will be ignored by primitive docker shell + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-ccd $tag docker_build_image_device_apspu: extends: .base_docker_images_except only: diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 2ba1ebe751f6397710f82e8d246c74fe9eaae8dd..e7af81cae189b00800053ea1c24ed43faf243ba9 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -169,6 +169,16 @@ } } }, + "CCD": { + "STAT": { + "CCD": { + "STAT/CCD/1": { + "properties": { + } + } + } + } + }, "APSPU": { "STAT": { "APSPU": { diff --git a/CDB/stations/DTS_Outside_ConfigDb.json b/CDB/stations/DTS_Outside_ConfigDb.json index 523f2eb8d88e55ec42d1881d4c7de728881ef64f..cbfa8255c171cb2c47c81de6dd372105d7413cb0 100644 --- a/CDB/stations/DTS_Outside_ConfigDb.json +++ b/CDB/stations/DTS_Outside_ConfigDb.json @@ -24,6 +24,7 @@ "STAT/PCON/1", "STAT/APSPU/1", "STAT/APSCT/1", + "STAT/CCD/1", "STAT/RECV/1", "STAT/UNB2/1", "STAT/SDP/1", @@ -60,6 +61,25 @@ } } }, + "CCD": { + "STAT": { + "CCD": { + "STAT/CCD/1": { + "properties": { + "OPC_Server_Name": [ + "10.87.6.67 " + ], + "OPC_Server_Port": [ + "4843" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, "APSPU": { "STAT": { "APSPU": { diff --git a/CDB/stations/simulators_ConfigDb.json b/CDB/stations/simulators_ConfigDb.json index 7cd92391917029be134fdc9fd4846b5540153663..bb686ecf733a7925bafa3883bb86ed132fe89d90 100644 --- a/CDB/stations/simulators_ConfigDb.json +++ b/CDB/stations/simulators_ConfigDb.json @@ -32,6 +32,25 @@ } } }, + "CCD": { + "STAT": { + "CCD": { + "STAT/CCD/1": { + "properties": { + "OPC_Server_Name": [ + "ccd-sim" + ], + "OPC_Server_Port": [ + "4843" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, "APSPU": { "STAT": { "APSPU": { @@ -125,7 +144,7 @@ "RECV, HBAT_LED_on_RW" ], "Shutdown_Device_List":[ - "STAT/SDP/1", "STAT/UNB2/1", "STAT/RECV/1", "STAT/APSCT/1", "STAT/APSPU/1" + "STAT/SDP/1", "STAT/UNB2/1", "STAT/RECV/1", "STAT/APSCT/1", "STAT/CCD/1","STAT/APSPU/1" ] } } diff --git a/bin/start-ds.sh b/bin/start-ds.sh index 66389714f17770339ee645129adc9dcb26fa21d7..71cb29a29bfa977fbf6033c8479c9e59435485b5 100755 --- a/bin/start-ds.sh +++ b/bin/start-ds.sh @@ -37,6 +37,8 @@ else rm -rf /tmp/tangostationcontrol cp -R /opt/lofar/tango/tangostationcontrol /tmp/ cd /tmp/tangostationcontrol || exit 1 + # Remove the build directory if copied from the source + rm -rf build pip -vvv install --upgrade --force-reinstall ./ fi diff --git a/docker-compose/ccd-sim.yml b/docker-compose/ccd-sim.yml new file mode 100644 index 0000000000000000000000000000000000000000..b02d3693abc28ad95fde8b57515613c8cae09204 --- /dev/null +++ b/docker-compose/ccd-sim.yml @@ -0,0 +1,25 @@ +# +# Docker compose file that launches an APSCT simulator +# +# Defines: +# - apsct-sim +# +version: '2.1' + +services: + ccd-sim: + build: + context: pypcc-sim-base + args: + - LOCAL_DOCKER_REGISTRY_HOST=${LOCAL_DOCKER_REGISTRY_HOST} + - LOCAL_DOCKER_REGISTRY_LOFAR=${LOCAL_DOCKER_REGISTRY_LOFAR} + container_name: ${CONTAINER_NAME_PREFIX}ccd-sim + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + entrypoint: hwtr --simulator --port 4843 --config CCDTR + restart: on-failure diff --git a/docker-compose/device-ccd.yml b/docker-compose/device-ccd.yml new file mode 100644 index 0000000000000000000000000000000000000000..ffbfafcf31c9cfaea3ead633787b5bb0b9f69c47 --- /dev/null +++ b/docker-compose/device-ccd.yml @@ -0,0 +1,47 @@ +# +# Docker compose file that launches an interactive iTango session. +# +# Connect to the interactive session with 'docker attach itango'. +# Disconnect with the Docker deattach sequence: <CTRL>+<P> <CTRL>+<Q> +# +# Defines: +# - itango: iTango interactive session +# +# Requires: +# - lofar-device-base.yml +# +version: '2.1' + +services: + device-ccd: + image: device-ccd + # build explicitly, as docker-compose does not understand a local image + # being shared among services. + build: + context: . + dockerfile: lofar-device-base/Dockerfile + args: + SOURCE_IMAGE: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}device-ccd + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5721:5721" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ..:/opt/lofar/tango:rw + environment: + - TANGO_HOST=${TANGO_HOST} + working_dir: /opt/lofar/tango + entrypoint: + - bin/start-ds.sh + # 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 + - l2ss-ccd Ccd STAT -v -ORBendPoint giop:tcp:device-ccd:5721 -ORBendPointPublish giop:tcp:${HOSTNAME}:5721 + restart: on-failure diff --git a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index af329f05b03ae4bdc3b10542e96949c2f5e2b604..350ecb1e87f4829ddd60698831bbf75d941782a9 100644 --- a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -1,5 +1,6 @@ # Create shortcuts for our devices apsct = DeviceProxy("STAT/APSCT/1") +ccd = DeviceProxy("STAT/CCD/1") apspu = DeviceProxy("STAT/APSPU/1") recv = DeviceProxy("STAT/RECV/1") sdp = DeviceProxy("STAT/SDP/1") @@ -17,4 +18,4 @@ docker = DeviceProxy("STAT/Docker/1") temperaturemanager = DeviceProxy("STAT/TemperatureManager/1") # Put them in a list in case one wants to iterate -devices = [apsct, apspu, recv, sdp, bst, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker] +devices = [apsct, ccd, apspu, recv, sdp, bst, sst, xst, unb2, boot, tilebeam, beamlet, digitalbeam, antennafield, temperaturemanager, docker] diff --git a/docker-compose/tango-prometheus-exporter/lofar2-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-policy.json index 5d4ef40e092dd820d851cac7d8e152d45add336a..606f06499472aa11324b7566739efd6de37fdcab 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-policy.json @@ -15,6 +15,8 @@ }, "stat/apsct/1": { }, + "stat/ccd/1": { + }, "stat/apspu/1": { }, "stat/beamlet/1": { diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index 65beb8bc65ef32c79d29794281e5f3da2023456a..3047557a3678940748746acc6f7e7e3a59ea6090 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -73,9 +73,9 @@ sleep 1 # dsconfig container must be up and running... # shellcheck disable=SC2016 echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true' | make run dsconfig bash - -DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control" +DEVICES="device-boot device-apsct device-ccd device-apspu device-sdp device-recv device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control" -SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim" +SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim ccd-sim" # Build only the required images, please do not build everything that makes CI # take really long to finish, especially grafana / jupyter / prometheus. diff --git a/sbin/tag_and_push_docker_image.sh b/sbin/tag_and_push_docker_image.sh index d12bee575e594e0264e39c8eca6013704eb4a805..44605c52c7eed433cf89d0fab66d51946ce305cd 100755 --- a/sbin/tag_and_push_docker_image.sh +++ b/sbin/tag_and_push_docker_image.sh @@ -64,11 +64,13 @@ LOCAL_IMAGES=( "lofar-device-base lofar-device-base y" "apsct-sim docker-compose_apsct-sim y" "apspu-sim docker-compose_apspu-sim y" + "ccd-sim docker-compose_ccd-sim y" "recv-sim docker-compose_recv-sim y" "sdptr-sim docker-compose_sdptr-sim y" - "unb2-sim docker-compose_unb2-sim y" + "unb2-sim docker-compose_unb2-sim y" "device-antennafield device-antennafield y" "device-apsct device-apsct y" "device-apspu device-apspu y" + "device-ccd device-ccd y" "device-boot device-boot y" "device-docker device-docker y" "device-observation device-observation y" "device-observation-control device-observation-control y" @@ -159,13 +161,13 @@ if [ ! -z "${1+x}" ] && [ "${1}" != "pull" ]; then local_url="${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/${2}" # If tag is not latest, than it is not a tagged master build and we can - # pull the latest image as cache. + # pull the latest image as cache (if it already exists). if [ "${tag}" != "latest" ]; then - docker pull "${local_url}:latest" + docker pull "${local_url}:latest" || true fi make build "${1}" - docker tag "${2}" "${local_url}:${tag}" + docker tag "${2}" "${local_url}:${tag}" || docker tag "${2/_/-}" "${local_url}:${tag}" docker push "${local_url}:${tag}" fi done diff --git a/tangostationcontrol/docs/source/devices/ccd.rst b/tangostationcontrol/docs/source/devices/ccd.rst new file mode 100644 index 0000000000000000000000000000000000000000..a419254829f659ddf09cedf99a7e76cd9382b61e --- /dev/null +++ b/tangostationcontrol/docs/source/devices/ccd.rst @@ -0,0 +1,6 @@ +.. _ccd: + +CCD +-------------------- + +The ``ccd == DeviceProxy("STAT/CCD/1")`` Clock Control Device controls the clock diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index 07c5fb4ac45444e941b31b3869198b2504284389..6bd156c2b7f9d3cda99ad3af8a7e01bbc33c45c8 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -29,6 +29,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st devices/boot devices/docker devices/psoc + devices/ccd devices/temperature-manager devices/configure configure_station diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index 127f89141b4fc26fd283816923d9b1708bfa8a26..510034a343b89b2bc2a24bd212bafe77a4565a67 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -35,6 +35,7 @@ where=. [options.entry_points] console_scripts = l2ss-apsct = tangostationcontrol.devices.apsct:main + l2ss-ccd = tangostationcontrol.devices.ccd:main l2ss-apspu = tangostationcontrol.devices.apspu:main l2ss-psoc = tangostationcontrol.devices.psoc:main l2ss-pcon = tangostationcontrol.devices.pcon:main diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md index cb4efc08e5345657f96db0cc9afbf74e6a0c7d0f..4d5bc3a070be1340c26db626ef7dde9235df87c4 100644 --- a/tangostationcontrol/tangostationcontrol/devices/README.md +++ b/tangostationcontrol/tangostationcontrol/devices/README.md @@ -18,4 +18,4 @@ If a new device is added, it will (likely) need to be referenced in several plac - Add to `sbin/tag_and_push_docker_image.sh` the LOCAL_IMAGES device name, imagine name and build for integration boolean triple, - Add to `tangostationcontrol/docs/source/devices/` to mention the device in the end-user documentation. - Adjust `tangostationcontrol/docs/source/index.rst` to include the newly created file in `docs/source/devices/`. - +- Adjust `docker-compose/tango-prometheus-exporter/lofar2-policy.json` to include this device in the prometheus exporter diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index d9ea40ea3bc9dbf1c3e08d80caabbfaca2ddd55f..25b58719c287c4a6fe6e4b690f0228187ac17989 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -90,7 +90,8 @@ class AntennaField(lofar_device): Antenna_Names = device_property( doc="Name of each antenna", dtype='DevVarStringArray', - mandatory=False + mandatory=False, + default_value = [f'Antenna{n+1}' for n in range(MAX_NUMBER_OF_HBAT)] ) # ----- Antenna states diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py index cb172c34d3b4249691518609f18bd5a7ceced613..8d51d269f3e83eb2eb0a45442cec4209e00ecf13 100644 --- a/tangostationcontrol/tangostationcontrol/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -238,6 +238,7 @@ class Boot(lofar_device): "STAT/PCON/1", # PCON boot early because it is responsible for power delivery. "STAT/APSPU/1", # APS Power Units control other hardware we want to initialise "STAT/APSCT/1", + "STAT/CCD/1", "STAT/RECV/1", # RCUs are input for SDP, so initialise them first "STAT/UNB2/1", # Uniboards host SDP, so initialise them first "STAT/SDP/1", # SDP controls the mask for SST/XST/BST/Beamlet, so initialise it first diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py new file mode 100644 index 0000000000000000000000000000000000000000..e053d26c4e879fca236a4277742c96c0f119d350 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the RECV project +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" CCD Device Server for LOFAR2.0 + +""" + +# PyTango imports +from tango import DebugIt +from tango.server import command, attribute, device_property +from tango import AttrWriteType +import numpy +# Additional import + +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python +from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES +from tangostationcontrol.devices.device_decorators import only_in_states +from tangostationcontrol.devices.opcua_device import opcua_device + +import logging +logger = logging.getLogger() + +__all__ = ["CCD", "main"] + + +@device_logging_to_python() +class CCD(opcua_device): + # ----------------- + # Device Properties + # ----------------- + + CCDTR_monitor_rate_RW_default = device_property( + dtype='DevLong64', + mandatory=False, + default_value=1 + ) + + # ----- Timing values + + CCD_On_Off_timeout = device_property( + doc='Maximum amount of time to wait after turning CCD on or off', + dtype='DevFloat', + mandatory=False, + default_value=10.0 + ) + + # ---------- + # Attributes + # ---------- + CCDTR_I2C_error_R = attribute_wrapper(comms_annotation=["CCDTR_I2C_error_R" ], datatype=numpy.int64) + CCDTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["CCDTR_monitor_rate_RW" ], datatype=numpy.int64, access=AttrWriteType.READ_WRITE) + CCDTR_translator_busy_R = attribute_wrapper(comms_annotation=["CCDTR_translator_busy_R" ], datatype=bool) + CCD_clear_lock_R = attribute_wrapper(comms_annotation=["CCD_clear_lock_R" ], datatype=bool) + CCD_clear_lock_RW = attribute_wrapper(comms_annotation=["CCD_clear_lock_RW" ], datatype=bool, access=AttrWriteType.READ_WRITE) + CCD_FAN_RPM_R = attribute_wrapper(comms_annotation=["CCD_FAN_RPM_R" ], datatype=numpy.float64) + CCD_INPUT_10MHz_good_R = attribute_wrapper(comms_annotation=["CCD_INPUT_10MHz_good_R" ], datatype=bool) + CCD_INPUT_PPS_good_R = attribute_wrapper(comms_annotation=["CCD_INPUT_PPS_good_R" ], datatype=bool) + CCD_loss_lock_R = attribute_wrapper(comms_annotation=["CCD_loss_lock_R" ], datatype=bool) + CCD_PCB_ID_R = attribute_wrapper(comms_annotation=["CCD_PCB_ID_R" ], datatype=numpy.int64) + CCD_PCB_number_R = attribute_wrapper(comms_annotation=["CCD_PCB_number_R" ], datatype=str) + CCD_PCB_version_R = attribute_wrapper(comms_annotation=["CCD_PCB_version_R" ], datatype=str) + CCD_PLL_locked_R = attribute_wrapper(comms_annotation=["CCD_PLL_locked_R" ], datatype=bool) + CCD_PWR_CLK_DIST_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_CLK_DIST_3V3_R" ], datatype=numpy.float64) + CCD_PWR_CLK_INPUT_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_CLK_INPUT_3V3_R" ], datatype=numpy.float64) + CCD_PWR_CTRL_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_CTRL_3V3_R" ], datatype=numpy.float64) + CCD_PWR_OCXO_INPUT_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_OCXO_INPUT_3V3_R" ], datatype=numpy.float64) + CCD_PWR_on_R = attribute_wrapper(comms_annotation=["CCD_PWR_on_R" ], datatype=bool) + CCD_PWR_PLL_INPUT_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_PLL_INPUT_3V3_R" ], datatype=numpy.float64) + CCD_PWR_PPS_INPUT_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_PPS_INPUT_3V3_R" ], datatype=numpy.float64) + CCD_PWR_PPS_OUTPUT_3V3_R = attribute_wrapper(comms_annotation=["CCD_PWR_PPS_OUTPUT_3V3_R" ], datatype=numpy.float64) + CCD_TEMP_R = attribute_wrapper(comms_annotation=["CCD_TEMP_R" ], datatype=numpy.float64) + # ---------- + # Summarising Attributes + # ---------- + CCD_error_R = attribute(dtype=bool, fisallowed="is_attribute_access_allowed") + + def read_CCD_error_R(self): + errors = [self.read_attribute("CCDTR_I2C_error_R") > 0, + self.alarm_val("CCD_loss_lock_R"), + self.read_attribute("CCD_INPUT_10MHz_good_R"), + not self.read_attribute("CCD_INPUT_10MHz_good_R"), + not self.read_attribute("CCD_INPUT_PPS_good_R") and not self.read_attribute("CCD_clear_lock_R"), + not self.read_attribute("CCD_PLL_locked_R")] + return any(errors) + + CCD_TEMP_error_R = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=1000) + CCD_VOUT_error_R = attribute(dtype=bool, fisallowed="is_attribute_access_allowed") + + def read_CCD_TEMP_error_R(self): + return (self.alarm_val("CCD_TEMP_R")) + + def read_CCD_VOUT_error_R(self): + return ( self.alarm_val("CCD_PWR_CLK_DIST_3V3_R") + or self.alarm_val("CCD_PWR_CLK_INPUT_3V3_R") + or self.alarm_val("CCD_PWR_CTRL_3V3_R") + or self.alarm_val("CCD_PWR_OCXO_INPUT_3V3_R") + or self.alarm_val("CCD_PWR_PLL_INPUT_3V3_R") + or self.alarm_val("CCD_PWR_PPS_INPUT_3V3_R") + or self.alarm_val("CCD_PWR_PPS_OUTPUT_3V3_R") + or (not self.read_attribute("CCD_PWR_on_R")) + ) + + # -------- + # overloaded functions + # -------- + + @command() + @DebugIt() + @only_in_states(DEFAULT_COMMAND_STATES) + def reset_hardware(self): + """ Initialise the CCD hardware. """ + + # Cycle clock + self.CCD_off() + self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout) + self.CCD_on() + self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout) + + if not self.read_attribute("CCD_PLL_locked_R"): + if self.read_attribute("CCDTR_I2C_error_R"): + raise Exception("I2C is not working. Maybe power cycle subrack to restart CLK board and translator?") + else: + raise Exception("CCD clock is not locked") + + def _disable_hardware(self): + """ Disable the CCD hardware. """ + + # Turn off the CCD + self.CCD_off() + self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout) + + # -------- + # Commands + # -------- + + @command() + @DebugIt() + @only_in_states(DEFAULT_COMMAND_STATES) + def CCD_off(self): + """ + + :return:None + """ + self.opcua_connection.call_method(["CCD_off"]) + + @command() + @DebugIt() + @only_in_states(DEFAULT_COMMAND_STATES) + def CCD_on(self): + """ + + :return:None + """ + self.opcua_connection.call_method(["CCD_on"]) + + + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the ObservationControl module.""" + return entry(CCD, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py new file mode 100644 index 0000000000000000000000000000000000000000..3f259be1c3d11269fc387fe85e42b5f05b9e8764 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_ccd.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from .base import AbstractTestBases + + +class TestDeviceCCD(AbstractTestBases.TestDeviceBase): + + def setUp(self): + super().setUp("STAT/CCD/1")