Skip to content
Snippets Groups Projects
Commit 0bff897c authored by Jan David Mol's avatar Jan David Mol
Browse files

Merge branch 'master' into 'L2SS-626-derive-hba-deltas'

# Conflicts:
#   tangostationcontrol/tangostationcontrol/devices/recv.py
parents bb466412 480cbcdb
Branches
Tags
1 merge request!246L2SS-626: Calculate iHBADeltas from the values we actually measure and set
Showing
with 770 additions and 2012 deletions
...@@ -26,7 +26,7 @@ endif ...@@ -26,7 +26,7 @@ endif
# the host. # the host.
LOG_HOSTNAME ?= localhost LOG_HOSTNAME ?= localhost
# If the first make argument is "start" or "stop"... # If the first make argument is "start", "stop"...
ifeq (start,$(firstword $(MAKECMDGOALS))) ifeq (start,$(firstword $(MAKECMDGOALS)))
SERVICE_TARGET = true SERVICE_TARGET = true
else ifeq (stop,$(firstword $(MAKECMDGOALS))) else ifeq (stop,$(firstword $(MAKECMDGOALS)))
...@@ -48,6 +48,8 @@ else ifeq (attach,$(firstword $(MAKECMDGOALS))) ...@@ -48,6 +48,8 @@ else ifeq (attach,$(firstword $(MAKECMDGOALS)))
ifndef TANGO_HOST ifndef TANGO_HOST
$(error TANGO_HOST must specify the Tango database device, e.g., make TANGO_HOST=powersupply-databaseds:10000 ...) $(error TANGO_HOST must specify the Tango database device, e.g., make TANGO_HOST=powersupply-databaseds:10000 ...)
endif endif
else ifeq (run,$(firstword $(MAKECMDGOALS)))
RUN_TARGET = true
endif endif
ifdef SERVICE_TARGET ifdef SERVICE_TARGET
...@@ -55,6 +57,13 @@ ifdef SERVICE_TARGET ...@@ -55,6 +57,13 @@ ifdef SERVICE_TARGET
SERVICE := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) SERVICE := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# ...and turn them into do-nothing targets # ...and turn them into do-nothing targets
$(eval $(SERVICE):;@:) $(eval $(SERVICE):;@:)
else ifdef RUN_TARGET
# Isolate second argument as service, the rest is arguments for run command
SERVICE := $(wordlist 2, 2, $(MAKECMDGOALS))
# ...and turn them into do-nothing targets
$(eval $(SERVICE):;@:)
SERVICE_ARGS := $(wordlist 3, $(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
$(eval $(SERVICE_ARGS):;@:)
endif endif
# #
...@@ -131,7 +140,7 @@ DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \ ...@@ -131,7 +140,7 @@ DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \
DOCKER_GID=$(DOCKER_GID) DOCKER_GID=$(DOCKER_GID)
.PHONY: up down minimal start stop restart build build-nocache status clean pull help .PHONY: up down minimal run start stop restart build build-nocache status clean pull help
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
pull: ## pull the images from the Docker hub pull: ## pull the images from the Docker hub
...@@ -150,6 +159,9 @@ build-nocache: ## rebuild images from scratch ...@@ -150,6 +159,9 @@ build-nocache: ## rebuild images from scratch
up: minimal ## start the base TANGO system and prepare requested services up: minimal ## start the base TANGO system and prepare requested services
$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up --no-start --no-recreate $(SERVICE) $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up --no-start --no-recreate $(SERVICE)
run: minimal ## run a service using arguments and delete it afterwards
$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) run --rm $(SERVICE) $(SERVICE_ARGS)
down: ## stop all services and tear down the system down: ## stop all services and tear down the system
$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down
ifneq ($(NETWORK_MODE),host) ifneq ($(NETWORK_MODE),host)
......
...@@ -10,6 +10,8 @@ services: ...@@ -10,6 +10,8 @@ services:
- control - control
ports: ports:
- "5432:5432/tcp" - "5432:5432/tcp"
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on: depends_on:
- databaseds - databaseds
environment: environment:
...@@ -28,13 +30,15 @@ services: ...@@ -28,13 +30,15 @@ services:
image: hdbppts-cm image: hdbppts-cm
build: build:
context: tango-archiver-ts context: tango-archiver-ts
container_name: ${CONTAINER_NAME_PREFIX}hdbppts-cm
networks: networks:
- control - control
container_name: ${CONTAINER_NAME_PREFIX}hdbppts-cm
depends_on: depends_on:
- databaseds - databaseds
- dsconfig - dsconfig
- archiver-timescale - archiver-timescale
extra_hosts:
- "host.docker.internal:host-gateway"
environment: environment:
- TANGO_HOST=${TANGO_HOST} - TANGO_HOST=${TANGO_HOST}
- HdbManager=archiving/hdbppts/confmanager01 - HdbManager=archiving/hdbppts/confmanager01
...@@ -54,13 +58,15 @@ services: ...@@ -54,13 +58,15 @@ services:
image: hdbppts-es image: hdbppts-es
build: build:
context: tango-archiver-ts context: tango-archiver-ts
container_name: ${CONTAINER_NAME_PREFIX}hdbppts-es
networks: networks:
- control - control
container_name: ${CONTAINER_NAME_PREFIX}hdbppts-es
depends_on: depends_on:
- databaseds - databaseds
- dsconfig - dsconfig
- archiver-timescale - archiver-timescale
extra_hosts:
- "host.docker.internal:host-gateway"
environment: environment:
- TANGO_HOST=${TANGO_HOST} - TANGO_HOST=${TANGO_HOST}
- HdbManager=archiving/hdbppts/confmanager01 - HdbManager=archiving/hdbppts/confmanager01
......
...@@ -12,7 +12,7 @@ datasources: ...@@ -12,7 +12,7 @@ datasources:
# <string> custom UID which can be used to reference this datasource in other parts of the configuration, if not specified will be generated automatically # <string> custom UID which can be used to reference this datasource in other parts of the configuration, if not specified will be generated automatically
uid: 6W2nM-Vnz uid: 6W2nM-Vnz
# <string> url # <string> url
url: prometheus:9090 url: http://prometheus:9090
# <string> Deprecated, use secureJsonData.password # <string> Deprecated, use secureJsonData.password
password: password:
# <string> database user, if used # <string> database user, if used
......
...@@ -29,3 +29,8 @@ services: ...@@ -29,3 +29,8 @@ services:
- --strict - --strict
- -- - --
- tox --recreate -e integration - tox --recreate -e integration
command:
# Allow for arguments to be passed that wil be put after the entrypoint
# tox is configured to take these arguments as integration test directory
# specifications.
- ""
...@@ -6,4 +6,5 @@ COPY resources/02_hdb_schema.sql docker-entrypoint-initdb.d/003_hdb_schema.sql ...@@ -6,4 +6,5 @@ COPY resources/02_hdb_schema.sql docker-entrypoint-initdb.d/003_hdb_schema.sql
COPY resources/03_hdb_roles.sql docker-entrypoint-initdb.d/004_hdb_roles.sql COPY resources/03_hdb_roles.sql docker-entrypoint-initdb.d/004_hdb_roles.sql
COPY resources/04_hdb_ext_aggregates.sql docker-entrypoint-initdb.d/005_hdb_ext_aggregates.sql COPY resources/04_hdb_ext_aggregates.sql docker-entrypoint-initdb.d/005_hdb_ext_aggregates.sql
COPY resources/05_lofar_func.sh docker-entrypoint-initdb.d/006_lofar_func.sh COPY resources/05_lofar_func.sh docker-entrypoint-initdb.d/006_lofar_func.sh
COPY resources/06_cleanup.sql docker-entrypoint-initdb.d/007_cleanup.sql COPY resources/06_lofar_views.sql docker-entrypoint-initdb.d/007_lofar_views.sql
COPY resources/07_cleanup.sql docker-entrypoint-initdb.d/008_cleanup.sql
\c hdb
-- NOTE: We concatenate domain/family/member here, which means we can't index
-- the resulting column. However, queries also supply the attribute name,
-- which we can index. The scan on the device name is then limited to
-- entries which have the same attribute name across devices.
-- DOUBLE --
CREATE OR REPLACE VIEW lofar_array_double AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devdouble att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_double AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devdouble att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- BOOLEAN --
CREATE OR REPLACE VIEW lofar_array_boolean AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devboolean att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_boolean AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devboolean att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- UCHAR --
CREATE OR REPLACE VIEW lofar_array_uchar AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devuchar att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_uchar AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devuchar att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- SHORT --
CREATE OR REPLACE VIEW lofar_array_short AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devshort att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_short AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devshort att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- USHORT --
CREATE OR REPLACE VIEW lofar_array_ushort AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devushort att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_ushort AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devushort att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- LONG --
CREATE OR REPLACE VIEW lofar_array_long AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devlong att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_long AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devlong att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- ULONG --
CREATE OR REPLACE VIEW lofar_array_ulong AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devulong att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_ulong AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devulong att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- LONG64 --
CREATE OR REPLACE VIEW lofar_array_long64 AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devlong64 att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_long64 AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devlong64 att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- ULONG64 --
CREATE OR REPLACE VIEW lofar_array_ulong64 AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devulong64 att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_ulong64 AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devulong64 att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- FLOAT --
CREATE OR REPLACE VIEW lofar_array_float AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devfloat att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_float AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devfloat att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- STRING --
CREATE OR REPLACE VIEW lofar_array_string AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devstring att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_string AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devstring att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- STATE --
CREATE OR REPLACE VIEW lofar_array_state AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devstate att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_state AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devstate att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- ENCODED --
CREATE OR REPLACE VIEW lofar_array_encoded AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devencoded att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_encoded AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devencoded att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
-- ENUM --
CREATE OR REPLACE VIEW lofar_array_enum AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
array_element.idx - 1 AS x,
array_element.val as value
FROM att_array_devenum att
-- add array values, and their index
JOIN LATERAL UNNEST(att.value_r) WITH ORDINALITY AS array_element(val,idx) ON TRUE
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
CREATE OR REPLACE VIEW lofar_scalar_enum AS
SELECT
att.data_time AS data_time,
CONCAT_WS('/', domain, family, member) AS device,
ac.name AS name,
value_r as value
FROM att_scalar_devenum att
-- add the device information
JOIN att_conf ac ON att.att_conf_id = ac.att_conf_id
WHERE att.value_r IS NOT NULL;
\ No newline at end of file
...@@ -21,5 +21,5 @@ services: ...@@ -21,5 +21,5 @@ services:
max-file: "10" max-file: "10"
networks: networks:
- control - control
entrypoint: python3 pypcc2.py --simulator --port 4841 --config UNB2 entrypoint: python3 pypcc2.py --simulator --port 4841 --config UNB2TR
restart: on-failure restart: on-failure
This diff is collapsed.
%% Cell type:markdown id:6bdc7054 tags: %% Cell type:markdown id:6bdc7054 tags:
# Test LRx.y: Test Name # Test LRx.y: Test Name
This notebook documents test output. This notebook documents test output.
Instructions: Instructions:
1. *PRESS File -> Make a Copy*, 1. *PRESS File -> Make a Copy*,
1. Rename the notebook to the name of the test, 1. Rename the notebook to the name of the test,
1. Update the title at the top of this section, 1. Update the title at the top of this section,
1. Fill in the sections with empty blocks with code and text, 1. Fill in the sections with empty blocks with code and text,
1. Execute the provided initialisation code, 1. Execute the provided initialisation code,
1. Run the tests, 1. Run the tests,
1. *Rerun everything top to bottom to make sure the notebook is correct*, 1. *Rerun everything top to bottom to make sure the notebook is correct*,
1. Fill in the results & verdict. 1. Fill in the results & verdict.
1. Export the Jupyter Notebook to PDF and upload the file to the Polarion test results page. 1. Export the Jupyter Notebook to PDF and upload the file to the Polarion test results page.
1. ...and you're done! 1. ...and you're done!
%% Cell type:markdown id:63785004 tags: %% Cell type:markdown id:63785004 tags:
## Author ## Author
Descibe who ran this test, and who helped (if applicable): Descibe who ran this test, and who helped (if applicable):
%% Cell type:markdown id:3c720d4b tags: %% Cell type:markdown id:3c720d4b tags:
(your name) (your name)
%% Cell type:markdown id:ff837bcb tags: %% Cell type:markdown id:ff837bcb tags:
## Timestamp ## Timestamp
This test was executed at: This test was executed at:
%% Cell type:code id:00418ee4 tags: %% Cell type:code id:00418ee4 tags:
``` python ``` python
# Run this code # Run this code
import datetime import datetime
print(f"Test was executed at {datetime.datetime.isoformat(datetime.datetime.now(), ' ')}") print(f"Test was executed at {datetime.datetime.isoformat(datetime.datetime.now(), ' ')}")
``` ```
%% Cell type:markdown id:0b4a59a5 tags: %% Cell type:markdown id:0b4a59a5 tags:
## Purpose ## Purpose
Describe the purpose and context of this notebook, possibly including any links to external references, e.g. the Polarion reference number: Describe the purpose and context of this notebook, possibly including any links to external references, e.g. the Polarion reference number:
%% Cell type:markdown id:09d4d0a1 tags: %% Cell type:markdown id:09d4d0a1 tags:
(purpose) (purpose)
%% Cell type:markdown id:4c6489f3 tags: %% Cell type:markdown id:4c6489f3 tags:
## Methodology ## Methodology
Provide a summary of how we are going to prove compliance: Provide a summary of how we are going to prove compliance:
%% Cell type:markdown id:ceae21d4 tags: %% Cell type:markdown id:ceae21d4 tags:
(methodology) (methodology)
%% Cell type:markdown id:9033f262 tags: %% Cell type:markdown id:9033f262 tags:
## Initialisation ## Initialisation
The following sections contain boilerplate code to get the station to a well-defined state. If this is not applicable or broken, just note that here: The following sections contain boilerplate code to get the station to a well-defined state. If this is not applicable or broken, just note that here:
%% Cell type:markdown id:00d4e336 tags: %% Cell type:markdown id:00d4e336 tags:
%% Cell type:markdown id:7532d05e tags: %% Cell type:markdown id:7532d05e tags:
### Hot reboot ### Reboot
Makes sure the software and hardware are all in a known state. Makes sure the software and hardware are all in a known state.
%% Cell type:code id:c7a3effa tags:
``` python
# Restart boot device
boot.off()
boot.initialise()
boot.on()
```
%% Cell type:code id:b4dd21b1 tags: %% Cell type:code id:b4dd21b1 tags:
``` python ``` python
# Reboot the station # Reboot the station
boot.boot() boot.reboot()
``` ```
%% Cell type:code id:78a4db84 tags: %% Cell type:code id:78a4db84 tags:
``` python ``` python
# Wait for reboot to complete # Wait for reboot to complete
import time import time
while boot.booting_R: while boot.booting_R:
time.sleep(2) time.sleep(2)
print(f"Initialisation at {boot.progress_R}%: {boot.status_R}") print(f"Initialisation at {boot.progress_R}%: {boot.status_R}")
assert boot.progress_R == 100, f"Failed to fully initialise station: {boot.status_R}" assert boot.progress_R == 100, f"Failed to fully initialise station: {boot.status_R}"
if boot.uninitialised_devices_R: if boot.uninitialised_devices_R:
print(f"Warning! Did not initialise {boot.uninitialised_devices_R}. This might be inconsequential for this test.") print(f"Warning! Did not initialise {boot.uninitialised_devices_R}. This might be inconsequential for this test.")
``` ```
%% Cell type:markdown id:9bc072af tags: %% Cell type:markdown id:9bc072af tags:
### Active versions ### Active versions
List the versions currently running on the station. List the versions currently running on the station.
%% Cell type:code id:35b815d4 tags: %% Cell type:code id:35b815d4 tags:
``` python ``` python
def summarise(l: list) -> list: def summarise(l: list) -> list:
return [f"{idx}: {version}" for idx,version in enumerate(l) if version] or ["no versions reported"] return [f"{idx}: {version}" for idx,version in enumerate(l) if version] or ["no versions reported"]
versions = { versions = {
"SC": {dev.name():dev.version_R for dev in devices}, "SC": {dev.name():dev.version_R for dev in devices},
"SDP": { "SDP": {
"FPGA firmware": summarise(sdp.FPGA_firmware_version_R), "FPGA firmware": summarise(sdp.FPGA_firmware_version_R),
"FPGA hardware": summarise(sdp.FPGA_hardware_version_R), "FPGA hardware": summarise(sdp.FPGA_hardware_version_R),
"SDPTR": sdp.TR_software_version_R, "SDPTR": sdp.TR_software_version_R,
}, },
"RECV": { "RECV": {
"PCB": summarise(recv.RCU_PCB_version_R), "PCB": summarise(recv.RCU_PCB_version_R),
}, },
"APSCT": { "APSCT": {
"PCB": apsct.APSCT_PCB_version_R, "PCB": apsct.APSCT_PCB_version_R,
}, },
"APSPU": { "APSPU": {
"PCB": apspu.APSPU_PCB_version_R, "PCB": apspu.APSPU_PCB_version_R,
}, },
"UNB2": { "UNB2": {
"PCB": summarise(unb2.UNB2_PCB_version_R), "PCB": summarise(unb2.UNB2_PCB_version_R),
} }
} }
from pprint import pprint from pprint import pprint
pprint(versions, width=120) pprint(versions, width=120)
``` ```
%% Cell type:markdown id:e51a06b7 tags: %% Cell type:markdown id:e51a06b7 tags:
## Test setup ## Test setup
Setup the hardware for the test: Setup the hardware for the test:
%% Cell type:code id:e72dc2df tags: %% Cell type:code id:e72dc2df tags:
``` python ``` python
# Your code to configure the station for this test # Your code to configure the station for this test
``` ```
%% Cell type:markdown id:772dff7c tags: %% Cell type:markdown id:772dff7c tags:
## Run test ## Run test
%% Cell type:code id:26570aea tags: %% Cell type:code id:26570aea tags:
``` python ``` python
# Your code that triggers the actual test (if this is an explicit step) # Your code that triggers the actual test (if this is an explicit step)
``` ```
%% Cell type:markdown id:6c604116 tags: %% Cell type:markdown id:6c604116 tags:
## Test results ## Test results
%% Cell type:code id:d290d8dd tags: %% Cell type:code id:d290d8dd tags:
``` python ``` python
# plot sst in after # plot sst in after
``` ```
%% Cell type:markdown id:d3cdb620 tags: %% Cell type:markdown id:d3cdb620 tags:
## Discuss results ## Discuss results
How should the results be interpreted? Are there remaining worries and todo's based on this result? How should the results be interpreted? Are there remaining worries and todo's based on this result?
%% Cell type:markdown id:6e082c7c tags: %% Cell type:markdown id:6e082c7c tags:
(Explain results, and caveats) (Explain results, and caveats)
%% Cell type:markdown id:a95fbf48 tags: %% Cell type:markdown id:a95fbf48 tags:
## Verdict ## Verdict
The test passed/did not pass: The test passed/did not pass:
%% Cell type:markdown id:9a2a7a97 tags: %% Cell type:markdown id:9a2a7a97 tags:
(Explain whether the result is good enough, or what needs to be done to improve) (Explain whether the result is good enough, or what needs to be done to improve)
......
...@@ -17,9 +17,10 @@ cd "$LOFAR20_DIR/docker-compose" || exit 1 ...@@ -17,9 +17,10 @@ cd "$LOFAR20_DIR/docker-compose" || exit 1
make build device-sdp device-recv device-sst device-unb2 device-xst make build device-sdp device-recv device-sst device-unb2 device-xst
make build sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim make build sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
make build databaseds dsconfig elk integration-test make build databaseds dsconfig elk integration-test
make build archiver-timescale hdbppts-cm hdbppts-es
# Start and stop sequence # Start and stop sequence
make stop device-boot device-docker device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beam sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim make stop device-boot device-docker device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beam sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim hdbppts-es hdbppts-cm archiver-timescale
make start databaseds dsconfig elk make start databaseds dsconfig elk
# Give dsconfig and databaseds time to start # Give dsconfig and databaseds time to start
...@@ -30,7 +31,6 @@ sleep 60 ...@@ -30,7 +31,6 @@ sleep 60
bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/LOFAR_ConfigDb.json bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/LOFAR_ConfigDb.json
bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/simulators_ConfigDb.json bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/simulators_ConfigDb.json
bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/dummy_positions_ConfigDb.json bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/dummy_positions_ConfigDb.json
#bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/integration_ConfigDb.json
cd "$LOFAR20_DIR/docker-compose" || exit 1 cd "$LOFAR20_DIR/docker-compose" || exit 1
make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
...@@ -39,6 +39,8 @@ make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim ...@@ -39,6 +39,8 @@ make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
sleep 5 sleep 5
make start device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beam make start device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beam
# Archive devices -> starting order is important
make start archiver-timescale hdbppts-cm hdbppts-es
# Give devices time to restart # Give devices time to restart
# TODO(Corne Lukken): Use a nicer more reliable mechanism # TODO(Corne Lukken): Use a nicer more reliable mechanism
...@@ -48,5 +50,5 @@ sleep 60 ...@@ -48,5 +50,5 @@ sleep 60
cd "$LOFAR20_DIR/docker-compose" || exit 1 cd "$LOFAR20_DIR/docker-compose" || exit 1
make up integration-test make up integration-test
# Run the integration test with the output displayed on stdout # Run the default integration tests
docker start -a "${CONTAINER_NAME_PREFIX}"integration-test make run integration-test default
...@@ -3,13 +3,19 @@ ...@@ -3,13 +3,19 @@
Boot Boot
==================== ====================
The ``boot == DeviceProxy("STAT/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. This device provides the following commands: The ``boot == DeviceProxy("STAT/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. It is the only device that starts in the ``ON`` state, so it can be used immediately to initialise other devices.
:boot(): Stop and start the other devices in the correct order, set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Initialisation is aborted if an error is encountered. This device provides the following commands:
:boot(): Start the other devices in the correct order, if they are not ON. Set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Use the attributes defined below to track the boot progress.
:returns: ``None``
:warm_boot(): Like ``boot()``, but do not initialise the hardware. Just start our software devices.
:returns: ``None`` :returns: ``None``
:resume(): Resume an earlier boot attempt: start initialising devices from the first one that failed to initialise, instead of from scratch. :reboot(): Like ``boot()``, but turn off all other devices first.
:returns: ``None`` :returns: ``None``
...@@ -35,4 +41,4 @@ The initialisation process can subsequently be followed through monitoring the f ...@@ -35,4 +41,4 @@ The initialisation process can subsequently be followed through monitoring the f
:type: ``str[]`` :type: ``str[]``
A useful pattern is thus to call ``boot()``, wait for ``booting_R == False``, and then check whether the initalisation was succesful, if ``progress_R == 100``. If a device fails to initialise, most likely the :doc:`../interfaces/logs` will need to be consulted. A useful pattern is thus to call ``boot()``, wait for ``booting_R == False``, and then check whether the initalisation was succesful, if ``uninitialised_devices_R == []``. If a device fails to initialise, check its status (``<device>.status()``), or consult the :doc:`../interfaces/logs`.
...@@ -13,7 +13,7 @@ TangoDB ...@@ -13,7 +13,7 @@ TangoDB
The TangoDB database is a persistent store for the properties of each device. The properties encode static settings, such as the hardware addresses, and default values for control attributes. The TangoDB database is a persistent store for the properties of each device. The properties encode static settings, such as the hardware addresses, and default values for control attributes.
Each device queries the TangoDB for the value of its properties during the ``initialise()`` call. Default values for control attributes can then be applied by explicitly calling ``set_defaults()``. The ``boot`` device also calls ``set_defaults()`` when initialising the station. The rationale being that the defaults can be applied at boot, but shouldn't be applied automatically during operations, as not to disturb running hardware. Each device queries the TangoDB for the value of its properties during the ``boot()`` (or ``initialise()``) call. Default values for control attributes can then be applied by explicitly calling ``set_defaults()``. The ``boot`` device also calls ``set_defaults()`` when initialising the station. The rationale being that the defaults can be applied at boot, but shouldn't be applied automatically during operations, as not to disturb running hardware.
Device interaction Device interaction
```````````````````````````` ````````````````````````````
...@@ -32,7 +32,7 @@ Properties can also be changed:: ...@@ -32,7 +32,7 @@ Properties can also be changed::
device.put_property(changeset) device.put_property(changeset)
Note that new values for properties will only be picked up by the device during ``initialise()``, so you will have to turn the device off and on. Note that new values for properties will only be picked up by the device during ``boot()`` (or ``initialise()``), so you will have to turn the device off and on.
Command-line interaction Command-line interaction
`````````````````````````` ``````````````````````````
...@@ -46,18 +46,3 @@ and changes can be applied using:: ...@@ -46,18 +46,3 @@ and changes can be applied using::
bin/update_ConfigDb.sh changeset.json bin/update_ConfigDb.sh changeset.json
.. note:: The ``dsconfig`` docker container needs to be running for these commands to work. .. note:: The ``dsconfig`` docker container needs to be running for these commands to work.
Jive
``````````````````````````
The TangoDB can also be interactively queried and modified using Jive. Jive is an X11 application provided by the ``jive`` image as part of the software stack of the station. It must however be started on-demand, with a correctly configured ``$DISPLAY``::
cd docker-compose
make start jive
If Jive does not appear, check ``docker logs jive`` to see what went wrong.
For information on how to use Jive, see https://tango-controls.readthedocs.io/en/latest/tools-and-extensions/built-in/jive/.
.. note:: If you need an X11 server on Windows, see :ref:`x11_on_windows`.
...@@ -20,17 +20,18 @@ The state of a device is then queried with ``device.state()``. Each device can b ...@@ -20,17 +20,18 @@ The state of a device is then queried with ``device.state()``. Each device can b
- ``DevState.OFF``: The device is not operating, - ``DevState.OFF``: The device is not operating,
- ``DevState.INIT``: The device is being initialised, - ``DevState.INIT``: The device is being initialised,
- ``DevState.STANDBY``: The device is initialised and ready to be configured further, - ``DevState.STANDBY``: The device is initialised and ready to be configured further,
- ``DevState.ON``: The device is operational. - ``DevState.ON``: The device is operational,
- ``DevState.ALARM``: The device is operational, but one or more attributes are in alarm,
- ``DevState.FAULT``: The device is malfunctioning. Functionality cannot be counted on. - ``DevState.FAULT``: The device is malfunctioning. Functionality cannot be counted on.
- The ``device.state()`` function can throw an error, if the device cannot be reached at all. For example, because it's docker container is not running. See the :ref:`docker` device on how to start it. - The ``device.state()`` function can throw an error, if the device cannot be reached at all. For example, because it's docker container is not running. See the :ref:`docker` device on how to start it.
Each device provides the following commands to change the state: Each device provides the following commands to change the state:
:off(): Turn the device ``OFF`` from any state. :boot(): Turn on the device, and initialise the hardware. Moves from ``OFF`` to ``ON``.
:initialise(): Initialise the device from the ``OFF`` state, to bring it to the ``STANDBY`` state. :warm_boot(): Turn on the device, but do not change the hardware. Moves from ``OFF`` to ``ON``.
:on(): Mark the device as operational, from the ``STANDBY`` state, bringing it to ``ON``. :off(): Turn the device ``OFF`` from any state.
The following procedure is a good way to bring a device to ``ON`` from any state:: The following procedure is a good way to bring a device to ``ON`` from any state::
...@@ -38,9 +39,7 @@ The following procedure is a good way to bring a device to ``ON`` from any state ...@@ -38,9 +39,7 @@ The following procedure is a good way to bring a device to ``ON`` from any state
if device.state() == DevState.FAULT: if device.state() == DevState.FAULT:
device.off() device.off()
if device.state() == DevState.OFF: if device.state() == DevState.OFF:
device.initialise() device.boot()
if device.state() == DevState.STANDBY:
device.on()
return device.state() return device.state()
...@@ -50,7 +49,7 @@ FAULT ...@@ -50,7 +49,7 @@ FAULT
`````````` ``````````
If a device enters the ``FAULT`` state, it means an error occurred that is fundamental to the operation of the software device. For example, the connection If a device enters the ``FAULT`` state, it means an error occurred that is fundamental to the operation of the software device. For example, the connection
to the hardware was lost. TO see the error reason, use to the hardware was lost. To see the error reason, use
:status(): The verbose status of the device, f.e. the reason why the device went to ``FAULT``. :status(): The verbose status of the device, f.e. the reason why the device went to ``FAULT``.
...@@ -71,13 +70,17 @@ Of course, the device could go into ``FAULT`` again, even during the ``initialis ...@@ -71,13 +70,17 @@ Of course, the device could go into ``FAULT`` again, even during the ``initialis
Initialise hardware Initialise hardware
```````````````````` ````````````````````
Most devices provide the following commands, in order to configure the hardware with base settings: Most devices provide the following commands, in order to configure the hardware with base settings. Note that these are automatically called during ``boot()``, in this order:
:initialise(): Initialise the device (connect to the hardware). Moves from ``OFF`` to ``STANDBY``.
:set_defaults(): Upload default attribute settings from the TangoDB to the hardware. :set_defaults(): Upload default attribute settings from the TangoDB to the hardware.
:initialise_hardware(): For devices that control hardware, this command runs the hardware initialisation procedure. :initialise_hardware(): For devices that control hardware, this command runs the hardware initialisation procedure.
Typically, ``set_defaults()`` and ``initialise_hardware()`` are called in that order in the ``STANDBY`` state. See also :ref:`boot`, which provides functionality to initialise all the devices. :on(): Mark the device as operational. Moves from ``STANDBY`` to ``ON``.
See also :ref:`boot`, which provides functionality to initialise all the devices.
.. _attributes: .. _attributes:
......
...@@ -30,12 +30,7 @@ and make sure they are all up and running:: ...@@ -30,12 +30,7 @@ and make sure they are all up and running::
make status make status
You should see the following state: You should see all containers either in the ``Up`` state or in ``Exit 0``. If not, you can inspect why with ``docker logs <container>``. Note that the containers will automatically be restarted on failure, and also if you reboot. Stop them explicitly to bring them down (``make stop <container>``).
- Containers ``astor``, ``hdbpp-viewer``, ``jive``, ``log-viewer`` and ``pogo`` will have State ``Exit 1``. These are containers that are interactive X11 tools, and not needed for now,
- Other containers have either State ``Up`` or ``Exit 0``.
If not, you can inspect why with ``docker logs <container>``. Note that the containers will automatically be restarted on failure, and also if you reboot. Stop them explicitly to bring them down (``make stop <container>``).
Post-boot Initialisation Post-boot Initialisation
--------------------------- ---------------------------
...@@ -44,29 +39,25 @@ After bootstrapping, and after a reboot, the software and hardware of the statio ...@@ -44,29 +39,25 @@ After bootstrapping, and after a reboot, the software and hardware of the statio
The following commands start all the software devices to control the station hardware, and initialise the hardware with the configured default settings. Go to http://localhost:8888, start a new *Station Control* notebook, and initiate the software boot sequence:: The following commands start all the software devices to control the station hardware, and initialise the hardware with the configured default settings. Go to http://localhost:8888, start a new *Station Control* notebook, and initiate the software boot sequence::
# reset our boot device
boot.off()
assert boot.state() == DevState.OFF
boot.initialise()
assert boot.state() == DevState.STANDBY
boot.on()
assert boot.state() == DevState.ON
# start and initialise the other devices # start and initialise the other devices
boot.initialise_station() boot.boot()
# wait for the devices to be initialised # wait for the devices to be initialised
import time import time
while boot.initialising_station_R: while boot.booting_R:
print(f"Still initialising station. {boot.initialisation_progress_R}% complete. State: {boot.initialisation_status_R}") print(f"Still initialising station. {boot.progress_R}% complete. State: {boot.status_R}")
time.sleep(1) time.sleep(1)
# print conclusion # print conclusion
if boot.initialisation_progress_R == 100: if boot.progress_R == 100:
print("Done initialising station.") print("Done initialising station.")
else: else:
print(f"Failed to initialise station: {boot.initialisation_status_R}") print(f"Failed to initialise station: {boot.status_R}")
# print what did and did not get initialised
print(f"Initialised devices: {boot.initialised_devices_R}")
print(f"Uninitialised devices: {boot.uninitialised_devices_R}")
See :ref:`boot` for more information on the ``boot`` device. See :ref:`boot` for more information on the ``boot`` device.
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# PyTango imports # PyTango imports
from tango import DebugIt from tango import DebugIt
from tango.server import command from tango.server import command, attribute, device_property
from tango import AttrWriteType, DevState from tango import AttrWriteType, DevState
import numpy import numpy
# Additional import # Additional import
...@@ -36,6 +36,12 @@ class APSCT(opcua_device): ...@@ -36,6 +36,12 @@ class APSCT(opcua_device):
# Device Properties # Device Properties
# ----------------- # -----------------
APSCTTR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
# ---------- # ----------
# Attributes # Attributes
# ---------- # ----------
...@@ -66,6 +72,38 @@ class APSCT(opcua_device): ...@@ -66,6 +72,38 @@ class APSCT(opcua_device):
APSCT_PWR_PPSDIST_3V3_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R" ],datatype=numpy.float64) APSCT_PWR_PPSDIST_3V3_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R" ],datatype=numpy.float64)
APSCT_TEMP_R = attribute_wrapper(comms_annotation=["APSCT_TEMP_R" ],datatype=numpy.float64) APSCT_TEMP_R = attribute_wrapper(comms_annotation=["APSCT_TEMP_R" ],datatype=numpy.float64)
# ----------
# Summarising Attributes
# ----------
APSCT_error_R = attribute(dtype=bool)
def read_APSCT_error_R(self):
return ((self.proxy.APSCTTR_I2C_error_R > 0)
| self.alarm_val("APSCT_PCB_ID_R")
| ~self.proxy.APSCT_INPUT_10MHz_good_R
| (~self.proxy.APSCT_INPUT_PPS_good_R & ~self.proxy.ASPCT_PPS_ignore_R)
| (~self.proxy.APSCT_PLL_160MHz_locked_R & ~self.proxy.APSCT_PLL_200MHz_locked_R)
| (self.proxy.APSCT_PLL_200MHz_locked_R & self.proxy.APSCT_PLL_200MHz_error_R)
| (self.proxy.APSCT_PLL_160MHz_locked_R & self.proxy.APSCT_PLL_160MHz_error_R)
)
APSCT_TEMP_error_R = attribute(dtype=bool)
APSCT_VOUT_error_R = attribute(dtype=bool)
def read_APSCT_TEMP_error_R(self):
return (self.alarm_val("APSCT_TEMP_R"))
def read_APSCT_VOUT_error_R(self):
return ( self.alarm_val("APSCT_PWR_PPSDIST_3V3_R")
| self.alarm_val("APSCT_PWR_CLKDIST1_3V3_R")
| self.alarm_val("APSCT_PWR_CLKDIST2_3V3_R")
| self.alarm_val("APSCT_PWR_CTRL_3V3_R")
| self.alarm_val("APSCT_PWR_INPUT_3V3_R")
| (self.proxy.APSCT_PWR_PLL_160MHz_on_R & self.alarm_val("APSCT_PWR_PLL_160MHz_3V3_R"))
| (self.proxy.APSCT_PWR_PLL_200MHz_on_R & self.alarm_val("APSCT_PWR_PLL_200MHz_3V3_R"))
| ~self.proxy.APSCT_PWR_on_R
)
# -------- # --------
# overloaded functions # overloaded functions
# -------- # --------
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
# PyTango imports # PyTango imports
from tango import AttrWriteType from tango import AttrWriteType
from tango.server import attribute, device_property
import numpy import numpy
# Additional import # Additional import
...@@ -30,6 +31,12 @@ class APSPU(opcua_device): ...@@ -30,6 +31,12 @@ class APSPU(opcua_device):
# Device Properties # Device Properties
# ----------------- # -----------------
APSPUTR_monitor_rate_RW_default = device_property(
dtype='DevLong64',
mandatory=False,
default_value=1
)
# ---------- # ----------
# Attributes # Attributes
# ---------- # ----------
...@@ -53,6 +60,40 @@ class APSPU(opcua_device): ...@@ -53,6 +60,40 @@ class APSPU(opcua_device):
APSPU_RCU2D_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_TEMP_R" ],datatype=numpy.float64) APSPU_RCU2D_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_TEMP_R" ],datatype=numpy.float64)
APSPU_RCU2D_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_VOUT_R" ],datatype=numpy.float64) APSPU_RCU2D_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_VOUT_R" ],datatype=numpy.float64)
# ----------
# Summarising Attributes
# ----------
APSPU_error_R = attribute(dtype=bool)
def read_APSPU_error_R(self):
return ((self.proxy.APSPUTR_I2C_error_R > 0)
| self.alarm_val("APSPU_PCB_ID_R")
| self.alarm_val("APSPU_FAN1_RPM_R")
| self.alarm_val("APSPU_FAN2_RPM_R")
| self.alarm_val("APSPU_FAN3_RPM_R"))
APSPU_IOUT_error_R = attribute(dtype=bool)
APSPU_TEMP_error_R = attribute(dtype=bool)
APSPU_VOUT_error_R = attribute(dtype=bool)
def read_APSPU_IOUT_error_R(self):
return ( self.alarm_val("APSPU_LBA_IOUT_R")
| self.alarm_val("APSPU_RCU2A_IOUT_R")
| self.alarm_val("APSPU_RCU2D_IOUT_R")
)
def read_APSPU_TEMP_error_R(self):
return ( self.alarm_val("APSPU_LBA_TEMP_R")
| self.alarm_val("APSPU_RCU2A_TEMP_R")
| self.alarm_val("APSPU_RCU2D_TEMP_R")
)
def read_APSPU_VOUT_error_R(self):
return ( self.alarm_val("APSPU_LBA_VOUT_R")
| self.alarm_val("APSPU_RCU2A_VOUT_R")
| self.alarm_val("APSPU_RCU2D_VOUT_R")
)
# -------- # --------
# overloaded functions # overloaded functions
# -------- # --------
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
import numpy import numpy
import datetime import datetime
from json import loads
from tango.server import attribute, command from tango.server import attribute, command
from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray, DevString
# Additional import # Additional import
from tangostationcontrol.common.entrypoint import entry from tangostationcontrol.common.entrypoint import entry
...@@ -82,9 +84,7 @@ class Beam(lofar_device): ...@@ -82,9 +84,7 @@ class Beam(lofar_device):
def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()): def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
""" """
Calculate the delays (in seconds) based on the pointing list and the timestamp Calculate the delays (in seconds) based on the pointing list and the timestamp
TBD: antenna and reference positions will be retrieved from RECV and not stored as BEAM device properties
""" """
delays = numpy.zeros((96,16), dtype=numpy.float64) delays = numpy.zeros((96,16), dtype=numpy.float64)
for tile in range(96): for tile in range(96):
...@@ -182,6 +182,30 @@ class Beam(lofar_device): ...@@ -182,6 +182,30 @@ class Beam(lofar_device):
self._HBAT_set_pointing(pointing_direction, timestamp) self._HBAT_set_pointing(pointing_direction, timestamp)
@command(dtype_in = DevString)
@DebugIt()
@only_in_states([DevState.ON])
def HBAT_set_pointing_for_specific_time(self, parameters: DevString = None):
"""
Uploads beam weights based on a given pointing direction 2D array (96 tiles x 3 parameters)
for the given timestamp
Parameters are given in a json document.
pointing_direction: array of 96 casacore pointings (3 string parameters)
timestamp: POSIX timestamp
"""
pointing_parameters = loads(parameters)
pointing_direction = list(pointing_parameters["pointing_direction"])
timestamp_param = float(pointing_parameters["timestamp"])
timestamp = datetime.datetime.fromtimestamp(timestamp_param)
# Reshape the flatten pointing array
pointing_direction = numpy.array(pointing_direction).reshape(96,3)
self._HBAT_set_pointing(pointing_direction, timestamp)
# ---------- # ----------
# Run server # Run server
# ---------- # ----------
......
...@@ -17,7 +17,7 @@ Boots the rest of the station software. ...@@ -17,7 +17,7 @@ Boots the rest of the station software.
from tango import DebugIt from tango import DebugIt
from tango.server import command from tango.server import command
from tango.server import device_property, attribute from tango.server import device_property, attribute
from tango import AttrWriteType, DeviceProxy, DevState from tango import AttrWriteType, DeviceProxy, DevState, DevSource
# Additional import # Additional import
import numpy import numpy
...@@ -40,17 +40,18 @@ class InitialisationException(Exception): ...@@ -40,17 +40,18 @@ class InitialisationException(Exception):
class DevicesInitialiser(object): class DevicesInitialiser(object):
""" """
Initialise devices on this station. Initialise devices on this station which are not already on (reboot=False),
or all of them (reboot=True).
Devices which are unreachable are assumed to be brought down explicitly, Devices which are unreachable are assumed to be brought down explicitly,
and are ignored (unless ignore_unavailable_devices == False). and are ignored.
Initialisation happens in a separate thread. It is started by calling Initialisation happens in a separate thread. It is started by calling
the start() method, and progress can be followed by inspecting the the start() method, and progress can be followed by inspecting the
members progress (0-100), status (string), and is_running() (bool). members progress (0-100), status (string), and is_running() (bool).
""" """
def __init__(self, device_names, ignore_unavailable_devices=True, initialise_hardware=True, proxy_timeout=10.0): def __init__(self, device_names, reboot=False, initialise_hardware=True, proxy_timeout=10.0):
self.ignore_unavailable_devices = ignore_unavailable_devices self.reboot = reboot
self.initialise_hardware = initialise_hardware self.initialise_hardware = initialise_hardware
self.device_names = device_names self.device_names = device_names
...@@ -74,10 +75,11 @@ class DevicesInitialiser(object): ...@@ -74,10 +75,11 @@ class DevicesInitialiser(object):
self.set_status(f"Obtaining a DeviceProxy to {name}") self.set_status(f"Obtaining a DeviceProxy to {name}")
devices[name] = DeviceProxy(name) devices[name] = DeviceProxy(name)
# set the timeout for all proxies # set the timeout for all proxies, and never read state from a cache
self.set_status("Configuring DeviceProxies") self.set_status("Configuring DeviceProxies")
for device in devices.values(): for device in devices.values():
device.set_timeout_millis(int(self.proxy_timeout * 1000)) device.set_timeout_millis(int(self.proxy_timeout * 1000))
device.set_source(DevSource.DEV)
return devices return devices
...@@ -150,8 +152,10 @@ class DevicesInitialiser(object): ...@@ -150,8 +152,10 @@ class DevicesInitialiser(object):
if self.device_initialised[device]: if self.device_initialised[device]:
continue continue
if self.is_available(device) or not self.ignore_unavailable_devices: if self.is_available(device):
self.start_device(device) if self.reboot or self.devices[device].state() not in [DevState.ON, DevState.ALARM]:
self.stop_device(device)
self.boot_device(device)
# mark device as initialised # mark device as initialised
self.device_initialised[device] = True self.device_initialised[device] = True
...@@ -185,40 +189,25 @@ class DevicesInitialiser(object): ...@@ -185,40 +189,25 @@ class DevicesInitialiser(object):
proxy.Off() proxy.Off()
if proxy.state() != DevState.OFF: if proxy.state() != DevState.OFF:
raise InitialisationException(f"Could not turn off device {device_name}. Please look at its logs.") raise InitialisationException(f"Could not turn off device {device_name}. It reports status: {proxy.status()}")
self.set_status(f"[stopping {device_name}] Stopped device.") self.set_status(f"[stopping {device_name}] Stopped device.")
def start_device(self, device_name: str): def boot_device(self, device_name: str):
""" Run the startup sequence for device 'device_name'. """ """ Run the startup sequence for device 'device_name'. """
proxy = self.devices[device_name] proxy = self.devices[device_name]
# go to a well-defined state, which may be needed if the user calls self.set_status(f"[restarting {device_name}] Booting device.")
# this function explicitly.
self.stop_device(device_name)
# setup connections to hardware
self.set_status(f"[restarting {device_name}] Initialising device.")
proxy.Initialise()
if proxy.state() != DevState.STANDBY:
raise InitialisationException(f"Could not initialise device {device_name}. Please look at its logs.")
# configure the device
self.set_status(f"[restarting {device_name}] Setting defaults.")
proxy.set_defaults()
if self.initialise_hardware: if self.initialise_hardware:
self.set_status(f"[restarting {device_name}] Initialising hardware.") proxy.boot()
proxy.initialise_hardware() else:
proxy.warm_boot()
# mark as ready for service if proxy.state() not in [DevState.ON, DevState.ALARM]: # ALARM still means booting was succesful
self.set_status(f"[restarting {device_name}] Turning on device.") raise InitialisationException(f"Could not boot device {device_name}. It reports status: {proxy.status()}")
proxy.On()
if proxy.state() != DevState.ON:
raise InitialisationException(f"Could not turn on device {device_name}. Please look at its logs.")
self.set_status(f"[restarting {device_name}] Succesfully started.") self.set_status(f"[restarting {device_name}] Succesfully booted.")
@device_logging_to_python() @device_logging_to_python()
class Boot(lofar_device): class Boot(lofar_device):
...@@ -255,16 +244,6 @@ class Boot(lofar_device): ...@@ -255,16 +244,6 @@ class Boot(lofar_device):
], ],
) )
# By default, we assume any device is not available
# because its docker container was not started, which
# is an explicit and thus intentional action.
# We ignore such devices when initialising the station.
Ignore_Unavailable_Devices = device_property(
dtype='DevBoolean',
mandatory=False,
default_value=True,
)
# ---------- # ----------
# Attributes # Attributes
# ---------- # ----------
...@@ -274,22 +253,17 @@ class Boot(lofar_device): ...@@ -274,22 +253,17 @@ class Boot(lofar_device):
initialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if initialised], doc="Which devices were initialised succesfully") initialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if initialised], doc="Which devices were initialised succesfully")
uninitialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if not initialised], doc="Which devices have not been initialised or failed to initialise") uninitialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if not initialised], doc="Which devices have not been initialised or failed to initialise")
@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).
"""
logger.debug("Shutting down...")
self.Off()
logger.debug("Shut down. Good bye.")
# -------- # --------
# overloaded functions # overloaded functions
# -------- # --------
def init_device(self):
super().init_device()
# always turn on automatically, so the user doesn't have to boot the boot device
# note: we overloaded our own boot() to boot the station, so explicitly call our own initialisation
self.Initialise()
self.On()
@log_exceptions() @log_exceptions()
def configure_for_off(self): def configure_for_off(self):
""" user code here. is called when the state is set to OFF """ """ user code here. is called when the state is set to OFF """
...@@ -301,21 +275,16 @@ class Boot(lofar_device): ...@@ -301,21 +275,16 @@ class Boot(lofar_device):
@log_exceptions() @log_exceptions()
def configure_for_initialise(self): def configure_for_initialise(self):
# create an initialiser object so we can query it even before starting the (first) initialisation # create an initialiser object so we can query it even before starting the (first) initialisation
self.initialiser = DevicesInitialiser(self.Device_Names, self.Ignore_Unavailable_Devices, self.Initialise_Hardware, self.DeviceProxy_Time_Out) self.initialiser = DevicesInitialiser(self.Device_Names, False, self.Initialise_Hardware, self.DeviceProxy_Time_Out)
@command() def _boot(self, reboot=False, initialise_hardware=True):
@DebugIt()
@only_in_states([DevState.ON])
@fault_on_error()
@log_exceptions()
def boot(self):
""" """
Initialise or re-initialise all devices on the station. Initialise all devices on the station that are not yet on (reboot=False), or shut them down first (reboot=True).
This command will take a while to execute, so should be called asynchronously. If initialise_hardware is set, the hardware behind the devices is also explicitly reinitialised. Turn this
off to perform a warm boot.
If resume == True, a previously started attempt is resumed from the device This command will take a while to execute, so should be called asynchronously.
that failed to initialise earlier.
:return:None :return:None
""" """
...@@ -324,7 +293,6 @@ class Boot(lofar_device): ...@@ -324,7 +293,6 @@ class Boot(lofar_device):
# already initialising # already initialising
return return
# join any previous attempt, if any # join any previous attempt, if any
try: try:
self.initialiser.stop() self.initialiser.stop()
...@@ -332,30 +300,29 @@ class Boot(lofar_device): ...@@ -332,30 +300,29 @@ class Boot(lofar_device):
pass pass
# start new initialisation attempt # start new initialisation attempt
self.initialiser = DevicesInitialiser(self.Device_Names, self.Ignore_Unavailable_Devices, self.Initialise_Hardware, self.DeviceProxy_Time_Out) self.initialiser = DevicesInitialiser(self.Device_Names, reboot, initialise_hardware, self.DeviceProxy_Time_Out)
self.initialiser.start() self.initialiser.start()
@command() @command()
@DebugIt() @DebugIt()
@only_in_states([DevState.ON]) @only_in_states([DevState.ON])
@fault_on_error()
@log_exceptions() @log_exceptions()
def resume(self): def boot(self):
""" self._boot(reboot=False, initialise_hardware=self.Initialise_Hardware)
Resume booting. A previously started boot() attempt is resumed from
the first device that failed to initialise.
This command will take a while to execute, so should be called asynchronously.
:return:None
"""
if self.initialiser.is_running(): @command()
# already initialising @DebugIt()
return @only_in_states([DevState.ON])
@log_exceptions()
def reboot(self):
self._boot(reboot=True, initialise_hardware=self.Initialise_Hardware)
# just start it again @command()
self.initialiser.start() @DebugIt()
@only_in_states([DevState.ON])
@log_exceptions()
def warm_boot(self):
self._boot(reboot=False, initialise_hardware=False)
# ---------- # ----------
# Run server # Run server
......
...@@ -44,14 +44,18 @@ class Docker(lofar_device): ...@@ -44,14 +44,18 @@ class Docker(lofar_device):
# ---------- # ----------
# Attributes # Attributes
# ---------- # ----------
archiver_maria_db_R = attribute_wrapper(comms_annotation={"container": "archiver-maria-db"}, datatype=numpy.bool_) archiver_timescale_R = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=numpy.bool_)
archiver_maria_db_RW = attribute_wrapper(comms_annotation={"container": "archiver-maria-db"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) archiver_timescale_RW = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
databaseds_R = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=numpy.bool_) databaseds_R = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=numpy.bool_)
databaseds_RW = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) databaseds_RW = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_apsct_R = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=numpy.bool_) device_apsct_R = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=numpy.bool_)
device_apsct_RW = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) device_apsct_RW = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_apspu_R = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=numpy.bool_) device_apspu_R = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=numpy.bool_)
device_apspu_RW = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) device_apspu_RW = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_beam_R = attribute_wrapper(comms_annotation={"container": "device-beam"}, datatype=numpy.bool_)
device_beam_RW = attribute_wrapper(comms_annotation={"container": "device-beam"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_boot_R = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=numpy.bool_)
device_boot_RW = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_recv_R = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=numpy.bool_) device_recv_R = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=numpy.bool_)
device_recv_RW = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) device_recv_RW = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
device_sdp_R = attribute_wrapper(comms_annotation={"container": "device-sdp"}, datatype=numpy.bool_) device_sdp_R = attribute_wrapper(comms_annotation={"container": "device-sdp"}, datatype=numpy.bool_)
...@@ -70,10 +74,10 @@ class Docker(lofar_device): ...@@ -70,10 +74,10 @@ class Docker(lofar_device):
elk_RW = attribute_wrapper(comms_annotation={"container": "elk"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) elk_RW = attribute_wrapper(comms_annotation={"container": "elk"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
grafana_R = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=numpy.bool_) grafana_R = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=numpy.bool_)
grafana_RW = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) grafana_RW = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
hdbpp_cm_R = attribute_wrapper(comms_annotation={"container": "hdbpp-cm"}, datatype=numpy.bool_) hdbppts_cm_R = attribute_wrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=numpy.bool_)
hdbpp_cm_RW = attribute_wrapper(comms_annotation={"container": "hdbpp-cm"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) hdbppts_cm_RW = attribute_wrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
hdbpp_es_R = attribute_wrapper(comms_annotation={"container": "hdbpp-es"}, datatype=numpy.bool_) hdbppts_es_R = attribute_wrapper(comms_annotation={"container": "hdbppts-es"}, datatype=numpy.bool_)
hdbpp_es_RW = attribute_wrapper(comms_annotation={"container": "hdbpp-es"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) hdbppts_es_RW = attribute_wrapper(comms_annotation={"container": "hdbppts-es"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
itango_R = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=numpy.bool_) itango_R = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=numpy.bool_)
itango_RW = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) itango_RW = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
jupyter_R = attribute_wrapper(comms_annotation={"container": "jupyter"}, datatype=numpy.bool_) jupyter_R = attribute_wrapper(comms_annotation={"container": "jupyter"}, datatype=numpy.bool_)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment