Fabric Bridge: use AttributeAccessInterface for BridgedDeviceBasicInformationCluster, expose more attributes (#34845)

* Add extra attributes to the bridged device basic info structures, remove nonsense comments

* Make use of AAI for BridgedDeviceBasicInformation cluster

* Restyled by gn

* Fix sizes for software version

* Bump revision to 4

---------

Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
index 10cb48c..38f2f8f 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
+++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
@@ -30,9 +30,11 @@
 
   sources = [
     "include/BridgedDevice.h",
+    "include/BridgedDeviceBasicInformationImpl.h",
     "include/BridgedDeviceManager.h",
     "include/CHIPProjectAppConfig.h",
     "src/BridgedDevice.cpp",
+    "src/BridgedDeviceBasicInformationImpl.cpp",
     "src/BridgedDeviceManager.cpp",
     "src/ZCLCallbacks.cpp",
   ]
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h
new file mode 100644
index 0000000..2340343
--- /dev/null
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h
@@ -0,0 +1,32 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#pragma once
+
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/AttributeAccessInterface.h>
+
+class BridgedDeviceBasicInformationImpl : public chip::app::AttributeAccessInterface
+{
+public:
+    BridgedDeviceBasicInformationImpl() :
+        chip::app::AttributeAccessInterface(chip::NullOptional /* endpointId */,
+                                            chip::app::Clusters::BridgedDeviceBasicInformation::Id)
+    {}
+
+    // AttributeAccessInterface implementation
+    CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & path, chip::app::AttributeValueEncoder & encoder) override;
+    CHIP_ERROR Write(const chip::app::ConcreteDataAttributePath & path, chip::app::AttributeValueDecoder & decoder) override;
+};
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
new file mode 100644
index 0000000..62630d7
--- /dev/null
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -0,0 +1,78 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#include "BridgedDeviceBasicInformationImpl.h"
+
+#include "BridgedDeviceManager.h"
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+
+#include <app/AttributeAccessInterfaceRegistry.h>
+
+static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 4;
+static constexpr unsigned kBridgedDeviceBasicInformationFeatureMap      = 0;
+
+using namespace ::chip;
+using namespace ::chip::app;
+using namespace ::chip::app::Clusters;
+
+CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePath & path, AttributeValueEncoder & encoder)
+{
+    // Registration is done for the bridged device basic information only
+    VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id);
+
+    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId);
+    VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND);
+
+    switch (path.mAttributeId)
+    {
+    case BasicInformation::Attributes::Reachable::Id:
+        encoder.Encode(dev->IsReachable());
+        break;
+    case BasicInformation::Attributes::NodeLabel::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetName()));
+        break;
+    case BasicInformation::Attributes::ClusterRevision::Id:
+        encoder.Encode(kBridgedDeviceBasicInformationClusterRevision);
+        break;
+    case BasicInformation::Attributes::FeatureMap::Id:
+        encoder.Encode(kBridgedDeviceBasicInformationFeatureMap);
+        break;
+    default:
+        return CHIP_ERROR_INVALID_ARGUMENT;
+    }
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR BridgedDeviceBasicInformationImpl::Write(const ConcreteDataAttributePath & path, AttributeValueDecoder & decoder)
+{
+    VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id);
+
+    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId);
+    VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND);
+
+    if (!dev->IsReachable())
+    {
+        return CHIP_ERROR_NOT_CONNECTED;
+    }
+
+    ChipLogProgress(NotSpecified, "Bridged device basic information attempt to write attribute: ep=%d", path.mAttributeId);
+
+    // nothing writable right now ...
+
+    return CHIP_ERROR_INVALID_ARGUMENT;
+}
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index 170b39c..7e78baa 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -45,8 +45,13 @@
 
 namespace {
 
-constexpr uint8_t kMaxRetries = 10;
-constexpr int kNodeLabelSize  = 32;
+constexpr uint8_t kMaxRetries      = 10;
+constexpr int kNodeLabelSize       = 32;
+constexpr int kUniqueIdSize        = 32;
+constexpr int kVendorNameSize      = 32;
+constexpr int kProductNameSize     = 32;
+constexpr int kHardwareVersionSize = 32;
+constexpr int kSoftwareVersionSize = 32;
 
 // Current ZCL implementation of Struct uses a max-size array of 254 bytes
 constexpr int kDescriptorAttributeArraySize = 254;
@@ -76,27 +81,44 @@
 //   - Bridged Device Basic Information
 //   - Administrator Commissioning
 
+// clang-format off
 // Declare Descriptor cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0),  /* parts list */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0),  /* parts list */
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Bridged Device Basic Information cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */
-    DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0),              /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* feature map */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  // The attributes below are MANDATORY in the Bridged Device Information Cluster
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::UniqueID::Id, CHAR_STRING, kUniqueIdSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0),
+
+  // The attributes below are OPTIONAL in the bridged device, however they are MANDATORY in the BasicInformation cluster
+  // so they can always be provided if desired
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorName::Id, CHAR_STRING, kVendorNameSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorID::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductName::Id, CHAR_STRING, kProductNameSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductID::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersion::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersionString::Id, CHAR_STRING,
+                            kHardwareVersionSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, INT32U, 4, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersionString::Id, CHAR_STRING,
+                            kSoftwareVersionSize, 0),
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Administrator Commissioning cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0),              /* NodeLabel */
-    DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0), /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0),     /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0),
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+// clang-format on
 
 constexpr CommandId administratorCommissioningCommands[] = {
     app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id,
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp
index 26e7279..d4da982 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp
@@ -25,88 +25,26 @@
 using namespace ::chip;
 using namespace ::chip::app::Clusters;
 
-#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u)
 #define ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION (1u)
-#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u)
-#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u)
 
 // External attribute read callback function
 Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId,
                                                                          const EmberAfAttributeMetadata * attributeMetadata,
                                                                          uint8_t * buffer, uint16_t maxReadLength)
 {
-    AttributeId attributeId = attributeMetadata->attributeId;
-
-    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpoint);
-    if (dev == nullptr)
-    {
-        return Protocols::InteractionModel::Status::Failure;
-    }
-
-    if (clusterId == BridgedDeviceBasicInformation::Id)
-    {
-        using namespace BridgedDeviceBasicInformation::Attributes;
-        ChipLogProgress(NotSpecified, "HandleReadBridgedDeviceBasicAttribute: attrId=%d, maxReadLength=%d", attributeId,
-                        maxReadLength);
-
-        if ((attributeId == Reachable::Id) && (maxReadLength == 1))
-        {
-            *buffer = dev->IsReachable() ? 1 : 0;
-        }
-        else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32))
-        {
-            MutableByteSpan zclNameSpan(buffer, maxReadLength);
-            MakeZclCharString(zclNameSpan, dev->GetName());
-        }
-        else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2))
-        {
-            uint16_t rev = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION;
-            memcpy(buffer, &rev, sizeof(rev));
-        }
-        else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4))
-        {
-            uint32_t featureMap = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP;
-            memcpy(buffer, &featureMap, sizeof(featureMap));
-        }
-        else
-        {
-            return Protocols::InteractionModel::Status::Failure;
-        }
-        return Protocols::InteractionModel::Status::Success;
-    }
-
     if (clusterId == AdministratorCommissioning::Id)
     {
         // TODO(#34791) This is a workaround to prevent crash. CADMIN is still reading incorrect
         // Attribute values on dynamic endpoint as it only reads the root node and not the actual bridge
         // device we are representing here, when addressing the issue over there we can more easily
         // resolve this workaround.
-        if ((attributeId == AdministratorCommissioning::Attributes::ClusterRevision::Id) && (maxReadLength == 2))
+        if ((attributeMetadata->attributeId == AdministratorCommissioning::Attributes::ClusterRevision::Id) && (maxReadLength == 2))
         {
             uint16_t rev = ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION;
             memcpy(buffer, &rev, sizeof(rev));
             return Protocols::InteractionModel::Status::Success;
         }
-        return Protocols::InteractionModel::Status::Failure;
     }
 
     return Protocols::InteractionModel::Status::Failure;
 }
