diff --git a/tangostationcontrol/docs/source/devices/recv.rst b/tangostationcontrol/docs/source/devices/recv.rst
index 3bf2e1ba090b96c1cd49b77708f127de0c60c259..5e555d91c5deaa7c1131313d809707d38a94a835 100644
--- a/tangostationcontrol/docs/source/devices/recv.rst
+++ b/tangostationcontrol/docs/source/devices/recv.rst
@@ -9,9 +9,11 @@ The ``recv == DeviceProxy("STAT/RECV/1")`` device controls the RCUs, the LBA ant
 
 :Ant_mask_RW: Controls which antennas will actually be configured when attributes referring to antennas are written.
 
-  :type: ``bool[N_RCUs][N_antennas_per_RCU]``
+  :type: ``bool[N_antennas]``
 
-Typically, ``N_RCUs == 32``, and ``N_antennas_per_RCU == 3``.
+Typically, ``N_RCUs == 32``, and ``N_antennas == 96``.
+
+.. note:: The antennas are hooked up to the RCUs in sets of 3, in order.
 
 Error information
 `````````````````````
@@ -24,7 +26,7 @@ These attributes summarise the basic state of the device. Any elements which are
 
 :ANT_error_R: Whether the antennas appear usable.
 
-  :type: ``bool[N_RCUs][N_antennas_per_RCU]``
+  :type: ``bool[N_antennas]``
 
 :RCU_IOUT_error_R: Whether there are alarms on any of the amplitudes in the measured currents.
 
diff --git a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
index 9375b6d5d2b75c5ebfd66b3cab2318e586227b65..b28c7fe51c71ffb4756804c4d7a19e5c5e0cdc6f 100644
--- a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
@@ -1,3 +1,6 @@
+from operator import mul
+from functools import reduce
+
 from tango.server import attribute
 from tango import AttrWriteType
 
@@ -79,11 +82,15 @@ class attribute_wrapper(attribute):
             max_dim_y = 0
             dtype = (datatype,)
         elif len(dims) == 2:
-            max_dim_x = dims[0]
-            max_dim_y = dims[1]
+            max_dim_x = dims[1]
+            max_dim_y = dims[0]
             dtype = ((datatype,),)
         else:
-            raise ValueError(f"Only up to 2D arrays are supported. Supplied dimensions: {dims}")
+            # >2D arrays collapse into the X and Y dimensions. The Y (major) dimension mirrors the first dimension given, the
+            # rest collapses into the X (minor) dimension.
+            max_dim_x = reduce(mul, dims[1:])
+            max_dim_y = dims[0]
+            dtype = ((datatype,),)
 
         if access == AttrWriteType.READ_WRITE:
             """ If the attribute is of READ_WRITE type, assign the write and read functions to it"""
@@ -142,7 +149,7 @@ class attribute_wrapper(attribute):
         #
         # NOTE: fisallowed=<callable> does not work: https://gitlab.com/tango-controls/pytango/-/issues/435
         # So we have to use fisallowed=<str> here, which causes the function device.<str> to be called.
-        super().__init__(dtype=dtype, max_dim_y=max_dim_y, max_dim_x=max_dim_x, access=access, fisallowed="is_attribute_access_allowed", **kwargs)
+        super().__init__(dtype=dtype, max_dim_y=max_dim_y, max_dim_x=max_dim_x, access=access, fisallowed="is_attribute_access_allowed", format=str(dims), **kwargs)
 
     def get_attribute_io(self, device):
         """
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index 38701a47ae231c938012099596802aa74fc54c1c..22e5f922fbc3853bf29b865cc075b206116e89e2 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -375,14 +375,10 @@ class HBATToRecvMapper(object):
             "RCU_band_select_RW":       numpy.zeros(96, dtype=numpy.int64)
         }
         self.__reshape_attributes_in = {
-            "ANT_mask_RW": (96,),
             "HBAT_BF_delay_steps_RW": (96, 32),
-            "RCU_band_select_RW": (96,),
         }
         self.__reshape_attributes_out = {
-            "ANT_mask_RW": (32, 3),
             "HBAT_BF_delay_steps_RW": (96, 32),
-            "RCU_band_select_RW": (32, 3)
         }
 
     def map_read(self, mapped_attribute, recv_results):
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index cba1a6578894cf88de1a6e6fad8b308515187ea1..4b594bd30f89e26585a63e3424d4c73129ae521a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -280,6 +280,15 @@ class lofar_device(Device, metaclass=DeviceMeta):
             try:
                 default_value = getattr(self, f"{name}_default")
 
+                # properties are always 0D or 1D, but arrays can be 2D.
+                # in the latter case, we need to reshape the default.
+                attr = getattr(self, name)
+                max_dim_x, max_dim_y = attr.get_max_dim_x(), attr.get_max_dim_y()
+
+                if max_dim_y > 1:
+                    # 2D array -> reshape 1D default
+                    default_value = numpy.array(default_value).reshape(max_dim_y, max_dim_x)
+
                 # set the attribute to the configured default
                 logger.debug(textwrap.shorten(f"Setting attribute {name} to {default_value}", 150))
                 self.proxy.write_attribute(name, default_value)
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index 96da333820f69238ad34e2159752fac2cf0263e4..9fd0d8697ada0a60d0c35c7e32d29fd1f2845d42 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -54,7 +54,7 @@ class RECV(opcua_device):
     ANT_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[[True] * 3] * 32
+        default_value=[True] * 96
     )
 
     RCU_mask_RW_default = device_property(
@@ -66,13 +66,13 @@ class RECV(opcua_device):
     RCU_band_select_RW_default = device_property(
         dtype='DevVarLong64Array',
         mandatory=False,
-        default_value=[[0] * 3] * 32
+        default_value=[0] * 96
     )
 
     RCU_PWR_ANT_on_RW = device_property(
         dtype='DevVarLong64Array',
         mandatory=False,
-        default_value=[[False] * 3] * 32 # turn power off by default in test setups, f.e. to prevent blowing up the noise sources
+        default_value=[False] * 96 # turn power off by default in test setups, f.e. to prevent blowing up the noise sources
     )
 
     RECVTR_monitor_rate_RW_default = device_property(
@@ -128,26 +128,26 @@ class RECV(opcua_device):
     # ----------
     # Attributes
     # ----------
-    ANT_mask_RW                  = attribute_wrapper(comms_annotation=["ANT_mask_RW"               ],datatype=bool         , dims=(3,32), access=AttrWriteType.READ_WRITE)
+    ANT_mask_RW                  = attribute_wrapper(comms_annotation=["ANT_mask_RW"               ],datatype=bool         , dims=(96,), access=AttrWriteType.READ_WRITE)
     
     # The HBAT beamformer delays represent 32 delays for each of the 96 inputs.
     # The 32 delays deconstruct as delays[polarisation][dipole], and each delay is the number of 'delay steps' to apply (0.5ns for HBAT1).
-    HBAT_BF_delay_steps_R        = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_R"     ],datatype=numpy.int64  , dims=(32,96))
-    HBAT_BF_delay_steps_RW       = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_RW"    ],datatype=numpy.int64  , dims=(32,96), access=AttrWriteType.READ_WRITE)
-    HBAT_LED_on_R                = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"             ],datatype=bool         , dims=(32,96))
-    HBAT_LED_on_RW               = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW"            ],datatype=bool         , dims=(32,96), access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_LNA_on_R            = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R"         ],datatype=bool         , dims=(32,96))
-    HBAT_PWR_LNA_on_RW           = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_RW"        ],datatype=bool         , dims=(32,96), access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_on_R                = attribute_wrapper(comms_annotation=["HBAT_PWR_on_R"             ],datatype=bool         , dims=(32,96))
-    HBAT_PWR_on_RW               = attribute_wrapper(comms_annotation=["HBAT_PWR_on_RW"            ],datatype=bool         , dims=(32,96), access=AttrWriteType.READ_WRITE)
-    RCU_ADC_locked_R             = attribute_wrapper(comms_annotation=["RCU_ADC_locked_R"          ],datatype=bool         , dims=(3,32))
-    RCU_attenuator_dB_R          = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_R"       ],datatype=numpy.int64  , dims=(3,32))
-    RCU_attenuator_dB_RW         = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_RW"      ],datatype=numpy.int64  , dims=(3,32), access=AttrWriteType.READ_WRITE)
-    RCU_band_select_R            = attribute_wrapper(comms_annotation=["RCU_band_select_R"         ],datatype=numpy.int64  , dims=(3,32))
-    RCU_band_select_RW           = attribute_wrapper(comms_annotation=["RCU_band_select_RW"        ],datatype=numpy.int64  , dims=(3,32), access=AttrWriteType.READ_WRITE)
-    RCU_DTH_freq_R               = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R"            ],datatype=numpy.int64  , dims=(3,32))
-    RCU_DTH_freq_RW              = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW"           ],datatype=numpy.int64  , dims=(3,32), access=AttrWriteType.READ_WRITE)
-    RCU_DTH_on_R                 = attribute_wrapper(comms_annotation=["RCU_DTH_on_R"              ],datatype=bool         , dims=(3,32))
+    HBAT_BF_delay_steps_R        = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_R"     ],datatype=numpy.int64  , dims=(96,2,16))
+    HBAT_BF_delay_steps_RW       = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_RW"    ],datatype=numpy.int64  , dims=(96,2,16), access=AttrWriteType.READ_WRITE)
+    HBAT_LED_on_R                = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"             ],datatype=bool         , dims=(96,2,16))
+    HBAT_LED_on_RW               = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW"            ],datatype=bool         , dims=(96,2,16), access=AttrWriteType.READ_WRITE)
+    HBAT_PWR_LNA_on_R            = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R"         ],datatype=bool         , dims=(96,2,16))
+    HBAT_PWR_LNA_on_RW           = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_RW"        ],datatype=bool         , dims=(96,2,16), access=AttrWriteType.READ_WRITE)
+    HBAT_PWR_on_R                = attribute_wrapper(comms_annotation=["HBAT_PWR_on_R"             ],datatype=bool         , dims=(96,2,16))
+    HBAT_PWR_on_RW               = attribute_wrapper(comms_annotation=["HBAT_PWR_on_RW"            ],datatype=bool         , dims=(96,2,16), access=AttrWriteType.READ_WRITE)
+    RCU_ADC_locked_R             = attribute_wrapper(comms_annotation=["RCU_ADC_locked_R"          ],datatype=bool         , dims=(96,))
+    RCU_attenuator_dB_R          = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_R"       ],datatype=numpy.int64  , dims=(96,))
+    RCU_attenuator_dB_RW         = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_RW"      ],datatype=numpy.int64  , dims=(96,), access=AttrWriteType.READ_WRITE)
+    RCU_band_select_R            = attribute_wrapper(comms_annotation=["RCU_band_select_R"         ],datatype=numpy.int64  , dims=(96,))
+    RCU_band_select_RW           = attribute_wrapper(comms_annotation=["RCU_band_select_RW"        ],datatype=numpy.int64  , dims=(96,), access=AttrWriteType.READ_WRITE)
+    RCU_DTH_freq_R               = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R"            ],datatype=numpy.int64  , dims=(96,))
+    RCU_DTH_freq_RW              = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW"           ],datatype=numpy.int64  , dims=(96,), access=AttrWriteType.READ_WRITE)
+    RCU_DTH_on_R                 = attribute_wrapper(comms_annotation=["RCU_DTH_on_R"              ],datatype=bool         , dims=(96,))
     RCU_LED_green_on_R           = attribute_wrapper(comms_annotation=["RCU_LED_green_on_R"        ],datatype=bool         , dims=(32,))
     RCU_LED_green_on_RW          = attribute_wrapper(comms_annotation=["RCU_LED_green_on_RW"       ],datatype=bool         , dims=(32,), access=AttrWriteType.READ_WRITE)
     RCU_LED_red_on_R             = attribute_wrapper(comms_annotation=["RCU_LED_red_on_R"          ],datatype=bool         , dims=(32,))
@@ -160,11 +160,11 @@ class RECV(opcua_device):
     RCU_PWR_2V5_R                = attribute_wrapper(comms_annotation=["RCU_PWR_2V5_R"             ],datatype=numpy.float64, dims=(32,))
     RCU_PWR_3V3_R                = attribute_wrapper(comms_annotation=["RCU_PWR_3V3_R"             ],datatype=numpy.float64, dims=(32,))
     RCU_PWR_ANALOG_on_R          = attribute_wrapper(comms_annotation=["RCU_PWR_ANALOG_on_R"       ],datatype=bool         , dims=(32,))
-    RCU_PWR_ANT_IOUT_R           = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_IOUT_R"        ],datatype=numpy.float64, dims=(3,32))
-    RCU_PWR_ANT_on_R             = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_R"          ],datatype=bool         , dims=(3,32))
-    RCU_PWR_ANT_on_RW            = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_RW"         ],datatype=bool         , dims=(3,32), access=AttrWriteType.READ_WRITE)
-    RCU_PWR_ANT_VIN_R            = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"         ],datatype=numpy.float64, dims=(3,32))
-    RCU_PWR_ANT_VOUT_R           = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R"        ],datatype=numpy.float64, dims=(3,32))
+    RCU_PWR_ANT_IOUT_R           = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_IOUT_R"        ],datatype=numpy.float64, dims=(96,))
+    RCU_PWR_ANT_on_R             = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_R"          ],datatype=bool         , dims=(96,))
+    RCU_PWR_ANT_on_RW            = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_RW"         ],datatype=bool         , dims=(96,), access=AttrWriteType.READ_WRITE)
+    RCU_PWR_ANT_VIN_R            = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"         ],datatype=numpy.float64, dims=(96,))
+    RCU_PWR_ANT_VOUT_R           = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R"        ],datatype=numpy.float64, dims=(96,))
     RCU_PWR_DIGITAL_on_R         = attribute_wrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R"      ],datatype=bool         , dims=(32,))
     RCU_PWR_good_R               = attribute_wrapper(comms_annotation=["RCU_PWR_good_R"            ],datatype=bool         , dims=(32,))
     RCU_TEMP_R                   = attribute_wrapper(comms_annotation=["RCU_TEMP_R"                ],datatype=numpy.float64, dims=(32,))
@@ -181,7 +181,7 @@ class RECV(opcua_device):
         return (2 * self.read_attribute("RCU_LED_green_on_R") + 4 * self.read_attribute("RCU_LED_red_on_R")).astype(numpy.uint32)
 
     RCU_error_R                  = attribute(dtype=(bool,), max_dim_x=32, fisallowed="is_attribute_access_allowed")
-    ANT_error_R                  = attribute(dtype=((bool,),), max_dim_x=3, max_dim_y=32, fisallowed="is_attribute_access_allowed")
+    ANT_error_R                  = attribute(dtype=(bool,), max_dim_x=96, fisallowed="is_attribute_access_allowed")
 
     def read_RCU_error_R(self):
         return self.read_attribute("RCU_mask_RW") & (
@@ -194,14 +194,14 @@ class RECV(opcua_device):
                  ~self.read_attribute("RCU_ADC_locked_R")
                )
 
-    RECV_IOUT_error_R          = attribute(dtype=(bool,), max_dim_x=32)
+    RECV_IOUT_error_R          = attribute(dtype=(bool,), max_dim_x=96)
     RECV_TEMP_error_R          = attribute(dtype=(bool,), max_dim_x=32, polling_period=1000)
-    RECV_VOUT_error_R          = attribute(dtype=(bool,), max_dim_x=32)
+    RECV_VOUT_error_R          = attribute(dtype=(bool,), max_dim_x=96)
 
     def read_RECV_IOUT_error_R(self):
-        return (self.read_attribute("ANT_mask_RW") & (
+        return self.read_attribute("ANT_mask_RW") & (
                  self.alarm_val("RCU_PWR_ANT_IOUT_R")
-               )).any(axis=1)
+               )
 
     def read_RECV_TEMP_error_R(self):
         # Don't apply the mask here --- we always want to know if things get too hot!
@@ -213,7 +213,7 @@ class RECV(opcua_device):
         return (self.read_attribute("ANT_mask_RW") & (
                  self.alarm_val("RCU_PWR_ANT_VIN_R")
                | self.alarm_val("RCU_PWR_ANT_VOUT_R")
-               )).any(axis=1) | (self.read_attribute("RCU_mask_RW") & (
+               )).reshape(32,3).any(axis=1) | (self.read_attribute("RCU_mask_RW") & (
                  self.alarm_val("RCU_PWR_1V8_R")
                | self.alarm_val("RCU_PWR_2V5_R")
                | self.alarm_val("RCU_PWR_3V3_R")
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index 6bdf4f3779dab651b0a0d2d89d359e9560353a8f..309016fa7edb9256a88713eac13205cc79eae090 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -72,7 +72,7 @@ class Beamlet(opcua_device):
     FPGA_bf_weights_xy_yx_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value = [[0] * A_PN * N_POL * N_BEAMLETS_CTRL] * N_PN
+        default_value = [0] * N_PN * A_PN * N_POL * N_BEAMLETS_CTRL
     )
 
     subband_select_RW_default = device_property(
@@ -93,43 +93,43 @@ class Beamlet(opcua_device):
     # Attributes
     # ----------
 
-    FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(16,))
-    FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(16,))
-    FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(16,))
-    FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
-    FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(16,))
-    FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(N_PN,))
+    FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(N_PN,))
+    FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(N_PN,))
+    FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_PN,))
+    FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(N_PN,))
+    FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
     FPGA_beamlet_output_bsn_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_bsn_R"], datatype=numpy.int64, dims=(N_PN, N_BEAMSETS_CTRL))
 
-    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_BEAMSETS_CTRL, N_PN))
-    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_BEAMSETS_CTRL, N_PN))
+    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL))
+    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL))
 
     # boolean[N_PN][N_BEAMSETS_CTRL]
-    FPGA_beamlet_output_ready_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_BEAMSETS_CTRL, N_PN))
+    FPGA_beamlet_output_ready_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL))
     # boolean[N_PN][N_BEAMSETS_CTRL]
-    FPGA_beamlet_output_xon_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_BEAMSETS_CTRL, N_PN))
+    FPGA_beamlet_output_xon_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL))
 
     # uint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
     # Select subband per dual-polarisation beamlet.
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(A_PN * N_POL * N_BEAMLETS_CTRL, N_PN))
-    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(A_PN * N_POL * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL))
+    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
 
     # uint32[N_PN][N_beamset_ctrl]
-    FPGA_bf_ring_nof_transport_hops_R = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_BEAMSETS_CTRL, N_PN))
-    FPGA_bf_ring_nof_transport_hops_RW = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_BEAMSETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_ring_nof_transport_hops_R = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_PN, N_BEAMSETS_CTRL))
+    FPGA_bf_ring_nof_transport_hops_RW = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_PN, N_BEAMSETS_CTRL), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
     # Co-polarization BF weights. The N_POL = 2 parameter index is:
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(A_PN * N_POL * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(A_PN * N_POL *  N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
     # Cross-polarization BF weights. The N_POL = 2 parameter index is (note that index pol in range 0:N_POL-1 is the antenna polarization, so index !pol is the beamlet polarization):
@@ -140,19 +140,19 @@ class Beamlet(opcua_device):
 
     # cint16[N_PN][N_POL_BF][A_PN][N_POL][N_BEAMLETS_CTRL]
     # Full Jones matrix of BF weights.
-    FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_POL_BF * A_PN * N_POL * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_POL_BF * A_PN * N_POL * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_PN, N_POL_BF, A_PN, N_POL, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_PN, N_POL_BF, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_PN][A_PN][N_BEAMLETS_CTRL]
     # BF weights for separate access to respectively w_xx, w_xy, w_yx, and w_yy.
-    FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(A_PN * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN * N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
+    FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
 
     subband_select_RW = attribute(dtype=(numpy.uint32,), max_dim_x=N_BEAMLETS_CTRL, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
index 7f0816afcd5a94b06bbfb76f68f4af857daf1161..e39782b48b68d773f968a89b3b568849f8d183ef 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
@@ -85,7 +85,7 @@ class BST(Statistics):
     # number of packets with invalid payloads
     nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(BSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
     # latest BSTs
-    bst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BSTCollector.MAX_BEAMLETS, BSTCollector.MAX_BLOCKS), datatype=numpy.uint64)
+    bst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BSTCollector.MAX_BLOCKS, BSTCollector.MAX_BEAMLETS), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest BSTs
     bst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_timestamps"}, dims=(BSTCollector.MAX_BLOCKS,), datatype=numpy.uint64)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index d4c4c1c4a2cea160c676af37d399a795d4a80476..b0038a0f1161c6c926f88815ebc27d0eaba53ef3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -110,52 +110,57 @@ class SDP(opcua_device):
     # Attributes
     # ----------
 
-    FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(16,))
-    FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(16,), doc="Active FPGA image (0=factory, 1=user)")
-    FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=str, dims=(16,))
-    FPGA_pps_present_R = attribute_wrapper(comms_annotation=["FPGA_pps_present_R"], datatype=bool, dims=(16,))
-    FPGA_pps_capture_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_capture_cnt_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_pps_expected_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_pps_expected_cnt_RW = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=bool, dims=(16,))
-    FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_node_offset_R = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_ring_node_offset_RW = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_nof_nodes_R = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_ring_nof_nodes_RW = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_use_cable_to_next_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_R"], datatype=bool, dims=(16,))
-    FPGA_ring_use_cable_to_next_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_use_cable_to_previous_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=bool, dims=(16,))
-    FPGA_ring_use_cable_to_previous_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,))
-    FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(8192,), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_fsub_type_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(12 * 512, 16))
-    FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(12 * 512, 16), access=AttrWriteType.READ_WRITE)
-    FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(16,))
-    FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(16,))
-    FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(12, 16))
-    FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=bool, dims=(12, 16))
-    FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["FPGA_wg_enable_RW"], datatype=bool, dims=(12, 16), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(12, 16))
-    FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["FPGA_wg_phase_R"], datatype=numpy.float_, dims=(12, 16))
-    FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE)
-    TR_fpga_mask_R = attribute_wrapper(comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(16,))
-    TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["TR_fpga_mask_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(16,))
+    # TODO(needs to not be statically declared as this can change depending on the station and configuration)
+    S_pn = 12 # Number of ADC signal inputs per Processing Node (PN) FPGA.
+    N_pn = 16 # Number of FPGAs per antenna band that is controlled via the SC - SDP interface.
+    N_beamsets_ctrl = 2
+
+    FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,))
+    FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(N_pn,), doc="Active FPGA image (0=factory, 1=user)")
+    FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=str, dims=(N_pn,))
+    FPGA_pps_present_R = attribute_wrapper(comms_annotation=["FPGA_pps_present_R"], datatype=bool, dims=(N_pn,))
+    FPGA_pps_capture_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_capture_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_pps_expected_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_pps_expected_cnt_RW = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_node_offset_R = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_ring_node_offset_RW = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_nof_nodes_R = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_ring_nof_nodes_RW = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_next_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_R"], datatype=bool, dims=(N_pn,))
+    FPGA_ring_use_cable_to_next_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_previous_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=bool, dims=(N_pn,))
+    FPGA_ring_use_cable_to_previous_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(N_pn, 512))
+    FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(N_pn, 512), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_fsub_type_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(N_pn, S_pn, 512))
+    FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn, 512), access=AttrWriteType.READ_WRITE)
+    FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(N_pn,))
+    FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(N_pn,))
+    FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=bool, dims=(N_pn, S_pn))
+    FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["FPGA_wg_enable_RW"], datatype=bool, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["FPGA_wg_phase_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    TR_fpga_mask_R = attribute_wrapper(comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(N_pn,))
+    TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["TR_fpga_mask_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(N_pn,))
     TR_sdp_config_first_fpga_nr_R = attribute_wrapper(comms_annotation=["TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32)
     TR_sdp_config_nof_beamsets_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_beamsets_R"], datatype=numpy.uint32)
     TR_sdp_config_nof_fpgas_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32)
@@ -163,26 +168,21 @@ class SDP(opcua_device):
     TR_start_time_R = attribute_wrapper(comms_annotation=["TR_start_time_R"], datatype=numpy.int64)
     TR_tod_R = attribute_wrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,))
     TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["TR_tod_pps_delta_R"], datatype=numpy.double)
-
-    # TODO(needs to not be statically declared as this can change depending on the station and configuration)
-    S_pn = 12 # Number of ADC signal inputs per Processing Node (PN) FPGA.
-    N_pn = 16 # Number of FPGAs per antenna band that is controlled via the SC - SDP interface.
-    N_beamsets_ctrl = 2
     
     # OPC-UA MP only points for AIT
-    FPGA_signal_input_mean_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(S_pn, N_pn))
-    FPGA_signal_input_rms_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(S_pn, N_pn))
+    FPGA_signal_input_mean_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(N_pn, S_pn))
+    FPGA_signal_input_rms_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(N_pn, S_pn))
 
-    FPGA_jesd204b_csr_rbd_count_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
-    FPGA_jesd204b_csr_dev_syncn_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
-    FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
-    FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
+    FPGA_jesd204b_csr_rbd_count_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_csr_dev_syncn_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
 
     FPGA_signal_input_bsn_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
     FPGA_signal_input_nof_blocks_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_blocks_R"], datatype=numpy.int32, dims=(N_pn,))
     FPGA_signal_input_nof_samples_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_samples_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_signal_input_samples_delay_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_R"], datatype=numpy.uint32, dims=(S_pn, N_pn))
-    FPGA_signal_input_samples_delay_RW = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_RW"], datatype=numpy.uint32, dims=(S_pn, N_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_signal_input_samples_delay_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_signal_input_samples_delay_RW = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
 
     FPGA_bst_offload_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
index 8a51d009fef7dd97f9ae821485ef0bb21114d903..30946bdcda6c504d08d6c30a6e4e8490e6253c75 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
@@ -99,7 +99,7 @@ class SST(Statistics):
     # number of packets with invalid payloads
     nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(SSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
     # latest SSTs
-    sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(SSTCollector.MAX_SUBBANDS, SSTCollector.MAX_INPUTS), datatype=numpy.uint64)
+    sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(SSTCollector.MAX_INPUTS, SSTCollector.MAX_SUBBANDS), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest SSTs
     sst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(SSTCollector.MAX_INPUTS,), datatype=numpy.uint64)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
index 62134c8ba4eda6fd532a9a8b33d5d9f6cb37830a..ccb39ccf6214e638c0eb47cea4aa8b53afd088f9 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
@@ -151,9 +151,9 @@ class XST(Statistics):
     # number of packets with invalid payloads
     nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
     # latest XSTs
-    xst_blocks_R            = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(XSTCollector.MAX_BLOCKS * XSTCollector.BLOCK_LENGTH * XSTCollector.BLOCK_LENGTH * XSTCollector.VALUES_PER_COMPLEX, XSTCollector.MAX_PARALLEL_SUBBANDS), datatype=numpy.int64)
+    xst_blocks_R            = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_BLOCKS, XSTCollector.BLOCK_LENGTH, XSTCollector.BLOCK_LENGTH, XSTCollector.VALUES_PER_COMPLEX), datatype=numpy.int64)
     # whether the values in the block are conjugated and transposed
-    xst_conjugated_R        = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(XSTCollector.MAX_BLOCKS, XSTCollector.MAX_PARALLEL_SUBBANDS), datatype=bool)
+    xst_conjugated_R        = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_BLOCKS), datatype=bool)
     # reported timestamp for each subband in the latest XSTs
     xst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
     # which subband the XSTs describe
diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py
index 51cd13735a8f8b72a1ee8ed77efb1da6dc3fef2a..1725acc4002c2d84f9bec0553b3ceb18db4095a2 100644
--- a/tangostationcontrol/tangostationcontrol/devices/unb2.py
+++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py
@@ -73,38 +73,38 @@ class UNB2(opcua_device):
         'UNB2_mask_RW'
     ]
 
-    UNB2TR_I2C_bus_DDR4_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"],datatype=numpy.int64  , dims=(4,2))
+    UNB2TR_I2C_bus_DDR4_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"],datatype=numpy.int64  , dims=(2,4))
     UNB2TR_I2C_bus_error_R       = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_error_R"    ],datatype=numpy.int64  , dims=(2,))
-    UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"],datatype=numpy.int64  , dims=(4,2))
+    UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"],datatype=numpy.int64  , dims=(2,4))
     UNB2TR_I2C_bus_PS_error_R    = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ],datatype=numpy.int64  , dims=(2,))
-    UNB2TR_I2C_bus_QSFP_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"],datatype=numpy.int64  , dims=(24,2))
+    UNB2TR_I2C_bus_QSFP_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"],datatype=numpy.int64  , dims=(2,24))
     UNB2TR_monitor_rate_RW       = attribute_wrapper(comms_annotation=["UNB2TR_monitor_rate_RW"    ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
     UNB2TR_translator_busy_R     = attribute_wrapper(comms_annotation=["UNB2TR_translator_busy_R"  ],datatype=bool)
     UNB2_DC_DC_48V_12V_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ],datatype=numpy.float64, dims=(2,))
     UNB2_DC_DC_48V_12V_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ],datatype=numpy.float64, dims=(2,))
     UNB2_DC_DC_48V_12V_VIN_R     = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R"  ],datatype=numpy.float64, dims=(2,))
     UNB2_DC_DC_48V_12V_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ],datatype=numpy.float64, dims=(2,))
-    UNB2_FPGA_DDR4_SLOT_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"],datatype=numpy.float64, dims=(8,2))
-    UNB2_FPGA_POL_CORE_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_CORE_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_CORE_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_ERAM_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_ERAM_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_ERAM_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_HGXB_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_HGXB_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_HGXB_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_PGM_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_PGM_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_PGM_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_RXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_RXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_RXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_TXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_TXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_POL_TXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"],datatype=numpy.float64, dims=(4,2))
-    UNB2_FPGA_QSFP_CAGE_LOS_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ],datatype=numpy.int64  , dims=(24,2))
-    UNB2_FPGA_QSFP_CAGE_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"],datatype=numpy.float64, dims=(24,2))
+    UNB2_FPGA_DDR4_SLOT_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"],datatype=numpy.float64, dims=(2,8))
+    UNB2_FPGA_POL_CORE_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_CORE_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_CORE_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_ERAM_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_ERAM_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_ERAM_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_HGXB_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_HGXB_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_HGXB_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_PGM_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_PGM_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_PGM_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_RXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_RXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_RXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_TXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_TXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_POL_TXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"],datatype=numpy.float64, dims=(2,4))
+    UNB2_FPGA_QSFP_CAGE_LOS_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ],datatype=numpy.int64  , dims=(2,24))
+    UNB2_FPGA_QSFP_CAGE_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"],datatype=numpy.float64, dims=(2,24))
     UNB2_Front_Panel_LED_colour_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"],datatype=numpy.int64  , dims=(2,))
     UNB2_Front_Panel_LED_colour_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"],datatype=numpy.int64  , dims=(2,), access=AttrWriteType.READ_WRITE)
     UNB2_mask_RW                 = attribute_wrapper(comms_annotation=["UNB2_mask_RW"              ],datatype=bool, dims=(2,), access=AttrWriteType.READ_WRITE)
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics_writer/test_statistics_writer_sst.py b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics_writer/test_statistics_writer_sst.py
index 448fb0cabb3d367831b6603cd239b50a246a2bd4..fea84464ecb0aa0a4de0fef8423200a619da9cbb 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics_writer/test_statistics_writer_sst.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics_writer/test_statistics_writer_sst.py
@@ -69,9 +69,9 @@ class TestStatisticsWriterSST(BaseIntegrationTestCase):
                 self.assertIsNotNone(stat)
                 self.assertEqual(121, stat.data_id_signal_input_index)
                 # Test RECV attributes               
-                self.assertListEqual(stat.rcu_attenuator_dB.tolist(), [[0] * 3] * 32)
-                self.assertListEqual(stat.rcu_band_select.tolist(), [[0] * 3] * 32)
-                self.assertListEqual(stat.rcu_dth_on.tolist(), [[False] * 3] * 32)
+                self.assertListEqual(stat.rcu_attenuator_dB.tolist(), [0] * 96)
+                self.assertListEqual(stat.rcu_band_select.tolist(), [0] * 96)
+                self.assertListEqual(stat.rcu_dth_on.tolist(), [False] * 96)
         
     def test_no_tango_SST_statistics(self):
 
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/toolkit/test_archiver.py b/tangostationcontrol/tangostationcontrol/integration_test/default/toolkit/test_archiver.py
index a0cb2e7ae876735554fc4fa53314c4cb7fdd5ac2..01cfc73b052e71131213810ed1ef6e29bda0a67b 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/toolkit/test_archiver.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/toolkit/test_archiver.py
@@ -145,7 +145,7 @@ class TestArchiver(BaseIntegrationTestCase):
         
         polling_period=1000
         archive_event_period=5000
-        attr_fullname = 'stat/recv/1/ant_mask_rw'  # boolean 3x32
+        attr_fullname = 'stat/recv/1/hbat_pwr_on_rw'  # boolean 96x32
         self.archiver.add_attribute_to_archiver(attr_fullname, polling_period, archive_event_period)
         time.sleep(3)
         # Test if the attribute has been correctly added to event subscriber
@@ -158,7 +158,7 @@ class TestArchiver(BaseIntegrationTestCase):
         self.assertTrue(len(records)>0)
         item = records[-1]                                                  # last table record
         self.assertEqual('stat/recv/1',item.device)                         # column device
-        self.assertEqual('ant_mask_rw',item.name)                           # column attribute
+        self.assertEqual('hbat_pwr_on_rw',item.name)                        # column attribute
         self.assertEqual(datetime,type(item.data_time))                     # column datetime
         self.assertEqual(int,type(item.x))                                  # column index x
         self.assertEqual(int,type(item.y))                                  # column index y
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
index 485250131cc8221f4881cec6a158816265ad60a4..cfc90c25c7b06e61d7e0dca9f67cc0a46daac281 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
@@ -216,85 +216,85 @@ class TestAttributeTypes(base.TestCase):
             dev_init(self)
 
     class str_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=str, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=str, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class bool_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="bool_image_R", datatype=bool, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="bool_image_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="bool_image_R", datatype=bool, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="bool_image_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class float32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="float32_image_R", datatype=numpy.float32, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="float32_image_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="float32_image_R", datatype=numpy.float32, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="float32_image_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class float64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="float64_image_R", datatype=numpy.float64, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="float64_image_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="float64_image_R", datatype=numpy.float64, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="float64_image_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class double_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="double_image_R", datatype=numpy.double, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="double_image_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="double_image_R", datatype=numpy.double, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="double_image_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class uint8_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="uint8_image_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="uint8_image_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class uint16_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="uint16_image_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="uint16_image_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class uint32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="uint32_image_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="uint32_image_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class uint64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="uint64_image_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="uint64_image_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class int16_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int16_image_R", datatype=numpy.int16, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="int16_image_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="int16_image_R", datatype=numpy.int16, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="int16_image_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class int32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int32_image_R", datatype=numpy.int32, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="int32_image_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="int32_image_R", datatype=numpy.int32, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="int32_image_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
     class int64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int64_image_R", datatype=numpy.int64, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="int64_image_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="int64_image_R", datatype=numpy.int64, dims=(3,2))
+        image_RW = attribute_wrapper(comms_annotation="int64_image_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
index 94256ba5ce4bbba274f45d41ca6098acdd434381..eca4686a8c65aec51980734383eb80ee3ce1fc15 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
@@ -30,7 +30,7 @@ class TestHBATToRecvMapper(base.TestCase):
     def test_ant_read_mask_r_no_mapping(self):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 3)
 
-        receiver_values = [[[False] * 3] * 32, [[False] * 3] * 32, [[False] * 3] * 32]
+        receiver_values = [[False] * 96, [False] * 96, [False] * 96]
         expected = [False] * 48
         actual = mapper.map_read("ANT_mask_RW", receiver_values)
         numpy.testing.assert_equal(expected, actual)
@@ -38,7 +38,7 @@ class TestHBATToRecvMapper(base.TestCase):
     def test_ant_read_mask_r_hba_0_and_1_on_rcu_1_and_0_of_recv_1(self):
         mapper = HBATToRecvMapper(self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, self.POWER_NOT_CONNECTED, 3)
 
-        receiver_values = [[[False, True, False]] + [[False, False, False]] * 31, [[False] * 3] * 32, [[False] * 3] * 32]
+        receiver_values = [[False, True, False] + [False, False, False] * 31, [False] * 96, [False] * 96]
         expected = [True, False] + [False] * 46
         actual = mapper.map_read("ANT_mask_RW", receiver_values)
 
@@ -46,7 +46,7 @@ class TestHBATToRecvMapper(base.TestCase):
     
     def test_rcu_band_select_no_mapping(self):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 3)
-        receiver_values = [[[0] * 3] * 32, [[0] * 3] * 32, [[0] * 3] * 32]
+        receiver_values = [[0] * 96, [0] * 96, [0] * 96]
         expected = [0] * 48
         actual = mapper.map_read("RCU_band_select_RW", receiver_values)
         numpy.testing.assert_equal(expected, actual)
@@ -193,7 +193,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1)
 
         set_values = [False] * 48
-        expected = [[[False] * 3] * 32]
+        expected = [[False] * 96]
         actual = mapper.map_write("ANT_mask_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
 
@@ -201,7 +201,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 2)
 
         set_values = [False] * 48
-        expected = [[[False] * 3] * 32] * 2
+        expected = [[False] * 96] * 2
         actual = mapper.map_write("ANT_mask_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
 
@@ -209,7 +209,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, self.POWER_NOT_CONNECTED, 1)
 
         set_values = [True, False] + [False] * 46
-        expected = [[[False, True, False]] + [[False] * 3] * 31]
+        expected = [[False, True, False] + [False] * 93]
         actual = mapper.map_write("ANT_mask_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
     
@@ -217,7 +217,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1)
 
         set_values = [0] * 48
-        expected = [[[0] * 3] * 32]
+        expected = [[0] * 96]
         actual = mapper.map_write("RCU_band_select_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
     
@@ -225,7 +225,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 2)
 
         set_values = [0] * 48
-        expected = [[[0] * 3] * 32] * 2
+        expected = [[0] * 96] * 2
         actual = mapper.map_write("RCU_band_select_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
     
@@ -233,7 +233,7 @@ class TestHBATToRecvMapper(base.TestCase):
         mapper = HBATToRecvMapper(self.CONTROL_HBA_0_AND_1_ON_RCU_1_AND_0_OF_RECV_1, self.POWER_NOT_CONNECTED, 1)
 
         set_values = [1, 0] + [0] * 46
-        expected = [[[0, 1, 0]] + [[0] * 3] * 31]
+        expected = [[0, 1, 0] + [0] * 93]
         actual = mapper.map_write("RCU_band_select_RW", set_values)
         numpy.testing.assert_equal(expected, actual)