diff --git a/README.md b/README.md index 01a1f0f3bd5346be3abfee03e1ef89fc4290066f..65d47484fa671a49ac39671844c6f8801ba4c38d 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,8 @@ Next change the version in the following places: # Release Notes +* 0.32.2 Change hardware_powered_R to hardware_powered_fraction_R to report partial power. + Implemented hardware_powered_fraction_R for more devices. * 0.32.1 Do not serve stale metrics * 0.32.0 Add available_in_power_state_R attribute to determine from which station state a device will be available * 0.31.4 Bugfixes for DTS configuration, diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION index fd9620c08c1510d4be7d653d09b499dec0f4eb20..989b29cc323f5dacffba2e29082af6e69efafb82 100644 --- a/tangostationcontrol/VERSION +++ b/tangostationcontrol/VERSION @@ -1 +1 @@ -0.32.1 +0.32.2 diff --git a/tangostationcontrol/tangostationcontrol/devices/apsct.py b/tangostationcontrol/tangostationcontrol/devices/apsct.py index b17a82068d51fae576c317861e4e409afdfd80fa..7c7c1890e17719bbecdd180ecc221c730636cc84 100644 --- a/tangostationcontrol/tangostationcontrol/devices/apsct.py +++ b/tangostationcontrol/tangostationcontrol/devices/apsct.py @@ -204,9 +204,9 @@ class APSCT(OPCUADevice): # overloaded functions # -------- - def _read_hardware_powered_R(self): + def _read_hardware_powered_fraction_R(self): """Read attribute which monitors the power""" - return self.read_attribute("APSCT_PWR_on_R") + return 1.0 * self.read_attribute("APSCT_PWR_on_R") def _power_hardware_on(self): """Turns on the 200MHz clock.""" diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py index ddb2773d64810c3c5174d6677a918706deb7e338..5122e67ec89fe71cb107ccd106903f3f8600469b 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/beam_device.py @@ -156,14 +156,14 @@ class BeamDevice(AsyncDevice): Tracking_enabled_R = attribute( access=AttrWriteType.READ, - doc="Whether the tile beam is updated periodically", + doc="Whether the beam is updated periodically", dtype=bool, fget=lambda self: bool(self.Beam_tracker and self.Beam_tracker.is_alive()), ) Tracking_enabled_RW = attribute( access=AttrWriteType.READ_WRITE, - doc="Whether the tile beam should be updated periodically", + doc="Whether the beam should be updated periodically", dtype=bool, fget=lambda self: self._tracking_enabled_rw, ) @@ -218,7 +218,7 @@ class BeamDevice(AsyncDevice): # store the new values self._beam_manager.new_pointing_direction = numpy.array(value, dtype="<U32") - # force update across tiles if pointing changes + # force update if pointing changes self.Beam_tracker.force_update() logger.info("Pointing direction update requested") @@ -234,6 +234,10 @@ class BeamDevice(AsyncDevice): # overloaded functions # -------- + async def _read_hardware_powered_fraction_R(self): + # We consider 'powered' if the beam tracker is running + return 1.0 * await self.async_read_attribute("Tracking_enabled_R") + def _init_device(self, beam_manager: AbstractBeamManager): super()._init_device() diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py index 8a8ede8e7f9ffcca30b4351a2268ded4b350722f..406046c857acf894c7186d84f4b85721e46823e2 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/lofar_device.py @@ -226,9 +226,11 @@ class LOFARDevice(Device): fget=lambda self: numpy.int64(self._access_count), ) - hardware_powered_R = attribute( - dtype=bool, - fget=lambda self: self._read_hardware_powered_R(), + hardware_powered_fraction_R = attribute( + doc="Fraction of hardware that is powered on (0 = nothing, 1 = all).", + dtype=numpy.float64, + fget=lambda self: self._read_hardware_powered_fraction_R(), + fisallowed="is_attribute_access_allowed", ) event_thread_running_R = attribute( @@ -647,11 +649,11 @@ class LOFARDevice(Device): # increase the number of accesses self._access_count += 1 - def _read_hardware_powered_R(self): - """Overloadable function called in read attribute hardware_powered_R""" + def _read_hardware_powered_fraction_R(self): + """Overloadable function called to ask whether all hardware is powered.""" # If device backs no hardware, assume it's powered - return True + return 1.0 def properties_changed(self): pass diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/recv_device.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/recv_device.py index 3551c33cd97c3bd5e8db90c63deecf5d3f0c2dbb..fff0279ebe0598c9c518666215625c68126c3b90 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/recv_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/recv_device.py @@ -386,6 +386,17 @@ class RECVDevice(OPCUADevice): # overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + + mask = self.read_attribute("RCU_mask_RW") + powered = self.read_attribute("RCU_PWR_good_R") + + try: + return numpy.count_nonzero(powered & mask) / numpy.count_nonzero(mask) + except ZeroDivisionError: + return 1.0 + def _power_hardware_on(self): """Power the RCUs.""" diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py index 6eb0d9d6ee95c9c3e06061a5840d3a1723995026..9aecfc11fbfa24a095e7ed8516bdc326b04d2511 100644 --- a/tangostationcontrol/tangostationcontrol/devices/ccd.py +++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py @@ -217,9 +217,9 @@ class CCD(OPCUADevice): self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout) logger.debug("Put CCD in off state") - def _read_hardware_powered_R(self): + def _read_hardware_powered_fraction_R(self): """Read attribute which monitors the power""" - return self.read_attribute("CCD_PWR_on_R") + return 1.0 * self.read_attribute("CCD_PWR_on_R") def _power_hardware_on(self): """Forward the clock signal.""" diff --git a/tangostationcontrol/tangostationcontrol/devices/ec.py b/tangostationcontrol/tangostationcontrol/devices/ec.py index 3bc7354e2cfa77603f22906121d05883c795416a..85893daf0bb4c1d01359f86ee231cacb8b450fbf 100644 --- a/tangostationcontrol/tangostationcontrol/devices/ec.py +++ b/tangostationcontrol/tangostationcontrol/devices/ec.py @@ -113,11 +113,11 @@ class EC(OPCUADevice): # overloaded functions # -------- - def _read_hardware_powered_R(self): + def _read_hardware_powered_fraction_R(self): # the device and translator are one, so if # the translator is reachable, the hardware # is powered. - return self.read_attribute("connected_R") + return 1.0 * self.read_attribute("connected_R") # -------- # Commands diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py index 56a716b2d881acbf0ee3c74dcbf27e311463439c..77e54b87e27497ba6d9995c9acd11aa60acfdc12 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py @@ -669,6 +669,10 @@ class Beamlet(OPCUADevice): # Overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + return 1.0 * any(self.read_attribute("FPGA_beamlet_output_enable_R")) + def configure_for_initialise(self): super().configure_for_initialise() diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py index 256b082b895ad7f840992c183297f8ed4dafe758..9a259373d79c60872f526b435ed7b0814832976a 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py @@ -195,6 +195,10 @@ class BST(Statistics): # Overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + return 1.0 * any(self.read_attribute("FPGA_bst_offload_enable_R")) + def _power_hardware_on(self): self.proxy.write_attribute( "FPGA_bst_offload_enable_RW", self.FPGA_bst_offload_enable_RW_default diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py b/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py index cdfc9f2218b322bd312213d00325a0d93a67a949..fb136f35d1cae485bbdbb7d1a1bbf7eaa42368ac 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/firmware.py @@ -366,6 +366,19 @@ class SDPFirmware(OPCUADevice): self.Firmware_Boot_timeout, ) + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + + boot_image = self.read_attribute("FPGA_boot_image_R") + mask = self.read_attribute("TR_fpga_mask_R") + + try: + return numpy.count_nonzero((boot_image == 1) & mask) / numpy.count_nonzero( + mask + ) + except ZeroDivisionError: + return 1.0 + def _power_hardware_on(self): """Boot the SDP Firmware user image""" diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py index 5baa9b113419fd1c2c24022c754adc089cdd4698..76f0c0df9ee2d27d5fb744939c4d56fa0ec08351 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py @@ -555,6 +555,17 @@ class SDP(OPCUADevice): # overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + + mask = self.control.read_parent_attribute("TR_fpga_mask_R") + powered = self.read_attribute("FPGA_processing_enable_R") + + try: + return numpy.count_nonzero(powered & mask) / numpy.count_nonzero(mask) + except ZeroDivisionError: + return 1.0 + def configure_for_initialise(self): super().configure_for_initialise() diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py index 63d05a5cb838eaacba01c79118ba62ac93ebacf8..a237a3ac2473bc8f8d11c121937788b091da523f 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py @@ -222,6 +222,10 @@ class SST(Statistics): # Overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + return 1.0 * any(self.read_attribute("FPGA_sst_offload_enable_R")) + def _power_hardware_on(self): self.proxy.write_attribute( "FPGA_sst_offload_enable_RW", self.FPGA_sst_offload_enable_RW_default diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py index 45d7cbe3c510f47f809ce5c874c570296261fc83..49f6407fac17134de03ca180501b21b860cd5bbf 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py @@ -722,6 +722,31 @@ class XST(Statistics): # Overloaded functions # -------- + def _read_hardware_powered_fraction_R(self): + """Read attribute which monitors the power""" + + processing_enabled = self.read_attribute("FPGA_xst_processing_enable_R") + offload_enabled = self.read_attribute("FPGA_xst_offload_enable_R") + + expected_processing_enabled = numpy.array( + self.FPGA_xst_processing_enable_RW_default, dtype=bool + ) + expected_offload_enabled = numpy.array( + self.FPGA_xst_offload_enable_RW_default, dtype=bool + ) + + mask = expected_processing_enabled | expected_offload_enabled + + try: + # "powered" means processing and offload is as expected for the FPGAs required + return numpy.count_nonzero( + (processing_enabled == expected_processing_enabled) + & (offload_enabled == expected_offload_enabled) + & mask + ) / numpy.count_nonzero(mask) + except ZeroDivisionError: + return 1.0 + def _power_hardware_on(self): self.proxy.write_attribute( "FPGA_xst_processing_enable_RW", self.FPGA_xst_processing_enable_RW_default diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py index 55d9309721dc9ea957d1c31b4a4884a3073bb627..85d7e4de354acdab7998440a5263382229d3b61d 100644 --- a/tangostationcontrol/tangostationcontrol/devices/unb2.py +++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py @@ -427,10 +427,16 @@ class UNB2(OPCUADevice): # overloaded functions # -------- - def _read_hardware_powered_R(self): + def _read_hardware_powered_fraction_R(self): """Read attribute which monitors the power""" - # Return True if all uniboards are powered - return all(self.read_attribute("UNB2_PWR_on_R")) + + mask = self.read_attribute("UNB2_mask_RW") + powered = self.read_attribute("UNB2_PWR_on_R") + + try: + return numpy.count_nonzero(powered & mask) / numpy.count_nonzero(mask) + except ZeroDivisionError: + return 1.0 def _power_hardware_on(self): """Power the Uniboards.""" @@ -438,7 +444,9 @@ class UNB2(OPCUADevice): self.UNB2_on() self.wait_attribute("UNB2TR_translator_busy_R", False, self.UNB2_On_Off_timeout) - self.wait_attribute("hardware_powered_R", True, self.UNB2_On_Off_timeout) + self.wait_attribute( + "hardware_powered_fraction_R", 1.0, self.UNB2_On_Off_timeout + ) def _power_hardware_off(self): """Disable the Uniboards."""