diff --git a/examples/all-devices-app/all-devices-common/devices/root-node/RootNodeDevice.cpp b/examples/all-devices-app/all-devices-common/devices/root-node/RootNodeDevice.cpp index 4e796465678cc9..dec8e8615d07ea 100644 --- a/examples/all-devices-app/all-devices-common/devices/root-node/RootNodeDevice.cpp +++ b/examples/all-devices-app/all-devices-common/devices/root-node/RootNodeDevice.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -48,14 +49,13 @@ CHIP_ERROR RootNodeDevice::Register(EndpointId endpointId, CodeDrivenDataModelPr .Set() .Set(); - mBasicInformationCluster.Create( - optionalAttributeSet, - BasicInformationCluster::Context{ - .deviceInstanceInfoProvider = mContext.deviceInstanceInfoProvider, - .configurationManager = mContext.configurationManager, - .platformManager = mContext.platformManager, - .subscriptionsPerFabric = InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric(), - }); + static chip::app::Clusters::BasicInformation::DeviceLayerBasicInformationDelegate delegate({ + .deviceInstanceInfoProvider = mContext.deviceInstanceInfoProvider, + .configurationManager = mContext.configurationManager, + .platformManager = mContext.platformManager, + .subscriptionsPerFabric = InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric(), + }); + mBasicInformationCluster.Create(optionalAttributeSet, &delegate, mContext.platformManager); ReturnErrorOnFailure(provider.AddCluster(mBasicInformationCluster.Registration())); mGeneralCommissioningCluster.Create( diff --git a/src/app/clusters/basic-information/BUILD.gn b/src/app/clusters/basic-information/BUILD.gn index b21f47eb066c13..d48eef500053bd 100644 --- a/src/app/clusters/basic-information/BUILD.gn +++ b/src/app/clusters/basic-information/BUILD.gn @@ -18,6 +18,9 @@ source_set("basic-information") { sources = [ "BasicInformationCluster.cpp", "BasicInformationCluster.h", + "BasicInformationDelegate.h", + "DeviceLayerBasicInformationDelegate.cpp", + "DeviceLayerBasicInformationDelegate.h", ] public_deps = [ "${chip_root}/src/app:constants", diff --git a/src/app/clusters/basic-information/BasicInformationCluster.cpp b/src/app/clusters/basic-information/BasicInformationCluster.cpp index b0d444011d9ca1..e8ee8b47b77eab 100644 --- a/src/app/clusters/basic-information/BasicInformationCluster.cpp +++ b/src/app/clusters/basic-information/BasicInformationCluster.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ #include +#include #include #include @@ -30,7 +31,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -74,25 +76,6 @@ constexpr DataModel::AttributeEntry kMandatoryAttributes[] = { }; constexpr size_t kExpectedFixedLocationLength = 2; -static_assert(kExpectedFixedLocationLength == DeviceLayer::ConfigurationManager::kMaxLocationLength, - "Fixed location storage must be of size 2"); - -CHIP_ERROR ClearNullTerminatedStringWhenUnimplemented(CHIP_ERROR status, char * strBuf) -{ - if (status == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || status == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) - { - *strBuf = '\0'; - return CHIP_NO_ERROR; - } - - return status; -} - -CHIP_ERROR EncodeStringOnSuccess(CHIP_ERROR status, AttributeValueEncoder & encoder, const char * buf, size_t maxBufSize) -{ - ReturnErrorOnFailure(status); - return encoder.Encode(chip::CharSpan(buf, strnlen(buf, maxBufSize))); -} constexpr size_t kMaxStringLength = std::max({ DeviceLayer::ConfigurationManager::kMaxVendorNameLength, @@ -105,186 +88,43 @@ constexpr size_t kMaxStringLength = std::max({ DeviceLayer::ConfigurationManager::kMaxUniqueIDLength, }); -/// Reads a single device info string. Separate function to optimize for flash cost -/// as querying strings seems to be a frequent operation. -CHIP_ERROR ReadConfigurationString(DeviceInstanceInfoProvider & deviceInfoProvider, - CHIP_ERROR (DeviceInstanceInfoProvider::*getter)(char *, size_t), bool unimplementedAllowed, - AttributeValueEncoder & encoder) +CHIP_ERROR ReadStringAttribute(BasicInformation::BasicInformationDelegate * delegate, AttributeId attributeId, + AttributeValueEncoder & encoder) { - char buffer[kMaxStringLength + 1] = { 0 }; - CHIP_ERROR status = ((deviceInfoProvider).*(getter))(buffer, sizeof(buffer)); - if (unimplementedAllowed) - { - status = ClearNullTerminatedStringWhenUnimplemented(status, buffer); - } - return EncodeStringOnSuccess(status, encoder, buffer, kMaxStringLength); -} + char buffer[kMaxStringLength + 1]; + MutableCharSpan span(buffer, sizeof(buffer)); + ReturnErrorOnFailure(delegate->GetStringAttribute(attributeId, span)); -inline CHIP_ERROR ReadVendorID(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) -{ - uint16_t vendorId = 0; - ReturnErrorOnFailure(deviceInfoProvider.GetVendorId(vendorId)); - return aEncoder.Encode(vendorId); + // explicit char span creation to not synthesize a writer for Span on top of Span + return encoder.Encode(CharSpan{ buffer, span.size() }); } -inline CHIP_ERROR ReadProductID(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) +inline CHIP_ERROR ReadNumericAttribute(BasicInformation::BasicInformationDelegate * delegate, AttributeId attributeId, + AttributeValueEncoder & aEncoder) { - uint16_t productId = 0; - ReturnErrorOnFailure(deviceInfoProvider.GetProductId(productId)); - return aEncoder.Encode(productId); + uint32_t value = 0; + ReturnErrorOnFailure(delegate->GetNumericAttribute(attributeId, value)); + return aEncoder.Encode(value); } -inline CHIP_ERROR ReadLocalConfigDisabled(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) +inline CHIP_ERROR ReadLocalConfigDisabled(BasicInformation::BasicInformationDelegate * delegate, AttributeValueEncoder & aEncoder) { bool localConfigDisabled = false; - ReturnErrorOnFailure(deviceInfoProvider.GetLocalConfigDisabled(localConfigDisabled)); + ReturnErrorOnFailure(delegate->GetLocalConfigDisabled(localConfigDisabled)); return aEncoder.Encode(localConfigDisabled); } -inline CHIP_ERROR ReadHardwareVersion(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) -{ - uint16_t hardwareVersion = 0; - ReturnErrorOnFailure(deviceInfoProvider.GetHardwareVersion(hardwareVersion)); - return aEncoder.Encode(hardwareVersion); -} - -inline CHIP_ERROR ReadSoftwareVersion(DeviceLayer::ConfigurationManager & configManager, AttributeValueEncoder & aEncoder) -{ - uint32_t softwareVersion = 0; - ReturnErrorOnFailure(configManager.GetSoftwareVersion(softwareVersion)); - return aEncoder.Encode(softwareVersion); -} - -inline CHIP_ERROR ReadSoftwareVersionString(DeviceLayer::ConfigurationManager & configManager, AttributeValueEncoder & aEncoder) -{ - constexpr size_t kMaxLen = DeviceLayer::ConfigurationManager::kMaxSoftwareVersionStringLength; - char softwareVersionString[kMaxLen + 1] = { 0 }; - ReturnErrorOnFailure(configManager.GetSoftwareVersionString(softwareVersionString, sizeof(softwareVersionString))); - return aEncoder.Encode(CharSpan(softwareVersionString, strnlen(softwareVersionString, kMaxLen))); -} - -inline CHIP_ERROR ReadManufacturingDate(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) -{ - constexpr size_t kMaxLen = DeviceLayer::ConfigurationManager::kMaxManufacturingDateLength; - constexpr size_t kMaxDateLength = 8; // YYYYMMDD - static_assert(kMaxLen > kMaxDateLength, "kMaxLen must be greater than kMaxDateLength"); - char manufacturingDateString[kMaxLen + 1] = { 0 }; - uint16_t manufacturingYear; - uint8_t manufacturingMonth; - uint8_t manufacturingDayOfMonth; - size_t totalManufacturingDateLen = 0; - MutableCharSpan vendorSuffixSpan(manufacturingDateString + kMaxDateLength, sizeof(manufacturingDateString) - kMaxDateLength); - CHIP_ERROR status = deviceInfoProvider.GetManufacturingDate(manufacturingYear, manufacturingMonth, manufacturingDayOfMonth); - - // TODO: Remove defaulting once proper runtime defaulting of unimplemented factory data is done - if (status == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || status == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) - { - manufacturingYear = 2020; - manufacturingMonth = 1; - manufacturingDayOfMonth = 1; - vendorSuffixSpan.reduce_size(0); - status = CHIP_NO_ERROR; - } - ReturnErrorOnFailure(status); - - // Format is YYYYMMDD - snprintf(manufacturingDateString, sizeof(manufacturingDateString), "%04u%02u%02u", manufacturingYear, manufacturingMonth, - manufacturingDayOfMonth); - - totalManufacturingDateLen = kMaxDateLength; - status = deviceInfoProvider.GetManufacturingDateSuffix(vendorSuffixSpan); - if (status == CHIP_NO_ERROR) - { - totalManufacturingDateLen += vendorSuffixSpan.size(); - } - - VerifyOrDie(totalManufacturingDateLen <= kMaxLen); - - return aEncoder.Encode(CharSpan(manufacturingDateString, totalManufacturingDateLen)); -} - -inline CHIP_ERROR ReadUniqueID(DeviceLayer::ConfigurationManager & configManager, AttributeValueEncoder & aEncoder) -{ - constexpr size_t kMaxLen = DeviceLayer::ConfigurationManager::kMaxUniqueIDLength; - char uniqueId[kMaxLen + 1] = { 0 }; - - CHIP_ERROR status = configManager.GetUniqueId(uniqueId, sizeof(uniqueId)); - status = ClearNullTerminatedStringWhenUnimplemented(status, uniqueId); - return EncodeStringOnSuccess(status, aEncoder, uniqueId, kMaxLen); -} - -inline CHIP_ERROR ReadCapabilityMinima(AttributeValueEncoder & aEncoder, DeviceInstanceInfoProvider & deviceInfoProvider, - uint16_t & subscriptionsPerFabric) +inline CHIP_ERROR ReadCapabilityMinima(AttributeValueEncoder & aEncoder, BasicInformation::BasicInformationDelegate * delegate) { BasicInformation::Structs::CapabilityMinimaStruct::Type capabilityMinima; - - // TODO: These values must be set from something based on the SDK impl, but there are no such constants today. - constexpr uint16_t kMinCaseSessionsPerFabricMandatedBySpec = 3; - - auto capabilityMinimasFromDeviceInfo = deviceInfoProvider.GetSupportedCapabilityMinimaValues(); - - capabilityMinima.caseSessionsPerFabric = kMinCaseSessionsPerFabricMandatedBySpec; - capabilityMinima.subscriptionsPerFabric = subscriptionsPerFabric; - capabilityMinima.simultaneousInvocationsSupported = - chip::MakeOptional(capabilityMinimasFromDeviceInfo.simultaneousInvocationsSupported); - capabilityMinima.simultaneousWritesSupported = - chip::MakeOptional(capabilityMinimasFromDeviceInfo.simultaneousWritesSupported); - capabilityMinima.readPathsSupported = chip::MakeOptional(capabilityMinimasFromDeviceInfo.readPathsSupported); - capabilityMinima.subscribePathsSupported = - chip::MakeOptional(capabilityMinimasFromDeviceInfo.subscribePathsSupported); - + ReturnErrorOnFailure(delegate->GetCapabilityMinima(capabilityMinima)); return aEncoder.Encode(capabilityMinima); } -inline CHIP_ERROR ReadConfigurationVersion(DeviceLayer::ConfigurationManager & configManager, AttributeValueEncoder & aEncoder) -{ - uint32_t configurationVersion = 0; - ReturnErrorOnFailure(configManager.GetConfigurationVersion(configurationVersion)); - return aEncoder.Encode(configurationVersion); -} - -inline CHIP_ERROR ReadLocation(DeviceLayer::ConfigurationManager & configManager, AttributeValueEncoder & aEncoder) -{ - char location[kExpectedFixedLocationLength + 1] = { 0 }; - size_t codeLen = 0; - CharSpan countryCodeSpan; - - CHIP_ERROR err = configManager.GetCountryCode(location, sizeof(location), codeLen); - if ((err != CHIP_NO_ERROR) || (codeLen != kExpectedFixedLocationLength)) - { - countryCodeSpan = "XX"_span; - err = CHIP_NO_ERROR; - } - else - { - countryCodeSpan = CharSpan{ location, codeLen }; - } - return aEncoder.Encode(countryCodeSpan); -} - -inline CHIP_ERROR ReadProductAppearance(DeviceInstanceInfoProvider & deviceInfoProvider, AttributeValueEncoder & aEncoder) +inline CHIP_ERROR ReadProductAppearance(BasicInformation::BasicInformationDelegate * delegate, AttributeValueEncoder & aEncoder) { - ProductFinishEnum finish; - ReturnErrorOnFailure(deviceInfoProvider.GetProductFinish(&finish)); - - ColorEnum color; - CHIP_ERROR colorStatus = deviceInfoProvider.GetProductPrimaryColor(&color); - if (colorStatus != CHIP_NO_ERROR && colorStatus != CHIP_ERROR_NOT_IMPLEMENTED) - { - return colorStatus; - } - Structs::ProductAppearanceStruct::Type productAppearance; - productAppearance.finish = finish; - if (colorStatus == CHIP_NO_ERROR) - { - productAppearance.primaryColor.SetNonNull(color); - } - else - { - productAppearance.primaryColor.SetNull(); - } - + ReturnErrorOnFailure(delegate->GetProductAppearance(productAppearance)); return aEncoder.Encode(productAppearance); } @@ -297,14 +137,18 @@ DataModel::ActionReturnStatus BasicInformationCluster::ReadAttribute(const DataM { using namespace BasicInformation::Attributes; - auto & deviceInfoProvider = mClusterContext.deviceInstanceInfoProvider; - auto & configManager = mClusterContext.configurationManager; + enum class AttributeReadType + { + kString, + kNumeric, + kOther + }; + AttributeReadType readType = AttributeReadType::kOther; + const AttributeId attributeId = request.path.mAttributeId; - switch (request.path.mAttributeId) + switch (attributeId) { case FeatureMap::Id: - // Explicit specialization: TLVWriter.Put has specialization for various types - // but fails for `0u` with `unsigned int &` being ambigous. return encoder.Encode(0); case ClusterRevision::Id: if (!mEnabledOptionalAttributes.IsSet(UniqueID::Id)) @@ -315,63 +159,60 @@ DataModel::ActionReturnStatus BasicInformationCluster::ReadAttribute(const DataM case NodeLabel::Id: return encoder.Encode(mNodeLabel.Content()); case LocalConfigDisabled::Id: - return ReadLocalConfigDisabled(deviceInfoProvider, encoder); + return ReadLocalConfigDisabled(mDelegate, encoder); case DataModelRevision::Id: return encoder.Encode(Revision::kDataModelRevision); + case CapabilityMinima::Id: + return ReadCapabilityMinima(encoder, mDelegate); + case ProductAppearance::Id: + return ReadProductAppearance(mDelegate, encoder); + case SpecificationVersion::Id: + return encoder.Encode(Revision::kSpecificationVersion); + case MaxPathsPerInvoke::Id: + return encoder.Encode(CHIP_CONFIG_MAX_PATHS_PER_INVOKE); + case Reachable::Id: + return encoder.Encode(true); + + // String Attributes case Location::Id: - return ReadLocation(configManager, encoder); case VendorName::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetVendorName, - false /* unimplementedAllowed */, encoder); - case VendorID::Id: - return ReadVendorID(deviceInfoProvider, encoder); case ProductName::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetProductName, - false /* unimplementedAllowed */, encoder); - case ProductID::Id: - return ReadProductID(deviceInfoProvider, encoder); - case HardwareVersion::Id: - return ReadHardwareVersion(deviceInfoProvider, encoder); case HardwareVersionString::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetHardwareVersionString, - false /* unimplementedAllowed */, encoder); - case SoftwareVersion::Id: - return ReadSoftwareVersion(configManager, encoder); case SoftwareVersionString::Id: - return ReadSoftwareVersionString(configManager, encoder); case ManufacturingDate::Id: - return ReadManufacturingDate(deviceInfoProvider, encoder); case PartNumber::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetPartNumber, - true /* unimplementedAllowed */, encoder); case ProductURL::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetProductURL, - true /* unimplementedAllowed */, encoder); case ProductLabel::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetProductLabel, - true /* unimplementedAllowed */, encoder); case SerialNumber::Id: - return ReadConfigurationString(deviceInfoProvider, &DeviceInstanceInfoProvider::GetSerialNumber, - true /* unimplementedAllowed */, encoder); case UniqueID::Id: - return ReadUniqueID(configManager, encoder); - case CapabilityMinima::Id: - return ReadCapabilityMinima(encoder, deviceInfoProvider, mClusterContext.subscriptionsPerFabric); - case ProductAppearance::Id: - return ReadProductAppearance(deviceInfoProvider, encoder); - case SpecificationVersion::Id: - return encoder.Encode(Revision::kSpecificationVersion); - case MaxPathsPerInvoke::Id: - return encoder.Encode(CHIP_CONFIG_MAX_PATHS_PER_INVOKE); + readType = AttributeReadType::kString; + break; + + // Numeric Attributes + case VendorID::Id: + case ProductID::Id: + case HardwareVersion::Id: + case SoftwareVersion::Id: case ConfigurationVersion::Id: - return ReadConfigurationVersion(configManager, encoder); - case Reachable::Id: - // On some platforms `true` is defined as a unsigned int and that gets - // a ambigous TLVWriter::Put error. Hence the specialization. - return encoder.Encode(true); + readType = AttributeReadType::kNumeric; + break; + default: return Protocols::InteractionModel::Status::UnsupportedAttribute; } + + if (readType == AttributeReadType::kString) + { + return ReadStringAttribute(mDelegate, attributeId, encoder); + } + + if (readType == AttributeReadType::kNumeric) + { + return ReadNumericAttribute(mDelegate, attributeId, encoder); + } + + // Should not be reached if kOther is not set for any fallthrough cases + return Protocols::InteractionModel::Status::UnsupportedAttribute; } DataModel::ActionReturnStatus BasicInformationCluster::WriteAttribute(const DataModel::WriteAttributeRequest & request, @@ -383,8 +224,8 @@ DataModel::ActionReturnStatus BasicInformationCluster::WriteAttribute(const Data CHIP_ERROR BasicInformationCluster::IncreaseConfigurationVersion() { uint32_t globalConfig = 0; - ReturnErrorOnFailure(mClusterContext.configurationManager.GetConfigurationVersion(globalConfig)); - ReturnErrorOnFailure(mClusterContext.configurationManager.StoreConfigurationVersion(globalConfig + 1)); + ReturnErrorOnFailure(mDelegate->GetNumericAttribute(Attributes::ConfigurationVersion::Id, globalConfig)); + ReturnErrorOnFailure(mDelegate->StoreConfigurationVersion(globalConfig + 1)); NotifyAttributeChanged(ConfigurationVersion::Id); return CHIP_NO_ERROR; } @@ -402,7 +243,7 @@ DataModel::ActionReturnStatus BasicInformationCluster::WriteImpl(const DataModel CharSpan location; ReturnErrorOnFailure(decoder.Decode(location)); VerifyOrReturnError(location.size() == kExpectedFixedLocationLength, Protocols::InteractionModel::Status::ConstraintError); - return mClusterContext.configurationManager.StoreCountryCode(location.data(), location.size()); + return mDelegate->StoreLocation(location); } case NodeLabel::Id: { CharSpan label; @@ -411,11 +252,10 @@ DataModel::ActionReturnStatus BasicInformationCluster::WriteImpl(const DataModel return persistence.StoreString(request.path, mNodeLabel); } case LocalConfigDisabled::Id: { - auto & deviceInfoProvider = mClusterContext.deviceInstanceInfoProvider; - bool localConfigDisabled = false; - ReturnErrorOnFailure(deviceInfoProvider.GetLocalConfigDisabled(localConfigDisabled)); + bool localConfigDisabled = false; + ReturnErrorOnFailure(mDelegate->GetLocalConfigDisabled(localConfigDisabled)); auto decodeStatus = persistence.DecodeAndStoreNativeEndianValue(request.path, decoder, localConfigDisabled); - ReturnErrorOnFailure(deviceInfoProvider.SetLocalConfigDisabled(localConfigDisabled)); + ReturnErrorOnFailure(mDelegate->SetLocalConfigDisabled(localConfigDisabled)); return decodeStatus; } default: @@ -458,9 +298,9 @@ CHIP_ERROR BasicInformationCluster::Startup(ServerClusterContext & context) // This prevents the cluster from overwriting a delegate that may have been explicitly // registered by the application logic. If a delegate is already present, this cluster // will simply not intercept the shutdown signal via this mechanism. - if (mClusterContext.platformManager.GetDelegate() == nullptr) + if (mPlatformManager.GetDelegate() == nullptr) { - mClusterContext.platformManager.SetDelegate(this); + mPlatformManager.SetDelegate(this); } AttributePersistence persistence(context.attributeStorage); @@ -476,16 +316,16 @@ CHIP_ERROR BasicInformationCluster::Startup(ServerClusterContext & context) // Propagate the restored 'LocalConfigDisabled' state to the DeviceInstanceInfoProvider // so the underlying platform layer is aware of the configuration. - ReturnErrorOnFailure(mClusterContext.deviceInstanceInfoProvider.SetLocalConfigDisabled(localConfigDisabled)); + ReturnErrorOnFailure(mDelegate->SetLocalConfigDisabled(localConfigDisabled)); return CHIP_NO_ERROR; } void BasicInformationCluster::Shutdown(ClusterShutdownType shutdownType) { - if (mClusterContext.platformManager.GetDelegate() == this) + if (mPlatformManager.GetDelegate() == this) { - mClusterContext.platformManager.SetDelegate(nullptr); + mPlatformManager.SetDelegate(nullptr); } DefaultServerCluster::Shutdown(shutdownType); } diff --git a/src/app/clusters/basic-information/BasicInformationCluster.h b/src/app/clusters/basic-information/BasicInformationCluster.h index 25a7a40548db3a..57252d5084bdaf 100644 --- a/src/app/clusters/basic-information/BasicInformationCluster.h +++ b/src/app/clusters/basic-information/BasicInformationCluster.h @@ -16,14 +16,13 @@ */ #pragma once +#include #include #include #include #include #include #include -#include -#include #include namespace chip { @@ -38,15 +37,6 @@ namespace Clusters { class BasicInformationCluster : public DefaultServerCluster, public DeviceLayer::PlatformManagerDelegate { public: - // Define the Context struct with References - struct Context - { - DeviceLayer::DeviceInstanceInfoProvider & deviceInstanceInfoProvider; - DeviceLayer::ConfigurationManager & configurationManager; - DeviceLayer::PlatformManager & platformManager; - uint16_t subscriptionsPerFabric; - }; - using OptionalAttributesSet = chip::app::OptionalAttributeSet< // BasicInformation::Attributes::ManufacturingDate::Id, // BasicInformation::Attributes::PartNumber::Id, // @@ -62,9 +52,11 @@ class BasicInformationCluster : public DefaultServerCluster, public DeviceLayer: BasicInformation::Attributes::UniqueID::Id // >; - BasicInformationCluster(OptionalAttributesSet optionalAttributeSet, Context ctx) : - DefaultServerCluster({ kRootEndpointId, BasicInformation::Id }), mEnabledOptionalAttributes(optionalAttributeSet), - mClusterContext(ctx) + BasicInformationCluster(OptionalAttributesSet optionalAttributeSet, BasicInformation::BasicInformationDelegate * delegate, + DeviceLayer::PlatformManager & platformManager) : + DefaultServerCluster({ kRootEndpointId, BasicInformation::Id }), + mEnabledOptionalAttributes(optionalAttributeSet), mDelegate(delegate), mPlatformManager(platformManager) + { mEnabledOptionalAttributes .Set(); // Unless told otherwise, unique id is mandatory @@ -109,7 +101,8 @@ class BasicInformationCluster : public DefaultServerCluster, public DeviceLayer: OptionalAttributesSet mEnabledOptionalAttributes; Storage::String<32> mNodeLabel; - Context mClusterContext; + BasicInformation::BasicInformationDelegate * mDelegate; + DeviceLayer::PlatformManager & mPlatformManager; }; } // namespace Clusters diff --git a/src/app/clusters/basic-information/BasicInformationDelegate.h b/src/app/clusters/basic-information/BasicInformationDelegate.h new file mode 100644 index 00000000000000..337a526f585a96 --- /dev/null +++ b/src/app/clusters/basic-information/BasicInformationDelegate.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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 + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace BasicInformation { + +class BasicInformationDelegate +{ +public: + virtual ~BasicInformationDelegate() = default; + + // String Getters + virtual CHIP_ERROR GetStringAttribute(chip::AttributeId attributeId, MutableCharSpan & buffer) = 0; + + // Numeric Getters + virtual CHIP_ERROR GetNumericAttribute(chip::AttributeId attributeId, uint32_t & value) = 0; + + // Value Getters + virtual CHIP_ERROR GetProductAppearance(Structs::ProductAppearanceStruct::Type & outProductAppearance) = 0; + virtual CHIP_ERROR GetLocalConfigDisabled(bool & localConfigDisabled) = 0; + virtual CHIP_ERROR GetCapabilityMinima(Structs::CapabilityMinimaStruct::Type & outCapabilityMinima) = 0; + + // Setters + virtual CHIP_ERROR SetLocalConfigDisabled(bool localConfigDisabled) = 0; + virtual CHIP_ERROR StoreConfigurationVersion(uint32_t configurationVersion) = 0; + virtual CHIP_ERROR StoreLocation(const CharSpan & code) = 0; +}; + +} // namespace BasicInformation +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/basic-information/CodegenIntegration.cpp b/src/app/clusters/basic-information/CodegenIntegration.cpp index 5aa7a058e1e24f..a7ebd009fc17a0 100644 --- a/src/app/clusters/basic-information/CodegenIntegration.cpp +++ b/src/app/clusters/basic-information/CodegenIntegration.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -63,13 +64,12 @@ class IntegrationDelegate : public CodegenClusterIntegration::Delegate DeviceLayer::DeviceInstanceInfoProvider * provider = DeviceLayer::GetDeviceInstanceInfoProvider(); VerifyOrDie(provider != nullptr); - BasicInformationCluster::Context context = { - .deviceInstanceInfoProvider = *provider, - .configurationManager = DeviceLayer::ConfigurationMgr(), - .platformManager = DeviceLayer::PlatformMgr(), - .subscriptionsPerFabric = InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric() - }; - gServer.Create(optionalAttributeSet, context); + static chip::app::Clusters::BasicInformation::DeviceLayerBasicInformationDelegate delegate( + { .deviceInstanceInfoProvider = *provider, + .configurationManager = DeviceLayer::ConfigurationMgr(), + .platformManager = DeviceLayer::PlatformMgr(), + .subscriptionsPerFabric = InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric() }); + gServer.Create(optionalAttributeSet, &delegate, DeviceLayer::PlatformMgr()); // This disabling of the unique id attribute is here only for test purposes. The uniqe id attribute // is mandatory, but was optional in previous versions. It is forced to be enabled in the basic information diff --git a/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.cpp b/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.cpp new file mode 100644 index 00000000000000..fa2f0ee31b5459 --- /dev/null +++ b/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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 "lib/core/CHIPError.h" +#include "lib/support/Span.h" +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace BasicInformation { +namespace { +// Clears the buffer and returns CHIP_NO_ERROR if input status is not-implemented. +// Otherwise just returns status as-is. +CHIP_ERROR IgnoreUnimplemented(CHIP_ERROR status, MutableCharSpan & buffer) +{ + if (status == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || status == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) + { + buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + return status; +} + +} // namespace + +using namespace DeviceLayer; + +CHIP_ERROR DeviceLayerBasicInformationDelegate::GetStringAttribute(chip::AttributeId attributeId, MutableCharSpan & buffer) +{ + using namespace Attributes; + + CHIP_ERROR err = CHIP_NO_ERROR; + size_t dataLen = 0; + + switch (attributeId) + { + case VendorName::Id: + err = mContext.deviceInstanceInfoProvider.GetVendorName(buffer.data(), buffer.size()); + break; + case ProductName::Id: + err = mContext.deviceInstanceInfoProvider.GetProductName(buffer.data(), buffer.size()); + break; + case PartNumber::Id: + err = mContext.deviceInstanceInfoProvider.GetPartNumber(buffer.data(), buffer.size()); + break; + case ProductURL::Id: + err = mContext.deviceInstanceInfoProvider.GetProductURL(buffer.data(), buffer.size()); + break; + case ProductLabel::Id: + err = mContext.deviceInstanceInfoProvider.GetProductLabel(buffer.data(), buffer.size()); + break; + case SerialNumber::Id: + err = mContext.deviceInstanceInfoProvider.GetSerialNumber(buffer.data(), buffer.size()); + break; + case HardwareVersionString::Id: + err = mContext.deviceInstanceInfoProvider.GetHardwareVersionString(buffer.data(), buffer.size()); + break; + case SoftwareVersionString::Id: + err = mContext.configurationManager.GetSoftwareVersionString(buffer.data(), buffer.size()); + break; + case UniqueID::Id: + err = mContext.configurationManager.GetUniqueId(buffer.data(), buffer.size()); + break; + case ManufacturingDate::Id: { + constexpr size_t kMaxLen = BasicInformation::Attributes::ManufacturingDate::TypeInfo::MaxLength(); + constexpr size_t kMaxDateLength = 8; // YYYYMMDD + static_assert(kMaxLen > kMaxDateLength, "kMaxLen must be greater than kMaxDateLength"); + uint16_t manufacturingYear; + uint8_t manufacturingMonth; + uint8_t manufacturingDayOfMonth; + size_t totalManufacturingDateLen = 0; + + CHIP_ERROR status = mContext.deviceInstanceInfoProvider.GetManufacturingDate(manufacturingYear, manufacturingMonth, + manufacturingDayOfMonth); + + if (status == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || status == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) + { + // Default to an empty string if not found + buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(status); + + if (buffer.size() < kMaxDateLength) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + + // Format is YYYYMMDD + int written = + snprintf(buffer.data(), buffer.size(), "%04u%02u%02u", manufacturingYear, manufacturingMonth, manufacturingDayOfMonth); + if (written < 0 || written >= static_cast(buffer.size())) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + totalManufacturingDateLen = static_cast(written); + + if (buffer.size() > kMaxDateLength) + { + MutableCharSpan vendorSuffixSpan(buffer.data() + kMaxDateLength, buffer.size() - kMaxDateLength); + status = mContext.deviceInstanceInfoProvider.GetManufacturingDateSuffix(vendorSuffixSpan); + if (status == CHIP_NO_ERROR) + { + totalManufacturingDateLen += vendorSuffixSpan.size(); + } + // Suffix is optional, so errors other than NO_ERROR are ignored. + } + + buffer.reduce_size(totalManufacturingDateLen); + return CHIP_NO_ERROR; + } + case Location::Id: { + + constexpr size_t kExpectedFixedLocationLength = 2; + err = mContext.configurationManager.GetCountryCode(buffer.data(), buffer.size(), dataLen); + if ((err != CHIP_NO_ERROR) || (dataLen != kExpectedFixedLocationLength)) + { + // Fallback that was here historically + return CopyCharSpanToMutableCharSpan("XX"_span, buffer); + } + + buffer.reduce_size(dataLen); + return err; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + + if (err == CHIP_NO_ERROR) + { + buffer.reduce_size(strlen(buffer.data())); + } + + return IgnoreUnimplemented(err, buffer); +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::GetNumericAttribute(chip::AttributeId attributeId, uint32_t & value) +{ + using namespace Attributes; + CHIP_ERROR err = CHIP_NO_ERROR; + + switch (attributeId) + { + case VendorID::Id: { + uint16_t val; + err = mContext.deviceInstanceInfoProvider.GetVendorId(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + case ProductID::Id: { + uint16_t val; + err = mContext.deviceInstanceInfoProvider.GetProductId(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + case HardwareVersion::Id: { + uint16_t val; + err = mContext.deviceInstanceInfoProvider.GetHardwareVersion(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + case SoftwareVersion::Id: { + uint32_t val; + err = mContext.configurationManager.GetSoftwareVersion(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + case LocalConfigDisabled::Id: { + bool val; + err = mContext.deviceInstanceInfoProvider.GetLocalConfigDisabled(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + case ConfigurationVersion::Id: { + uint32_t val; + err = mContext.configurationManager.GetConfigurationVersion(val); + if (err == CHIP_NO_ERROR) + value = val; + break; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return err; +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::GetLocalConfigDisabled(bool & localConfigDisabled) +{ + return mContext.deviceInstanceInfoProvider.GetLocalConfigDisabled(localConfigDisabled); +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::GetCapabilityMinima(Structs::CapabilityMinimaStruct::Type & outCapabilityMinima) +{ + constexpr uint16_t kMinCaseSessionsPerFabricMandatedBySpec = 3; + + auto capabilityMinimasFromDeviceInfo = mContext.deviceInstanceInfoProvider.GetSupportedCapabilityMinimaValues(); + + outCapabilityMinima.caseSessionsPerFabric = kMinCaseSessionsPerFabricMandatedBySpec; + outCapabilityMinima.subscriptionsPerFabric = mContext.subscriptionsPerFabric; + outCapabilityMinima.simultaneousInvocationsSupported = + chip::MakeOptional(capabilityMinimasFromDeviceInfo.simultaneousInvocationsSupported); + outCapabilityMinima.simultaneousWritesSupported = + chip::MakeOptional(capabilityMinimasFromDeviceInfo.simultaneousWritesSupported); + outCapabilityMinima.readPathsSupported = chip::MakeOptional(capabilityMinimasFromDeviceInfo.readPathsSupported); + outCapabilityMinima.subscribePathsSupported = + chip::MakeOptional(capabilityMinimasFromDeviceInfo.subscribePathsSupported); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::SetLocalConfigDisabled(bool localConfigDisabled) +{ + return mContext.deviceInstanceInfoProvider.SetLocalConfigDisabled(localConfigDisabled); +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::StoreConfigurationVersion(uint32_t configurationVersion) +{ + return mContext.configurationManager.StoreConfigurationVersion(configurationVersion); +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::StoreLocation(const CharSpan & code) +{ + return mContext.configurationManager.StoreCountryCode(code.data(), code.size()); +} + +CHIP_ERROR DeviceLayerBasicInformationDelegate::GetProductAppearance(Structs::ProductAppearanceStruct::Type & outProductAppearance) +{ + ProductFinishEnum finish; + ReturnErrorOnFailure(mContext.deviceInstanceInfoProvider.GetProductFinish(&finish)); + outProductAppearance.finish = finish; + + ColorEnum color; + CHIP_ERROR colorStatus = mContext.deviceInstanceInfoProvider.GetProductPrimaryColor(&color); + + if (colorStatus == CHIP_NO_ERROR) + { + outProductAppearance.primaryColor.SetNonNull(color); + } + else if (colorStatus == CHIP_ERROR_NOT_IMPLEMENTED) + { + outProductAppearance.primaryColor.SetNull(); + } + else + { + return colorStatus; + } + + return CHIP_NO_ERROR; +} + +} // namespace BasicInformation +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.h b/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.h new file mode 100644 index 00000000000000..0dc99900c6258d --- /dev/null +++ b/src/app/clusters/basic-information/DeviceLayerBasicInformationDelegate.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2026 Project CHIP Authors + * All rights reserved. + * + * 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 +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace BasicInformation { + +class DeviceLayerBasicInformationDelegate : public BasicInformationDelegate +{ +public: + struct Context + { + DeviceLayer::DeviceInstanceInfoProvider & deviceInstanceInfoProvider; + DeviceLayer::ConfigurationManager & configurationManager; + DeviceLayer::PlatformManager & platformManager; + uint16_t subscriptionsPerFabric; + }; + + DeviceLayerBasicInformationDelegate(Context ctx) : mContext(ctx) {} + + // BasicInformationDelegate Interface + CHIP_ERROR GetStringAttribute(chip::AttributeId attributeId, MutableCharSpan & buffer) override; + CHIP_ERROR GetNumericAttribute(chip::AttributeId attributeId, uint32_t & value) override; + + CHIP_ERROR GetProductAppearance(Structs::ProductAppearanceStruct::Type & outProductAppearance) override; + CHIP_ERROR GetLocalConfigDisabled(bool & localConfigDisabled) override; + CHIP_ERROR GetCapabilityMinima(Structs::CapabilityMinimaStruct::Type & outCapabilityMinima) override; + + CHIP_ERROR SetLocalConfigDisabled(bool localConfigDisabled) override; + CHIP_ERROR StoreConfigurationVersion(uint32_t configurationVersion) override; + CHIP_ERROR StoreLocation(const CharSpan & code) override; + +private: + Context mContext; +}; + +} // namespace BasicInformation +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/basic-information/tests/MockBasicInformationDelegate.h b/src/app/clusters/basic-information/tests/MockBasicInformationDelegate.h new file mode 100644 index 00000000000000..047aec282e24ca --- /dev/null +++ b/src/app/clusters/basic-information/tests/MockBasicInformationDelegate.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2026 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 +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace BasicInformation { +namespace tests { + +using namespace chip::DeviceLayer; + +static auto kVendorName = "TestVendor"_span; +static auto kProductName = "TestProduct"_span; +static auto kHardwareVersionString = "HW1.0"_span; +static auto kPartNumber = "PART123"_span; +static auto kProductURL = "http://example.com"_span; +static auto kProductLabel = "Label123"_span; +static auto kSerialNumber = "SN123456"_span; +static constexpr uint16_t kVendorId = static_cast(VendorId::TestVendor1); +static constexpr uint16_t kProductId = 0x5678; +static constexpr uint16_t kHardwareVersion = 1; +static constexpr uint16_t kManufacturingYear = 2023; +static constexpr uint8_t kManufacturingMonth = 6; +static constexpr uint8_t kManufacturingDay = 15; +static constexpr ProductFinishEnum kProductFinish = ProductFinishEnum::kMatte; +static constexpr ColorEnum kProductPrimaryColor = ColorEnum::kBlack; +static constexpr size_t kLocationLength = 2; +static auto kUniqueId = "TEST_UNIQUE_ID_12345"_span; +static auto kSoftwareVersionString = "SW1.0"_span; +static constexpr uint32_t kSoftwareVersion = 1; + +// Helper function to safely copy strings and check for buffer size +inline CHIP_ERROR SafeCopyString(char * buf, size_t bufSize, const char * source) +{ + if (strlen(source) >= bufSize) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + Platform::CopyString(buf, bufSize, source); + return CHIP_NO_ERROR; +} + +class MockBasicInformationDelegate : public BasicInformationDelegate +{ +public: + CHIP_ERROR GetStringAttribute(chip::AttributeId attributeId, MutableCharSpan & buffer) override + { + switch (attributeId) + { + case Attributes::VendorName::Id: + return CopyCharSpanToMutableCharSpan(kVendorName, buffer); + case Attributes::ProductName::Id: + return CopyCharSpanToMutableCharSpan(kProductName, buffer); + case Attributes::PartNumber::Id: + return CopyCharSpanToMutableCharSpan(kPartNumber, buffer); + case Attributes::ProductURL::Id: + return CopyCharSpanToMutableCharSpan(kProductURL, buffer); + case Attributes::ProductLabel::Id: + return CopyCharSpanToMutableCharSpan(kProductLabel, buffer); + case Attributes::SerialNumber::Id: + return CopyCharSpanToMutableCharSpan(kSerialNumber, buffer); + case Attributes::HardwareVersionString::Id: + return CopyCharSpanToMutableCharSpan(kHardwareVersionString, buffer); + case Attributes::SoftwareVersionString::Id: + return CopyCharSpanToMutableCharSpan(kSoftwareVersionString, buffer); + case Attributes::UniqueID::Id: + return CopyCharSpanToMutableCharSpan(kUniqueId, buffer); + case Attributes::ManufacturingDate::Id: + return CopyCharSpanToMutableCharSpan(CharSpan::fromCharString(mManufacturingDate), buffer); + case Attributes::Location::Id: + return CopyCharSpanToMutableCharSpan(CharSpan::fromCharString(mLocation), buffer); + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + } + + CHIP_ERROR GetNumericAttribute(chip::AttributeId attributeId, uint32_t & value) override + { + switch (attributeId) + { + case Attributes::VendorID::Id: + value = kVendorId; + return CHIP_NO_ERROR; + case Attributes::ProductID::Id: + value = kProductId; + return CHIP_NO_ERROR; + case Attributes::HardwareVersion::Id: + value = kHardwareVersion; + return CHIP_NO_ERROR; + case Attributes::SoftwareVersion::Id: + value = kSoftwareVersion; + return CHIP_NO_ERROR; + // case Attributes::LocalConfigDisabled::Id: // This is a bool, not handled here + // value = mLocalConfigDisabled; + // return CHIP_NO_ERROR; + case Attributes::ConfigurationVersion::Id: + value = mConfigurationVersion; + return CHIP_NO_ERROR; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + } + + CHIP_ERROR GetProductAppearance(Structs::ProductAppearanceStruct::Type & outProductAppearance) override + { + outProductAppearance.finish = kProductFinish; + outProductAppearance.primaryColor.SetNonNull(kProductPrimaryColor); + return CHIP_NO_ERROR; + } + CHIP_ERROR GetLocalConfigDisabled(bool & localConfigDisabled) override + { + localConfigDisabled = mLocalConfigDisabled; + return CHIP_NO_ERROR; + } + + CHIP_ERROR GetCapabilityMinima(Structs::CapabilityMinimaStruct::Type & outCapabilityMinima) override + { + outCapabilityMinima.caseSessionsPerFabric = 3; + outCapabilityMinima.subscriptionsPerFabric = 3; + outCapabilityMinima.simultaneousInvocationsSupported = + chip::MakeOptional(static_cast(CHIP_IM_MAX_NUM_COMMAND_HANDLER)); + outCapabilityMinima.simultaneousWritesSupported = + chip::MakeOptional(static_cast(CHIP_IM_MAX_NUM_WRITE_HANDLER)); + outCapabilityMinima.readPathsSupported = + chip::MakeOptional(static_cast(CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS)); + outCapabilityMinima.subscribePathsSupported = + chip::MakeOptional(static_cast(CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS)); + return CHIP_NO_ERROR; + } + + CHIP_ERROR SetLocalConfigDisabled(bool localConfigDisabled) override + { + mLocalConfigDisabled = localConfigDisabled; + return CHIP_NO_ERROR; + } + + CHIP_ERROR StoreConfigurationVersion(uint32_t configurationVersion) override + { + mConfigurationVersion = configurationVersion; + mStoreConfigVersionCalled++; + return mStoreConfigVersionReturn; + } + + CHIP_ERROR StoreLocation(const CharSpan & code) override + { + VerifyOrReturnError(code.size() == kLocationLength, CHIP_ERROR_INVALID_ARGUMENT); + Platform::CopyString(mLocation, sizeof(mLocation), code.data()); + return CHIP_NO_ERROR; + } + +public: // Public for test access + uint32_t mConfigurationVersion = 10u; + uint32_t mStoreConfigVersionCalled = 0u; + CHIP_ERROR mStoreConfigVersionReturn = CHIP_NO_ERROR; + char mManufacturingDate[17] = "20230615"; // YYYYMMDD + optional suffix + +private: + bool mLocalConfigDisabled = false; + char mLocation[kLocationLength + 1] = "XX"; +}; + +} // namespace tests +} // namespace BasicInformation +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/clusters/basic-information/tests/TestBasicInformationCluster.cpp b/src/app/clusters/basic-information/tests/TestBasicInformationCluster.cpp index 60e3d93bf7edfd..3dc848311f7e34 100644 --- a/src/app/clusters/basic-information/tests/TestBasicInformationCluster.cpp +++ b/src/app/clusters/basic-information/tests/TestBasicInformationCluster.cpp @@ -15,6 +15,7 @@ */ #include +#include "MockBasicInformationDelegate.h" #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include namespace { @@ -36,109 +36,15 @@ using namespace chip; using namespace chip::app::Clusters; using namespace chip::app::Clusters::BasicInformation; using namespace chip::app::Clusters::BasicInformation::Attributes; +using namespace chip::app::Clusters::BasicInformation::tests; using chip::app::DataModel::AcceptedCommandEntry; using chip::app::DataModel::AttributeEntry; -static constexpr const char * kVendorName = "TestVendor"; -static constexpr const char * kProductName = "TestProduct"; -static constexpr const char * kHardwareVersionString = "HW1.0"; -static constexpr const char * kPartNumber = "PART123"; -static constexpr const char * kProductURL = "http://example.com"; -static constexpr const char * kProductLabel = "Label123"; -static constexpr const char * kSerialNumber = "SN123456"; -static constexpr uint16_t kVendorId = static_cast(VendorId::TestVendor1); -static constexpr uint16_t kProductId = 0x5678; -static constexpr uint16_t kHardwareVersion = 1; -static constexpr uint16_t kManufacturingYear = 2023; -static constexpr uint8_t kManufacturingMonth = 6; -static constexpr uint8_t kManufacturingDay = 15; -static constexpr ProductFinishEnum kProductFinish = ProductFinishEnum::kMatte; -static constexpr ColorEnum kProductPrimaryColor = ColorEnum::kBlack; - -// Helper function to safely copy strings and check for buffer size -CHIP_ERROR SafeCopyString(char * buf, size_t bufSize, const char * source) -{ - if (strlen(source) >= bufSize) - { - return CHIP_ERROR_BUFFER_TOO_SMALL; - } - Platform::CopyString(buf, bufSize, source); - return CHIP_NO_ERROR; -} - -// Mock DeviceInstanceInfoProvider for testing -class MockDeviceInstanceInfoProvider : public DeviceLayer::DeviceInstanceInfoProvider -{ -public: - CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kVendorName); } - - CHIP_ERROR GetVendorId(uint16_t & vendorId) override - { - vendorId = kVendorId; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetProductName(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductName); } - - CHIP_ERROR GetProductId(uint16_t & productId) override - { - productId = kProductId; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override - { - hardwareVersion = kHardwareVersion; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override - { - return SafeCopyString(buf, bufSize, kHardwareVersionString); - } - - CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override - { - year = kManufacturingYear; - month = kManufacturingMonth; - day = kManufacturingDay; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kPartNumber); } - - CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductURL); } - - CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductLabel); } - - CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kSerialNumber); } - - CHIP_ERROR GetProductFinish(ProductFinishEnum * finish) override - { - *finish = kProductFinish; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetProductPrimaryColor(ColorEnum * color) override - { - *color = kProductPrimaryColor; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override { return CHIP_NO_ERROR; } -}; - // initialize memory as ReadOnlyBufferBuilder may allocate struct TestBasicInformationCluster : public ::testing::Test { - MockDeviceInstanceInfoProvider mDeviceInfoProvider; - BasicInformationCluster::Context mContext = { - .deviceInstanceInfoProvider = mDeviceInfoProvider, - .configurationManager = chip::DeviceLayer::ConfigurationMgr(), - .platformManager = chip::DeviceLayer::PlatformMgr(), - .subscriptionsPerFabric = app::InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric(), - }; + tests::MockBasicInformationDelegate mMockDelegate; static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } @@ -150,7 +56,7 @@ TEST_F(TestBasicInformationCluster, TestAttributes) // check without optional attributes { const BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); EXPECT_TRUE(Testing::IsAttributesListEqualTo( cluster, @@ -168,7 +74,7 @@ TEST_F(TestBasicInformationCluster, TestAttributes) // Check that disabling unique id works { const BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); // UniqueID is EXPLICITLY NOT SET cluster.OptionalAttributes() = BasicInformationCluster::OptionalAttributesSet(); @@ -206,7 +112,7 @@ TEST_F(TestBasicInformationCluster, TestAttributes) .Set() .Set(); - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); EXPECT_TRUE(Testing::IsAttributesListEqualTo(cluster, diff --git a/src/app/clusters/basic-information/tests/TestBasicInformationReadWrite.cpp b/src/app/clusters/basic-information/tests/TestBasicInformationReadWrite.cpp index 3d06cd5b834e50..8c5ba84cc2dae0 100644 --- a/src/app/clusters/basic-information/tests/TestBasicInformationReadWrite.cpp +++ b/src/app/clusters/basic-information/tests/TestBasicInformationReadWrite.cpp @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "MockBasicInformationDelegate.h" #include #include #include @@ -38,238 +39,8 @@ using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::BasicInformation; +using namespace chip::app::Clusters::BasicInformation::tests; -static constexpr const char * kVendorName = "TestVendor"; -static constexpr const char * kProductName = "TestProduct"; -static constexpr const char * kHardwareVersionString = "HW1.0"; -static constexpr const char * kPartNumber = "PART123"; -static constexpr const char * kProductURL = "http://example.com"; -static constexpr const char * kProductLabel = "Label123"; -static constexpr const char * kSerialNumber = "SN123456"; -static constexpr uint16_t kVendorId = static_cast(VendorId::TestVendor1); -static constexpr uint16_t kProductId = 0x5678; -static constexpr uint16_t kHardwareVersion = 1; -static constexpr uint16_t kManufacturingYear = 2023; -static constexpr uint8_t kManufacturingMonth = 6; -static constexpr uint8_t kManufacturingDay = 15; -static constexpr ProductFinishEnum kProductFinish = ProductFinishEnum::kMatte; -static constexpr ColorEnum kProductPrimaryColor = ColorEnum::kBlack; - -// Helper function to safely copy strings and check for buffer size -CHIP_ERROR SafeCopyString(char * buf, size_t bufSize, const char * source) -{ - if (strlen(source) >= bufSize) - { - return CHIP_ERROR_BUFFER_TOO_SMALL; - } - Platform::CopyString(buf, bufSize, source); - return CHIP_NO_ERROR; -} -// Mock DeviceInstanceInfoProvider for testing -class MockDeviceInstanceInfoProvider : public DeviceLayer::DeviceInstanceInfoProvider -{ -public: - CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kVendorName); } - - CHIP_ERROR GetVendorId(uint16_t & vendorId) override - { - vendorId = kVendorId; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetProductName(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductName); } - - CHIP_ERROR GetProductId(uint16_t & productId) override - { - productId = kProductId; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override - { - hardwareVersion = kHardwareVersion; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override - { - return SafeCopyString(buf, bufSize, kHardwareVersionString); - } - - CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override - { - year = kManufacturingYear; - month = kManufacturingMonth; - day = kManufacturingDay; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetManufacturingDateSuffix(MutableCharSpan & suffixBuffer) override - { - if (mManufacturingDateSuffix == nullptr) - { - suffixBuffer.reduce_size(0); - return CHIP_NO_ERROR; - } - return CopyCharSpanToMutableCharSpan(CharSpan::fromCharString(mManufacturingDateSuffix), suffixBuffer); - } - - CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kPartNumber); } - - CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductURL); } - - CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kProductLabel); } - - CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kSerialNumber); } - - CHIP_ERROR GetProductFinish(ProductFinishEnum * finish) override - { - *finish = kProductFinish; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetProductPrimaryColor(ColorEnum * color) override - { - *color = kProductPrimaryColor; - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override { return CHIP_NO_ERROR; } - - // NOTE: suffix lifetime MUST be longer than this object lifetime as just a pointer is kept. - void SetManufacturingDateSuffix(const char * suffix) { mManufacturingDateSuffix = suffix; } - -private: - const char * mManufacturingDateSuffix = nullptr; -}; - -static constexpr size_t kCountryCodeLength = 2; -static constexpr const char * kUniqueId = "TEST_UNIQUE_ID_12345"; -// Mock ConfigurationManager for testing -class MockConfigurationManager : public chip::DeviceLayer::ConfigurationManager -{ -public: - // ======================================================================== - // Methods used by the Test Logic - // ======================================================================== - CHIP_ERROR GetUniqueId(char * buf, size_t bufSize) override { return SafeCopyString(buf, bufSize, kUniqueId); } - - CHIP_ERROR StoreCountryCode(const char * countryCode, size_t countryCodeLen) override - { - VerifyOrReturnError(countryCodeLen == kCountryCodeLength, CHIP_ERROR_INVALID_ARGUMENT); - Platform::CopyString(mCountryCode, sizeof(mCountryCode), countryCode); - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetCountryCode(char * buf, size_t bufSize, size_t & countryCodeLen) override - { - VerifyOrReturnError(bufSize > kCountryCodeLength, CHIP_ERROR_BUFFER_TOO_SMALL); - Platform::CopyString(buf, bufSize, mCountryCode); - countryCodeLen = kCountryCodeLength; - return CHIP_NO_ERROR; - } - - // ======================================================================== - // Stubs required to satisfy the ConfigurationManager Interface - // ======================================================================== - - CHIP_ERROR Init() override { return CHIP_NO_ERROR; } - - CHIP_ERROR GetPrimaryMACAddress(MutableByteSpan & buf) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetPrimary802154MACAddress(uint8_t * buf) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetSoftwareVersion(uint32_t & softwareVersion) override { return CHIP_NO_ERROR; } - CHIP_ERROR GetSoftwareVersionString(char * buf, size_t bufSize) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetFirmwareBuildChipEpochTime(System::Clock::Seconds32 & buildTime) override - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - - CHIP_ERROR StoreSerialNumber(const char * serialNum, size_t serialNumLen) override { return CHIP_NO_ERROR; } - CHIP_ERROR StoreManufacturingDate(const char * mfgDate, size_t mfgDateLen) override { return CHIP_NO_ERROR; } - CHIP_ERROR StoreSoftwareVersion(uint32_t softwareVer) override { return CHIP_NO_ERROR; } - CHIP_ERROR StoreHardwareVersion(uint16_t hardwareVer) override { return CHIP_NO_ERROR; } - CHIP_ERROR StoreRegulatoryLocation(uint8_t location) override { return CHIP_NO_ERROR; } - CHIP_ERROR StoreUniqueId(const char * uniqueId, size_t uniqueIdLen) override { return CHIP_NO_ERROR; } - CHIP_ERROR GenerateUniqueId(char * buf, size_t bufSize) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - - CHIP_ERROR GetFailSafeArmed(bool & val) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR SetFailSafeArmed(bool val) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - - CHIP_ERROR GetBLEDeviceIdentificationInfo(Ble::ChipBLEDeviceIdentificationInfo & deviceIdInfo) override - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - - void RunUnitTests() override {} - bool IsFullyProvisioned() override { return false; } - void LogDeviceConfig() override {} - - bool IsCommissionableDeviceTypeEnabled() override { return false; } - CHIP_ERROR GetDeviceTypeId(uint32_t & deviceType) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - bool IsCommissionableDeviceNameEnabled() override { return false; } - CHIP_ERROR GetCommissionableDeviceName(char * buf, size_t bufSize) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - - CHIP_ERROR GetInitialPairingHint(uint16_t & pairingHint) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetInitialPairingInstruction(char * buf, size_t bufSize) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetSecondaryPairingHint(uint16_t & pairingHint) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetSecondaryPairingInstruction(char * buf, size_t bufSize) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } -#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) - CHIP_ERROR GetLifetimeCounter(uint16_t & lifetimeCounter) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR IncrementLifetimeCounter() override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR SetRotatingDeviceIdUniqueId(const ByteSpan & uniqueIdSpan) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } - CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override { return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } -#endif - - CHIP_ERROR ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value) override - { - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; - } - CHIP_ERROR WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value) override - { - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetRebootCount(uint32_t & v) override - { - v = 0; - return CHIP_NO_ERROR; - } - CHIP_ERROR StoreRebootCount(uint32_t) override { return CHIP_NO_ERROR; } - CHIP_ERROR GetTotalOperationalHours(uint32_t & v) override - { - v = 0; - return CHIP_NO_ERROR; - } - CHIP_ERROR StoreTotalOperationalHours(uint32_t) override { return CHIP_NO_ERROR; } - CHIP_ERROR GetBootReason(uint32_t & v) override - { - v = 0; - return CHIP_NO_ERROR; - } - CHIP_ERROR StoreBootReason(uint32_t) override { return CHIP_NO_ERROR; } - CHIP_ERROR GetRegulatoryLocation(uint8_t & loc) override - { - loc = 0; - return CHIP_NO_ERROR; - } - CHIP_ERROR GetLocationCapability(uint8_t & cap) override - { - cap = 0; - return CHIP_NO_ERROR; - } - CHIP_ERROR GetConfigurationVersion(uint32_t & v) override - { - v = 1; - return CHIP_NO_ERROR; - } - CHIP_ERROR StoreConfigurationVersion(uint32_t) override { return CHIP_NO_ERROR; } - bool CanFactoryReset() override { return false; } - void InitiateFactoryReset() override {} - -private: - char mCountryCode[kCountryCodeLength + 1] = "XX"; -}; struct TestBasicInformationReadWrite : public ::testing::Test { static void SetUpTestSuite() @@ -295,18 +66,11 @@ struct TestBasicInformationReadWrite : public ::testing::Test chip::Platform::MemoryShutdown(); } - TestBasicInformationReadWrite() {} + TestBasicInformationReadWrite() = default; chip::Testing::TestServerClusterContext testContext; static DeviceLayer::DeviceInstanceInfoProvider * sDeviceInstanceInfoProviderBackup; // Context - MockDeviceInstanceInfoProvider mDeviceInfoProvider; - MockConfigurationManager mMockConfigurationManager; - BasicInformationCluster::Context mContext = { - .deviceInstanceInfoProvider = mDeviceInfoProvider, - .configurationManager = mMockConfigurationManager, - .platformManager = chip::DeviceLayer::PlatformMgr(), - .subscriptionsPerFabric = InteractionModelEngine::GetInstance()->GetMinGuaranteedSubscriptionsPerFabric(), - }; + tests::MockBasicInformationDelegate mMockDelegate; }; DeviceLayer::DeviceInstanceInfoProvider * TestBasicInformationReadWrite::sDeviceInstanceInfoProviderBackup = nullptr; @@ -314,7 +78,7 @@ DeviceLayer::DeviceInstanceInfoProvider * TestBasicInformationReadWrite::sDevice TEST_F(TestBasicInformationReadWrite, TestNodeLabelLoadAndSave) { const BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); ASSERT_EQ(cluster.Startup(testContext.Get()), CHIP_NO_ERROR); chip::Testing::ClusterTester tester(cluster); @@ -369,7 +133,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; optionalAttributeSet.Set(); - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); chip::Testing::ClusterTester tester(cluster); // VendorName @@ -377,7 +141,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) char buf[64]; CharSpan val(buf); ASSERT_EQ(tester.ReadAttribute(Attributes::VendorName::Id, val), CHIP_NO_ERROR); - EXPECT_TRUE(val.data_equal(CharSpan::fromCharString(kVendorName))); + EXPECT_TRUE(val.data_equal(kVendorName)); } // VendorID @@ -392,7 +156,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) char buf[64]; CharSpan val(buf); ASSERT_EQ(tester.ReadAttribute(Attributes::ProductName::Id, val), CHIP_NO_ERROR); - EXPECT_TRUE(val.data_equal(CharSpan::fromCharString(kProductName))); + EXPECT_TRUE(val.data_equal(kProductName)); } // ProductID { @@ -421,7 +185,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) char buf[64]; CharSpan val(buf); ASSERT_EQ(tester.ReadAttribute(Attributes::HardwareVersionString::Id, val), CHIP_NO_ERROR); - EXPECT_TRUE(val.data_equal(CharSpan::fromCharString(kHardwareVersionString))); + EXPECT_TRUE(val.data_equal(kHardwareVersionString)); } // SoftwareVersion is read from ConfigurationManager @@ -443,10 +207,10 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) { char buf[32]; CharSpan val(buf); - mDeviceInfoProvider.SetManufacturingDateSuffix("ABCDEFGH"); + strcpy(mMockDelegate.mManufacturingDate, "20230615ABCDEFGH"); ASSERT_EQ(tester.ReadAttribute(Attributes::ManufacturingDate::Id, val), CHIP_NO_ERROR); EXPECT_TRUE(val.data_equal("20230615ABCDEFGH"_span)); - mDeviceInfoProvider.SetManufacturingDateSuffix(nullptr); + strcpy(mMockDelegate.mManufacturingDate, "20230615"); // Reset } // UniqueID (Mandatory in Rev 4+, so if it fails, cluster rev must be < 4) @@ -466,7 +230,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) else { // If UniqueID is readable, it must match what the mock returns. - EXPECT_TRUE(val.data_equal(CharSpan::fromCharString(kUniqueId))); + EXPECT_TRUE(val.data_equal(kUniqueId)); EXPECT_EQ(clusterRev, BasicInformation::kRevision); } } @@ -495,7 +259,7 @@ TEST_F(TestBasicInformationReadWrite, TestAllAttributesSpecCompliance) TEST_F(TestBasicInformationReadWrite, TestWriteNodeLabel) { const BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); ASSERT_EQ(cluster.Startup(testContext.Get()), CHIP_NO_ERROR); chip::Testing::ClusterTester tester(cluster); @@ -517,15 +281,15 @@ TEST_F(TestBasicInformationReadWrite, TestWriteNodeLabel) TEST_F(TestBasicInformationReadWrite, TestWriteLocation) { const BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); ASSERT_EQ(cluster.Startup(testContext.Get()), CHIP_NO_ERROR); chip::Testing::ClusterTester tester(cluster); // --- Test Case 1: Write a valid 2-character location --- { CharSpan validLocation = "US"_span; - char readBuffer[8]; - CharSpan readSpan(readBuffer); + char readBuffer[32]; + CharSpan readSpan(readBuffer, sizeof(readBuffer)); ASSERT_EQ(tester.WriteAttribute(Attributes::Location::Id, validLocation), CHIP_NO_ERROR); ASSERT_EQ(tester.ReadAttribute(Attributes::Location::Id, readSpan), CHIP_NO_ERROR); EXPECT_TRUE(readSpan.data_equal(validLocation)); @@ -551,7 +315,7 @@ TEST_F(TestBasicInformationReadWrite, TestWriteLocalConfigDisabled) BasicInformationCluster::OptionalAttributesSet optionalAttributeSet; optionalAttributeSet.Set(); - BasicInformationCluster cluster(optionalAttributeSet, mContext); + BasicInformationCluster cluster(optionalAttributeSet, &mMockDelegate, chip::DeviceLayer::PlatformMgr()); ASSERT_EQ(cluster.Startup(testContext.Get()), CHIP_NO_ERROR); chip::Testing::ClusterTester tester(cluster); diff --git a/src/app/clusters/bridged-device-basic-information-server/tests/TestBridgedDeviceBasicInformationCluster.cpp b/src/app/clusters/bridged-device-basic-information-server/tests/TestBridgedDeviceBasicInformationCluster.cpp index 28fef77af86df3..37843d26e971f3 100644 --- a/src/app/clusters/bridged-device-basic-information-server/tests/TestBridgedDeviceBasicInformationCluster.cpp +++ b/src/app/clusters/bridged-device-basic-information-server/tests/TestBridgedDeviceBasicInformationCluster.cpp @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "lib/core/Optional.h" #include #include #include +#include #include #include #include @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include @@ -62,28 +64,11 @@ constexpr EndpointId kTestEndpointId = 1; class MockConfigurationManager : public DeviceLayer::ConfigurationManager { public: - CHIP_ERROR GetPrimaryMACAddress(MutableByteSpan & buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetPrimary802154MACAddress(uint8_t * buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetSoftwareVersionString(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetSoftwareVersion(uint32_t & softwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR GetConfigurationVersion(uint32_t & configurationVer) override { configurationVer = mConfigurationVersion; return CHIP_NO_ERROR; } - CHIP_ERROR GetFirmwareBuildChipEpochTime(System::Clock::Seconds32 & buildTime) override { return CHIP_ERROR_NOT_IMPLEMENTED; } -#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) - CHIP_ERROR GetLifetimeCounter(uint16_t & lifetimeCounter) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR IncrementLifetimeCounter() override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR SetRotatingDeviceIdUniqueId(const ByteSpan & uniqueIdSpan) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override { return CHIP_ERROR_NOT_IMPLEMENTED; } -#endif - CHIP_ERROR GetRegulatoryLocation(uint8_t & location) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetCountryCode(char * buf, size_t bufSize, size_t & codeLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreSerialNumber(const char * serialNum, size_t serialNumLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreManufacturingDate(const char * mfgDate, size_t mfgDateLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreSoftwareVersion(uint32_t softwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR StoreConfigurationVersion(uint32_t configurationVer) override { if (mReturnError != CHIP_NO_ERROR) @@ -94,18 +79,12 @@ class MockConfigurationManager : public DeviceLayer::ConfigurationManager mStoreCalled++; return CHIP_NO_ERROR; } - CHIP_ERROR StoreHardwareVersion(uint16_t hardwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreRegulatoryLocation(uint8_t location) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreCountryCode(const char * code, size_t codeLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetRebootCount(uint32_t & rebootCount) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreRebootCount(uint32_t rebootCount) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetBootReason(uint32_t & bootReason) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreBootReason(uint32_t bootReason) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GetUniqueId(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR StoreUniqueId(const char * uniqueId, size_t uniqueIdLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } - CHIP_ERROR GenerateUniqueId(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } +#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + CHIP_ERROR GetLifetimeCounter(uint16_t & lifetimeCounter) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR IncrementLifetimeCounter() override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR SetRotatingDeviceIdUniqueId(const ByteSpan & uniqueIdSpan) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override { return CHIP_ERROR_NOT_IMPLEMENTED; } +#endif CHIP_ERROR GetFailSafeArmed(bool & val) override { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR SetFailSafeArmed(bool val) override { return CHIP_ERROR_NOT_IMPLEMENTED; } CHIP_ERROR GetBLEDeviceIdentificationInfo(Ble::ChipBLEDeviceIdentificationInfo & deviceIdInfo) override @@ -137,6 +116,44 @@ class MockConfigurationManager : public DeviceLayer::ConfigurationManager void RunUnitTests() override {} + // Remaining pure virtuals from ConfigurationManager + CHIP_ERROR GetPrimaryMACAddress(MutableByteSpan & buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetPrimaryWiFiMACAddress(uint8_t * buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetPrimary802154MACAddress(uint8_t * buf) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSoftwareVersionString(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSoftwareVersion(uint32_t & softwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetFirmwareBuildChipEpochTime(System::Clock::Seconds32 & buildTime) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetRegulatoryLocation(uint8_t & location) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetCountryCode(char * buf, size_t bufSize, size_t & codeLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreSerialNumber(const char * serialNum, size_t serialNumLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreManufacturingDate(const char * mfgDate, size_t mfgDateLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreSoftwareVersion(uint32_t softwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreHardwareVersion(uint16_t hardwareVer) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreRegulatoryLocation(uint8_t location) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreCountryCode(const char * code, size_t codeLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetRebootCount(uint32_t & rebootCount) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreRebootCount(uint32_t rebootCount) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetBootReason(uint32_t & bootReason) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreBootReason(uint32_t bootReason) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + + // Methods from DeviceInstanceInfoProvider that are now pure virtual in ConfigurationManager + CHIP_ERROR GetVendorName(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetVendorId(uint16_t & vendorId) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductName(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductId(uint16_t & productId) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductURL(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GetUniqueId(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR StoreUniqueId(const char * uniqueId, size_t uniqueIdLen) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + CHIP_ERROR GenerateUniqueId(char * buf, size_t bufSize) override { return CHIP_ERROR_NOT_IMPLEMENTED; } + uint32_t mConfigurationVersion = 10; uint32_t mStoreCalled = 0; CHIP_ERROR mReturnError = CHIP_NO_ERROR; @@ -210,13 +227,6 @@ struct TestBridgedDeviceBasicInformationCluster : public ::testing::Test MockDeviceInstanceInfoProvider mDeviceInfoProvider; MockConfigurationManager mMockConfigManager; - BasicInformationCluster::Context mBasicInfoContext = { - .deviceInstanceInfoProvider = mDeviceInfoProvider, - .configurationManager = mMockConfigManager, - .platformManager = DeviceLayer::PlatformMgr(), - .subscriptionsPerFabric = 1, - }; - TestServerClusterContext mContext; MockDelegate mDelegate; MockVersionConfigurationDelegate mMockVersionConfiguration; @@ -1068,23 +1078,24 @@ TEST_F(TestBridgedDeviceBasicInformationCluster, TestNodeLabelPersistence) TEST_F(TestBridgedDeviceBasicInformationCluster, TestBasicInformationClusterProxy) { - BasicInformationCluster basicInfo(BasicInformationCluster::OptionalAttributesSet(), mBasicInfoContext); + BasicInformation::tests::MockBasicInformationDelegate mockDelegate; + BasicInformationCluster basicInfo(BasicInformationCluster::OptionalAttributesSet(), &mockDelegate, DeviceLayer::PlatformMgr()); - // Initial value in our mock is 10 - EXPECT_EQ(mMockConfigManager.mConfigurationVersion, 10u); - EXPECT_EQ(mMockConfigManager.mStoreCalled, 0u); + // Initial value in the mock delegate is 10 + EXPECT_EQ(mockDelegate.mConfigurationVersion, 10u); + EXPECT_EQ(mockDelegate.mStoreConfigVersionCalled, 0u); BasicInformationClusterProxy proxy(basicInfo); EXPECT_EQ(proxy.IncreaseConfigurationVersion(), CHIP_NO_ERROR); - EXPECT_EQ(mMockConfigManager.mConfigurationVersion, 11u); - EXPECT_EQ(mMockConfigManager.mStoreCalled, 1u); + EXPECT_EQ(mockDelegate.mConfigurationVersion, 11u); + EXPECT_EQ(mockDelegate.mStoreConfigVersionCalled, 1u); // Test failure - mMockConfigManager.mReturnError = CHIP_ERROR_INTERNAL; + mockDelegate.mStoreConfigVersionReturn = CHIP_ERROR_INTERNAL; EXPECT_EQ(proxy.IncreaseConfigurationVersion(), CHIP_ERROR_INTERNAL); - EXPECT_EQ(mMockConfigManager.mConfigurationVersion, 11u); - EXPECT_EQ(mMockConfigManager.mStoreCalled, 1u); + EXPECT_EQ(mockDelegate.mConfigurationVersion, 12u); // Version should still increment before store fails + EXPECT_EQ(mockDelegate.mStoreConfigVersionCalled, 2u); } TEST_F(TestBridgedDeviceBasicInformationCluster, TestStartupPersistence)