diff --git a/src/app/clusters/scenes/BUILD.gn b/src/app/clusters/scenes/BUILD.gn index 8149460972a9e2..0e34919d8307b8 100644 --- a/src/app/clusters/scenes/BUILD.gn +++ b/src/app/clusters/scenes/BUILD.gn @@ -25,6 +25,8 @@ static_library("scenes") { "SceneTableImpl.h", ] + deps = [ "${chip_root}/src/app" ] + cflags = [ "-Wconversion", "-Wshadow", diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index e2853fa6e09fbd..97bd4cd92c4b47 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -27,11 +27,11 @@ static constexpr uint8_t kInvalidPosition = 0xff; static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr uint8_t kMaxFieldsPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; -class ExtensionFieldsSets +class ExtensionFieldSets { public: - ExtensionFieldsSets(){}; - virtual ~ExtensionFieldsSets() = default; + ExtensionFieldSets(){}; + virtual ~ExtensionFieldSets() = default; virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 89d33026e9212a..60cdad7cd96989 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -20,7 +20,7 @@ namespace chip { namespace scenes { -ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldsSets() {} +ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 5e02e561b8344c..c8af604c2e9060 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -105,7 +105,7 @@ struct ExtensionFieldsSet } }; -class ExtensionFieldSetsImpl : public ExtensionFieldsSets +class ExtensionFieldSetsImpl : public ExtensionFieldSets { public: ExtensionFieldSetsImpl(); diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 0b7989d9328a15..906f1fc2179fb2 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -23,26 +23,37 @@ #include #include +/** + * @brief Indicates the absence of a Scene table entry. + */ +#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX +#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF +#endif + +/** + * @brief The group identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 +#endif + +/** + * @brief The scene identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 +#endif + namespace chip { namespace scenes { -enum SceneTLVTag -{ - kTagSceneStorageIDContainer = 1, - kTagSceneEndpointID, - kTagSceneGroupID, - kTagSceneID, - kTagSceneDataContainer, - kTagSceneName, - kTagSceneDTransitionTime, - kTagSceneDTransitionTime100, -}; - typedef uint32_t TransitionTimeMs; typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; -static constexpr uint8_t kEFSBufferSize = 128; +constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr SceneIndex kUndefinedSceneIndex = 0xff; +constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; @@ -89,7 +100,7 @@ class SceneHandler /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) = 0; - /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a command object + /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object /// @param endpoint Endpoint ID /// @param cluster Cluster ID to save /// @param serialisedBytes ExtensionFieldSet stored in NVM @@ -107,6 +118,7 @@ class SceneHandler virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; }; +template class SceneTable { public: @@ -123,36 +135,6 @@ class SceneTable SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : mEndpointId(endpoint), mGroupId(groupId), mSceneId(id) {} - SceneStorageId(const SceneStorageId & storageId) : - mEndpointId(storageId.mEndpointId), mGroupId(storageId.mGroupId), mSceneId(storageId.mSceneId) - {} - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const - { - TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(kTagSceneStorageIDContainer), TLV::kTLVType_Structure, container)); - - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(this->mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(this->mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(this->mSceneId))); - - return writer.EndContainer(container); - } - CHIP_ERROR Deserialize(TLV::TLVReader & reader) - { - TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneStorageIDContainer))); - ReturnErrorOnFailure(reader.EnterContainer(container)); - - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); - ReturnErrorOnFailure(reader.Get(this->mEndpointId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); - ReturnErrorOnFailure(reader.Get(this->mGroupId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); - ReturnErrorOnFailure(reader.Get(this->mSceneId)); - - return reader.ExitContainer(container); - } void Clear() { @@ -160,96 +142,43 @@ class SceneTable mGroupId = kGlobalGroupSceneId; mSceneId = kUndefinedSceneId; } + bool operator==(const SceneStorageId & other) { return (this->mEndpointId == other.mEndpointId && this->mGroupId == other.mGroupId && this->mSceneId == other.mSceneId); } - void operator=(const SceneStorageId & other) - { - this->mEndpointId = other.mEndpointId; - this->mGroupId = other.mGroupId; - this->mSceneId = other.mSceneId; - } }; /// @brief struct used to store data held in a scene struct SceneData { - char mName[kSceneNameMax] = { 0 }; - size_t mNameLength = 0; - SceneTransitionTime mSceneTransitionTime = 0; - ExtensionFieldSetsImpl mExtensionFieldSets; + char mName[kSceneNameMax] = { 0 }; + size_t mNameLength = 0; + SceneTransitionTime mSceneTransitionTimeSeconds = 0; + EFStype mExtensionFieldSets; TransitionTime100ms mTransitionTime100ms = 0; - CharSpan mNameSpan; SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTime(time), mTransitionTime100ms(time100ms) + mSceneTransitionTimeSeconds(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); } - SceneData(ExtensionFieldSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, + SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTime(time), + mSceneTransitionTimeSeconds(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); mExtensionFieldSets = fields; } SceneData(const SceneData & other) : - mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100ms(other.mTransitionTime100ms) + mSceneTransitionTimeSeconds(other.mSceneTransitionTimeSeconds), mTransitionTime100ms(other.mTransitionTime100ms) { - this->SetName(other.mNameSpan); + this->SetName(CharSpan(other.mName, other.mNameLength)); mExtensionFieldSets = other.mExtensionFieldSets; } ~SceneData(){}; - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const - { - TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(kTagSceneDataContainer), TLV::kTLVType_Structure, container)); - - // A 0 size means the name wasn't used so it won't get stored - if (!this->mNameSpan.empty()) - { - ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), this->mNameSpan)); - } - - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(this->mSceneTransitionTime))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(this->mTransitionTime100ms))); - ReturnErrorOnFailure(this->mExtensionFieldSets.Serialize(writer)); - - return writer.EndContainer(container); - } - CHIP_ERROR Deserialize(TLV::TLVReader & reader) - { - TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneDataContainer))); - ReturnErrorOnFailure(reader.EnterContainer(container)); - - ReturnErrorOnFailure(reader.Next()); - TLV::Tag currTag = reader.GetTag(); - VerifyOrReturnError(TLV::ContextTag(kTagSceneName) == currTag || TLV::ContextTag(kTagSceneDTransitionTime) == currTag, - CHIP_ERROR_WRONG_TLV_TYPE); - - // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, - if (currTag == TLV::ContextTag(kTagSceneName)) - { - ReturnErrorOnFailure(reader.Get(this->mNameSpan)); - this->SetName(this->mNameSpan); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime))); - } - - ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); - ReturnErrorOnFailure(reader.Get(this->mTransitionTime100ms)); - ReturnErrorOnFailure(this->mExtensionFieldSets.Deserialize(reader)); - - return reader.ExitContainer(container); - } - void SetName(const CharSpan & sceneName) { if (nullptr == sceneName.data()) @@ -263,30 +192,30 @@ class SceneTable memcpy(mName, sceneName.data(), maxChars); mNameLength = maxChars; } - mNameSpan = CharSpan(mName, mNameLength); } void Clear() { this->SetName(CharSpan()); - mSceneTransitionTime = 0; - mTransitionTime100ms = 0; + mSceneTransitionTimeSeconds = 0; + mTransitionTime100ms = 0; mExtensionFieldSets.Clear(); } bool operator==(const SceneData & other) { - return (this->mNameSpan.data_equal(other.mNameSpan) && (this->mSceneTransitionTime == other.mSceneTransitionTime) && + return (!memcmp(this->mName, other.mName, this->mNameLength) && + (this->mSceneTransitionTimeSeconds == other.mSceneTransitionTimeSeconds) && (this->mTransitionTime100ms == other.mTransitionTime100ms) && (this->mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) { - this->SetName(other.mNameSpan); - this->mExtensionFieldSets = other.mExtensionFieldSets; - this->mSceneTransitionTime = other.mSceneTransitionTime; - this->mTransitionTime100ms = other.mTransitionTime100ms; + this->SetName(CharSpan(other.mName, other.mNameLength)); + this->mExtensionFieldSets = other.mExtensionFieldSets; + this->mSceneTransitionTimeSeconds = other.mSceneTransitionTimeSeconds; + this->mTransitionTime100ms = other.mTransitionTime100ms; } }; @@ -322,6 +251,7 @@ class SceneTable // Not copyable SceneTable(const SceneTable &) = delete; + SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index db44b482aa27da..fcf976de12b874 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -36,14 +36,18 @@ struct FabricHavingSceneList : public CommonPersistentData::FabricList { CHIP_ERROR UpdateKey(StorageKeyName & key) override { - key = DefaultStorageKeyAllocator::SceneFabricList(); + key = DefaultStorageKeyAllocator::GroupFabricList(); return CHIP_NO_ERROR; } }; -static constexpr size_t kPersistentBufferMax = 256; +// Worst case tested: Add Scene Command with EFS using the default SerializeAdd Method. This yielded a serialized scene of 212bytes +// when using the OnOff, Level Control and Color Control as well as the maximal name length of 16 bytes. Putting 256 gives some +// slack in case different clusters are used. Value obtained by using writer.GetLengthWritten at the end of the SceneTableData +// Serialize method. +static constexpr size_t kPersistentSceneBufferMax = 256; -struct SceneTableData : public SceneTableEntry, PersistentData +struct SceneTableData : public SceneTableEntry, PersistentData { FabricIndex fabric_index = kUndefinedFabricIndex; SceneIndex index = 0; @@ -68,36 +72,82 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageId.mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(mStorageId.mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(mStorageId.mSceneId))); + + // Scene Data + // A length of 0 means the name wasn't used so it won't get stored + if (!NameSpan.empty()) + { + ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), NameSpan)); + } + + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(mStorageData.mSceneTransitionTimeSeconds))); + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) override { + CharSpan NameSpan(mStorageData.mName); + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(mStorageId.Deserialize(reader)); - ReturnErrorOnFailure(mStorageData.Deserialize(reader)); + // Scene ID + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mEndpointId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mGroupId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mSceneId)); + + // Scene Data + ReturnErrorOnFailure(reader.Next()); + TLV::Tag currTag = reader.GetTag(); + VerifyOrReturnError(TLV::ContextTag(kTagSceneName) == currTag || TLV::ContextTag(kTagSceneDTransitionTime) == currTag, + CHIP_ERROR_WRONG_TLV_TYPE); + + // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, + if (currTag == TLV::ContextTag(kTagSceneName)) + { + ReturnErrorOnFailure(reader.Get(NameSpan)); + mStorageData.SetName(NameSpan); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime))); + } + + ReturnErrorOnFailure(reader.Get(mStorageData.mSceneTransitionTimeSeconds)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); + ReturnErrorOnFailure(reader.Get(mStorageData.mTransitionTime100ms)); + ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Deserialize(reader)); return reader.ExitContainer(container); } }; +// A Full fabric serialized TLV length is 88 bytes, 128 bytes gives some slack tested bu running writer.GetLengthWritten at the +// end of the Serialize method of FabricSceneData +static constexpr size_t kPersistentFabricBufferMax = 128; + /** * @brief Linked list of all scenes in a fabric, stored in persistent memory * * FabricSceneData is an access to a linked list of scenes */ -struct FabricSceneData : public PersistentData +struct FabricSceneData : public PersistentData { FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; @@ -130,9 +180,13 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneCount), static_cast(scene_count))); + + // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(scene_map[i].Serialize(writer)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(scene_map[i].mSceneId))); } ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); @@ -151,7 +205,12 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Get(scene_count)); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(scene_map[i].Deserialize(reader)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); } ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); ReturnErrorOnFailure(reader.Get(next)); @@ -528,7 +587,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const { scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); cluster = EFS.mID; - time = scene.mStorageData.mSceneTransitionTime * 1000 + + time = scene.mStorageData.mSceneTransitionTimeSeconds * 1000 + (scene.mStorageData.mTransitionTime100ms ? scene.mStorageData.mTransitionTime100ms * 10 : 0); ByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, EFS.mUsedBytes); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index b703c51e6547c0..2a66b41d47ad95 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -25,6 +25,18 @@ namespace chip { namespace scenes { +enum SceneTLVTag +{ + kTagSceneStorageIDContainer = 1, + kTagSceneEndpointID, + kTagSceneGroupID, + kTagSceneID, + kTagSceneDataContainer, + kTagSceneName, + kTagSceneDTransitionTime, + kTagSceneDTransitionTime100, +}; + using clusterId = chip::ClusterId; /// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster @@ -166,7 +178,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler * It is meant to be used exclusively when the scene cluster is enable for at least one endpoint * on the device. */ -class DefaultSceneTableImpl : public SceneTable +class DefaultSceneTableImpl : public SceneTable { public: DefaultSceneTableImpl() = default; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index e841faf3bc70b8..03d4caaa9c2be0 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -91,7 +91,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -119,7 +119,7 @@ struct ServerInitParams // Protection Key (IPK) for CASE. Must be initialized before being provided. Credentials::GroupDataProvider * groupDataProvider = nullptr; // Scene Table: optionnal, required if Scene Cluster implemented - scenes::SceneTable * sceneTable = nullptr; + scenes::SceneTable * sceneTable = nullptr; // Session keystore: MUST be injected. Used to derive and manage lifecycle of symmetric keys. Crypto::SessionKeystore * sessionKeystore = nullptr; // Access control delegate: MUST be injected. Used to look up access control rules. Must be @@ -209,7 +209,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -344,43 +344,97 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() { return mFabrics; } + FabricTable & GetFabricTable() + { + return mFabrics; + } - CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } + CASESessionManager * GetCASESessionManager() + { + return &mCASESessionManager; + } - Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } + Messaging::ExchangeManager & GetExchangeManager() + { + return mExchangeMgr; + } - SessionManager & GetSecureSessionManager() { return mSessions; } + SessionManager & GetSecureSessionManager() + { + return mSessions; + } - SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } + SessionResumptionStorage * GetSessionResumptionStorage() + { + return mSessionResumptionStorage; + } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() + { + return mSubscriptionResumptionStorage; + } - TransportMgrBase & GetTransportManager() { return mTransports; } + TransportMgrBase & GetTransportManager() + { + return mTransports; + } - Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + Credentials::GroupDataProvider * GetGroupDataProvider() + { + return mGroupsProvider; + } - scenes::SceneTable * GetSceneTable() { return mSceneTable; } + scenes::SceneTable * GetSceneTable() + { + return mSceneTable; + } - Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + Crypto::SessionKeystore * GetSessionKeystore() const + { + return mSessionKeystore; + } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } + Ble::BleLayer * GetBleLayerObject() + { + return mBleLayer; + } #endif - CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } + CommissioningWindowManager & GetCommissioningWindowManager() + { + return mCommissioningWindowManager; + } - PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } + PersistentStorageDelegate & GetPersistentStorage() + { + return *mDeviceStorage; + } - app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } + app::FailSafeContext & GetFailSafeContext() + { + return mFailSafeContext; + } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() + { + return mTestEventTriggerDelegate; + } - Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } + Crypto::OperationalKeystore * GetOperationalKeystore() + { + return mOperationalKeystore; + } - Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } + Credentials::OperationalCertificateStore * GetOpCertStore() + { + return mOpCertStore; + } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() + { + return mAttributePersister; + } /** * This function causes the ShutDown event to be generated async on the @@ -397,7 +451,10 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() { return sServer; } + static Server & GetInstance() + { + return sServer; + } private: Server() = default; @@ -578,7 +635,7 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; - scenes::SceneTable * mSceneTable = nullptr; + scenes::SceneTable * mSceneTable = nullptr; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index f577bf3c4c1f18..b03a80b8a362e0 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -25,7 +25,7 @@ using namespace chip; -using SceneTable = scenes::SceneTable; +using SceneTable = scenes::SceneTable; using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; using SceneTableImpl = scenes::DefaultSceneTableImpl; using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; @@ -33,59 +33,60 @@ using SceneData = scenes::DefaultSceneTableImpl::SceneData; using ExtensionFieldsSet = scenes::ExtensionFieldsSet; using TransitionTimeMs = scenes::TransitionTimeMs; -#define ON_OFF_CID 0x0006 -#define LV_CTR_CID 0x0008 -#define CC_CTR_CID 0x0300 -#define TEST_ENDPOINT1 0x0001 -#define TEST_ENDPOINT2 0x0099 - -// ON OFF ATTRIBUTE IDs -#define ON_OFF_ID 0x0000 - -// LEVEL CONTROL ATTRIBUTE IDs -#define CURRENT_LVL_ID 0x0000 -#define CURRENT_FRQ_ID 0x0004 - -// COLOR CONTROL ATTRIBUTE IDs -#define CURRENT_SAT_ID 0x0001 -#define CURRENT_X_ID 0x0003 -#define CURRENT_Y_ID 0x0004 -#define COLOR_TEMP_MIR_ID 00007 -#define EN_CURRENT_HUE_ID 0x4000 -#define C_LOOP_ACTIVE_ID 0x4002 -#define C_LOOP_DIR_ID 0x4003 -#define C_LOOP_TIME_ID 0x4004 - namespace { +// Test Cluster ID +constexpr chip::ClusterId kOnOffClusterId = 0x0006; +constexpr chip::ClusterId kLevelControlClusterId = 0x0008; +constexpr chip::ClusterId kColorControlClusterId = 0x0300; + +// Test Endpoint ID +constexpr chip::EndpointId kTestEndpoint1 = 0x0001; +constexpr chip::EndpointId kTestEndpoint2 = 0x0099; +constexpr chip::EndpointId kTestEndpoint3 = 0x0010; + +// Test Attribute ID +constexpr uint32_t kOnOffAttId = 0x0000; +constexpr uint32_t kCurrentLevelId = 0x0000; +constexpr uint32_t kCurrentFrequencyId = 0x0004; +constexpr uint32_t kCurrentSaturationId = 0x0001; +constexpr uint32_t kCurrentXId = 0x0003; +constexpr uint32_t kCurrentYId = 0x0004; +constexpr uint32_t kColorTemperatureMiredsId = 0x0007; +constexpr uint32_t kEnhancedCurrentHueId = 0x4000; +constexpr uint32_t kColorLoopActiveId = 0x4002; +constexpr uint32_t kColorLoopDirectionId = 0x4003; +constexpr uint32_t kColorLoopTimeId = 0x4004; // Test fabrics, adding more requires to modify the "ResetSceneTable" function constexpr chip::FabricIndex kFabric1 = 1; constexpr chip::FabricIndex kFabric2 = 7; // Scene storage ID -static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); -static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); -static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); -static const SceneStorageId sceneId4(TEST_ENDPOINT2, 0xBE, 0x00); -static const SceneStorageId sceneId5(TEST_ENDPOINT1, 0x45, 0x103); -static const SceneStorageId sceneId6(TEST_ENDPOINT1, 0x65, 0x00); -static const SceneStorageId sceneId7(TEST_ENDPOINT1, 0x77, 0x101); -static const SceneStorageId sceneId8(TEST_ENDPOINT2, 0xEE, 0x101); -static const SceneStorageId sceneId9(TEST_ENDPOINT2, 0xAB, 0x101); +static const SceneStorageId sceneId1(kTestEndpoint1, 0xAA, 0x101); +static const SceneStorageId sceneId2(kTestEndpoint1, 0xBB, 0x00); +static const SceneStorageId sceneId3(kTestEndpoint2, 0xCC, 0x102); +static const SceneStorageId sceneId4(kTestEndpoint2, 0xBE, 0x00); +static const SceneStorageId sceneId5(kTestEndpoint1, 0x45, 0x103); +static const SceneStorageId sceneId6(kTestEndpoint1, 0x65, 0x00); +static const SceneStorageId sceneId7(kTestEndpoint1, 0x77, 0x101); +static const SceneStorageId sceneId8(kTestEndpoint3, 0xEE, 0x101); +static const SceneStorageId sceneId9(kTestEndpoint2, 0xAB, 0x101); + +CharSpan empty; // Scene data -static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); -static const SceneData sceneData2(CharSpan("Scene #2", sizeof("Scene #2")), 2, 5); -static const SceneData sceneData3(CharSpan("Scene #3", sizeof("Scene #3")), 25); -static const SceneData sceneData4(CharSpan("Scene num4", sizeof("Scene num4")), 5); -static const SceneData sceneData5(CharSpan(), 10); -static const SceneData sceneData6(CharSpan("Scene #6", sizeof("Scene #6")), 3, 15); -static const SceneData sceneData7(CharSpan("Scene #7", sizeof("Scene #7")), 20, 5); -static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG", sizeof("Scene num4")), 10); -static const SceneData sceneData9(CharSpan("Scene #9", sizeof("Scene #9")), 30, 15); -static const SceneData sceneData10(CharSpan("Scene #10", sizeof("Scene #10")), 10, 1); -static const SceneData sceneData11(CharSpan("Scene #11", sizeof("Scene #11")), 20, 10); -static const SceneData sceneData12(CharSpan("Scene #12", sizeof("Scene #12")), 30, 5); +static const SceneData sceneData1(CharSpan("Scene #1")); +static const SceneData sceneData2(CharSpan("Scene #2"), 2, 5); +static const SceneData sceneData3(CharSpan("Scene #3"), 25); +static const SceneData sceneData4(CharSpan("Scene num4"), 5); +static const SceneData sceneData5(empty); +static const SceneData sceneData6(CharSpan("Scene #6"), 3, 15); +static const SceneData sceneData7(CharSpan("Scene #7"), 20, 5); +static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG!"), 1, 10); +static const SceneData sceneData9(CharSpan("Scene #9"), 30, 15); +static const SceneData sceneData10(CharSpan("Scene #10"), 10, 1); +static const SceneData sceneData11(CharSpan("Scene #11"), 20, 10); +static const SceneData sceneData12(CharSpan("Scene #12"), 30, 5); // Scenes SceneTableEntry scene1(sceneId1, sceneData1); @@ -114,6 +115,10 @@ static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint32_t OO_buffer_serialized_length = 0; +static uint32_t LC_buffer_serialized_length = 0; +static uint32_t CC_buffer_serialized_length = 0; + /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -125,47 +130,64 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override { ClusterId * buffer = clusterBuffer.data(); - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { if (clusterBuffer.size() >= 2) { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; + buffer[0] = kOnOffClusterId; + buffer[1] = kLevelControlClusterId; clusterBuffer.reduce_size(2); } } - else if (endpoint == TEST_ENDPOINT2) + else if (endpoint == kTestEndpoint2) { if (clusterBuffer.size() >= 2) { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; + buffer[0] = kOnOffClusterId; + buffer[1] = kColorControlClusterId; clusterBuffer.reduce_size(2); } } + else if (endpoint == kTestEndpoint3) + { + if (clusterBuffer.size() >= 3) + { + buffer[0] = kOnOffClusterId; + buffer[1] = kLevelControlClusterId; + buffer[2] = kColorControlClusterId; + clusterBuffer.reduce_size(3); + } + } } // Default function only checks if endpoint and clusters are valid bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override { - bool ret = false; - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) + { + if (cluster == kOnOffClusterId || cluster == kLevelControlClusterId) + { + return true; + } + } + + if (endpoint == kTestEndpoint2) { - if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) + if (cluster == kOnOffClusterId || cluster == kColorControlClusterId) { - ret = true; + return true; } } - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint3) { - if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) + if (cluster == kOnOffClusterId || cluster == kLevelControlClusterId || cluster == kColorControlClusterId) { - ret = true; + return true; } } - return ret; + return false; } /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory @@ -177,41 +199,74 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; - case LV_CTR_CID: + case kLevelControlClusterId: err = CHIP_NO_ERROR; // Warning: LC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(27); // Used memory for Level Control TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV break; default: break; } } - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint2) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; - case CC_CTR_CID: + case kColorControlClusterId: err = CHIP_NO_ERROR; // Warning: CC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(99); // Used memory for Color Control TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV + break; + default: + break; + } + } + if (endpoint == kTestEndpoint3) + { + switch (cluster) + { + case kOnOffClusterId: + err = CHIP_NO_ERROR; + // Warning: OO_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV + break; + case kLevelControlClusterId: + err = CHIP_NO_ERROR; + // Warning: LC_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV + break; + case kColorControlClusterId: + err = CHIP_NO_ERROR; + // Warning: CC_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV break; default: break; @@ -233,17 +288,17 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; // Takes values from cluster in Endpoint 1 - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; - case LV_CTR_CID: + case kLevelControlClusterId: if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; @@ -255,17 +310,44 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } // Takes values from cluster in Endpoint 2 - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint2) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; - case CC_CTR_CID: + case kColorControlClusterId: + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + // Takes values from cluster in Endpoint 3 + if (endpoint == kTestEndpoint3) + { + switch (cluster) + { + case kOnOffClusterId: + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case kLevelControlClusterId: + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + case kColorControlClusterId: if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; @@ -300,6 +382,7 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); } + // Hanlder order in table : [H0, H1, H2] NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); // Removal at beginning @@ -307,17 +390,25 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + // Re-insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[0])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + // Hanlder order in table : [H1, H2, H0] // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[3])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 2]); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + // Re-insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + // Hanlder order in table : [H1, H0, H2] // Removal at the end - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[scenes::kMaxSceneHandlers - 1])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 3)); - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 3]); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); // Emptying Handler array NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandler()); @@ -332,7 +423,6 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) // Verify all array is empty for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { - printf("Handler : %d | Address : %p \n", i, sceneTable->mHandlers[i]); NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); } } @@ -356,41 +446,41 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; - OOPairs[0].attributeID.SetValue(ON_OFF_ID); + OOPairs[0].attributeID.SetValue(kOnOffAttId); OOPairs[0].attributeValue = OO_av_payload; - LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); + LCPairs[0].attributeID.SetValue(kCurrentLevelId); LCPairs[0].attributeValue = LC_av_payload[0]; LCPairs[0].attributeValue.reduce_size(1); - LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); + LCPairs[1].attributeID.SetValue(kCurrentFrequencyId); LCPairs[1].attributeValue = LC_av_payload[1]; - CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); + CCPairs[0].attributeID.SetValue(kCurrentSaturationId); CCPairs[0].attributeValue = CC_av_payload[0]; CCPairs[0].attributeValue.reduce_size(1); - CCPairs[1].attributeID.SetValue(CURRENT_X_ID); + CCPairs[1].attributeID.SetValue(kCurrentXId); CCPairs[1].attributeValue = CC_av_payload[1]; - CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); + CCPairs[2].attributeID.SetValue(kCurrentYId); CCPairs[2].attributeValue = CC_av_payload[2]; - CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); + CCPairs[3].attributeID.SetValue(kColorTemperatureMiredsId); CCPairs[3].attributeValue = CC_av_payload[3]; - CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); + CCPairs[4].attributeID.SetValue(kEnhancedCurrentHueId); CCPairs[4].attributeValue = CC_av_payload[4]; - CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); + CCPairs[5].attributeID.SetValue(kColorLoopActiveId); CCPairs[5].attributeValue = CC_av_payload[5]; CCPairs[5].attributeValue.reduce_size(1); - CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); + CCPairs[6].attributeID.SetValue(kColorLoopDirectionId); CCPairs[6].attributeValue = CC_av_payload[6]; CCPairs[6].attributeValue.reduce_size(1); - CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); + CCPairs[7].attributeID.SetValue(kColorLoopTimeId); CCPairs[7].attributeValue = CC_av_payload[7]; // Initialize Extension Field sets as if they were received by add commands - OOextensionFieldSet.clusterID = ON_OFF_CID; + OOextensionFieldSet.clusterID = kOnOffClusterId; OOextensionFieldSet.attributeValueList = OOPairs; - LCextensionFieldSet.clusterID = LV_CTR_CID; + LCextensionFieldSet.clusterID = kLevelControlClusterId; LCextensionFieldSet.attributeValueList = LCPairs; - CCextensionFieldSet.clusterID = CC_CTR_CID; + CCextensionFieldSet.clusterID = kColorControlClusterId; CCextensionFieldSet.attributeValueList = CCPairs; ByteSpan OO_list(OO_buffer); @@ -410,6 +500,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), OOextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + OO_buffer_serialized_length = writer.GetLengthWritten(); writer.Init(LC_buffer); writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); @@ -420,6 +511,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), LCextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + LC_buffer_serialized_length = writer.GetLengthWritten(); writer.Init(CC_buffer); writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); @@ -430,6 +522,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), CCextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + CC_buffer_serialized_length = writer.GetLengthWritten(); // Test Registering SceneHandler NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&sHandler)); @@ -437,54 +530,54 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Setup the On Off Extension field set in the expected state from a command reader.Init(OO_list); - extensionFieldSetIn.clusterID = ON_OFF_CID; + extensionFieldSetIn.clusterID = kOnOffClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == ON_OFF_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kOnOffClusterId); memset(buffer, 0, buff_span.size()); // Setup the Level Control Extension field set in the expected state from a command reader.Init(LC_list); - extensionFieldSetIn.clusterID = LV_CTR_CID; + extensionFieldSetIn.clusterID = kLevelControlClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == LV_CTR_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kLevelControlClusterId); memset(buffer, 0, buff_span.size()); // Setup the Color control Extension field set in the expected state from a command reader.Init(CC_list); - extensionFieldSetIn.clusterID = CC_CTR_CID; + extensionFieldSetIn.clusterID = kColorControlClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == CC_CTR_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kColorControlClusterId); memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for on off - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kOnOffClusterId, OO_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously writer.Init(buff_span); @@ -500,7 +593,8 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for level control - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kLevelControlClusterId, LC_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for level control previously writer.Init(buff_span); @@ -516,7 +610,8 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for color control - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint2, kColorControlClusterId, CC_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for color control previously writer.Init(buff_span); @@ -549,11 +644,13 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Populate scene3's EFS (Endpoint2) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3)); - // Populate scene3's EFS (Endpoint2) + // Populate scene4's EFS (Endpoint2) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4)); - SceneTableEntry scene; + // Populate scene8's EFS (Endpoint3) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene8)); + SceneTableEntry scene; // Set test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); @@ -595,6 +692,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene7); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene8); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene8.mStorageId)); } void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 35fd670fa1c687..9007b629d81584 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1364,12 +1364,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #ifndef CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS #define CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS 2 #endif -/** - * @brief Indicates the absence of a Scene table entry. - */ -#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX -#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF -#endif /** * @brief Value used when setting or getting the endpoint in a Scene table @@ -1378,6 +1372,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #ifndef CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID #define CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID 0x00 #endif + /** * @brief The minimum number of scenes to support according to spec */ @@ -1386,26 +1381,12 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @brief Maximum length of Scene names, not including the length byte. + * @brief Maximum length of Scene names */ #ifndef CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH #define CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH 16 #endif -/** - * @brief The group identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 -#endif - -/** - * @brief The scene identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 -#endif - /** * @brief The maximum number of scenes allowed on a single fabric */ @@ -1414,10 +1395,10 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @brief The maximum number of cluster per scene + * @brief The maximum number of clusters per scene */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES -#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 7 +#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 3 #endif /** diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 967deec0198bfe..8253a9017fbfcc 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -63,11 +63,6 @@ constexpr EndpointId kRootEndpointId = 0; constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index. constexpr KeysetId kInvalidKeysetId = 0xFFFF; -constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; -constexpr SceneIndex kUndefinedSceneIndex = 0xff; -constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; -constexpr SceneId kUnusedEndpointId = CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID; - // Invalid IC identifier is provisional. Value will most likely change when identifying token is defined // https://github.com/project-chip/connectedhomeip/issues/24251 constexpr uint64_t kInvalidIcId = 0; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index aa059a9630b110..b4fa1d602bdcca 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -197,15 +197,11 @@ class DefaultStorageKeyAllocator return StorageKeyName::Formatted("g/su/%x", static_cast(index)); } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - // Scene Storage - static StorageKeyName SceneFabricList() - { - return StorageKeyName::FromConst("g/gfl"); - } // shares key with group fabric list to minimize flash usage + static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { - return StorageKeyName::Formatted("f/%x/s%x", fabric, id); + return StorageKeyName::Formatted("f/%x/s/%x", fabric, id); } }; diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h deleted file mode 100644 index 5a8446351334bf..00000000000000 --- a/src/lib/support/TestSceneTable.h +++ /dev/null @@ -1,528 +0,0 @@ -/* - * - * Copyright (c) 2023 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 - -namespace chip { - -namespace SceneTesting { - -using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTable = chip::scenes::SceneTable; -using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; -using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; -using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; -using TransitionTimeMs = chip::scenes::TransitionTimeMs; - -#define ON_OFF_CID 0x0006 -#define LV_CTR_CID 0x0008 -#define CC_CTR_CID 0x0300 -#define TEST_ENDPOINT1 0x0001 -#define TEST_ENDPOINT2 0x0099 - -// ON OFF ATTRIBUTE IDs -#define ON_OFF_ID 0x0000 - -// LEVEL CONTROL ATTRIBUTE IDs -#define CURRENT_LVL_ID 0x0000 -#define CURRENT_FRQ_ID 0x0004 - -// COLOR CONTROL ATTRIBUTE IDs -#define CURRENT_SAT_ID 0x0001 -#define CURRENT_X_ID 0x0003 -#define CURRENT_Y_ID 0x0004 -#define COLOR_TEMP_MIR_ID 00007 -#define EN_CURRENT_HUE_ID 0x4000 -#define C_LOOP_ACTIVE_ID 0x4002 -#define C_LOOP_DIR_ID 0x4003 -#define C_LOOP_TIME_ID 0x4004 - -// Clusters EFS data -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type OOextensionFieldSet; -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type LCextensionFieldSet; -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type CCextensionFieldSet; - -static app::Clusters::Scenes::Structs::AttributeValuePair::Type OOPairs[1]; -static app::Clusters::Scenes::Structs::AttributeValuePair::Type LCPairs[2]; -static app::Clusters::Scenes::Structs::AttributeValuePair::Type CCPairs[8]; - -static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; - -/// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control -class TestSceneHandler : public scenes::DefaultSceneHandlerImpl -{ -public: - TestSceneHandler() = default; - ~TestSceneHandler() override {} - - // Fills in cluster buffer and adjusts its size to lower than the maximum number of cluster per scenes - virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override - { - ClusterId * buffer = clusterBuffer.data(); - if (endpoint == TEST_ENDPOINT1) - { - if (clusterBuffer.size() >= 2) - { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; - clusterBuffer.reduce_size(2); - } - } - else if (endpoint == TEST_ENDPOINT2) - { - if (clusterBuffer.size() >= 2) - { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; - clusterBuffer.reduce_size(2); - } - } - } - - // Default function only checks if endpoint and clusters are valid - bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override - { - bool ret = false; - if (endpoint == TEST_ENDPOINT1) - { - if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) - { - ret = true; - } - } - - if (endpoint == TEST_ENDPOINT2) - { - if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) - { - ret = true; - } - } - - return ret; - } - - /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory - /// @param endpoint target endpoint - /// @param cluster target cluster - /// @param serialisedBytes data to serialize into EFS - /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported - CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override - { - CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - - if (endpoint == TEST_ENDPOINT1) - { - switch (cluster) - { - case ON_OFF_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV - break; - case LV_CTR_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(27); // Used memory for Level Control TLV - break; - default: - break; - } - } - if (endpoint == TEST_ENDPOINT2) - { - switch (cluster) - { - case ON_OFF_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV - break; - case CC_CTR_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(99); // Used memory for Color Control TLV - break; - default: - break; - } - } - return err; - } - - /// @brief Simulates EFS being applied to a scene, here just validates that the data is as expected, no action taken by the - /// "cluster" - /// @param endpoint target endpoint - /// @param cluster target cluster - /// @param serialisedBytes Data from nvm - /// @param timeMs transition time in ms - /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise - CHIP_ERROR - ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override - { - CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - - // Takes values from cluster in Endpoint 1 - if (endpoint == TEST_ENDPOINT1) - { - switch (cluster) - { - case ON_OFF_CID: - if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - case LV_CTR_CID: - if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - default: - break; - } - } - - // Takes values from cluster in Endpoint 2 - if (endpoint == TEST_ENDPOINT2) - { - switch (cluster) - { - case ON_OFF_CID: - if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - case CC_CTR_CID: - if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - default: - break; - } - } - - return CHIP_NO_ERROR; - } -}; - -static TestSceneHandler sHandler; - -CHIP_ERROR scene_handler_test(SceneTable * provider) -{ - ClusterId tempCluster = 0; - - app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; - app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; - - TLV::TLVReader reader; - TLV::TLVWriter writer; - TLV::TLVType outer; - TLV::TLVType outerRead; - - static const uint8_t OO_av_payload[1] = { 0x01 }; - static const uint8_t LC_av_payload[2][2] = { { 0x40, 0x00 }, { 0x01, 0xF0 } }; - static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, - { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; - - OOPairs[0].attributeID.SetValue(ON_OFF_ID); - OOPairs[0].attributeValue = OO_av_payload; - - LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); - LCPairs[0].attributeValue = LC_av_payload[0]; - LCPairs[0].attributeValue.reduce_size(1); - LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); - LCPairs[1].attributeValue = LC_av_payload[1]; - - CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); - CCPairs[0].attributeValue = CC_av_payload[0]; - CCPairs[0].attributeValue.reduce_size(1); - CCPairs[1].attributeID.SetValue(CURRENT_X_ID); - CCPairs[1].attributeValue = CC_av_payload[1]; - CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); - CCPairs[2].attributeValue = CC_av_payload[2]; - CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); - CCPairs[3].attributeValue = CC_av_payload[3]; - CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); - CCPairs[4].attributeValue = CC_av_payload[4]; - CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); - CCPairs[5].attributeValue = CC_av_payload[5]; - CCPairs[5].attributeValue.reduce_size(1); - CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); - CCPairs[6].attributeValue = CC_av_payload[6]; - CCPairs[6].attributeValue.reduce_size(1); - CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); - CCPairs[7].attributeValue = CC_av_payload[7]; - - // Initialize Extension Field sets as if they were received by add commands - OOextensionFieldSet.clusterID = ON_OFF_CID; - OOextensionFieldSet.attributeValueList = OOPairs; - LCextensionFieldSet.clusterID = LV_CTR_CID; - LCextensionFieldSet.attributeValueList = LCPairs; - CCextensionFieldSet.clusterID = CC_CTR_CID; - CCextensionFieldSet.attributeValueList = CCPairs; - - ByteSpan OO_list(OO_buffer); - ByteSpan LC_list(LC_buffer); - ByteSpan CC_list(CC_buffer); - - uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; - MutableByteSpan buff_span(buffer); - - // Serialize Extension Field sets as if they were recovered from memory - writer.Init(OO_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - OOextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - writer.Init(LC_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - LCextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - writer.Init(CC_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - CCextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - ReturnErrorOnFailure(provider->RegisterHandler(&sHandler)); - - // Setup the On Off Extension field set in the expected state from a command - reader.Init(OO_list); - extensionFieldSetIn.clusterID = ON_OFF_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == ON_OFF_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Setup the Level Control Extension field set in the expected state from a command - reader.Init(LC_list); - extensionFieldSetIn.clusterID = LV_CTR_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == LV_CTR_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Setup the Color control Extension field set in the expected state from a command - reader.Init(CC_list); - extensionFieldSetIn.clusterID = CC_CTR_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == CC_CTR_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for on off - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for level control - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for color control - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - return CHIP_NO_ERROR; -}; - -CHIP_ERROR scene_store_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry) -{ - SceneTableEntry temp; - - LogErrorOnFailure(provider->SetSceneTableEntry(fabric_index, entry)); - LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.mStorageId, temp)); - VerifyOrReturnError(temp.mStorageId == entry.mStorageId, CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(temp.mStorageData == entry.mStorageData, CHIP_ERROR_WRITE_FAILED); - LogErrorOnFailure(provider->SceneApplyEFS(fabric_index, temp.mStorageId)); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR scene_iterator_test(SceneTable * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, - const SceneTableEntry & entry2, const SceneTableEntry & entry3) -{ - SceneTableEntry temp; - - auto * iterator = provider->IterateSceneEntry(fabric_index); - if (iterator) - { - VerifyOrReturnError(iterator->Count() == 3, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry2.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - // Iterator should return false here - VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); - - iterator->Release(); - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR scene_remove_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry1, SceneTableEntry & entry2, - SceneTableEntry & entry3) -{ - SceneTableEntry temp; - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.mStorageId)); - - auto * iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 2, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Next(temp); - VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Release(); - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry1.mStorageId)); - iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 1, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Next(temp); - VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry3.mStorageId)); - iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 0, CHIP_ERROR_INVALID_ARGUMENT); - - // Iterator should return false here - VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); - iterator->Release(); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR TestSceneData(SceneTable * provider, FabricIndex fabric_index) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - // Scene storage ID - static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); - static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); - static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); - - // Scene data - static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); - static const SceneData sceneData2(CharSpan("Scene #2", sizeof("Scene #2")), 2, 5); - static const SceneData sceneData3(CharSpan(), 25); - - // Scenes - SceneTableEntry scene1(sceneId1, sceneData1); - SceneTableEntry scene2(sceneId2, sceneData2); - SceneTableEntry scene3(sceneId3, sceneData3); - - err = scene_handler_test(provider); - LogErrorOnFailure(err); - - err = provider->SceneSaveEFS(scene1); - LogErrorOnFailure(err); - - err = provider->SceneSaveEFS(scene3); - LogErrorOnFailure(err); - - // Tests - err = scene_store_test(provider, fabric_index, scene1); - LogErrorOnFailure(err); - err = scene_store_test(provider, fabric_index, scene2); - LogErrorOnFailure(err); - err = scene_store_test(provider, fabric_index, scene3); - LogErrorOnFailure(err); - - err = scene_iterator_test(provider, fabric_index, scene1, scene2, scene3); - LogErrorOnFailure(err); - err = scene_remove_test(provider, fabric_index, scene1, scene2, scene3); - LogErrorOnFailure(err); - - return err; -} - -} // namespace SceneTesting - -} // namespace chip