-
-// External attribute write callback function
-Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId,
-                                                                          const EmberAfAttributeMetadata * attributeMetadata,
-                                                                          uint8_t * buffer)
-{
-    uint16_t endpointIndex                  = emberAfGetDynamicIndexFromEndpoint(endpoint);
-    Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure;
-
-    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpointIndex);
-    if (dev != nullptr && dev->IsReachable())
-    {
-        ChipLogProgress(NotSpecified, "emberAfExternalAttributeWriteCallback: ep=%d, clusterId=%d", endpoint, clusterId);
-        ret = Protocols::InteractionModel::Status::Success;
-    }
-
-    return ret;
-}
diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp
index c708b25..24ad4aa 100644
--- a/examples/fabric-bridge-app/linux/main.cpp
+++ b/examples/fabric-bridge-app/linux/main.cpp
@@ -19,6 +19,7 @@
 #include <AppMain.h>
 
 #include "BridgedDevice.h"
+#include "BridgedDeviceBasicInformationImpl.h"
 #include "BridgedDeviceManager.h"
 #include "CommissionableInit.h"
 
@@ -48,6 +49,8 @@
 constexpr uint16_t kRetryIntervalS = 3;
 #endif
 
+BridgedDeviceBasicInformationImpl gBridgedDeviceBasicInformationAttributes;
+
 bool KeyboardHit()
 {
     int bytesWaiting;
@@ -175,6 +178,7 @@
     ChipLogDetail(NotSpecified, "Fabric-Bridge: ApplicationInit()");
 
     CommandHandlerInterfaceRegistry::RegisterCommandHandler(&gAdministratorCommissioningCommandHandler);
+    registerAttributeAccessOverride(&gBridgedDeviceBasicInformationAttributes);
 
 #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
     InitRpcServer(kFabricBridgeServerPort);