diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index a09edc5778a3178233cb7e57a1a42250d5bc95aa..61b2c19452f74235810ccd5400557f20ca78b87d 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -18,7 +18,8 @@ "STAT/EC/1", "STAT/PSOC/1", "STAT/PCON/1", - "STAT/AntennaField/HBA", + "STAT/AFH/HBA", + "STAT/AFL/LBA", "STAT/Configuration/1", "STAT/ObservationControl/1", "STAT/TemperatureManager/1", @@ -29,7 +30,8 @@ "STAT/CCD/1", "STAT/EC/1", "STAT/PSOC/1", - "STAT/AntennaField/HBA", + "STAT/AFH/HBA", + "STAT/AFL/LBA", "STAT/PCON/1", "STAT/ObservationControl/1", "STAT/TemperatureManager/1", @@ -100,10 +102,10 @@ } } }, - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA": { + "AFH": { + "STAT/AFH/HBA": { "properties": { "Control_Children": [ "STAT/SDPFirmware/HBA", @@ -123,6 +125,29 @@ } } }, + "AFL": { + "STAT": { + "AFL": { + "STAT/AFL/LBA": { + "properties": { + "Control_Children": [ + "STAT/SDPFirmware/LBA", + "STAT/DigitalBeam/LBA", + "STAT/APS/L0", + "STAT/APS/L1" + ], + "Power_Children": [ + "STAT/DigitalBeam/LBA" + ], + "RECV_Devices": [ + "STAT/RECVL/L0", + "STAT/RECVL/L1" + ] + } + } + } + } + }, "PSOC": { "STAT": { "PSOC": { @@ -158,7 +183,8 @@ ], "Power_Children": [ "STAT/CCD/1", - "STAT/SDPFirmware/HBA" + "STAT/SDPFirmware/HBA", + "STAT/SDPFirmware/LBA" ] } } @@ -189,6 +215,8 @@ "False" ], "Power_Children": [ + "STAT/APS/L0", + "STAT/APS/L1", "STAT/APS/H0" ] } @@ -246,6 +274,19 @@ "0.5" ] } + }, + "STAT/DigitalBeam/LBA": { + "properties": { + "Control_Children": [ + "STAT/Beamlet/LBA" + ], + "Beam_tracking_interval": [ + "1.0" + ], + "Beam_tracking_preparation_period": [ + "0.5" + ] + } } } } @@ -328,6 +369,82 @@ "10001" ] } + }, + "STAT/Beamlet/LBA": { + "properties": { + "FPGA_beamlet_output_hdr_eth_source_mac_RW_default": [ + "00:22:86:08:00:00", + "00:22:86:08:00:01", + "00:22:86:08:00:02", + "00:22:86:08:00:03", + "00:22:86:08:01:00", + "00:22:86:08:01:01", + "00:22:86:08:01:02", + "00:22:86:08:01:03", + "00:22:86:08:02:00", + "00:22:86:08:02:01", + "00:22:86:08:02:02", + "00:22:86:08:02:03", + "00:22:86:08:03:00", + "00:22:86:08:03:01", + "00:22:86:08:03:02", + "00:22:86:08:03:03" + ], + "FPGA_beamlet_output_hdr_ip_source_address_RW_default": [ + "192.168.0.1", + "192.168.0.2", + "192.168.0.3", + "192.168.0.4", + "192.168.1.1", + "192.168.1.2", + "192.168.1.3", + "192.168.1.4", + "192.168.2.1", + "192.168.2.2", + "192.168.2.3", + "192.168.2.4", + "192.168.3.1", + "192.168.3.2", + "192.168.3.3", + "192.168.3.4" + ], + "FPGA_beamlet_output_hdr_udp_source_port_RW_default": [ + "53248", + "53249", + "53250", + "53251", + "53252", + "53253", + "53254", + "53255", + "53256", + "53257", + "53258", + "53259", + "53260", + "53261", + "53262", + "53263" + ], + "FPGA_beamlet_output_hdr_udp_destination_port_RW_default": [ + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001" + ] + } } } } @@ -347,6 +464,16 @@ "STAT/RECVH/1" ] } + }, + "STAT/APS/L0": { + "properties": { + "Control_Children": [] + } + }, + "STAT/APS/L1": { + "properties": { + "Control_Children": [] + } } } } @@ -431,6 +558,14 @@ "STAT/Beamlet/HBA" ] } + }, + "STAT/SDPFirmware/LBA": { + "properties": { + "Control_Children": [], + "Power_Children": [ + "STAT/Beamlet/LBA" + ] + } } } } diff --git a/CDB/integrations/digitalbeam_cluster_ConfigDb.json b/CDB/integrations/digitalbeam_cluster_ConfigDb.json index c45565db5ac20015829900d2b6aa895c1b3a385e..6648f6c59d4b02dbd7eb5532094f7a62322b252d 100644 --- a/CDB/integrations/digitalbeam_cluster_ConfigDb.json +++ b/CDB/integrations/digitalbeam_cluster_ConfigDb.json @@ -459,10 +459,10 @@ } } }, - "AntennaField": { + "AFL": { "STAT": { - "AntennaField": { - "STAT/AntennaField/LBA": { + "AFL": { + "STAT/AFL/LBA": { "properties": { "RECV_Devices": [ "STAT/RECVL/L0", @@ -470,7 +470,7 @@ ], "Control_Children": [ "STAT/SDPFirmware/LBA", - "STAT/DigitalBeam/LBA", + "STAT/digitalbeam/LBA", "STAT/RECVL/L0", "STAT/RECVL/L1" ], @@ -581,106 +581,112 @@ " 0.0000330969", " 0.6030782884", "0.7976820024" ], "Frequency_Band_RW_default": [ - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90", - "LBA_30_90", "LBA_30_90" + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90", + "LBA_30_90", "LBA_30_90" ] } - }, - "STAT/AntennaField/HBA0": { + } + } + } + }, + "AFH": { + "STAT": { + "AFH": { + "STAT/AFH/HBA0": { "properties": { "RECV_Devices": [ "STAT/RECVH/H0" @@ -792,102 +798,102 @@ "3826990.269", "460895.632", "5064595.204" ], "HBAT_PQR_rotation_angles_deg": [ - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24", - "24" + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24", + "24" ], "PQR_to_ETRS_rotation_matrix": [ "-0.1195951054", "-0.7919544517", "0.5987530018", @@ -895,106 +901,106 @@ " 0.0000330969", " 0.6030782884", "0.7976820024" ], "Frequency_Band_RW_default": [ - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190", - "HBA_110_190", "HBA_110_190" + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190", + "HBA_110_190", "HBA_110_190" ] } }, - "STAT/AntennaField/HBA1": { + "STAT/AFH/HBA1": { "properties": { "RECV_Devices": [ "STAT/RECVH/H0" diff --git a/CDB/integrations/tilebeam_cluster_ConfigDb.json b/CDB/integrations/tilebeam_cluster_ConfigDb.json index 8e13959439e16a1e7aa180a7aa6ffd3d63936473..ccdc58ccb19c1c36d8c7f416555c9005f4e0b513 100644 --- a/CDB/integrations/tilebeam_cluster_ConfigDb.json +++ b/CDB/integrations/tilebeam_cluster_ConfigDb.json @@ -10,10 +10,10 @@ } } }, - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA0": { + "AFH": { + "STAT/AFH/HBA0": { "properties": { "RECV_Devices": [ "STAT/RECVH/1" @@ -128,7 +128,7 @@ ] } }, - "STAT/AntennaField/HBA1": { + "STAT/AFH/HBA1": { "properties": { "RECV_Devices": [ "STAT/RECVH/2" @@ -243,7 +243,7 @@ ] } }, - "STAT/AntennaField/HBA2": { + "STAT/AFH/HBA2": { "properties": { "RECV_Devices": [ "STAT/RECVH/3" @@ -358,7 +358,7 @@ ] } }, - "STAT/AntennaField/HBA3": { + "STAT/AFH/HBA3": { "properties": { "RECV_Devices": [ "STAT/RECVH/4" diff --git a/CDB/stations/DTS.json b/CDB/stations/DTS.json index e1fad56c4e9c09aec5ac325321fa75e2a03599c6..75cff8b02f606ff35fdf32edccb609a515b8fa98 100644 --- a/CDB/stations/DTS.json +++ b/CDB/stations/DTS.json @@ -11,8 +11,8 @@ "STAT/Calibration/1", "STAT/ObservationControl/1", "STAT/TemperatureManager/1", - "STAT/AntennaField/LBA", - "STAT/AntennaField/HBA" + "STAT/AFL/LBA", + "STAT/AFH/HBA" ], "Control_Children": [ "STAT/EC/1", @@ -23,8 +23,8 @@ "STAT/Calibration/1", "STAT/ObservationControl/1", "STAT/TemperatureManager/1", - "STAT/AntennaField/LBA", - "STAT/AntennaField/HBA", + "STAT/AFL/LBA", + "STAT/AFH/HBA", "STAT/APS/L0", "STAT/APS/L1", "STAT/APS/H0" @@ -311,10 +311,10 @@ } } }, - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA": { + "AFH": { + "STAT/AFH/HBA": { "properties": { "RECV_Devices": [ "STAT/RECVH/H0" @@ -363,8 +363,14 @@ " 0.00400627", " 0.60440575", "0.79666658" ] } - }, - "STAT/AntennaField/LBA": { + } + } + } + }, + "AFL":{ + "STAT": { + "AFL": { + "STAT/AFL/LBA": { "properties": { "RECV_Devices": [ "STAT/RECVL/L0", diff --git a/CDB/stations/cs001.json b/CDB/stations/cs001.json index e39335f81a4c9c6aed1f1cda145276d0703ca2cd..3d73427ee8ef4ed2733821b85617a1b75c7e2f99 100644 --- a/CDB/stations/cs001.json +++ b/CDB/stations/cs001.json @@ -8,9 +8,9 @@ "Power_Children": [ "STAT/EC/1", "STAT/TemperatureManager/1", - "STAT/AntennaField/LBA", - "STAT/AntennaField/HBA0", - "STAT/AntennaField/HBA1", + "STAT/AFL/LBA", + "STAT/AFH/HBA0", + "STAT/AFH/HBA1", "STAT/Calibration/1", "STAT/ObservationControl/1", "STAT/Configuration/1" @@ -27,9 +27,9 @@ "STAT/APS/L0", "STAT/APS/L1", "STAT/APS/H0", - "STAT/AntennaField/LBA", - "STAT/AntennaField/HBA0", - "STAT/AntennaField/HBA1" + "STAT/AFL/LBA", + "STAT/AFH/HBA0", + "STAT/AFH/HBA1" ], "Station_Name": [ "CS001" @@ -425,10 +425,10 @@ } } }, - "AntennaField": { + "AFL": { "STAT": { - "AntennaField": { - "STAT/AntennaField/LBA": { + "AFL": { + "STAT/AFL/LBA": { "properties": { "Antenna_Sets": [ "INNER", @@ -876,8 +876,14 @@ "3826905.065", "460885.717", "5064660.056" ] } - }, - "STAT/AntennaField/HBA0": { + } + } + } + }, + "AFH": { + "STAT": { + "AFH": { + "STAT/AFH/HBA0": { "properties": { "Antenna_Sets": [ "ALL" @@ -1017,7 +1023,7 @@ ] } }, - "STAT/AntennaField/HBA1": { + "STAT/AFH/HBA1": { "properties": { "Antenna_Sets": [ "ALL" diff --git a/CDB/stations/dummy_positions_ConfigDb.json b/CDB/stations/dummy_positions_ConfigDb.json index ee9fc852b9c772b65408bff8719e282cd663fd26..4dfe542f56c976c4fa3ae626d813f00096d7f49b 100644 --- a/CDB/stations/dummy_positions_ConfigDb.json +++ b/CDB/stations/dummy_positions_ConfigDb.json @@ -1,9 +1,9 @@ { "servers": { - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA": { + "AFH": { + "STAT/AFH/HBA": { "properties": { "Antenna_Sets": [ "INNER", diff --git a/CDB/stations/hba_core.json b/CDB/stations/hba_core.json index 1fff270bbc411d8390294c19fca9dceccb04df8d..f03fbc65794fef66842f2fb07e0a9521fff6e8cb 100644 --- a/CDB/stations/hba_core.json +++ b/CDB/stations/hba_core.json @@ -144,10 +144,10 @@ } } }, - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA0": { + "AFH": { + "STAT/AFH/HBA0": { "properties": { "Power_Children": [ "STAT/DigitalBeam/HBA0", @@ -161,9 +161,6 @@ "RECV_Devices": [ "STAT/RECVH/H0" ], - "Antenna_Type": [ - "HBA" - ], "HBAT_single_element_selection_GENERIC_201512": [ "0", "10", "4", "3", "14", "0", "5", "5", "3", "13", "10", "3", @@ -198,7 +195,7 @@ ] } }, - "STAT/AntennaField/HBA1": { + "STAT/AFH/HBA1": { "properties": { "Power_Children": [ "STAT/DigitalBeam/HBA1", @@ -212,9 +209,6 @@ "RECV_Devices": [ "STAT/RECVH/H0" ], - "Antenna_Type": [ - "HBA" - ], "HBAT_single_element_selection_GENERIC_201512": [ "0", "10", "4", "3", "14", "0", "5", "5", "3", "13", "10", "3", diff --git a/CDB/stations/hba_remote.json b/CDB/stations/hba_remote.json index e094e2b9112a94dda37885920fb88345df5825ea..dd4e7bdcfbb0ac688f07e8cc36f91b3b9c4d5b17 100644 --- a/CDB/stations/hba_remote.json +++ b/CDB/stations/hba_remote.json @@ -81,10 +81,10 @@ } } }, - "AntennaField": { + "AFH": { "STAT": { - "AntennaField": { - "STAT/AntennaField/HBA": { + "AFH": { + "STAT/AFH/HBA": { "properties": { "Power_Children": [ "STAT/DigitalBeam/HBA", @@ -98,9 +98,6 @@ "RECV_Devices": [ "STAT/RECVH/H0" ], - "Antenna_Type": [ - "HBA" - ], "HBAT_single_element_selection_GENERIC_201512": [ "0", "13", "12", "4", "11", "11", "7", "8", "2", "7", "11", "2", diff --git a/CDB/stations/lba.json b/CDB/stations/lba.json index 5a689fff6622b8e78ef7821b8352316645cef966..ec0d05e814ec13741fd7144b5700feec72efda7d 100644 --- a/CDB/stations/lba.json +++ b/CDB/stations/lba.json @@ -71,10 +71,10 @@ } } }, - "AntennaField": { + "AFL": { "STAT": { - "AntennaField": { - "STAT/AntennaField/LBA": { + "AFL": { + "STAT/AFL/LBA": { "properties": { "Power_Children": [ "STAT/DigitalBeam/LBA" @@ -87,9 +87,6 @@ "STAT/RECVL/L0", "STAT/RECVL/L1" ], - "Antenna_Type": [ - "LBA" - ], "Frequency_Band_RW_default": [ "LBA_10_90", "LBA_10_90", "LBA_10_90", "LBA_10_90", diff --git a/CDB/stations/testenv_cs001.json b/CDB/stations/testenv_cs001.json index 33bfdb2e053659e535755c5b64b78185ebfef18f..a6286bd311fe9f121cd75347e7156d48b352e428 100644 --- a/CDB/stations/testenv_cs001.json +++ b/CDB/stations/testenv_cs001.json @@ -326,7 +326,7 @@ "STAT/DigitalBeam/HBA1": { "properties": { "AntennaField_Device": [ - "STAT/AntennaField/HBA1" + "STAT/AFH/HBA1" ], "Beamlet_Device": [ "STAT/Beamlet/HBA1" diff --git a/README.md b/README.md index e2cbd8ff04b11c9a1d0a9b6f27744de374dbc57f..dbc58631e3705fbcf066a3f6b0bde00a0125ffbc 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,9 @@ Next change the version in the following places: # Release Notes +* 0.22.0 Split `Antennafield` in `AFL` and `AFH` devices in order to separate Low-Band + and High-Band functionalities + Removed `Antenna_Type_R` attribute from antennafield devices * 0.21.4 Replace `ACC-MIB.mib` with `SP2-MIB.mib` source file in PCON device * 0.21.3 Added DigitalBeam.Antenna_Usage_Mask_R to expose antennas used in beamforming * 0.21.2 Removed deprecated "Boot" device (use StationManager now) diff --git a/docker-compose/device-antennafield.yml b/docker-compose/device-afh.yml similarity index 84% rename from docker-compose/device-antennafield.yml rename to docker-compose/device-afh.yml index 705e43b517718da08e682e72e2ebdaed3504310c..849463c1c73705e4194ddb9979651e52380f74a5 100644 --- a/docker-compose/device-antennafield.yml +++ b/docker-compose/device-afh.yml @@ -16,10 +16,10 @@ version: '2.1' services: - device-antennafield: + device-afh: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/lofar-device-base:${TAG} - hostname: device-antennafield - container_name: device-antennafield + hostname: device-afh + container_name: device-afh logging: driver: "json-file" options: @@ -40,7 +40,7 @@ services: - TANGO_ZMQ_EVENT_PORT=5815 - TANGO_ZMQ_HEARTBEAT_PORT=5915 healthcheck: - test: l2ss-health dserver/AntennaField/STAT + test: l2ss-health dserver/AFH/STAT interval: 1m timeout: 30s retries: 3 @@ -50,7 +50,7 @@ services: - 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-antennafield AntennaField STAT -v -ORBendPoint giop:tcp:0:5715 -ORBendPointPublish giop:tcp:${HOSTNAME}:5715 + - l2ss-afh AFH STAT -v -ORBendPoint giop:tcp:0:5715 -ORBendPointPublish giop:tcp:${HOSTNAME}:5715 restart: on-failure stop_signal: SIGINT # request a graceful shutdown of Tango stop_grace_period: 2s diff --git a/docker-compose/device-afl.yml b/docker-compose/device-afl.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b47626ec93647070f0db80932baf9b3779e1f03 --- /dev/null +++ b/docker-compose/device-afl.yml @@ -0,0 +1,56 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 +# +# 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-afl: + image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/lofar-device-base:${TAG} + hostname: device-afl + container_name: device-afl + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5730:5730" # unique port for this DS + - "5830:5830" # ZeroMQ event port + - "5930:5930" # ZeroMQ heartbeat port + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ..:/opt/lofar/tango:rw + environment: + - TANGO_HOST=${TANGO_HOST} + - TANGO_ZMQ_EVENT_PORT=5830 + - TANGO_ZMQ_HEARTBEAT_PORT=5930 + healthcheck: + test: l2ss-health dserver/AFL/STAT + interval: 1m + timeout: 30s + retries: 3 + start_period: 30s + 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-afl AFL STAT -v -ORBendPoint giop:tcp:0:5730 -ORBendPointPublish giop:tcp:${HOSTNAME}:5730 + restart: on-failure + stop_signal: SIGINT # request a graceful shutdown of Tango + stop_grace_period: 2s diff --git a/docker-compose/jupyter-lab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter-lab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index c3a4210e1752e29983a4b2a0ccc8fa1b37b8a730..c76c3e2b4db62cbdc26bff0141be3ebb13511c5f 100644 --- a/docker-compose/jupyter-lab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyter-lab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -37,7 +37,7 @@ sst_l = OptionalDeviceProxy("STAT/SST/LBA") xst_l = OptionalDeviceProxy("STAT/XST/LBA") beamlet_l = OptionalDeviceProxy("STAT/Beamlet/LBA") digitalbeam_l = OptionalDeviceProxy("STAT/DigitalBeam/LBA") -antennafield_l = OptionalDeviceProxy("STAT/AntennaField/LBA") +af_l = OptionalDeviceProxy("STAT/AFL/LBA") sdpfirmware_h = OptionalDeviceProxy("STAT/SDPFirmware/HBA") sdp_h = OptionalDeviceProxy("STAT/SDP/HBA") @@ -47,7 +47,7 @@ xst_h = OptionalDeviceProxy("STAT/XST/HBA") beamlet_h = OptionalDeviceProxy("STAT/Beamlet/HBA") digitalbeam_h = OptionalDeviceProxy("STAT/DigitalBeam/HBA") tilebeam_h = OptionalDeviceProxy("STAT/TileBeam/HBA") -antennafield_h = OptionalDeviceProxy("STAT/AntennaField/HBA") +af_h = OptionalDeviceProxy("STAT/AFH/HBA") sdpfirmware_h0 = OptionalDeviceProxy("STAT/SDPFirmware/HBA0") sdp_h0 = OptionalDeviceProxy("STAT/SDP/HBA0") @@ -57,7 +57,7 @@ xst_h0 = OptionalDeviceProxy("STAT/XST/HBA0") beamlet_h0 = OptionalDeviceProxy("STAT/Beamlet/HBA0") digitalbeam_h0 = OptionalDeviceProxy("STAT/DigitalBeam/HBA0") tilebeam_h0 = OptionalDeviceProxy("STAT/TileBeam/HBA0") -antennafield_h0 = OptionalDeviceProxy("STAT/AntennaField/HBA0") +af_h0 = OptionalDeviceProxy("STAT/AFH/HBA0") sdpfirmware_h1 = OptionalDeviceProxy("STAT/SDPFirmware/HBA1") sdp_h1 = OptionalDeviceProxy("STAT/SDP/HBA1") @@ -67,7 +67,7 @@ xst_h1 = OptionalDeviceProxy("STAT/XST/HBA1") beamlet_h1 = OptionalDeviceProxy("STAT/Beamlet/HBA1") digitalbeam_h1 = OptionalDeviceProxy("STAT/DigitalBeam/HBA1") tilebeam_h1 = OptionalDeviceProxy("STAT/TileBeam/HBA1") -antennafield_h1 = OptionalDeviceProxy("STAT/AntennaField/HBA1") +af_h1 = OptionalDeviceProxy("STAT/AFH/HBA1") stationmanager = OptionalDeviceProxy("STAT/StationManager/1") ccd = OptionalDeviceProxy("STAT/CCD/1") diff --git a/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json index fe6010562b48d3ae6e78b70c46befe4a17c462d5..c181931ebdb89dfbbf34c5f9576587a85818df7b 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-fast-policy.json @@ -4,7 +4,9 @@ }, "devices": { - "stat/antennafield/*": { + "stat/afh/*": { + }, + "stat/afl/*": { }, "stat/apsct/*": { }, diff --git a/docker-compose/tango-prometheus-exporter/lofar2-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-policy.json index 27a43c2757467e21dd052d454b120cb5bd5afca9..895f6e307dddc2de5e9df3653816695fbe0b9627 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-policy.json @@ -8,7 +8,7 @@ }, "devices": { - "stat/antennafield/*": { + "stat/afh/*": { "include": [ "ANT_mask_RW" ], @@ -19,13 +19,16 @@ "HBAT_PWR_LNA_on_R", "HBAT_PWR_on_R", "HBAT_BF_delay_steps_*", - "Calibration_*", "FPGA_sdp_info_*" ] }, - "stat/antennafield/lba": { + "stat/afl/lba": { + "include": [ + "ANT_mask_RW" + ], "exclude": [ - "HBAT_*", + "Antenna_*", + "FPGA_sdp_info_*", "RCU_DAB_filter_on_*" ] }, diff --git a/docker-compose/tango-prometheus-exporter/lofar2-slow-policy.json b/docker-compose/tango-prometheus-exporter/lofar2-slow-policy.json index 4e65340d110e507e33e84f9ed502cda994ed37a0..c9aee832684042b4d73350d036cec68ecd58cf8d 100644 --- a/docker-compose/tango-prometheus-exporter/lofar2-slow-policy.json +++ b/docker-compose/tango-prometheus-exporter/lofar2-slow-policy.json @@ -4,7 +4,7 @@ }, "devices": { - "stat/antennafield/*": { + "stat/afh/*": { "include": [ "Antenna_*", "HBAT_antenna_ITRF_offsets_R", @@ -14,6 +14,12 @@ "FPGA_sdp_info_*" ] }, + "stat/afl/*": { + "include": [ + "Antenna_*", + "FPGA_sdp_info_*" + ] + }, "stat/apsct/*": { }, "stat/ccd/1": { diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index 2c4af601e1e46f8aff974b455f7dc1de8a7d50d0..c6ea4a4d4bcd84568928e167cc9638cf7c79bf3a 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -102,7 +102,7 @@ echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true # Devices list is used to explitly word split when supplied to commands, must # disable shellcheck SC2086 for each case. -DEVICES=(device-station-manager device-aps device-apsct device-ccd device-ec device-apspu device-sdpfirmware device-sdp device-recvh device-recvl 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-control device-configuration device-calibration) +DEVICES=(device-station-manager device-aps device-apsct device-ccd device-ec device-apspu device-sdpfirmware device-sdp device-recvh device-recvl device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-afh device-afl device-temperature-manager device-observation-control device-configuration device-calibration) SIMULATORS=(sdptr-sim recvh-sim recvl-sim unb2-sim apsct-sim apspu-sim ccd-sim ec-sim) @@ -155,9 +155,9 @@ make up integration-test integration_test default -integration_test tilebeam_performance "device-sdpfirmware device-sdp device-recvh device-recvl device-tilebeam device-antennafield" "${LOFAR20_DIR}/CDB/integrations/tilebeam_cluster_ConfigDb.json" +integration_test tilebeam_performance "device-sdpfirmware device-sdp device-recvh device-recvl device-tilebeam device-afh device-afl" "${LOFAR20_DIR}/CDB/integrations/tilebeam_cluster_ConfigDb.json" -integration_test digitalbeam_performance "device-sdpfirmware device-sdp device-recvh device-recvl device-digitalbeam device-beamlet device-antennafield" "${LOFAR20_DIR}/CDB/integrations/digitalbeam_cluster_ConfigDb.json" +integration_test digitalbeam_performance "device-sdpfirmware device-sdp device-recvh device-recvl device-digitalbeam device-beamlet device-afh device-afl" "${LOFAR20_DIR}/CDB/integrations/digitalbeam_cluster_ConfigDb.json" integration_test configuration "device-configuration" diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION index 6aec9e54405ad2ee89f3b14a98310b5b65d5701b..2157409059873c80aa93884ecb847639add77b7a 100644 --- a/tangostationcontrol/VERSION +++ b/tangostationcontrol/VERSION @@ -1 +1 @@ -0.21.4 +0.22.0 diff --git a/tangostationcontrol/docs/source/devices/antennafield.rst b/tangostationcontrol/docs/source/devices/afh-afl.rst similarity index 90% rename from tangostationcontrol/docs/source/devices/antennafield.rst rename to tangostationcontrol/docs/source/devices/afh-afl.rst index 6cc65ca6237d4e362bf3aaf2c56d7191ad1a5af1..b7b4c1c318492611e80b341f69e6fa21de93d059 100644 --- a/tangostationcontrol/docs/source/devices/antennafield.rst +++ b/tangostationcontrol/docs/source/devices/afh-afl.rst @@ -1,15 +1,15 @@ -AntennaField --------------------- +AntennaField-HB (AFH), AntennaField-LB (AFL) +--------------------------------------------- -The ``antennafield == DeviceProxy("STAT/AntennaField/1")`` device represents a set of *antennas* or *tiles* that collectively form an antenna field. It represents a selection of inputs from one or more ``RECV`` devices, mapped onto an ``SDP`` device, annotated with metadata such as positional information. +The ``afh == DeviceProxy("STAT/AFH/HBA")`` device represents a set of *antennas* or *tiles* that collectively form a High-Band antenna field. -:nr_antennas_R: The number of antennas or tiles in the antenna field. +The ``afl == DeviceProxy("STAT/AFL/LBA")`` device represents a set of *antennas* that collectively form a Low-Band antenna field. - :type: ``uint32`` +They represent a selection of inputs from one or more ``RECV`` devices, mapped onto an ``SDP`` device, annotated with metadata such as positional information. -:Antenna_Type_R: Which type of antenna is in this field (LBA or HBA). +:nr_antennas_R: The number of antennas or tiles in the antenna field. - :type: ``str`` + :type: ``uint32`` It provides many settings that map onto the ``RECV`` device directly, serving as a funnel: @@ -63,10 +63,6 @@ The antennas represented by the antenna field are selected by the following prop :type: ``str`` -:Antenna_Type: The type of antenna in this field (LBA or HBA). - - :type: ``str`` - Antenna mapping """""""""""""""""""" diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index 261a62f2668e848c06e44303f1aeca0f2b9811a3..872a3b4ca49cb40227e0e550c15e5105be446ac3 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -20,7 +20,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st interfaces/overview devices/overview devices/using - devices/antennafield + devices/afh-afl devices/tilebeam-digitalbeam devices/beamlet devices/recvh-recvl diff --git a/tangostationcontrol/docs/source/observing.rst b/tangostationcontrol/docs/source/observing.rst index 6586a25efbaa2b52fa5bd4bf2f35070a09fb4e19..ab506e119eb7b3bf5fdfb6c3dca5511b918141cf 100644 --- a/tangostationcontrol/docs/source/observing.rst +++ b/tangostationcontrol/docs/source/observing.rst @@ -71,7 +71,7 @@ This will configure the specified antenna field (f.e. ``HBA``) as follows: * ``STAT/DigitalBeam/HBA`` is configured to beam form the antennas in the specified ``antenna_set``, track all pointings given in ``SAPs[x].pointing``, and produce beamlets for all subbands in ``SAPs[x].subbands``. The beamlets mirror the subbands in the order in which they are specified, * The ``observation_id`` is used to annotate the beamlet data produced by this observation, -* ``STAT/AntennaField/HBA`` is configured to use the specified ``filter`` for the RCUs, +* ``STAT/AFH/HBA`` is configured to use the specified ``filter`` for the RCUs, * ``STAT/TileBeam/HBA`` is configured to beam form all HBA tiles, tracking the given ``tile_beam`` pointing. Observation Output diff --git a/tangostationcontrol/integration_test/default/devices/antennafield/__init__.py b/tangostationcontrol/integration_test/default/devices/antennafield/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..68ddd5cdc3efaa38e853aef337c08beb99c50c4c --- /dev/null +++ b/tangostationcontrol/integration_test/default/devices/antennafield/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 diff --git a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/integration_test/default/devices/antennafield/test_device_hba.py similarity index 83% rename from tangostationcontrol/integration_test/default/devices/test_device_antennafield.py rename to tangostationcontrol/integration_test/default/devices/antennafield/test_device_hba.py index d7995d502e9212acf9bbe2f12b0c49eedc431932..b65e62870dcf2eba5977395b95f0dd80ccae59e0 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py +++ b/tangostationcontrol/integration_test/default/devices/antennafield/test_device_hba.py @@ -20,13 +20,16 @@ from tangostationcontrol.common.constants import ( S_pn, ) from tangostationcontrol.common.frequency_bands import bands -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) -class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): +class TestHBADevice(AbstractTestBases.TestDeviceBase): def setUp(self): self.stationmanager_proxy = self.setup_stationmanager_proxy() - super().setUp("STAT/AntennaField/HBA0") + super().setUp("STAT/AFH/HBA0") # Typical tests emulate 'CS001_TILES' number of antennas in # the AntennaField. 'MAX_ANTENNA' is the number of inputs @@ -154,7 +157,8 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): def test_ANT_mask_RW_configured_after_Antenna_Usage_Mask_only_one_functioning_antenna( self, ): - """Verify if ANT_mask_RW values are correctly configured from Antenna_Usage_Mask values (only second antenna is OK)""" + """Verify if ANT_mask_RW values are correctly configured from + Antenna_Usage_Mask values (only second antenna is OK)""" antennafield_proxy = self.proxy @@ -378,61 +382,56 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): # Test whether changes in frequency band propagate properly. VALID_MODI = ["HBA_110_190", "HBA_170_230", "HBA_210_250"] - for antenna_type in ["HBA"]: - properties = { - "Antenna_Type": [antenna_type], - "Control_to_RECV_mapping": [1, 1] + [-1, -1] * (CS001_TILES - 1), - "Power_to_RECV_mapping": [1, 0] + [-1, -1] * (CS001_TILES - 1), - "Antenna_to_SDP_Mapping": [0, 1, 0, 0] + [-1, -1] * (CS001_TILES - 2), - } + properties = { + "Control_to_RECV_mapping": [1, 1] + [-1, -1] * (CS001_TILES - 1), + "Power_to_RECV_mapping": [1, 0] + [-1, -1] * (CS001_TILES - 1), + "Antenna_to_SDP_Mapping": [0, 1, 0, 0] + [-1, -1] * (CS001_TILES - 2), + } + + antennafield_proxy = self.proxy + antennafield_proxy.off() + antennafield_proxy.put_property(properties) + antennafield_proxy.boot() - antennafield_proxy = self.proxy - antennafield_proxy.off() - antennafield_proxy.put_property(properties) - antennafield_proxy.boot() - - for band in [b for b in bands.values() if b.name in VALID_MODI]: - # clear downstream settings - self.recv_proxy.write_attribute( - "RCU_band_select_RW", [[0] * N_rcu_inp] * N_rcu - ) - self.sdp_proxy.write_attribute("nyquist_zone_RW", [[0] * S_pn] * N_pn) - - antennafield_proxy.write_attribute( - "Frequency_Band_RW", [[band.name, band.name]] * CS001_TILES - ) - # Wait for Tango attributes updating - time.sleep(1) - - # test whether clock propagated correctly - numpy.testing.assert_equal( - band.clock, self.sdpfirmware_proxy.clock_RW, err_msg=f"{band.name}" - ) - - # test whether nyquist zone propagated correctly (for both polarisations!) - numpy.testing.assert_equal( - numpy.array( - [band.nyquist_zone, band.nyquist_zone] * 2 - + [0] * (N_pn * S_pn - 4) - ), - self.sdp_proxy.read_attribute("nyquist_zone_RW").value.flatten(), - err_msg=f"{band.name}", - ) - - # test whether rcu filter propagated correctly - numpy.testing.assert_equal( - numpy.array( - [band.rcu_band, band.rcu_band] + [0] * (N_rcu_inp * N_rcu - 2) - ), - self.recv_proxy.read_attribute( - "RCU_band_select_RW" - ).value.flatten(), - err_msg=f"{band.name}", - ) - - # test whether reading back results in the same band for our inputs - numpy.testing.assert_equal( - numpy.array([band.name, band.name]), - antennafield_proxy.read_attribute("Frequency_Band_RW").value[0], - err_msg=f"{band.name}", - ) + for band in [b for b in bands.values() if b.name in VALID_MODI]: + # clear downstream settings + self.recv_proxy.write_attribute( + "RCU_band_select_RW", [[0] * N_rcu_inp] * N_rcu + ) + self.sdp_proxy.write_attribute("nyquist_zone_RW", [[0] * S_pn] * N_pn) + + antennafield_proxy.write_attribute( + "Frequency_Band_RW", [[band.name, band.name]] * CS001_TILES + ) + # Wait for Tango attributes updating + time.sleep(1) + + # test whether clock propagated correctly + numpy.testing.assert_equal( + band.clock, self.sdpfirmware_proxy.clock_RW, err_msg=f"{band.name}" + ) + + # test whether nyquist zone propagated correctly (for both polarisations!) + numpy.testing.assert_equal( + numpy.array( + [band.nyquist_zone, band.nyquist_zone] * 2 + [0] * (N_pn * S_pn - 4) + ), + self.sdp_proxy.read_attribute("nyquist_zone_RW").value.flatten(), + err_msg=f"{band.name}", + ) + + # test whether rcu filter propagated correctly + numpy.testing.assert_equal( + numpy.array( + [band.rcu_band, band.rcu_band] + [0] * (N_rcu_inp * N_rcu - 2) + ), + self.recv_proxy.read_attribute("RCU_band_select_RW").value.flatten(), + err_msg=f"{band.name}", + ) + + # test whether reading back results in the same band for our inputs + numpy.testing.assert_equal( + numpy.array([band.name, band.name]), + antennafield_proxy.read_attribute("Frequency_Band_RW").value[0], + err_msg=f"{band.name}", + ) diff --git a/tangostationcontrol/integration_test/default/devices/base_device_classes/test_power_hierarchy.py b/tangostationcontrol/integration_test/default/devices/base_device_classes/test_power_hierarchy.py index b8330acf06c20d324a03dd773e514f22eebd510a..721a512468a8b85d4d56ac6e229cf32c164e73fc 100644 --- a/tangostationcontrol/integration_test/default/devices/base_device_classes/test_power_hierarchy.py +++ b/tangostationcontrol/integration_test/default/devices/base_device_classes/test_power_hierarchy.py @@ -30,7 +30,7 @@ class TestPowerHierarchyDevice(base.IntegrationTestCase): stationmanager_name = "STAT/StationManager/1" ec_name = "STAT/EC/1" - antennafield_name = "STAT/AntennaField/HBA0" + antennafield_name = "STAT/AFH/HBA0" aps_l0_name = "STAT/APS/L0" aps_l1_name = "STAT/APS/L1" aps_h0_name = "STAT/APS/H0" diff --git a/tangostationcontrol/integration_test/default/devices/test_device_calibration.py b/tangostationcontrol/integration_test/default/devices/test_device_calibration.py index fd0fdad70fdb93fc8927a6275e43e3dac164a184..9629ece0342cf802723f5d7f9c8146aae738003d 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_calibration.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_calibration.py @@ -75,7 +75,7 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): self.sdpfirmware_proxy = self.setup_sdpfirmware_proxy() self.sdp_proxy = self.setup_sdp_proxy() - self.antennafield_proxy = self.setup_proxy("STAT/AntennaField/HBA0") + self.antennafield_proxy = self.setup_proxy("STAT/AFH/HBA0") # make sure we restore any properties we modify self.original_antennafield_properties = self.antennafield_proxy.get_property( @@ -144,7 +144,6 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): def test_calibrate_recv(self): calibration_properties = { - "Antenna_Type": ["HBA"], "Antenna_Cables": ["50m", "80m"] * (DEFAULT_N_HBA_TILES // 2), "Control_to_RECV_mapping": # [1, 0, 1, 1, 1, 2, 1, x ... 1, 47] @@ -156,14 +155,14 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): "Frequency_Band_RW_default": ["HBA_110_190"] * (DEFAULT_N_HBA_TILES * 2), } - self.antennafield_proxy = self.setup_proxy("STAT/AntennaField/HBA0") + self.antennafield_proxy = self.setup_proxy("STAT/AFH/HBA0") self.antennafield_proxy.put_property(calibration_properties) self.antennafield_proxy.boot() self.proxy.boot() # calibrate - self.proxy.calibrate_recv("STAT/AntennaField/HBA0") + self.proxy.calibrate_recv("STAT/AFH/HBA0") # check the results rcu_attenuator_db_pwr = self.antennafield_proxy.RCU_attenuator_dB_RW[:, 0] @@ -202,7 +201,6 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): def test_calibrate_sdp(self): calibration_properties = { - "Antenna_Type": ["HBA"], "Antenna_Names": self.HBA_ANTENNA_NAMES, "Antenna_Cables": ["50m", "80m"] * (DEFAULT_N_HBA_TILES // 2), "Antenna_to_SDP_Mapping": [0, 1, 0, 0] @@ -217,14 +215,14 @@ class TestCalibrationDevice(AbstractTestBases.TestDeviceBase): "Frequency_Band_RW_default": ["HBA_110_190"] * (DEFAULT_N_HBA_TILES * 2), } - self.antennafield_proxy = self.setup_proxy("STAT/AntennaField/HBA0") + self.antennafield_proxy = self.setup_proxy("STAT/AFH/HBA0") self.antennafield_proxy.put_property(calibration_properties) self.antennafield_proxy.boot() self.proxy.boot() # calibrate - self.proxy.calibrate_sdp("STAT/AntennaField/HBA0") + self.proxy.calibrate_sdp("STAT/AFH/HBA0") # check the results # antenna #0 is on FPGA 0, input 2 and 3, diff --git a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py index 32c3b5666b87e407771f7ae86782d40c5ddfaf20..428b151885c789d7a9def82b4a1671c2021a7f9c 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py @@ -7,6 +7,8 @@ import time import numpy import timeout_decorator +from integration_test.device_proxy import TestDeviceProxy +from integration_test.default.devices.base import AbstractTestBases from tangostationcontrol.common.constants import ( MAX_ANTENNA, N_beamlets_ctrl, @@ -16,10 +18,10 @@ from tangostationcontrol.common.constants import ( CLK_160_MHZ, CS001_TILES, ) -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse - -from integration_test.device_proxy import TestDeviceProxy -from integration_test.default.devices.base import AbstractTestBases +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) logger = logging.getLogger() @@ -33,7 +35,7 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): ) antenna_use_ok = numpy.array([AntennaUse.AUTO] * MAX_ANTENNA) - antennafield_iden = "STAT/AntennaField/HBA0" + antennafield_iden = "STAT/AFH/HBA0" beamlet_iden = "STAT/Beamlet/HBA0" recv_iden = "STAT/RECVH/H0" sdpfirmware_iden = "STAT/SDPFirmware/HBA0" @@ -107,7 +109,6 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase): "1" + ("0" * (NR_TILES - 1)), "1" * NR_TILES, ], - "Antenna_Type": "HBA", } ) antennafield_proxy.off() diff --git a/tangostationcontrol/integration_test/default/devices/test_device_observation.py b/tangostationcontrol/integration_test/default/devices/test_device_observation.py index 6aa3527b937681a7d0dc6718f84ef6bc7b61e195..8dd06ebca2a9fa72feac5160b359e4ff53216146 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_observation.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_observation.py @@ -5,8 +5,11 @@ from datetime import datetime from json import loads import numpy -from tango import DevState, DevFailed +from integration_test.device_proxy import TestDeviceProxy +from integration_test.default.devices.base import AbstractTestBases + +from tango import DevState, DevFailed from tangostationcontrol.common.constants import ( N_beamlets_ctrl, N_elements, @@ -14,12 +17,12 @@ from tangostationcontrol.common.constants import ( MAX_ANTENNA, CS001_TILES, ) -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) from tangostationcontrol.test.devices.test_observation_base import TestObservationBase -from integration_test.device_proxy import TestDeviceProxy -from integration_test.default.devices.base import AbstractTestBases - class TestDeviceObservation(AbstractTestBases.TestDeviceBase): ANTENNA_TO_SDP_MAPPING = [ @@ -113,14 +116,13 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase): def setup_antennafield_proxy(self): # setup AntennaField - antennafield_proxy = TestDeviceProxy("STAT/AntennaField/HBA0") + antennafield_proxy = TestDeviceProxy("STAT/AFH/HBA0") power_mapping = [[1, i * 2 + 0] for i in range(CS001_TILES)] control_mapping = [[1, i * 2 + 1] for i in range(CS001_TILES)] antenna_qualities = numpy.array([AntennaQuality.OK] * MAX_ANTENNA) antenna_use = numpy.array([AntennaUse.AUTO] * MAX_ANTENNA) antennafield_proxy.put_property( { - "Antenna_Type": ["HBA"], "Power_to_RECV_mapping": numpy.array(power_mapping).flatten(), "Control_to_RECV_mapping": numpy.array(control_mapping).flatten(), "Antenna_to_SDP_Mapping": self.ANTENNA_TO_SDP_MAPPING, diff --git a/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py b/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py index b97cdf03f41235f29cbccd1a88fc5f4c7cefa062..2e65a37b4f54ff82c23cf678ed34e342cdd4d59f 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_observation_control.py @@ -6,14 +6,14 @@ from datetime import datetime from datetime import timedelta import numpy + +from integration_test.device_proxy import TestDeviceProxy +from integration_test.default.devices.base import AbstractTestBases from tango import DevFailed from tango import DevState from tangostationcontrol.common.constants import CS001_TILES from tangostationcontrol.test.devices.test_observation_base import TestObservationBase -from integration_test.device_proxy import TestDeviceProxy -from integration_test.default.devices.base import AbstractTestBases - class TestObservationControlDevice(AbstractTestBases.TestDeviceBase): ANTENNA_TO_SDP_MAPPING = [ @@ -102,7 +102,7 @@ class TestObservationControlDevice(AbstractTestBases.TestDeviceBase): def setup_antennafield_proxy(self): # setup AntennaField - antennafield_proxy = TestDeviceProxy("STAT/AntennaField/HBA0") + antennafield_proxy = TestDeviceProxy("STAT/AFH/HBA0") control_mapping = [[1, i] for i in range(CS001_TILES)] antennafield_proxy.put_property( { diff --git a/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py b/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py index 5d644bb06336c3757a0380cc2534ead782781ab4..728d2aabc3361b7dacf72b1320639b1e38e30bbd 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_tilebeam.py @@ -16,7 +16,10 @@ from tangostationcontrol.common.constants import ( N_elements, N_pol, ) -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) class NumpyEncoder(json.JSONEncoder): @@ -53,7 +56,7 @@ class TestDeviceTileBeam(AbstractTestBases.TestDeviceBase): def setup_antennafield_proxy(self): """Setup AntennaField""" - antennafield_proxy = TestDeviceProxy("STAT/AntennaField/HBA0") + antennafield_proxy = TestDeviceProxy("STAT/AFH/HBA0") control_mapping = [[1, i] for i in range(CS001_TILES)] antenna_qualities = numpy.array([AntennaQuality.OK] * MAX_ANTENNA) antenna_use = numpy.array([AntennaUse.AUTO] * MAX_ANTENNA) diff --git a/tangostationcontrol/integration_test/default/devices/test_observation.py b/tangostationcontrol/integration_test/default/devices/test_observation.py index 5f1548620da0b8aad9af5671ff426f04811c8107..6233bbd5bc8907106990ca3ea06e038823841eb5 100644 --- a/tangostationcontrol/integration_test/default/devices/test_observation.py +++ b/tangostationcontrol/integration_test/default/devices/test_observation.py @@ -29,7 +29,7 @@ class TestObservation(base.IntegrationTestCase): "STAT/Beamlet/HBA0", "STAT/DigitalBeam/HBA0", "STAT/TileBeam/HBA0", - "STAT/AntennaField/HBA0", + "STAT/AFH/HBA0", ]: proxy = TestDeviceProxy(device) proxy.off() diff --git a/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py b/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py index 8034af77013f7bb936bf75813a32baa9d6974416..8dbac6cf32b1e848816300e1ec60dd3c77b7be08 100644 --- a/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py +++ b/tangostationcontrol/integration_test/digitalbeam_performance/test_digitalbeam_performance.py @@ -11,7 +11,10 @@ from integration_test.device_proxy import TestDeviceProxy from tango import DevState -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) from tangostationcontrol.common.constants import MAX_ANTENNA, N_beamlets_ctrl @@ -42,11 +45,12 @@ class TestDigitalbeamPerformance(base.IntegrationTestCase): sdpfirmware_proxies.append(TestDeviceProxy(f"STAT/SDPFirmware/{item}")) sdp_proxies.append(TestDeviceProxy(f"STAT/SDP/{item}")) beamlet_proxies.append(TestDeviceProxy(f"STAT/Beamlet/{item}")) - antenna_field_proxies.append(TestDeviceProxy(f"STAT/AntennaField/{item}")) beam_proxies.append(TestDeviceProxy(f"STAT/DigitalBeam/{item}")) if item[0] == "H": + antenna_field_proxies.append(TestDeviceProxy(f"STAT/AFH/{item}")) recv_proxies.append(TestDeviceProxy(f"STAT/RECV{item[0]}/H0")) elif item[0] == "L": + antenna_field_proxies.append(TestDeviceProxy(f"STAT/AFL/{item}")) recv_proxies.append(TestDeviceProxy(f"STAT/RECV{item[0]}/L0")) recv_proxies.append(TestDeviceProxy(f"STAT/RECV{item[0]}/L1")) diff --git a/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py b/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py index f1dca1038003eeebedaa1fcec2a5f67405d47a97..a48b7e60165f584a25b183ddd9d378765ccaf458 100644 --- a/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py +++ b/tangostationcontrol/integration_test/tilebeam_performance/test_tilebeam_performance.py @@ -10,7 +10,10 @@ from integration_test import base from integration_test.device_proxy import TestDeviceProxy from tango import DevState -from tangostationcontrol.devices.antennafield import AntennaQuality, AntennaUse +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AntennaQuality, + AntennaUse, +) from tangostationcontrol.common.constants import DEFAULT_N_HBA_TILES logger = logging.getLogger() @@ -36,7 +39,7 @@ class TestTilebeamPerformance(base.IntegrationTestCase): "Control_Children" ] for hba_device in hba_devices: - manager_children.append(f"STAT/AntennaField/{hba_device}") + manager_children.append(f"STAT/AFH/{hba_device}") manager_proxy.put_property({"Control_Children": manager_children}) # SDPFirmware and SDP must be ready before AntennaField @@ -57,7 +60,7 @@ class TestTilebeamPerformance(base.IntegrationTestCase): # Beam / Recv [HBA0, HBA1, HBA2, HBA3] for i, item in enumerate(hba_devices): recv_proxies.append(TestDeviceProxy(f"STAT/RECVH/{i+1}")) - antenna_field_proxies.append(TestDeviceProxy(f"STAT/AntennaField/{item}")) + antenna_field_proxies.append(TestDeviceProxy(f"STAT/AFH/{item}")) beam_proxies.append(TestDeviceProxy(f"STAT/TileBeam/{item}")) # Recv and AntennaField devices must be ready before TileBeam diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index 11f69814ceb864875cb806b9c2866c967febb782..be133876d3a99016db419ba89ad314506e049f67 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -41,7 +41,8 @@ console_scripts = l2ss-tilebeam = tangostationcontrol.devices.tilebeam:main l2ss-beamlet = tangostationcontrol.devices.sdp.beamlet:main l2ss-digitalbeam = tangostationcontrol.devices.sdp.digitalbeam:main - l2ss-antennafield = tangostationcontrol.devices.antennafield:main + l2ss-afh = tangostationcontrol.devices.antennafield.afh:main + l2ss-afl = tangostationcontrol.devices.antennafield.afl:main l2ss-boot = tangostationcontrol.devices.boot:main l2ss-station-manager = tangostationcontrol.devices.station_manager:main l2ss-docker = tangostationcontrol.devices.docker:main diff --git a/tangostationcontrol/tangostationcontrol/common/antennas.py b/tangostationcontrol/tangostationcontrol/common/antennas.py index 57da4aa0b12be087d914d68c9a014df5967c0775..a06e58984a085fa775154e75fd8cc530789c5046 100644 --- a/tangostationcontrol/tangostationcontrol/common/antennas.py +++ b/tangostationcontrol/tangostationcontrol/common/antennas.py @@ -2,6 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 import numpy +from tango import Util +from tangostationcontrol.common.case_insensitive_string import CaseInsensitiveString + def antenna_set_to_mask( antenna_set: str, @@ -33,3 +36,36 @@ def antenna_set_to_mask( f"Unsupported antenna mask with the following antenna set: {antenna_set}. \ Must be one of {antenna_setlist}" ) from exc + + +def device_member_to_full_device_name(device_member: str) -> str: + """Retrieve the correct full Tango device name based on the antenna type + + :param device_member: antennafield Tango device member (n.b. domain/family/member) + + :raises ValueError: raised if device_member does not contain the antenna keywords + + :return: a string with the correct Tango device full name + """ + util = Util.instance() + if CaseInsensitiveString("LBA") in CaseInsensitiveString(device_member): + return f"{util.get_ds_inst_name()}/AFL/{device_member}" + if CaseInsensitiveString("HBA") in CaseInsensitiveString(device_member): + return f"{util.get_ds_inst_name()}/AFH/{device_member}" + raise ValueError(f"Invalid value for antennafield parameter: {device_member}") + + +def device_member_to_antenna_type(device_member: str) -> str: + """Determine whether the antennafield device is HBA or LBA + + :param device_member: antennafield Tango device member (n.b. domain/family/member) + + :raises ValueError: raised if device_name does not contain the antenna keywords + + :return: a string with the correct antenna type + """ + if CaseInsensitiveString("LBA") in CaseInsensitiveString(device_member): + return "LBA" + if CaseInsensitiveString("HBA") in CaseInsensitiveString(device_member): + return "HBA" + raise ValueError(f"Invalid value for antennafield: {device_member}") diff --git a/tangostationcontrol/tangostationcontrol/common/calibration.py b/tangostationcontrol/tangostationcontrol/common/calibration.py index d484c1d8762337e54e1746de4f21a63aee2d4151..7128a36aacfc17a393a3b631c2b550945e9c3c24 100644 --- a/tangostationcontrol/tangostationcontrol/common/calibration.py +++ b/tangostationcontrol/tangostationcontrol/common/calibration.py @@ -19,6 +19,8 @@ from tangostationcontrol.common.constants import ( ) from tangostationcontrol.common.sdp import complex_to_weights from tangostationcontrol.common.type_checking import device_name_matches +from tangostationcontrol.common.antennas import device_member_to_antenna_type +from tangostationcontrol.common.case_insensitive_string import CaseInsensitiveString logger = logging.getLogger() @@ -123,12 +125,12 @@ class CalibrationManager: (N_pn, A_pn, N_pol, N_subbands) ) - antennafield_name = antenna_field.name().split("/")[2].upper() - antenna_type = antenna_field.Antenna_Type_R + antennafield_member = antenna_field.name().split("/")[2] + antenna_type = device_member_to_antenna_type(antennafield_member) rcu_bands = antenna_field.RCU_band_select_RW antenna_names = antenna_field.Antenna_Names_R - is_hba = antenna_type.upper() != "LBA" + is_hba = CaseInsensitiveString(antenna_type) != CaseInsensitiveString("LBA") def get_antenna_calibration(antenna_name: str, rcu_band: int): """Return the calibration values for the given antenna and RCU band.""" @@ -144,15 +146,18 @@ class CalibrationManager: table.observation_station, self._station_name ): raise ValueError( - f"Expected calibration table for station {self._station_name}, but got {table.observation_station} in calibration file {calibration_filename}" + f"Expected calibration table for station {self._station_name}, but got \ + {table.observation_station} in calibration file {calibration_filename}" ) try: return table.antennas[antenna_name] - except KeyError: + except KeyError as exc: raise ValueError( - f"Could not find calibration values for field {antennafield_name} antenna {antenna_name} (index {antenna_nr}) in calibration file {calibration_filename}" - ) + f"Could not find calibration values for field {antennafield_member} \ + antenna {antenna_name} (index {antenna_nr}) in calibration file \ + {calibration_filename}" + ) from exc for antenna_nr, (rcu_band_x, rcu_band_y) in enumerate(rcu_bands): fpga_nr, input_nr = antenna_to_sdp_mapping[antenna_nr] @@ -220,10 +225,10 @@ def dB_to_factor(dB: numpy.ndarray) -> numpy.ndarray: return 10 ** (dB / 10) -# SDP input delay calibration def calibrate_input_samples_delay( antenna_field: DeviceProxy, sdpfirmware: DeviceProxy, sdp: DeviceProxy ): + """SDP input delay calibration""" # Mapping [antenna] -> [fpga][input] antenna_to_sdp_mapping = antenna_field.Antenna_to_SDP_Mapping_R diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md index ae4e123bec1c7331945d25c91cd9f3bd31c58831..b60272af1274de2827fd22a689611afcb37db560 100644 --- a/tangostationcontrol/tangostationcontrol/devices/README.md +++ b/tangostationcontrol/tangostationcontrol/devices/README.md @@ -11,7 +11,7 @@ If a new device is added, it will (likely) need to be referenced in several plac - Adjust `docker-compose/jupyter-lab/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter-Lab, - Adjust `tangostationcontrol/tangostationcontrol/devices/boot.py` to add the device to the station initialisation sequence, - Adjust `tangostationcontrol/tangostationcontrol/devices/docker.py` to have the device container available as R and RW attributes, -- Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned (current _unused_ port value: 5730), a unique 58xx port for ZMQ events, and a unique 59xx port for ZMQ heartbeat +- Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned (current _unused_ port value: 5731), a unique 58xx port for ZMQ events, and a unique 59xx port for ZMQ heartbeat - Adjust `tangostationcontrol/setup.cfg` to add an entry point for the device in the package installation, - Add to `tangostationcontrol/tangostationcontrol/integration_test/default/devices/` to add an integration test, - Adjust `sbin/run_integration_test.sh` to have the device started when running the integration tests, diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield/__init__.py b/tangostationcontrol/tangostationcontrol/devices/antennafield/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..68ddd5cdc3efaa38e853aef337c08beb99c50c4c --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield/afh.py b/tangostationcontrol/tangostationcontrol/devices/antennafield/afh.py new file mode 100644 index 0000000000000000000000000000000000000000..c936853420b5ecbfe926f44d00005749e148f2b1 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield/afh.py @@ -0,0 +1,289 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +""" High Band Antenna Device Server for LOFAR2.0 + +""" + +from math import pi +import numpy + +# PyTango imports +from tango import ( + AttrWriteType, + DevVarFloatArray, + DevVarLongArray, +) +from tango.server import device_property, attribute, command + +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AF, +) +from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets +from tangostationcontrol.common.constants import ( + N_elements, + MAX_ANTENNA, + N_pol, + N_xyz, +) +from tangostationcontrol.devices.base_device_classes.mapper import ( + MappedAttribute, +) + +__all__ = ["AFH", "main"] + + +@device_logging_to_python() +class AFH(AF): + """ + AntennaField HBAT implements the logic of LOFAR2 High Band Antennas + """ + + ANTENNA_TYPE = "HBA" + + # ----- HBA properties + + HBAT_PQR_rotation_angles_deg = device_property( + doc='Rotation of each tile in the PQ plane ("horizontal") in degrees.', + dtype="DevVarFloatArray", + mandatory=False, + default_value=[0.0] * MAX_ANTENNA, + ) + + PQR_to_ETRS_rotation_matrix = device_property( + doc="Field-specific rotation matrix to convert PQR offsets to ETRS/ITRF " + "offsets.", + dtype="DevVarFloatArray", + mandatory=False, + default_value=numpy.array( + [ # PQR->ETRS rotation matrix for the core stations + [-0.1195951054, -0.7919544517, 0.5987530018], + [0.9928227484, -0.0954186800, 0.0720990002], + [0.0000330969, 0.6030782884, 0.7976820024], + ] + ).flatten(), + ) + + HBAT_base_antenna_offsets = device_property( + doc="Offsets of the antennas in a HBAT, with respect to its reference " + "center (16x3).", + dtype="DevVarFloatArray", + mandatory=False, + default_value=HBATAntennaOffsets.HBAT1_BASE_ANTENNA_OFFSETS.flatten(), + ) + + # see also https://github.com/lofar-astron/lofarimaging/blob/9672b52bb9be8f3405e6e3f85701175bdc4bf211/lofarimaging/singlestationutil.py#L43 + HBAT_single_element_selection_GENERIC_201512 = device_property( + doc="Which element to select when using a single dipole per tile " + "in the 'GENERIC_201512' strategy", + dtype="DevVarLongArray", + mandatory=False, + default_value=[ + 0, + 10, + 4, + 3, + 14, + 0, + 5, + 5, + 3, + 13, + 10, + 3, + 12, + 2, + 7, + 15, + 6, + 14, + 7, + 5, + 7, + 9, + 0, + 15, + ], + ) + + # ----- RECV mapping + + Power_to_RECV_mapping = device_property( + dtype=(numpy.int32,), + doc="The mapping of Antenna power lines to RECV mapping. Each RECV can " + "handle 96 inputs. The Antenna number is the index and the value shows " + "to which receiver device it is connected and on which input. The " + "first integer is the input. The second integer is the RECV id. " + "Example: [0, 3] = first receiver of property `Control_Children` with " + "input 3. -1 means that the Antenna is not connected. The property is " + "stored in a one dimensional structure. It needs to be reshaped to a " + "list of lists of two items.", + mandatory=False, + default_value=[-1] * MAX_ANTENNA * 2, + ) + + # ----- Generic information + + @attribute( + access=AttrWriteType.READ, + dtype=(numpy.int32,), + max_dim_x=MAX_ANTENNA, + ) + def HBAT_single_element_selection_GENERIC_201512_R(self): + return numpy.array( + self.HBAT_single_element_selection_GENERIC_201512, dtype=numpy.int32 + ) + + # ----- Attributes mapped on RECV + + HBAT_BF_delay_steps_R = MappedAttribute( + "HBAT_BF_delay_steps_R", + dtype=((numpy.int64,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + ) + HBAT_BF_delay_steps_RW = MappedAttribute( + "HBAT_BF_delay_steps_RW", + dtype=((numpy.int64,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + access=AttrWriteType.READ_WRITE, + ) + HBAT_LED_on_R = MappedAttribute( + "HBAT_LED_on_R", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + ) + HBAT_LED_on_RW = MappedAttribute( + "HBAT_LED_on_RW", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + access=AttrWriteType.READ_WRITE, + ) + HBAT_PWR_LNA_on_R = MappedAttribute( + "HBAT_PWR_LNA_on_R", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + ) + HBAT_PWR_LNA_on_RW = MappedAttribute( + "HBAT_PWR_LNA_on_RW", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + access=AttrWriteType.READ_WRITE, + ) + HBAT_PWR_on_R = MappedAttribute( + "HBAT_PWR_on_R", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + ) + HBAT_PWR_on_RW = MappedAttribute( + "HBAT_PWR_on_RW", + dtype=((bool,),), + max_dim_x=N_elements * N_pol, + max_dim_y=MAX_ANTENNA, + access=AttrWriteType.READ_WRITE, + ) + + # ----- Position information + + HBAT_antenna_ITRF_offsets_R = attribute( + access=AttrWriteType.READ, + doc="For each tile, the offsets of the antennas within that, " + 'in ITRF ("iHBADeltas"). True shape: nrtiles x 16 x 3.', + dtype=((numpy.float64,),), + max_dim_x=MAX_ANTENNA * N_xyz, + max_dim_y=MAX_ANTENNA, + ) + + def read_HBAT_antenna_ITRF_offsets_R(self): + """Returns the ITRF differences between the center of the tile and its + individual elements, which is a (nrtiles)x16x3 matrix (16 elements with 3 + ITRF coordinates each), returned as a (nrtiles)x48 matrix. + + This takes the relative offsets between the elements in the tiles as + described in HBAT_base_antenna_offsets. These offsets are in PQR space, + which is the plane of the station. The tiles are rotated locally in this + space according to the HBAT_PQR_rotation_angles_deg, and finally translated + into global ETRS coordinates using the PQR_to_ETRS_rotation_matrix. + + The relative ITRF offsets are the same as relative ETRS offsets. + + NB: In all of this, the absolute position of each tile is actually + irrelevant, as all the tiles lie on the same plane in ITRF.""" + + # the relative offsets between the elements is fixed in + # HBAT_base_antenna_offsets + base_antenna_offsets = numpy.array(self.HBAT_base_antenna_offsets).reshape( + N_elements, N_xyz + ) + + pqr_to_etrs_rotation_matrix = numpy.array( + self.PQR_to_ETRS_rotation_matrix + ).reshape(N_xyz, N_xyz) + + # each tile has its own rotation angle, resulting in different offsets per tile + all_offsets = numpy.array( + [ + HBATAntennaOffsets.ITRF_offsets( + base_antenna_offsets, + angle_deg * pi / 180, + pqr_to_etrs_rotation_matrix, + ) + for angle_deg in self.HBAT_PQR_rotation_angles_deg + ] + ) + + return all_offsets.reshape(-1, N_elements * N_xyz) + + # -------- + # Overloaded functions + # -------- + + # -------- + # Commands + # -------- + + @command(dtype_in=DevVarFloatArray, dtype_out=DevVarLongArray) + def calculate_HBAT_bf_delay_steps(self, delays: numpy.ndarray): + num_tiles = self.read_nr_antennas_R() + + delays = delays.reshape(num_tiles, N_elements) + + result_values = numpy.zeros((num_tiles, N_elements * N_pol), dtype=numpy.int64) + control_mapping = numpy.reshape(self.Control_to_RECV_mapping, (-1, N_pol)) + + for recv_idx, recv_proxy in enumerate(self.recv_proxies): + # collect all delays for this recv_proxy + recv_result_indices = numpy.where(control_mapping[:, 0] == (recv_idx + 1)) + recv_delays = delays[recv_result_indices] + + if not recv_result_indices: + # no RCUs are actually used from this recv_proxy + continue + + # convert them into delay steps + flatten_delay_steps = numpy.array( + recv_proxy.calculate_HBAT_bf_delay_steps(recv_delays.flatten()), + dtype=numpy.int64, + ) + delay_steps = numpy.reshape(flatten_delay_steps, (-1, N_elements * N_pol)) + + # write back into same positions we collected them from + result_values[recv_result_indices] = delay_steps + + return result_values.flatten() + + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the AntennaField module.""" + return entry(AFH, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield/afl.py b/tangostationcontrol/tangostationcontrol/devices/antennafield/afl.py new file mode 100644 index 0000000000000000000000000000000000000000..c9567405a150b132c3b38e89a60f1ba71e989907 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield/afl.py @@ -0,0 +1,55 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +""" Low Band Antenna Device Server for LOFAR2.0 + +""" +import numpy +from tango.server import device_property + +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python + +from tangostationcontrol.common.constants import MAX_ANTENNA +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( + AF, +) + +__all__ = ["AFL", "main"] + + +@device_logging_to_python() +class AFL(AF): + """ + AntennaField LBA implements the logic of LOFAR2 Low Band Antennas + """ + + ANTENNA_TYPE = "LBA" + + # ----- RECV mapping + + Power_to_RECV_mapping = device_property( + dtype=(numpy.int32,), + doc="The mapping of Antenna power lines to RECV mapping. Each RECV can " + "handle 96 inputs. The Antenna number is the index and the value shows " + "to which receiver device it is connected and on which input. The " + "first integer is the input. The second integer is the RECV id. " + "Example: [0, 3] = first receiver of property `Control_Children` with " + "input 3. -1 means that the Antenna is not connected. The property is " + "stored in a one dimensional structure. It needs to be reshaped to a " + "list of lists of two items.", + mandatory=False, + default_value=[-1] * MAX_ANTENNA * 2, + ) + + # -------- + # Overloaded functions + # -------- + + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the AntennaField module.""" + return entry(AFL, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/antennafield_device.py similarity index 76% rename from tangostationcontrol/tangostationcontrol/devices/antennafield.py rename to tangostationcontrol/tangostationcontrol/devices/base_device_classes/antennafield_device.py index 37309355de3390a6791d60d060b5df5ec0dd93e3..75433fd6d6445c2154be40f157b8648f5e3280b3 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/antennafield_device.py @@ -1,13 +1,12 @@ -# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) -# SPDX-License-Identifier: Apache-2.0 +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 -""" AntennaField Device Server for LOFAR2.0 +""" AntennaField Abstract Device Server for LOFAR2.0 """ import logging -from enum import IntEnum -from math import pi from typing import List, Dict +from enum import IntEnum import numpy @@ -15,8 +14,6 @@ import numpy from tango import ( AttrWriteType, DevVarBooleanArray, - DevVarFloatArray, - DevVarLongArray, DebugIt, ) from tango.server import device_property, attribute, command @@ -25,10 +22,8 @@ from tango.server import device_property, attribute, command from tangostationcontrol.beam.geo import ETRS_to_ITRF from tangostationcontrol.beam.geo import GEO_to_GEOHASH from tangostationcontrol.beam.geo import ITRF_to_GEO -from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets from tangostationcontrol.common.cables import cable_types from tangostationcontrol.common.constants import ( - N_elements, MAX_ANTENNA, N_pol, N_xyz, @@ -52,23 +47,28 @@ from tangostationcontrol.devices.types import DeviceTypes from tangostationcontrol.devices.base_device_classes.mapper import ( MappingKeys, MappedAttribute, - AntennaToRecvMapper, AntennaToSdpMapper, RecvDeviceWalker, + HBAToRecvMapper, + LBAToRecvMapper, ) logger = logging.getLogger() -__all__ = ["AntennaField", "main"] +__all__ = ["AF", "AntennaUse", "AntennaQuality", "main"] class AntennaUse(IntEnum): + """Enum representing the use for each antenna""" + AUTO = 0 # use antenna only if it's OK or SUSPICIOUS ON = 1 # force antenna to be on, regardless of quality OFF = 2 # force antenna to be off, regardless of quality class AntennaQuality(IntEnum): + """Enum representing the quality of each antenna""" + OK = 0 SUSPICIOUS = 1 BROKEN = 2 @@ -76,8 +76,13 @@ class AntennaQuality(IntEnum): @device_logging_to_python() -class AntennaField(LOFARDevice): - """Manages the antennas in a single antenna field, by acting as a +class AF(LOFARDevice): + """ + AntennaField Device is an abstract Device which serves as a common base + for HBA and LBA devices, containing all the common points and + the shared logic of these two devices. + + Manages the antennas in a single antenna field, by acting as a a mapping onto one or more RECV devices. The antenna field models a number of antennas, each of which @@ -108,7 +113,7 @@ class AntennaField(LOFARDevice): name for name in dir(cls) if isinstance(getattr(cls, name), MappedAttribute) ] for attr in mapped_attrs: - attr_instance = getattr(AntennaField, attr) + attr_instance = getattr(cls, attr) # check the variable 'mapping_device' if attr_instance.mapping_device == device_name: result.append(attr) @@ -137,14 +142,16 @@ class AntennaField(LOFARDevice): # ----- Antenna set Antenna_Sets = device_property( - doc="String representation of officially offered set of antennas, for use in digital beamforming.", + doc="String representation of officially offered set of antennas, " + "for use in digital beamforming.", dtype="DevVarStringArray", mandatory=False, default_value=["ALL"], ) Antenna_Set_Masks = device_property( - doc="String encoding of the corresponding antenna masks for the antennafield, for use in digital beamforming. Excludes calibration antennas.", + doc="String encoding of the corresponding antenna masks for the antennafield, " + "for use in digital beamforming. Excludes calibration antennas.", dtype="DevVarStringArray", mandatory=False, default_value=["1" * MAX_ANTENNA], @@ -168,13 +175,6 @@ class AntennaField(LOFARDevice): # ----- Antenna properties - Antenna_Type = device_property( - doc="Type of antenna in this field (LBA or HBA)", - dtype="DevString", - mandatory=False, - default_value="LBA", - ) - Antenna_Needs_Power = device_property( doc="Whether to provide power to each antenna (False for noise sources)", dtype="DevVarBooleanArray", @@ -242,70 +242,6 @@ class AntennaField(LOFARDevice): default_value=2015.5, ) - # ----- HBA properties - - HBAT_PQR_rotation_angles_deg = device_property( - doc='Rotation of each tile in the PQ plane ("horizontal") in degrees.', - dtype="DevVarFloatArray", - mandatory=False, - default_value=[0.0] * MAX_ANTENNA, - ) - - PQR_to_ETRS_rotation_matrix = device_property( - doc="Field-specific rotation matrix to convert PQR offsets to ETRS/ITRF " - "offsets.", - dtype="DevVarFloatArray", - mandatory=False, - default_value=numpy.array( - [ # PQR->ETRS rotation matrix for the core stations - [-0.1195951054, -0.7919544517, 0.5987530018], - [0.9928227484, -0.0954186800, 0.0720990002], - [0.0000330969, 0.6030782884, 0.7976820024], - ] - ).flatten(), - ) - - HBAT_base_antenna_offsets = device_property( - doc="Offsets of the antennas in a HBAT, with respect to its reference " - "center (16x3).", - dtype="DevVarFloatArray", - mandatory=False, - default_value=HBATAntennaOffsets.HBAT1_BASE_ANTENNA_OFFSETS.flatten(), - ) - - # see also https://github.com/lofar-astron/lofarimaging/blob/9672b52bb9be8f3405e6e3f85701175bdc4bf211/lofarimaging/singlestationutil.py#L43 - HBAT_single_element_selection_GENERIC_201512 = device_property( - doc="Which element to select when using a single dipole per tile in the 'GENERIC_201512' strategy", - dtype="DevVarLongArray", - mandatory=False, - default_value=[ - 0, - 10, - 4, - 3, - 14, - 0, - 5, - 5, - 3, - 13, - 10, - 3, - 12, - 2, - 7, - 15, - 6, - 14, - 7, - 5, - 7, - 9, - 0, - 15, - ], - ) - # ----- SDP mapping Antenna_to_SDP_Mapping = device_property( @@ -328,20 +264,6 @@ class AntennaField(LOFARDevice): # NB: the power line transports the X polarisation, # the control line transports the Y polarisation - Power_to_RECV_mapping = device_property( - dtype=(numpy.int32,), - doc="The mapping of Antenna power lines to RECV mapping. Each RECV can " - "handle 96 inputs. The Antenna number is the index and the value shows " - "to which receiver device it is connected and on which input. The " - "first integer is the input. The second integer is the RECV id. " - "Example: [0, 3] = first receiver of property `Control_Children` with " - "input 3. -1 means that the Antenna is not connected. The property is " - "stored in a one dimensional structure. It needs to be reshaped to a " - "list of lists of two items.", - mandatory=False, - default_value=[-1] * MAX_ANTENNA * 2, - ) - Control_to_RECV_mapping = device_property( dtype=(numpy.int32,), doc="The mapping of Antenna control lines to RECV mapping. Each RECV can " @@ -364,10 +286,6 @@ class AntennaField(LOFARDevice): # ----- Generic information - Antenna_Type_R = attribute( - doc="The type of antenna in this field (LBA or HBA).", - dtype=str, - ) Antenna_Names_R = attribute( access=AttrWriteType.READ, dtype=(str,), @@ -424,16 +342,6 @@ class AntennaField(LOFARDevice): self.PQR_to_ETRS_rotation_matrix, dtype=numpy.float64 ).reshape(3, 3) - @attribute( - access=AttrWriteType.READ, - dtype=(numpy.int32,), - max_dim_x=MAX_ANTENNA, - ) - def HBAT_single_element_selection_GENERIC_201512_R(self): - return numpy.array( - self.HBAT_single_element_selection_GENERIC_201512, dtype=numpy.int32 - ) - Frequency_Band_RW = attribute( doc="The selected frequency band of each polarisation of each antenna.", dtype=((str,),), @@ -522,58 +430,6 @@ class AntennaField(LOFARDevice): max_dim_x=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, ) - HBAT_BF_delay_steps_R = MappedAttribute( - "HBAT_BF_delay_steps_R", - dtype=((numpy.int64,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - ) - HBAT_BF_delay_steps_RW = MappedAttribute( - "HBAT_BF_delay_steps_RW", - dtype=((numpy.int64,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - access=AttrWriteType.READ_WRITE, - ) - HBAT_LED_on_R = MappedAttribute( - "HBAT_LED_on_R", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - ) - HBAT_LED_on_RW = MappedAttribute( - "HBAT_LED_on_RW", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - access=AttrWriteType.READ_WRITE, - ) - HBAT_PWR_LNA_on_R = MappedAttribute( - "HBAT_PWR_LNA_on_R", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - ) - HBAT_PWR_LNA_on_RW = MappedAttribute( - "HBAT_PWR_LNA_on_RW", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - access=AttrWriteType.READ_WRITE, - ) - HBAT_PWR_on_R = MappedAttribute( - "HBAT_PWR_on_R", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - ) - HBAT_PWR_on_RW = MappedAttribute( - "HBAT_PWR_on_RW", - dtype=((bool,),), - max_dim_x=N_elements * N_pol, - max_dim_y=MAX_ANTENNA, - access=AttrWriteType.READ_WRITE, - ) RCU_band_select_R = MappedAttribute( "RCU_band_select_R", dtype=((numpy.int64,),), @@ -652,6 +508,7 @@ class AntennaField(LOFARDevice): max_dim_x=2, max_dim_y=MAX_ANTENNA, ) + # ----- Attributes mapped on SDP FPGA_sdp_info_observation_id_R = MappedAttribute( @@ -704,15 +561,6 @@ class AntennaField(LOFARDevice): dtype=str, ) - HBAT_antenna_ITRF_offsets_R = attribute( - access=AttrWriteType.READ, - doc="For each tile, the offsets of the antennas within that, " - 'in ITRF ("iHBADeltas"). True shape: nrtiles x 16 x 3.', - dtype=((numpy.float64,),), - max_dim_x=MAX_ANTENNA * N_xyz, - max_dim_y=MAX_ANTENNA, - ) - Antenna_Reference_ITRF_R = attribute( access=AttrWriteType.READ, doc="Absolute reference position of each tile, in ITRF (XYZ)", @@ -747,9 +595,6 @@ class AntennaField(LOFARDevice): # Super must be called after variable assignment due to executing init_device! super().__init__(cl, name) - def read_Antenna_Type_R(self): - return self.Antenna_Type - def read_Antenna_Names_R(self): return self.Antenna_Names @@ -765,7 +610,7 @@ class AntennaField(LOFARDevice): ) def read_Frequency_Band_RW(self): - antenna_type = self.Antenna_Type + antenna_type = self.ANTENNA_TYPE # fetch settings from RECV, use X polarisation for reference rcu_band_select = self.read_attribute("RCU_band_select_RW") @@ -794,10 +639,10 @@ class AntennaField(LOFARDevice): f"Unsupported frequency band: {val}. Must be one of {list(bands)}." ) - if bands[val].antenna_type != self.Antenna_Type: + if bands[val].antenna_type != self.ANTENNA_TYPE: raise ValueError( f"Unsupported frequency band for our antenna type: {val} \ - is for {bands[val].antenna_type}, but we are {self.Antenna_Type}." + is for {bands[val].antenna_type}, but we are {self.ANTENNA_TYPE}." ) if ( @@ -859,8 +704,8 @@ class AntennaField(LOFARDevice): return numpy.array( [ [ - cable_types[cable].get_loss(self.Antenna_Type, rcu_band[0]), - cable_types[cable].get_loss(self.Antenna_Type, rcu_band[1]), + cable_types[cable].get_loss(self.ANTENNA_TYPE, rcu_band[0]), + cable_types[cable].get_loss(self.ANTENNA_TYPE, rcu_band[1]), ] if recv > 0 else [0, 0] @@ -930,46 +775,6 @@ class AntennaField(LOFARDevice): def read_Antenna_Field_Reference_GEOHASH_R(self): return GEO_to_GEOHASH(self.read_Antenna_Field_Reference_GEO_R()) - def read_HBAT_antenna_ITRF_offsets_R(self): - """Returns the ITRF differences between the center of the tile and its - individual elements, which is a (nrtiles)x16x3 matrix (16 elements with 3 - ITRF coordinates each), returned as a (nrtiles)x48 matrix. - - This takes the relative offsets between the elements in the tiles as - described in HBAT_base_antenna_offsets. These offsets are in PQR space, - which is the plane of the station. The tiles are rotated locally in this - space according to the HBAT_PQR_rotation_angles_deg, and finally translated - into global ETRS coordinates using the PQR_to_ETRS_rotation_matrix. - - The relative ITRF offsets are the same as relative ETRS offsets. - - NB: In all of this, the absolute position of each tile is actually - irrelevant, as all the tiles lie on the same plane in ITRF.""" - - # the relative offsets between the elements is fixed in - # HBAT_base_antenna_offsets - base_antenna_offsets = numpy.array(self.HBAT_base_antenna_offsets).reshape( - N_elements, N_xyz - ) - - pqr_to_etrs_rotation_matrix = numpy.array( - self.PQR_to_ETRS_rotation_matrix - ).reshape(N_xyz, N_xyz) - - # each tile has its own rotation angle, resulting in different offsets per tile - all_offsets = numpy.array( - [ - HBATAntennaOffsets.ITRF_offsets( - base_antenna_offsets, - angle_deg * pi / 180, - pqr_to_etrs_rotation_matrix, - ) - for angle_deg in self.HBAT_PQR_rotation_angles_deg - ] - ) - - return all_offsets.reshape(-1, N_elements * N_xyz) - def read_Antenna_Reference_ITRF_R(self): # provide ITRF coordinates if they were configured if self.Antenna_Reference_ITRF: @@ -999,6 +804,7 @@ class AntennaField(LOFARDevice): self.sdp_proxy = self.control.child(self.sdpfirmware_proxy.SDP_device_R) def __setup_recv_mapper(self): + """Initialise the RECV mapper based on the antenna type""" number_of_receivers = len(self.recv_proxies) # Reshape of mapping is needed because properties are stored in 1d arrays control_mapping = numpy.reshape(self.Control_to_RECV_mapping, (-1, 2)) @@ -1007,12 +813,20 @@ class AntennaField(LOFARDevice): MappingKeys.CONTROL: control_mapping, MappingKeys.POWER: power_mapping, } - self.__recv_mapper = AntennaToRecvMapper( - recv_mapping, - self.get_mapped_dimensions("RECV"), - number_of_receivers, - antenna_type=self.read_attribute("Antenna_Type_R"), - ) + if self.ANTENNA_TYPE == "HBA": + self.__recv_mapper = HBAToRecvMapper( + recv_mapping, + self.get_mapped_dimensions("RECV"), + number_of_receivers, + ) + elif self.ANTENNA_TYPE == "LBA": + self.__recv_mapper = LBAToRecvMapper( + recv_mapping, + self.get_mapped_dimensions("RECV"), + number_of_receivers, + ) + else: + raise ValueError def __setup_sdp_mapper(self): # Reshape of mapping is needed because properties are stored in 1d arrays @@ -1084,7 +898,7 @@ class AntennaField(LOFARDevice): self.configure_recv() self.configure_sdp() # Disable DAB filters for HBAs - if self.Antenna_Type == "HBA": + if self.ANTENNA_TYPE == "HBA": self.proxy.write_attribute( "RCU_DAB_filter_on_RW", [False] * self.read_nr_antennas_R(), @@ -1131,38 +945,6 @@ class AntennaField(LOFARDevice): def configure_sdp(self): """Configure SDP to process our antennas.""" - pass - - @command(dtype_in=DevVarFloatArray, dtype_out=DevVarLongArray) - def calculate_HBAT_bf_delay_steps(self, delays: numpy.ndarray): - num_tiles = self.read_nr_antennas_R() - - delays = delays.reshape(num_tiles, N_elements) - - result_values = numpy.zeros((num_tiles, N_elements * N_pol), dtype=numpy.int64) - control_mapping = numpy.reshape(self.Control_to_RECV_mapping, (-1, N_pol)) - - for recv_idx, recv_proxy in enumerate(self.recv_proxies): - # collect all delays for this recv_proxy - recv_result_indices = numpy.where(control_mapping[:, 0] == (recv_idx + 1)) - recv_delays = delays[recv_result_indices] - - if not recv_result_indices: - # no RCUs are actually used from this recv_proxy - continue - - # convert them into delay steps - flatten_delay_steps = numpy.array( - recv_proxy.calculate_HBAT_bf_delay_steps(recv_delays.flatten()), - dtype=numpy.int64, - ) - delay_steps = numpy.reshape(flatten_delay_steps, (-1, N_elements * N_pol)) - - # write back into same positions we collected them from - result_values[recv_result_indices] = delay_steps - - return result_values.flatten() - @command() @DebugIt() @only_in_states(DEFAULT_COMMAND_STATES) @@ -1188,5 +970,5 @@ class AntennaField(LOFARDevice): # Run server # ---------- def main(**kwargs): - """Main function of the ObservationControl module.""" - return entry(AntennaField, **kwargs) + """Main function of the AntennaField module.""" + return entry(AF, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/hierarchy_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/hierarchy_device.py index 364ee39f0bc5430e181492ae00bb4e584a9a5aaa..59facc1245071e3e1445a6962ea6606f1aefe265 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/hierarchy_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/hierarchy_device.py @@ -55,12 +55,12 @@ class AbstractHierarchyDevice: db = Database() - # Get servers: ['antennafield/STAT', 'digitalbeam/STAT', ...] + # Get servers: ['stationmanager/STAT', 'digitalbeam/STAT', ...] servers = db.get_server_list() devices = [] - # Find each device through devices per server: ['STAT/antennafield/HBA', ... ] + # Find each device through devices per server: ['STAT/DigitalBeam/HBA', ... ] for server in servers: devices.extend(db.get_device_name(server, server.split("/")[0])) diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py index 56d91572f08b150d66e46f9d5d5582af402885ac..79b459eac2bb278694aac09256241da0a2f0afd9 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py @@ -25,7 +25,13 @@ from tangostationcontrol.common.type_checking import type_not_sequence from tangostationcontrol.devices.recv.recvh import RECVH from tangostationcontrol.devices.sdp.sdp import SDP -__all__ = ["AntennaMapper", "AntennaToRecvMapper", "AntennaToSdpMapper"] +__all__ = [ + "AntennaMapper", + "AntennaToRecvMapper", + "AntennaToSdpMapper", + "HBAToRecvMapper", + "LBAToRecvMapper", +] class MappingKeys(Enum): @@ -295,7 +301,11 @@ class AntennaToSdpMapper(AntennaMapper): _VALUE_MAP_NONE_16 = numpy.full(N_pn, None) - def __init__(self, mapping_dict, mapped_dimensions) -> None: + def __init__( + self, + mapping_dict: Dict[str, numpy.ndarray], + mapped_dimensions: Dict[str, tuple], + ) -> None: super().__init__(mapping_dict) self._fpga_mapping = self._mapping_dict[MappingKeys.FPGA] @@ -329,7 +339,11 @@ class AntennaToRecvMapper(AntennaMapper): _VALUE_MAP_NONE_96_2 = numpy.full((MAX_ANTENNA, 2), None) def __init__( - self, mapping_dict, mapped_dimensions, number_of_receivers, antenna_type + self, + mapping_dict: Dict[str, numpy.ndarray], + mapped_dimensions: Dict[str, tuple], + number_of_receivers: Optional[int] = 1, + antenna_type: str = "HBA", ): super().__init__(mapping_dict, number_of_receivers, antenna_type) @@ -461,6 +475,36 @@ class AntennaToRecvMapper(AntennaMapper): return value_mapper +class LBAToRecvMapper(AntennaToRecvMapper): + """Class that sets a mapping between RECVs and LBA attributes""" + + def __init__( + self, + mapping_dict: Dict[str, numpy.ndarray], + mapped_dimensions: Dict[str, tuple], + number_of_receivers: Optional[int] = 1, + antenna_type="LBA", + ): + super().__init__( + mapping_dict, mapped_dimensions, number_of_receivers, antenna_type + ) + + +class HBAToRecvMapper(AntennaToRecvMapper): + """Class that sets a mapping between RECVs and HBA attributes""" + + def __init__( + self, + mapping_dict: Dict[str, numpy.ndarray], + mapped_dimensions: Dict[str, tuple], + number_of_receivers: Optional[int] = 1, + antenna_type="HBA", + ): + super().__init__( + mapping_dict, mapped_dimensions, number_of_receivers, antenna_type + ) + + class RecvDeviceWalker(object): """Walks over child devices with the appropriate mask set to affect the hardware under the parent's control..""" diff --git a/tangostationcontrol/tangostationcontrol/devices/calibration.py b/tangostationcontrol/tangostationcontrol/devices/calibration.py index df7c1ec31a3b50be659989098addc3f40c824502..238d09cfbfee87ad17b5e59506b0b3c34b0333bd 100644 --- a/tangostationcontrol/tangostationcontrol/devices/calibration.py +++ b/tangostationcontrol/tangostationcontrol/devices/calibration.py @@ -16,7 +16,10 @@ from tangostationcontrol.common.calibration import ( calibrate_RCU_attenuator_dB, calibrate_input_samples_delay, ) -from tangostationcontrol.common.case_insensitive_dict import CaseInsensitiveDict +from tangostationcontrol.common.case_insensitive_dict import ( + CaseInsensitiveDict, + CaseInsensitiveString, +) from tangostationcontrol.common.entrypoint import entry from tangostationcontrol.common.lofar_logging import ( device_logging_to_python, @@ -25,7 +28,8 @@ from tangostationcontrol.common.lofar_logging import ( from tangostationcontrol.common.proxy import create_device_proxy from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES from tangostationcontrol.common.type_checking import device_name_matches -from tangostationcontrol.devices.antennafield import AntennaField +from tangostationcontrol.devices.antennafield.afl import AFL +from tangostationcontrol.devices.antennafield.afh import AFH from tangostationcontrol.devices.device_decorators import only_in_states from tangostationcontrol.devices.base_device_classes.lofar_device import LOFARDevice from tangostationcontrol.devices.sdp.sdp import SDP @@ -44,6 +48,8 @@ class Calibration(LOFARDevice): self.event_subscriptions: list = [] self.sdpfirmware_proxies: CaseInsensitiveDict = CaseInsensitiveDict() self.sdp_proxies: CaseInsensitiveDict = CaseInsensitiveDict() + self.hba_proxies: CaseInsensitiveDict = CaseInsensitiveDict() + self.lba_proxies: CaseInsensitiveDict = CaseInsensitiveDict() self.ant_proxies: CaseInsensitiveDict = CaseInsensitiveDict() self.last_ant_calibration_timestamp: CaseInsensitiveDict[ str, datetime.datetime | None @@ -243,22 +249,32 @@ class Calibration(LOFARDevice): ) db = Database() - devices = db.get_device_exported_for_class(AntennaField.__name__) + devices = db.get_device_exported_for_class(AFH.__name__) + self.hba_proxies = { + CaseInsensitiveString(d): create_device_proxy(d) for d in devices + } for d in devices: - logger.debug(f"Found antenna field device {d}") - - self.ant_proxies[d] = create_device_proxy(d) + logger.debug("found HBA antenna field device %s", str(d)) self.last_ant_calibration_timestamp[d] = None + devices = db.get_device_exported_for_class(AFL.__name__) + self.lba_proxies = { + CaseInsensitiveString(d): create_device_proxy(d) for d in devices + } + for d in devices: + logger.debug("found LBA antenna field device %s", str(d)) + + self.ant_proxies = CaseInsensitiveDict({**self.hba_proxies, **self.lba_proxies}) + devices = db.get_device_exported_for_class(SDPFirmware.__name__) for d in devices: - logger.debug(f"Dound SDP firmware device {d}") + logger.debug("Found SDP firmware device %s", str(d)) self.sdpfirmware_proxies[d] = create_device_proxy(d) devices = db.get_device_exported_for_class(SDP.__name__) for d in devices: - logger.debug(f"Found SDP device {d}") + logger.debug("Found SDP device %s", (d)) self.sdp_proxies[d] = create_device_proxy(d) diff --git a/tangostationcontrol/tangostationcontrol/devices/docker.py b/tangostationcontrol/tangostationcontrol/devices/docker.py index 4778b61aa86a1cdb5ab17448651767428d5ee5f3..a308132a7d674f0c066dd0af263e04ff409bc147 100644 --- a/tangostationcontrol/tangostationcontrol/devices/docker.py +++ b/tangostationcontrol/tangostationcontrol/devices/docker.py @@ -212,11 +212,19 @@ class Docker(LOFARDevice): ) # Beam devices - device_antennafield_R = AttributeWrapper( - comms_annotation={"container": "device-antennafield"}, datatype=bool + device_hba_R = AttributeWrapper( + comms_annotation={"container": "device-afh"}, datatype=bool ) - device_antennafield_RW = AttributeWrapper( - comms_annotation={"container": "device-antennafield"}, + device_hba_RW = AttributeWrapper( + comms_annotation={"container": "device-afh"}, + datatype=bool, + access=AttrWriteType.READ_WRITE, + ) + device_lba_R = AttributeWrapper( + comms_annotation={"container": "device-afl"}, datatype=bool + ) + device_lba_RW = AttributeWrapper( + comms_annotation={"container": "device-afl"}, datatype=bool, access=AttrWriteType.READ_WRITE, ) diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py index 9e35080a3028bc119d14c556f28262dcc26d6c95..4962f4f5445cc59528ccb324c6e091a2fff97259 100644 --- a/tangostationcontrol/tangostationcontrol/devices/observation.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation.py @@ -24,6 +24,7 @@ from tangostationcontrol.common.entrypoint import entry from tangostationcontrol.common.lofar_logging import device_logging_to_python from tangostationcontrol.common.lofar_logging import log_exceptions from tangostationcontrol.common.proxy import create_device_proxy +from tangostationcontrol.common.antennas import device_member_to_full_device_name from tangostationcontrol.configuration import ObservationSettings from tangostationcontrol.devices.device_decorators import fault_on_error from tangostationcontrol.devices.device_decorators import only_in_states @@ -308,12 +309,10 @@ class Observation(LOFARDevice): # This could change when the parameter check becomes depending on # certain aspects that only an Observation device can know. - antennafield = self._observation_settings.antenna_field - util = Util.instance() - + antennafield = self._observation_settings.antenna_field self.antennafield_proxy = create_device_proxy( - f"{util.get_ds_inst_name()}/AntennaField/{antennafield}" + device_member_to_full_device_name(antennafield) ) # Set a reference of Beamlet device that is correlated to this device diff --git a/tangostationcontrol/tangostationcontrol/devices/types.py b/tangostationcontrol/tangostationcontrol/devices/types.py index 927bad643e6ec130a17369fe4a41c860649fd685..d6054a932a4b9abc0362588c3d3ba14fbb9fb2b7 100644 --- a/tangostationcontrol/tangostationcontrol/devices/types.py +++ b/tangostationcontrol/tangostationcontrol/devices/types.py @@ -11,7 +11,8 @@ class DeviceTypes(str, Enum): finding each class that inherits LOFARDevice. Todo? """ - AntennaField = "AntennaField" + AFH = "AFH" + AFL = "AFL" APS = "APS" APSCT = "APSCT" APSPU = "APSPU" diff --git a/tangostationcontrol/test/beam/test_geo.py b/tangostationcontrol/test/beam/test_geo.py index 9b9dcce6ff0af4d217c727472b40a5a02805d6d5..c2d61d60609b91aa44b05cb8df04eeec49cda351 100644 --- a/tangostationcontrol/test/beam/test_geo.py +++ b/tangostationcontrol/test/beam/test_geo.py @@ -1,12 +1,11 @@ # Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) # SPDX-License-Identifier: Apache-2.0 +from test import base import numpy.testing from tangostationcontrol.beam.geo import ETRS_to_ITRF, ETRS_to_GEO, GEO_to_GEOHASH -from test import base - class TestETRSToITRF(base.TestCase): def test_convert_single_coordinate(self): diff --git a/tangostationcontrol/test/common/test_calibration.py b/tangostationcontrol/test/common/test_calibration.py index 40cb48f5f99aa2fd18e408db45fdb73d635578ab..a87b4dc6553994e2d7c31a334a20d0318e8e894a 100644 --- a/tangostationcontrol/test/common/test_calibration.py +++ b/tangostationcontrol/test/common/test_calibration.py @@ -3,6 +3,7 @@ import os from os import path from unittest.mock import patch, Mock, call, PropertyMock +from test import base import numpy from numpy.testing import assert_array_equal @@ -16,7 +17,6 @@ from tangostationcontrol.common.calibration import ( ) from tangostationcontrol.common.constants import S_pn, N_subbands, N_pn, SDP_UNIT_WEIGHT from tangostationcontrol.common.sdp import complex_to_weights -from test import base class MockMinio: @@ -31,6 +31,8 @@ class MockMinio: clear=True, ) class TestCalibrationManager(base.TestCase): + """Test class for Calibration Manager""" + def test_sync_calibration_tables(self, minio): minio.return_value.list_objects.return_value = [ Mock(object_name="/unittest-station/file1.h5"), @@ -73,9 +75,8 @@ class TestCalibrationManager(base.TestCase): [[1, 1], [1, 2]], dtype=numpy.int32 ).reshape(-1, 2), Antenna_Names_R=[f"T{n + 1}" for n in range(2)], - Antenna_Type_R="HBA", RCU_band_select_RW=numpy.array([[1, 1], [2, 2]]), - **{"name.return_value": "Stat/AntennaField/TEST"}, + **{"name.return_value": "Stat/AFH/HBA0"}, ) subband_weights = numpy.array([[SDP_UNIT_WEIGHT] * S_pn * N_subbands] * N_pn) diff --git a/tangostationcontrol/test/common/test_lofar_logging.py b/tangostationcontrol/test/common/test_lofar_logging.py index e2fbdda8574296ec63f065b5298c622e8546e176..1b262b561775ec7f66fefa27417497fcae702d68 100644 --- a/tangostationcontrol/test/common/test_lofar_logging.py +++ b/tangostationcontrol/test/common/test_lofar_logging.py @@ -7,7 +7,7 @@ from test import base from tango import DevFailed from tango.test_context import DeviceTestContext from tangostationcontrol.common import lofar_logging -from tangostationcontrol.devices import antennafield +from tangostationcontrol.devices.antennafield import afh class TestExceptionToStr(base.TestCase): @@ -25,9 +25,7 @@ class TestExceptionToStr(base.TestCase): # Simulate DevFailed exception try: - with DeviceTestContext( - antennafield.AntennaField, properties={}, process=True - ) as proxy: + with DeviceTestContext(afh.AFH, properties={}, process=True) as proxy: proxy.boot() except DevFailed as ex: original_exc = str(ex) diff --git a/tangostationcontrol/test/devices/antennafield/__init__.py b/tangostationcontrol/test/devices/antennafield/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..68ddd5cdc3efaa38e853aef337c08beb99c50c4c --- /dev/null +++ b/tangostationcontrol/test/devices/antennafield/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 diff --git a/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/test/devices/antennafield/test_afh_device.py similarity index 79% rename from tangostationcontrol/test/devices/test_antennafield_device.py rename to tangostationcontrol/test/devices/antennafield/test_afh_device.py index fa54603431e74bf7b67e847ccdda6bf161ce649d..36aa5cf9011c0d746676c8fbdaf02cadbae36112 100644 --- a/tangostationcontrol/test/devices/test_antennafield_device.py +++ b/tangostationcontrol/test/devices/antennafield/test_afh_device.py @@ -18,22 +18,22 @@ from tangostationcontrol.common.constants import ( DEFAULT_N_HBA_TILES, N_pn, ) -from tangostationcontrol.devices import antennafield -from tangostationcontrol.devices.antennafield import ( +from tangostationcontrol.devices.antennafield import afh +from tangostationcontrol.devices.base_device_classes.antennafield_device import ( AntennaQuality, AntennaUse, - AntennaField, ) +from tangostationcontrol.devices.antennafield.afh import AFH from tangostationcontrol.devices.base_device_classes.mapper import ( MappingKeys, - AntennaToRecvMapper, + HBAToRecvMapper, AntennaToSdpMapper, ) logger = logging.getLogger() -SDP_MAPPED_ATTRS = AntennaField.get_mapped_dimensions("SDP") -RECV_MAPPED_ATTRS = AntennaField.get_mapped_dimensions("RECV") +SDP_MAPPED_ATTRS = AFH.get_mapped_dimensions("SDP") +RECV_MAPPED_ATTRS = AFH.get_mapped_dimensions("RECV") DEFAULT_N_LBA = DEFAULT_N_HBA_TILES # 48 antennas @@ -150,106 +150,7 @@ class TestAntennaToSdpMapper(base.TestCase): numpy.testing.assert_equal(expected, actual) -class TestLBAToRecvMapper(base.TestCase): - """Test class for AntennaToRecvMapper with LBA AntennaType""" - - # A mapping where Antennas are all not mapped to power RCUs - POWER_NOT_CONNECTED = [[-1, -1]] * 2 * DEFAULT_N_LBA - # A mapping where Antennas are all not mapped to control RCUs - CONTROL_NOT_CONNECTED = [[-1, -1]] * 2 * DEFAULT_N_LBA - # A mapping where first two Antennas are mapped on the first Receiver. - # The first Antenna control line on RCU 1 and the second Antenna control line - # on RCU 0. - POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 = ( - [[1, 1], [1, 0]] - + [[-1, -1]] * (DEFAULT_N_LBA - 2) - + [[2, 1], [2, 0]] - + [[-1, -1]] * (DEFAULT_N_LBA - 2) - ) - CONTROL_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 = ( - POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 - ) - ANTENNA_TYPE = "LBA" - - def test_map_write_rcu_pwr_ant_on_no_mapping_and_one_receiver(self): - recv_mapping = { - MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, - MappingKeys.POWER: self.POWER_NOT_CONNECTED, - } - mapper = AntennaToRecvMapper( - recv_mapping, - RECV_MAPPED_ATTRS, - 1, - self.ANTENNA_TYPE, - ) - - set_values = [None] * DEFAULT_N_LBA - expected = [[[None, None, None]] * N_rcu] - actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) - numpy.testing.assert_equal(expected, actual) - - def test_map_write_rcu_pwr_ant_on_no_mapping_and_two_receivers(self): - recv_mapping = { - MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, - MappingKeys.POWER: self.POWER_NOT_CONNECTED, - } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) - - set_values = [None] * DEFAULT_N_LBA - expected = [[[None, None, None]] * N_rcu] * 2 - actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) - numpy.testing.assert_equal(expected, actual) - - def test_map_write_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1_and_no_ctrl( - self, - ): - recv_mapping = { - MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, - MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, - } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) - - set_values = [1, 0] + [None] * (DEFAULT_N_LBA - 2) - expected = [[[None, None, None]] + [[None, None, None]] * (N_rcu - 1)] - actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) - numpy.testing.assert_equal(expected, actual) - - def test_map_read_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): - recv_mapping = { - MappingKeys.CONTROL: self.CONTROL_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, - MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, - } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) - - receiver_values = [[False, True] + [False] * (MAX_ANTENNA - 2)] * 2 - expected = ([True, False] + [False] * (int(MAX_ANTENNA / 2) - 2)) * 2 - actual = mapper.map_read("RCU_PWR_ANT_on_R", receiver_values) - numpy.testing.assert_equal(expected, actual) - - def test_map_write_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): - recv_mapping = { - MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, - MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, - } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) - - set_values = [1, 0] + [None] * (DEFAULT_N_LBA - 2) - expected = [[[None, None, None]] * N_rcu] - actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) - numpy.testing.assert_equal(expected, actual) - - class TestHBAToRecvMapper(base.TestCase): - """Test class for AntennaToRecvMapper with HBA AntennaType""" - # A mapping where Antennas are all not mapped to power RCUs POWER_NOT_CONNECTED = [[-1, -1]] * DEFAULT_N_HBA_TILES # A mapping where Antennas are all not mapped to control RCUs @@ -273,9 +174,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [False] * MAX_ANTENNA, @@ -291,9 +190,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [False, True, False] + [False, False, False] * (N_rcu - 1), @@ -310,9 +207,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [[0] * MAX_ANTENNA, [0] * MAX_ANTENNA, [0] * MAX_ANTENNA] expected = [[0, 0]] * DEFAULT_N_HBA_TILES actual = mapper.map_read("RCU_band_select_RW", receiver_values) @@ -323,9 +218,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[0] * N_rcu] * MAX_ANTENNA, @@ -341,9 +234,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[2] * N_rcu, [1] * N_rcu] + [[0] * N_rcu] * (MAX_ANTENNA - 2), @@ -362,9 +253,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[0] * N_rcu] * MAX_ANTENNA, @@ -380,9 +269,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[2] * N_rcu, [1] * N_rcu] + [[0] * N_rcu] * (MAX_ANTENNA - 2), @@ -401,9 +288,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -419,9 +304,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -441,9 +324,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -459,9 +340,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -481,9 +360,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -499,9 +376,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -521,9 +396,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -539,9 +412,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -561,9 +432,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -579,9 +448,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -601,9 +468,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False] * N_rcu] * MAX_ANTENNA, @@ -619,9 +484,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ [[False, True] * 16, [True, False] * 16] @@ -642,9 +505,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [list(range(32)), [0] * 32, [0] * 32] expected = [[0] * 2] * DEFAULT_N_HBA_TILES actual = mapper.map_read("RCU_PCB_ID_R", receiver_values) @@ -657,9 +518,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_3_AND_2_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [list(range(32)), [0] * 32, [0] * 32] expected = [[0, 3], [0, 2]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_PCB_ID_R", receiver_values) @@ -672,9 +531,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [list(range(32)), [0] * 32, [0] * 32] expected = [[1, 0], [0, 0]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_PCB_ID_R", receiver_values) @@ -687,9 +544,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_3_AND_2_OF_RECV_1, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [list(range(32)), [0] * 32, [0] * 32] expected = [[1, 3], [0, 2]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_PCB_ID_R", receiver_values) @@ -701,9 +556,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 3, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [ list(range(MAX_ANTENNA)), [0] * MAX_ANTENNA, @@ -720,9 +573,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) receiver_values = [list(range(MAX_ANTENNA))] expected = [[0, 1], [0, 0]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_attenuator_dB_R", receiver_values) @@ -735,9 +586,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) receiver_values = [list(range(MAX_ANTENNA))] expected = [[1, 0], [0, 0]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_attenuator_dB_R", receiver_values) @@ -750,9 +599,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_3_AND_2_OF_RECV_1, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) receiver_values = [list(range(MAX_ANTENNA))] expected = [[1, 3], [0, 2]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) actual = mapper.map_read("RCU_attenuator_dB_R", receiver_values) @@ -766,9 +613,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] @@ -781,9 +626,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] * 2 @@ -795,9 +638,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [True, False] + [None] * (DEFAULT_N_HBA_TILES - 2) expected = [[[False, True, None]] + [[None, None, None]] * (N_rcu - 1)] @@ -809,9 +650,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] @@ -823,9 +662,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] * 2 @@ -837,9 +674,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [1, 0] + [None] * (DEFAULT_N_HBA_TILES - 2) expected = [[[0, 1, None]] + [[None, None, None]] * (N_rcu - 1)] @@ -851,9 +686,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] @@ -865,9 +698,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [None] * DEFAULT_N_HBA_TILES expected = [[[None, None, None]] * N_rcu] * 2 @@ -879,9 +710,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1, 1], [0, 0]] + [[None, None]] * (DEFAULT_N_HBA_TILES - 2) expected = [[[0, 1, None]] + [[None, None, None]] * (N_rcu - 1)] @@ -893,9 +722,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA] @@ -907,9 +734,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [[1] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA, [[None] * N_rcu] * MAX_ANTENNA] @@ -921,9 +746,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1] * N_rcu, [2] * N_rcu] + [[None] * N_rcu] * ( DEFAULT_N_HBA_TILES - 2 @@ -937,9 +760,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA] @@ -951,9 +772,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA, [[None] * N_rcu] * MAX_ANTENNA] @@ -965,9 +784,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[False, True] * 16, [True, False] * 16] + [[None] * N_rcu] * ( DEFAULT_N_HBA_TILES - 2 @@ -984,9 +801,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA] @@ -998,9 +813,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA, [[None] * N_rcu] * MAX_ANTENNA] @@ -1012,9 +825,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[False, True] * 16, [True, False] * 16] + [[None] * N_rcu] * ( DEFAULT_N_HBA_TILES - 2 @@ -1031,9 +842,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA] actual = mapper.map_write("HBAT_PWR_on_RW", set_values) @@ -1044,9 +853,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 2, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 2) set_values = [[None] * N_rcu] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu] * MAX_ANTENNA, [[None] * N_rcu] * MAX_ANTENNA] @@ -1058,9 +865,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[False, True] * 16, [True, False] * 16] + [[None] * N_rcu] * ( DEFAULT_N_HBA_TILES - 2 @@ -1078,9 +883,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1, 1]] * DEFAULT_N_HBA_TILES expected = [[[None] * N_rcu_inp] * N_rcu] @@ -1095,9 +898,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, MappingKeys.POWER: self.POWER_NOT_CONNECTED, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1, 2], [3, 4]] + [[0, 0]] * (DEFAULT_N_HBA_TILES - 2) expected = [[[4, 2, None]] + [[None] * N_rcu_inp] * (N_rcu - 1)] @@ -1112,9 +913,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = set_values = [[1, 2], [3, 4]] + [[0, 0]] * ( DEFAULT_N_HBA_TILES - 2 @@ -1131,9 +930,7 @@ class TestHBAToRecvMapper(base.TestCase): MappingKeys.CONTROL: self.CONTROL_HBA_0_AND_1_ON_RCU_3_AND_2_OF_RECV_1, MappingKeys.POWER: self.POWER_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, } - mapper = AntennaToRecvMapper( - recv_mapping, RECV_MAPPED_ATTRS, 1, self.ANTENNA_TYPE - ) + mapper = HBAToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = set_values = [[1, 2], [3, 4]] + [[0, 0]] * ( DEFAULT_N_HBA_TILES - 2 @@ -1144,8 +941,8 @@ class TestHBAToRecvMapper(base.TestCase): numpy.testing.assert_equal(expected, actual) -class TestAntennafieldDevice(device_base.DeviceTestCase): - """Test class for AntennaField device""" +class TestHBADevice(device_base.DeviceTestCase): + """Test class for HBA device""" # some dummy values for mandatory properties AT_PROPERTIES = { @@ -1174,13 +971,13 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): def setUp(self): # DeviceTestCase setUp patches lofar_device DeviceProxy - super(TestAntennafieldDevice, self).setUp() + super(TestHBADevice, self).setUp() def test_read_Antenna_Field_Reference(self): """Verify if Antenna coordinates are correctly provided""" # Device uses ITRF coordinates by default with DeviceTestContext( - antennafield.AntennaField, properties=self.AT_PROPERTIES, process=True + afh.AFH, properties=self.AT_PROPERTIES, process=True ) as proxy: self.assertEqual(3.0, proxy.Antenna_Field_Reference_ITRF_R[0]) # Device derives coordinates from ETRS if ITRF ones are not found @@ -1193,7 +990,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): } with DeviceTestContext( - antennafield.AntennaField, properties=at_properties_v2, process=True + afh.AFH, properties=at_properties_v2, process=True ) as proxy: self.assertNotEqual( 3.0, proxy.Antenna_Field_Reference_ITRF_R[0] @@ -1203,7 +1000,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): """Verify if Antenna_Quality_R is correctly retrieved""" antenna_qualities = numpy.array([AntennaQuality.OK] * MAX_ANTENNA) with DeviceTestContext( - antennafield.AntennaField, properties=self.AT_PROPERTIES, process=False + afh.AFH, properties=self.AT_PROPERTIES, process=False ) as proxy: numpy.testing.assert_equal(antenna_qualities, proxy.Antenna_Quality_R) @@ -1211,7 +1008,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): """Verify if Antenna_Use_R is correctly retrieved""" antenna_use = numpy.array([AntennaUse.AUTO] * MAX_ANTENNA) with DeviceTestContext( - antennafield.AntennaField, properties=self.AT_PROPERTIES, process=False + afh.AFH, properties=self.AT_PROPERTIES, process=False ) as proxy: numpy.testing.assert_equal(antenna_use, proxy.Antenna_Use_R) @@ -1226,7 +1023,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): "Antenna_Use": antenna_use.tolist(), } with DeviceTestContext( - antennafield.AntennaField, + afh.AFH, properties={**self.AT_PROPERTIES, **antenna_properties}, process=False, ) as proxy: @@ -1247,7 +1044,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): "Antenna_Use": antenna_use.tolist(), } with DeviceTestContext( - antennafield.AntennaField, + afh.AFH, properties={**self.AT_PROPERTIES, **antenna_properties}, process=False, ) as proxy: @@ -1261,7 +1058,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): antenna_names = ["C0", "C1", "C2", "C3", "C4"] antenna_properties = {"Antenna_Names": antenna_names} with DeviceTestContext( - antennafield.AntennaField, + afh.AFH, properties={**self.AT_PROPERTIES, **antenna_properties}, process=False, ) as proxy: @@ -1271,7 +1068,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): def test_Antenna_Mask_all_antennas(self): """Verify if Antenna_Mask_R is correctly retrieved""" with DeviceTestContext( - antennafield.AntennaField, + afh.AFH, properties={**self.AT_PROPERTIES, **self.ANTENNA_PROPERTIES}, process=False, ) as proxy: @@ -1281,7 +1078,7 @@ class TestAntennafieldDevice(device_base.DeviceTestCase): def test_Antenna_Mask_half_antennas(self): """Verify if Antenna_Mask_R is correctly retrieved""" with DeviceTestContext( - antennafield.AntennaField, + afh.AFH, properties={**self.AT_PROPERTIES, **self.ANTENNA_PROPERTIES}, process=False, ) as proxy: diff --git a/tangostationcontrol/test/devices/antennafield/test_afl_device.py b/tangostationcontrol/test/devices/antennafield/test_afl_device.py new file mode 100644 index 0000000000000000000000000000000000000000..de2b1e5db0083f0cfa697c3486b50b43ebc80028 --- /dev/null +++ b/tangostationcontrol/test/devices/antennafield/test_afl_device.py @@ -0,0 +1,129 @@ +# Copyright (C) 2022 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +# invalid-name +# pylint: disable=C0103 + +import logging +from test import base + +import numpy + +from tangostationcontrol.common.constants import ( + N_rcu, + DEFAULT_N_HBA_TILES, + MAX_ANTENNA, +) +from tangostationcontrol.devices.antennafield.afl import AFL +from tangostationcontrol.devices.base_device_classes.mapper import ( + MappingKeys, + LBAToRecvMapper, +) + +logger = logging.getLogger() + +RECV_MAPPED_ATTRS = AFL.get_mapped_dimensions("RECV") +DEFAULT_N_LBA = DEFAULT_N_HBA_TILES # 48 antennas + + +class TestLBAToRecvMapper(base.TestCase): + """Test class for AntennaToRecvMapper with LBA AntennaType""" + + # A mapping where Antennas are all not mapped to power RCUs + POWER_NOT_CONNECTED = [[-1, -1]] * 2 * DEFAULT_N_LBA + # A mapping where Antennas are all not mapped to control RCUs + CONTROL_NOT_CONNECTED = [[-1, -1]] * 2 * DEFAULT_N_LBA + # A mapping where first two Antennas are mapped on the first Receiver. + # The first Antenna control line on RCU 1 and the second Antenna control line + # on RCU 0. + POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 = ( + [[1, 1], [1, 0]] + + [[-1, -1]] * (DEFAULT_N_LBA - 2) + + [[2, 1], [2, 0]] + + [[-1, -1]] * (DEFAULT_N_LBA - 2) + ) + CONTROL_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 = ( + POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1 + ) + + def test_map_write_rcu_pwr_ant_on_no_mapping_and_one_receiver(self): + recv_mapping = { + MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, + MappingKeys.POWER: self.POWER_NOT_CONNECTED, + } + mapper = LBAToRecvMapper( + recv_mapping, + RECV_MAPPED_ATTRS, + 1, + ) + + set_values = [None] * DEFAULT_N_LBA + expected = [[[None, None, None]] * N_rcu] + actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_write_rcu_pwr_ant_on_no_mapping_and_two_receivers(self): + recv_mapping = { + MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, + MappingKeys.POWER: self.POWER_NOT_CONNECTED, + } + mapper = LBAToRecvMapper( + recv_mapping, + RECV_MAPPED_ATTRS, + 2, + ) + + set_values = [None] * DEFAULT_N_LBA + expected = [[[None, None, None]] * N_rcu] * 2 + actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_write_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1_and_no_ctrl( + self, + ): + recv_mapping = { + MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, + MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, + } + mapper = LBAToRecvMapper( + recv_mapping, + RECV_MAPPED_ATTRS, + 1, + ) + + set_values = [1, 0] + [None] * (DEFAULT_N_LBA - 2) + expected = [[[None, None, None]] + [[None, None, None]] * (N_rcu - 1)] + actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_read_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + recv_mapping = { + MappingKeys.CONTROL: self.CONTROL_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, + MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, + } + mapper = LBAToRecvMapper( + recv_mapping, + RECV_MAPPED_ATTRS, + 2, + ) + + receiver_values = [[False, True] + [False] * (MAX_ANTENNA - 2)] * 2 + expected = ([True, False] + [False] * (int(MAX_ANTENNA / 2) - 2)) * 2 + actual = mapper.map_read("RCU_PWR_ANT_on_R", receiver_values) + numpy.testing.assert_equal(expected, actual) + + def test_map_write_rcu_pwr_ant_on_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self): + recv_mapping = { + MappingKeys.CONTROL: self.CONTROL_NOT_CONNECTED, + MappingKeys.POWER: self.POWER_LBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, + } + mapper = LBAToRecvMapper( + recv_mapping, + RECV_MAPPED_ATTRS, + 1, + ) + + set_values = [1, 0] + [None] * (DEFAULT_N_LBA - 2) + expected = [[[None, None, None]] * N_rcu] + actual = mapper.map_write("RCU_PWR_ANT_on_RW", set_values) + numpy.testing.assert_equal(expected, actual) diff --git a/tangostationcontrol/test/devices/base_device_classes/test_hierarchy_device.py b/tangostationcontrol/test/devices/base_device_classes/test_hierarchy_device.py index 748996c57953d5d4a038ea43737fa5ea1e540c7f..0b67775e99a759dad5b6e9221e39e34a3b47c5b6 100644 --- a/tangostationcontrol/test/devices/base_device_classes/test_hierarchy_device.py +++ b/tangostationcontrol/test/devices/base_device_classes/test_hierarchy_device.py @@ -28,7 +28,7 @@ class TestHierarchyDevice(device_base.DeviceTestCase): """Test whether read_attribute really returns the attribute.""" TEST_PROPERTY_CHILDREN = "hierarchy_children" - TEST_DEVICE_NAME = "stat/antennafield/lba" + TEST_DEVICE_NAME = "stat/afl/lba" TEST_CHILD_DEVICE = "stat/sdp/lba" class MyHierarchyDevice( @@ -215,8 +215,8 @@ class TestHierarchyDevice(device_base.DeviceTestCase): test_children = ["stat/sdp/1", "stat/sdp/2"] # Calls to get_property follow depth-first order test_property_calls = [ - {self.TEST_PROPERTY_NAME: ["stat/antennafield/1"]}, # sdp/1 - {self.TEST_PROPERTY_NAME: ["stat/tilebeam/1"]}, # antennafield/1 + {self.TEST_PROPERTY_NAME: ["stat/afl/1"]}, # sdp/1 + {self.TEST_PROPERTY_NAME: ["stat/tilebeam/1"]}, # lba/1 {self.TEST_PROPERTY_NAME: []}, # tilebeam/1 {self.TEST_PROPERTY_NAME: []}, # sdp/2 ] @@ -225,15 +225,13 @@ class TestHierarchyDevice(device_base.DeviceTestCase): test = test_hierarchy.children(depth=depth) # Test that antennafield is included - self.assertIsNotNone( - test["stat/sdp/1"]["children"].get("stat/antennafield/1") - ) + self.assertIsNotNone(test["stat/sdp/1"]["children"].get("stat/afl/1")) # Test that antennafield child is removed due to depth limit self.assertEqual( 0, - len(test["stat/sdp/1"]["children"]["stat/antennafield/1"]["children"]), - msg=f'{test["stat/sdp/1"]["children"]["stat/antennafield/1"]["children"]}', + len(test["stat/sdp/1"]["children"]["stat/afl/1"]["children"]), + msg=f'{test["stat/sdp/1"]["children"]["stat/afl/1"]["children"]}', ) self.children_test_base( @@ -288,7 +286,7 @@ class TestHierarchyDevice(device_base.DeviceTestCase): "stat/notexist/*", hierarchy_device.HierarchyMatchingFilter.REGEX ) - TEST_CHILDREN_ROOT = ["stat/ccd/1", "stat/psoc/1", "stat/antennafield/1"] + TEST_CHILDREN_ROOT = ["stat/ccd/1", "stat/psoc/1", "stat/afl/lba"] TEST_CHILDREN_ANTENNAFIELD = [ "stat/sdp/1", @@ -309,7 +307,7 @@ class TestHierarchyDevice(device_base.DeviceTestCase): TEST_GET_PROPERTY_CALLS = [ {TEST_PROPERTY_NAME: []}, # cdd/1 {TEST_PROPERTY_NAME: []}, # psoc/1 - {TEST_PROPERTY_NAME: TEST_CHILDREN_ANTENNAFIELD}, # antennafield/1 + {TEST_PROPERTY_NAME: TEST_CHILDREN_ANTENNAFIELD}, # afl/1 {TEST_PROPERTY_NAME: TEST_CHILDREN_SDP}, # sdp/1 {TEST_PROPERTY_NAME: []}, # xst/1 {TEST_PROPERTY_NAME: []}, # sst/1 @@ -344,43 +342,39 @@ class TestHierarchyDevice(device_base.DeviceTestCase): ) # Test antennafield has 4 children - self.assertEqual(4, len(test["stat/antennafield/1"]["children"])) + self.assertEqual(4, len(test["stat/afl/lba"]["children"])) # Test sdp has 3 children self.assertEqual( 3, - len(test["stat/antennafield/1"]["children"]["stat/sdp/1"]["children"]), + len(test["stat/afl/lba"]["children"]["stat/sdp/1"]["children"]), ) # Test all childs of sdp have no children for sdp_child in self.TEST_CHILDREN_SDP: - data = test["stat/antennafield/1"]["children"]["stat/sdp/1"][ - "children" - ][sdp_child]["children"] + data = test["stat/afl/lba"]["children"]["stat/sdp/1"]["children"][ + sdp_child + ]["children"] self.assertEqual(0, len(data), msg=f"{data}") # Test tilebeam has no children - data = test["stat/antennafield/1"]["children"]["stat/tilebeam/1"][ - "children" - ] + data = test["stat/afl/lba"]["children"]["stat/tilebeam/1"]["children"] self.assertEqual(0, len(data), msg=f"{data}") # Test digitalbeam has 1 child - data = test["stat/antennafield/1"]["children"]["stat/digitalbeam/1"][ - "children" - ] + data = test["stat/afl/lba"]["children"]["stat/digitalbeam/1"]["children"] self.assertEqual(1, len(data), msg=f"{data}") # Test beamlet has no children - data = test["stat/antennafield/1"]["children"]["stat/digitalbeam/1"][ - "children" - ]["stat/beamlet/1"]["children"] + data = test["stat/afl/lba"]["children"]["stat/digitalbeam/1"]["children"][ + "stat/beamlet/1" + ]["children"] self.assertEqual(0, len(data), msg=f"{data}") # Test aps has 5 children self.assertEqual( 5, - len(test["stat/antennafield/1"]["children"]["stat/aps/1"]["children"]), + len(test["stat/afl/lba"]["children"]["stat/aps/1"]["children"]), ) # Test all childs of aps have no children @@ -388,9 +382,9 @@ class TestHierarchyDevice(device_base.DeviceTestCase): self.assertEqual( 0, len( - test["stat/antennafield/1"]["children"]["stat/aps/1"][ - "children" - ][aps_child]["children"] + test["stat/afl/lba"]["children"]["stat/aps/1"]["children"][ + aps_child + ]["children"] ), )