From 9f1d75a4581e5dfab37074fcb422a95c84ead953 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:48:59 -0500 Subject: [PATCH] Added unit test for ExtensionFieldSets and applied suggestions from comments on PR Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSets.h | 11 +- .../scenes/ExtensionFieldSetsImpl.cpp | 73 ++--- .../clusters/scenes/ExtensionFieldSetsImpl.h | 109 ++++--- src/app/clusters/scenes/SceneTable.h | 104 +++--- src/app/clusters/scenes/SceneTableImpl.cpp | 67 ++-- src/app/clusters/scenes/SceneTableImpl.h | 49 +-- src/app/tests/BUILD.gn | 1 + src/app/tests/TestExtensionFieldSets.cpp | 308 ++++++++++++++++++ src/app/tests/TestSceneTable.cpp | 71 ++-- src/lib/core/CHIPConfig.h | 15 +- src/lib/core/DataModelTypes.h | 2 - src/lib/support/DefaultStorageKeyAllocator.h | 4 +- 12 files changed, 566 insertions(+), 248 deletions(-) create mode 100644 src/app/tests/TestExtensionFieldSets.cpp diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index 97bd4cd92c4b47..8c390a08fb521e 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -23,10 +23,11 @@ namespace chip { namespace scenes { -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; +static constexpr uint8_t kInvalidPosition = 0xff; +static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; +static constexpr uint8_t kMaxFieldBytesPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; +/// @brief class meant serialize all extension ßfield sets of a scene so it can be stored and retrieved from flash memory. class ExtensionFieldSets { public: @@ -37,7 +38,9 @@ class ExtensionFieldSets virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; virtual void Clear() = 0; virtual bool IsEmpty() const = 0; - virtual uint8_t GetFieldNum() const = 0; + /// @brief Gets a count of how many initialized fields sets are in the object + /// @return The number of initialized field sets in the object + virtual uint8_t GetFieldSetCount() const = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 48f2d939f07675..7f8f7034ed19ea 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -20,20 +20,21 @@ namespace chip { namespace scenes { -ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} +// ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSArrayContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSFieldNum), static_cast(this->mFieldNum))); - if (!this->IsEmpty()) + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kFieldSetsCount), static_cast(mFieldSetsCount))); + if (!IsEmpty()) { - for (uint8_t i = 0; i < this->mFieldNum; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - if (!this->mEFS[i].IsEmpty()) + if (!mEFS[i].IsEmpty()) { - ReturnErrorOnFailure(this->mEFS[i].Serialize(writer)); + ReturnErrorOnFailure(mEFS[i].Serialize(writer)); } } } @@ -44,17 +45,17 @@ CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSArrayContainer))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kFieldSetArrayContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSFieldNum))); - ReturnErrorOnFailure(reader.Get(this->mFieldNum)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kFieldSetsCount))); + ReturnErrorOnFailure(reader.Get(mFieldSetsCount)); if (!this->IsEmpty()) { - for (uint8_t i = 0; i < this->mFieldNum; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - ReturnErrorOnFailure(this->mEFS[i].Deserialize(reader)); + ReturnErrorOnFailure(mEFS[i].Deserialize(reader)); } } @@ -65,61 +66,55 @@ void ExtensionFieldSetsImpl::Clear() { if (!this->IsEmpty()) { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - this->mEFS[i].Clear(); + mEFS[i].Clear(); } } - this->mFieldNum = 0; + mFieldSetsCount = 0; } /// @brief Inserts a field Set set into the array of extension field Set sets for a scene entry. /// If the same ID is present in the EFS array, it will overwrite it. /// @param fieldSet field set to be inserted /// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_NO_MEMORY if the array is already full -CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) +CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fieldSet) { - CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; - uint8_t idPosition = kInvalidPosition; uint8_t firstEmptyPosition = kInvalidPosition; VerifyOrReturnError(fieldSet.mID != kInvalidClusterId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!fieldSet.IsEmpty(), CHIP_ERROR_INVALID_ARGUMENT); for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (this->mEFS[i].mID == fieldSet.mID) + if (mEFS[i].mID == fieldSet.mID) { - idPosition = i; - break; + mEFS[i] = fieldSet; + return CHIP_NO_ERROR; } - if (this->mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) + if (mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) { firstEmptyPosition = i; } } // if found, replace at found position, otherwise at insert first free position, otherwise return error - if (idPosition < kMaxClusterPerScenes) - { - this->mEFS[idPosition] = fieldSet; - err = CHIP_NO_ERROR; - } - else if (firstEmptyPosition < kMaxClusterPerScenes) + if (firstEmptyPosition < kMaxClusterPerScenes) { - this->mEFS[firstEmptyPosition] = fieldSet; - this->mFieldNum++; - err = CHIP_NO_ERROR; + mEFS[firstEmptyPosition] = fieldSet; + mFieldSetsCount++; + return CHIP_NO_ERROR; } - return err; + return CHIP_ERROR_NO_MEMORY; } -CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) { - VerifyOrReturnError(position < this->mFieldNum, CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_BUFFER_TOO_SMALL); - fieldSet = this->mEFS[position]; + fieldSet = mEFS[position]; return CHIP_NO_ERROR; } @@ -127,18 +122,18 @@ CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fi CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) { VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); + VerifyOrReturnValue(!this->IsEmpty() && !mEFS[position].IsEmpty(), CHIP_NO_ERROR); uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mEFS[position], &this->mEFS[nextPos], sizeof(ExtensionFieldsSet) * moveNum); + memmove(&mEFS[position], &mEFS[nextPos], sizeof(ExtensionFieldSet) * moveNum); - this->mFieldNum--; + mFieldSetsCount--; // Clear last occupied position - this->mEFS[mFieldNum].Clear(); // + mEFS[mFieldSetsCount].Clear(); // return CHIP_NO_ERROR; } diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 802e321ea975ca..7d9622e33f56df 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -23,49 +23,66 @@ namespace chip { namespace scenes { -enum EFSTLVTag +/// @brief Tags Used to serialize Extension Field Sets struct as well as individual field sets. +/// kArrayContainer: Tag for the container of the Struct with the EFS array +/// kFieldSetsCount: Tag representing the number of individual field sets +/// kIndividualContainer: Tag for the container of single EFS struct +/// kClusterID: Tag for the ClusterID of a field set +/// kBufferBytes: Tag for the serialized field set data +enum class TagEFS : uint8_t { - kTagEFSArrayContainer = 1, - kTagEFSFieldNum = 1, - kTagEFSContainer, - kTagEFSClusterID, - kTagEFS, + kFieldSetArrayContainer = 1, + kFieldSetsCount, + kIndividualContainer, + kClusterID, + kClusterFieldSetData, }; -using clusterId = chip::ClusterId; - -struct ExtensionFieldsSet +/// @brief Struct to serialize and de serialize a cluster extension field set +/// mID: Cluster ID, allows to identify which cluster is serialized +/// mBytesBuffer: Field ID serialized into a byte array +/// mUsedBytes: Number of bytes in the Buffer containing data, used for serializing only those bytes. +struct ExtensionFieldSet { - clusterId mID = kInvalidClusterId; - uint8_t mBytesBuffer[kMaxFieldsPerCluster] = { 0 }; - uint8_t mUsedBytes = 0; + ClusterId mID = kInvalidClusterId; + uint8_t mBytesBuffer[kMaxFieldBytesPerCluster] = { 0 }; + uint8_t mUsedBytes = 0; - ExtensionFieldsSet() = default; - ExtensionFieldsSet(clusterId cmID, const uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) + ExtensionFieldSet() = default; + ExtensionFieldSet(ClusterId cmID, const uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) { - if (dataSize <= kMaxFieldsPerCluster) + if (dataSize <= sizeof(mBytesBuffer)) { memcpy(mBytesBuffer, data, mUsedBytes); } + else + { + mUsedBytes = 0; + } } - ExtensionFieldsSet(clusterId cmID, ByteSpan bytes) : mID(cmID), mUsedBytes(static_cast(bytes.size())) + ExtensionFieldSet(ClusterId cmID, ByteSpan bytes) : mID(cmID), mUsedBytes(static_cast(bytes.size())) { - if (bytes.size() <= kMaxFieldsPerCluster) + if (bytes.size() <= sizeof(mBytesBuffer)) { memcpy(mBytesBuffer, bytes.data(), bytes.size()); } + else + { + mUsedBytes = 0; + } } - ~ExtensionFieldsSet() = default; + ~ExtensionFieldSet() = default; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagEFS::kIndividualContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSClusterID), static_cast(this->mID))); - ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(kTagEFS), mBytesBuffer, mUsedBytes)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kClusterID), static_cast(mID))); + ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(TagEFS::kClusterFieldSetData), mBytesBuffer, mUsedBytes)); return writer.EndContainer(container); } @@ -74,58 +91,58 @@ struct ExtensionFieldsSet { ByteSpan buffer; TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSContainer))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kIndividualContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSClusterID))); - ReturnErrorOnFailure(reader.Get(this->mID)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kClusterID))); + ReturnErrorOnFailure(reader.Get(mID)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFS))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kClusterFieldSetData))); ReturnErrorOnFailure(reader.Get(buffer)); - VerifyOrReturnError(buffer.size() <= kMaxFieldsPerCluster, CHIP_ERROR_BUFFER_TOO_SMALL); - this->mUsedBytes = static_cast(buffer.size()); - memcpy(this->mBytesBuffer, buffer.data(), this->mUsedBytes); + VerifyOrReturnError(buffer.size() <= sizeof(mBytesBuffer), CHIP_ERROR_BUFFER_TOO_SMALL); + mUsedBytes = static_cast(buffer.size()); + memcpy(mBytesBuffer, buffer.data(), mUsedBytes); return reader.ExitContainer(container); } void Clear() { - this->mID = kInvalidClusterId; - memset(this->mBytesBuffer, 0, kMaxFieldsPerCluster); - this->mUsedBytes = 0; + mID = kInvalidClusterId; + memset(mBytesBuffer, 0, kMaxFieldBytesPerCluster); + mUsedBytes = 0; } bool IsEmpty() const { return (this->mUsedBytes == 0); } - bool operator==(const ExtensionFieldsSet & other) + bool operator==(const ExtensionFieldSet & other) const { - return (this->mID == other.mID && !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes) && - this->mUsedBytes == other.mUsedBytes); + return (this->mID == other.mID && this->mUsedBytes == other.mUsedBytes && + !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes)); } }; class ExtensionFieldSetsImpl : public ExtensionFieldSets { public: - ExtensionFieldSetsImpl(); + ExtensionFieldSetsImpl(){}; ~ExtensionFieldSetsImpl() override{}; // overrides CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; void Clear() override; - bool IsEmpty() const override { return (this->mFieldNum == 0); } - uint8_t GetFieldNum() const override { return this->mFieldNum; }; + bool IsEmpty() const override { return (mFieldSetsCount == 0); } + uint8_t GetFieldSetCount() const override { return mFieldSetsCount; }; - // implementation - CHIP_ERROR InsertFieldSet(const ExtensionFieldsSet & field); - CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldsSet & field, uint8_t position); + CHIP_ERROR InsertFieldSet(const ExtensionFieldSet & field); + CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position); CHIP_ERROR RemoveFieldAtPosition(uint8_t position); - bool operator==(const ExtensionFieldSetsImpl & other) + // implementation + bool operator==(const ExtensionFieldSetsImpl & other) const { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { if (!(this->mEFS[i] == other.mEFS[i])) { @@ -137,18 +154,18 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets ExtensionFieldSetsImpl & operator=(const ExtensionFieldSetsImpl & other) { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < other.mFieldSetsCount; i++) { this->mEFS[i] = other.mEFS[i]; } - mFieldNum = other.mFieldNum; + mFieldSetsCount = other.mFieldSetsCount; return *this; } protected: - ExtensionFieldsSet mEFS[kMaxClusterPerScenes]; - uint8_t mFieldNum = 0; + ExtensionFieldSet mEFS[kMaxClusterPerScenes]; + uint8_t mFieldSetsCount = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d03e37583f26c4..50a89221d60969 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -17,50 +17,38 @@ #pragma once #include -#include +#include #include #include #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 { +// Storage index for scenes in nvm +typedef uint8_t SceneIndex; + typedef uint32_t TransitionTimeMs; typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; -constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr GroupId kGlobalGroupSceneId = 0x0000; constexpr SceneIndex kUndefinedSceneIndex = 0xff; -constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; +constexpr SceneId kUndefinedSceneId = 0xff; 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; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; +// Handler's are meant to retrieve a single cluster's extension field set, therefore the maximum number allowed is the maximal +// number of extension field set. +static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; + /// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the -/// scene Table +/// scene Table. The Scene Handler's are meant as interface between various clusters and the Scene table. The expected behaviour of +/// the table with the handler is: Once a scene command involving extension field set is received, the Scene Table will go through +/// the list of handlers to either retrieve, populate or apply Extension field sets. Each handler is meant to retrieve an extension +/// field set for a single cluster however it is also possible to use a single generic handler that handles all of them. class SceneHandler { public: @@ -83,46 +71,48 @@ class SceneHandler virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to fetch from command - /// @param serialisedBytes Buffer for ExtensionFieldSet in command - /// @param extensionFieldSet ExtensionFieldSets provided by the AddScene Command + /// @param endpoint[in] Endpoint ID + /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized + /// @param cluster[out] Cluster in the Extension field set, filled by the function + /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, + const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, + ClusterId & cluster, MutableByteSpan & serialisedBytes) = 0; - /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility to + /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility + /// to /// place the serialized data in serializedBytes as described below. - /// @param endpoint Target Endpoint - /// @param cluster Target Cluster - /// @param serializedBytes Output buffer, data needs to be writen in there and size adjusted to the size of the data written. + /// @param endpoint[in] Target Endpoint + /// @param cluster[in] Target Cluster + /// @param serializedBytes[out] Output buffer, data needs to be writen in there and size adjusted to the size of the data + /// written. /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; - /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to save - /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param endpoint[in] Endpoint ID + /// @param cluster[in] Cluster ID to save + /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - /// @param extensionFieldSet ExtensionFieldSet in command format + /// @param extensionFieldSet[out] ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID - /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param endpoint[in] Endpoint ID + /// @param cluster[in] Cluster ID + /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - /// @param timeMs Transition time in ms to apply the scene + /// @param timeMs[in] Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, TransitionTimeMs timeMs) = 0; - + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, + TransitionTimeMs timeMs) = 0; }; template @@ -135,11 +125,11 @@ class SceneTable // Identifies endpoint to which this scene applies EndpointId mEndpointId = kInvalidEndpointId; // Identifies group within the scope of the given fabric - SceneGroupID mGroupId = kGlobalGroupSceneId; - SceneId mSceneId = kUndefinedSceneId; + GroupId mGroupId = kGlobalGroupSceneId; + SceneId mSceneId = kUndefinedSceneId; SceneStorageId() = default; - SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : + SceneStorageId(EndpointId endpoint, SceneId id, GroupId groupId = kGlobalGroupSceneId) : mEndpointId(endpoint), mGroupId(groupId), mSceneId(id) {} @@ -157,6 +147,13 @@ class SceneTable }; /// @brief struct used to store data held in a scene + /// Members: + /// mName: char buffer holding the name of the scene, only serialized when mNameLenght is greater than 0 + /// mNameLength: lentgh of the name if a name was provided at scene creation + /// mSceneTransitionTimeSeconds: Time in seconds it will take a cluster to change to the scene + /// mExtensionFieldSets: class holding the different field sets of each cluster values to store with the scene + /// mTransitionTime100ms: Transition time in tenths of a second, allows for more precise transition when combiened with + /// mSceneTransitionTimeSeconds in enhanced scene commands struct SceneData { char mName[kSceneNameMax] = { 0 }; @@ -211,7 +208,7 @@ class SceneTable bool operator==(const SceneData & other) { - return (!memcmp(this->mName, other.mName, this->mNameLength) && + return (this->mNameLength == other.mNameLength && !memcmp(this->mName, other.mName, this->mNameLength) && (this->mSceneTransitionTimeSeconds == other.mSceneTransitionTimeSeconds) && (this->mTransitionTime100ms == other.mTransitionTime100ms) && (this->mExtensionFieldSets == other.mExtensionFieldSets)); @@ -229,7 +226,6 @@ class SceneTable /// @brief Struct combining both ID and data of a table entry struct SceneTableEntry { - // ID SceneStorageId mStorageId; @@ -268,14 +264,13 @@ class SceneTable virtual CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) = 0; virtual CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) = 0; virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; - virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; + virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) = 0; // SceneHandlers virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; virtual CHIP_ERROR UnregisterHandler(SceneHandler * handler) = 0; virtual CHIP_ERROR UnregisterAllHandlers() = 0; - // Extension field sets operation virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; virtual CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) = 0; @@ -288,7 +283,6 @@ class SceneTable virtual SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) = 0; - // Handlers virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } virtual bool HandlerListFull() { return (mNumHandlers >= kMaxSceneHandlers); } diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 01f8a0a72ec909..05ace24ad50b29 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -79,21 +79,21 @@ 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))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), static_cast(mStorageId.mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(mStorageId.mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), 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()) + if (!nameSpan.empty()) { - ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), NameSpan)); + ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(TagScene::kName), nameSpan)); } + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime), + static_cast(mStorageData.mSceneTransitionTimeSeconds))); ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(mStorageData.mSceneTransitionTimeSeconds))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); @@ -101,7 +101,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData CHIP_ERROR UpdateKey(StorageKeyName & key) override { VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); - key = DefaultStorageKeyAllocator::FabricScenesKey(fabric_index); + key = DefaultStorageKeyAllocator::FabricSceneDataKey(fabric_index); return CHIP_NO_ERROR; } @@ -186,9 +186,10 @@ struct FabricSceneData : public PersistentData // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - 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(TagScene::kEndpointID), static_cast(scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(scene_map[i].mSceneId))); } ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); @@ -207,11 +208,11 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Get(scene_count)); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); } ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); @@ -445,10 +446,10 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index /// @param fabric_index Fabric in which the scene belongs /// @param scened_idx Position in the Scene Table /// @return CHIP_NO_ERROR if removal was successful, errors if failed to remove the scene or to update the fabric after removing it -CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) +CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) { FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index, scened_idx); + SceneTableData scene(fabric_index, scene_idx); ReturnErrorOnFailure(scene.Delete(mStorage)); @@ -533,7 +534,7 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandler() +CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandlers() { for (uint8_t i = 0; i < this->mNumHandlers; i++) { @@ -556,8 +557,8 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); for (uint8_t j = 0; j < cSpan.size(); j++) { - ExtensionFieldsSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); + ExtensionFieldSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); EFS.mID = cArray[j]; ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); @@ -575,7 +576,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const { FabricSceneData fabric(fabric_index); SceneTableData scene(fabric_index); - ExtensionFieldsSet EFS; + ExtensionFieldSet EFS; TransitionTimeMs time; clusterId cluster; @@ -585,7 +586,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldNum(); i++) + for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldSetCount(); i++) { scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); cluster = EFS.mID; @@ -624,7 +625,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) return fabric.Delete(mStorage); } -DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) +DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntries(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); return mSceneEntryIterators.CreateObject(*this, fabric_index); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 2a66b41d47ad95..419cab78e9a601 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -16,6 +16,7 @@ */ #pragma once +#include #include #include #include @@ -25,16 +26,21 @@ namespace chip { namespace scenes { -enum SceneTLVTag +/// @brief Tags Used to serialize Scenes so they can be stored in flash memory. +/// kEndpointID: Tag for the Endpoint ID to which this scene applies to +/// kGroupID: Tag for GroupID if the Scene is a Group Scene +/// kID: Tag for the scene ID together with the two previous tag, forms the SceneStorageID +/// kName: Tag for the name of the scene +/// kTransitionTime: Tag for the transition time of the scene in seconds +/// kTransitionTime100: Tag for the transition time of the scene in tenth of a second (enhanced scenes) +enum class TagScene : uint8_t { - kTagSceneStorageIDContainer = 1, - kTagSceneEndpointID, - kTagSceneGroupID, - kTagSceneID, - kTagSceneDataContainer, - kTagSceneName, - kTagSceneDTransitionTime, - kTagSceneDTransitionTime100, + kEndpointID = 1, + kGroupID, + kID, + kName, + kTransitionTime, + kTransitionTime100, }; using clusterId = chip::ClusterId; @@ -53,14 +59,15 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler DefaultSceneHandlerImpl() = default; ~DefaultSceneHandlerImpl() override{}; - /// @brief Function to serialize data from an add scene command, assume the incoming extensionFieldSet is initialized - /// @param endpoint Target Endpoint - /// @param cluster Cluster in the Extension field set, filled by the function - /// @param serialisedBytes Mutable Byte span to hold EFS data from command - /// @param extensionFieldSet Extension field set from commmand, pre initialized - /// @return CHIP_NO_ERROR if success, specific CHIP_ERROR otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) override + /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. + /// @param endpoint[in] Endpoint ID + /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized + /// @param cluster[out] Cluster in the Extension field set, filled by the function + /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, + const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, + ClusterId & cluster, MutableByteSpan & serialisedBytes) override { app::DataModel::List attributeValueList; app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; @@ -115,7 +122,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @param cluster target cluster /// @param serialisedBytes data to deserialize into EFS /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, specific CHIP_ERROR otherwise - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { app::DataModel::DecodableList attributeValueList; @@ -192,12 +199,12 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) override; CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) override; CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) override; - CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; + CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) override; // SceneHandlers CHIP_ERROR RegisterHandler(SceneHandler * handler) override; CHIP_ERROR UnregisterHandler(SceneHandler * handler) override; - CHIP_ERROR UnregisterAllHandler() override; + CHIP_ERROR UnregisterAllHandlers() override; // Extension field sets operation CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; @@ -207,7 +214,7 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; // Iterators - SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) override; protected: class SceneEntryIteratorImpl : public SceneEntryIterator diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index a0b580bc93c65c..999691688c86f2 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -115,6 +115,7 @@ chip_test_suite("tests") { "TestEventLoggingNoUTCTime.cpp", "TestEventOverflow.cpp", "TestEventPathParams.cpp", + "TestExtensionFieldSets.cpp", "TestFabricScopedEventLogging.cpp", "TestInteractionModelEngine.cpp", "TestMessageDef.cpp", diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp new file mode 100644 index 00000000000000..900ffc1e25249f --- /dev/null +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -0,0 +1,308 @@ +/* + * + * 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. + */ + +#include +#include +#include +#include +#include + +using namespace chip; + +namespace { + +static constexpr size_t kPersistentSceneBufferMax = 256; + +// Test Cluster ID +constexpr chip::ClusterId kOnOffClusterId = 0x0006; +constexpr chip::ClusterId kLevelControlClusterId = 0x0008; +constexpr chip::ClusterId kColorControlClusterId = 0x0300; + +constexpr uint8_t kOnOffSize = 1; +constexpr uint8_t kLevelControlSize = 3; +constexpr uint8_t kColorControlSize = 14; + +static uint8_t onOffBuffer[scenes::kMaxFieldBytesPerCluster] = "0"; +static uint8_t levelControlBuffer[scenes::kMaxFieldBytesPerCluster] = "123"; +static uint8_t colorControlBuffer[scenes::kMaxFieldBytesPerCluster] = "abcdefghijklmn"; + +static const scenes::ExtensionFieldSet EFS1(kOnOffClusterId, onOffBuffer, kOnOffSize); +static const scenes::ExtensionFieldSet EFS2(kLevelControlClusterId, levelControlBuffer, kLevelControlSize); +static const scenes::ExtensionFieldSet EFS3(kColorControlClusterId, colorControlBuffer, kColorControlSize); + +static scenes::ExtensionFieldSetsImpl sEFSets; + +void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSet tempEFS; + + uint8_t empty_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t double_size_buffer[scenes::kMaxFieldBytesPerCluster * 2]; + ByteSpan bufferSpan(double_size_buffer); + + memset(double_size_buffer, static_cast(1), sizeof(double_size_buffer)); + + NL_TEST_ASSERT(aSuite, true == EFS->IsEmpty()); + + // Test creators of single ExtensionFieldSet + NL_TEST_ASSERT(aSuite, EFS1.mID == kOnOffClusterId); + NL_TEST_ASSERT(aSuite, EFS1.mUsedBytes == kOnOffSize); + NL_TEST_ASSERT(aSuite, !memcmp(onOffBuffer, EFS1.mBytesBuffer, EFS1.mUsedBytes)); + + NL_TEST_ASSERT(aSuite, EFS2.mID == kLevelControlClusterId); + NL_TEST_ASSERT(aSuite, EFS2.mUsedBytes == kLevelControlSize); + NL_TEST_ASSERT(aSuite, !memcmp(levelControlBuffer, EFS2.mBytesBuffer, EFS2.mUsedBytes)); + + NL_TEST_ASSERT(aSuite, EFS3.mID == kColorControlClusterId); + NL_TEST_ASSERT(aSuite, EFS3.mUsedBytes == kColorControlSize); + NL_TEST_ASSERT(aSuite, !memcmp(colorControlBuffer, EFS3.mBytesBuffer, EFS3.mUsedBytes)); + + // Test creation of EFS from Array and ByteSpan that are to big + tempEFS = scenes::ExtensionFieldSet(kOnOffClusterId, double_size_buffer, sizeof(double_size_buffer)); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kOnOffClusterId); + // Confirm EFS empty + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(empty_buffer))); + + tempEFS = scenes::ExtensionFieldSet(kLevelControlClusterId, bufferSpan); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kLevelControlClusterId); + // Confirm EFS empty + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(empty_buffer))); + + // Test creation of EFS from truncating an Array + tempEFS = scenes::ExtensionFieldSet(kColorControlClusterId, double_size_buffer, sizeof(tempEFS.mBytesBuffer)); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kColorControlClusterId); + // Confirm EFS was written + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == static_cast(sizeof(tempEFS.mBytesBuffer))); + NL_TEST_ASSERT(aSuite, !memcmp(double_size_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + + // Test clear EFS + tempEFS.Clear(); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kInvalidClusterId); + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + + // Test insertion of uninitialized EFS + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); + NL_TEST_ASSERT(aSuite, 0 == EFS->GetFieldSetCount()); + + // Test insertion of empty EFS + tempEFS.mID = kOnOffClusterId; + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); + NL_TEST_ASSERT(aSuite, 0 == EFS->GetFieldSetCount()); + + // Test insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, 1 == EFS->GetFieldSetCount()); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS2)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Test get + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); +} + +void TestSerializeDerializeExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSetsImpl testSceneEFS; + + scenes::ExtensionFieldSet tempEFS; + + uint8_t EFS1Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t EFS2Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t EFS3Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t sceneEFSBuffer[kPersistentSceneBufferMax] = { 0 }; + + uint32_t EFS1_serialized_length = 0; + uint32_t EFS2_serialized_length = 0; + uint32_t EFS3_serialized_length = 0; + uint32_t sceneEFS_serialized_length = 0; + + TLV::TLVReader reader; + TLV::TLVWriter writer; + TLV::TLVType outer; + TLV::TLVType outerRead; + + // Individual Field Sets serialize / deserialize + writer.Init(EFS1Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS1.Serialize(writer)); + writer.EndContainer(outer); + EFS1_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS1_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + writer.Init(EFS2Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS2.Serialize(writer)); + writer.EndContainer(outer); + EFS2_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS2_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + writer.Init(EFS3Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS3.Serialize(writer)); + writer.EndContainer(outer); + EFS3_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS3_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + reader.Init(EFS1Buffer); + 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 == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS1 == tempEFS); + + reader.Init(EFS2Buffer); + 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 == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS2 == tempEFS); + + reader.Init(EFS3Buffer); + 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 == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS3 == tempEFS); + + // All ExtensionFieldSets serialize / deserialize + writer.Init(sceneEFSBuffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->Serialize(writer)); + writer.EndContainer(outer); + sceneEFS_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, sceneEFS_serialized_length <= kPersistentSceneBufferMax); + + reader.Init(sceneEFSBuffer); + 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 == testSceneEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, *EFS == testSceneEFS); +} + +void TestRemoveExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSet tempEFS; + + // Order in EFS at this point: [EFS1, EFS2, EFS3] + // Removal at beginning + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(0)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + + // Order in EFS at this point: [EFS2, EFS3, EFS1] + // Removal at middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(1)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + + // Order in EFS at this point: [EFS2, EFS1, EFS3] + // Removal at end + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(2)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + + // Emptying the table + EFS->Clear(); + NL_TEST_ASSERT(aSuite, true == EFS->IsEmpty()); +} + +} // namespace +/** + * Tear down the test suite. + */ +int TestSetup(void * inContext) +{ + VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); + + return SUCCESS; +} + +/** + * Tear down the test suite. + */ +int TestTeardown(void * inContext) +{ + chip::Platform::MemoryShutdown(); + + return SUCCESS; +} + +int TestExtensionFieldSets() +{ + static nlTest sTests[] = { NL_TEST_DEF("TestInsertExtensionFieldSet", TestInsertExtensionFieldSet), + NL_TEST_DEF("TestSerializeDerializeExtensionFieldSet", TestSerializeDerializeExtensionFieldSet), + NL_TEST_DEF("TestRemoveExtensionFieldSet", TestRemoveExtensionFieldSet), + + NL_TEST_SENTINEL() }; + + nlTestSuite theSuite = { + "SceneTable", + &sTests[0], + TestSetup, + TestTeardown, + }; + + nlTestRunner(&theSuite, nullptr); + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestExtensionFieldSets) \ No newline at end of file diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index b03a80b8a362e0..7f776e6f3639ec 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -25,13 +25,13 @@ using namespace chip; -using SceneTable = scenes::SceneTable; -using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTableImpl = scenes::DefaultSceneTableImpl; -using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = scenes::DefaultSceneTableImpl::SceneData; -using ExtensionFieldsSet = scenes::ExtensionFieldsSet; -using TransitionTimeMs = scenes::TransitionTimeMs; +using SceneTable = scenes::SceneTable; +using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = scenes::DefaultSceneTableImpl; +using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = scenes::DefaultSceneTableImpl::SceneData; +using ExtensionFieldSet = scenes::ExtensionFieldSet; +using TransitionTimeMs = scenes::TransitionTimeMs; namespace { // Test Cluster ID @@ -111,9 +111,9 @@ 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 }; +static uint8_t OO_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; +static uint8_t LC_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; +static uint8_t CC_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; static uint32_t OO_buffer_serialized_length = 0; static uint32_t LC_buffer_serialized_length = 0; @@ -206,14 +206,14 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // 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); + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldBytesPerCluster); // 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; @@ -228,14 +228,14 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // 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 kColorControlClusterId: err = CHIP_NO_ERROR; // Warning: CC_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldBytesPerCluster); // 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; @@ -250,21 +250,21 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // 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); + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldBytesPerCluster); // 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); + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldBytesPerCluster); // 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; @@ -283,7 +283,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @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 + ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -411,7 +411,7 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); // Emptying Handler array - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandler()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandlers()); for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[i])); @@ -487,7 +487,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) ByteSpan LC_list(LC_buffer); ByteSpan CC_list(CC_buffer); - uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + uint8_t buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; MutableByteSpan buff_span(buffer); // Serialize Extension Field sets as if they were recovered from memory @@ -537,7 +537,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) 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(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); // 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())); @@ -553,7 +553,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) 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(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); // 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())); @@ -569,7 +569,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) 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(kTestEndpoint2, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, extensionFieldSetIn, tempCluster, buff_span)); // 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())); @@ -725,7 +725,7 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; - auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + auto * iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator != nullptr); @@ -764,7 +764,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove middle NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.mStorageId)); - auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + auto * iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); @@ -772,7 +772,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Add scene in middle, a spot should have been freed NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene9)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 8); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); NL_TEST_ASSERT(aSuite, scene == scene9); @@ -780,7 +780,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove the recently added scene 9 NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); @@ -788,7 +788,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove first NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); @@ -796,7 +796,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove Next NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 5); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); @@ -805,28 +805,28 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 4); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 3); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene6); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene7); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 1); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene12); @@ -834,14 +834,14 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove last NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); iterator->Release(); } @@ -927,6 +927,7 @@ int TestTeardown(void * inContext) return SUCCESS; } + int TestSceneTable() { static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestHandlerRegistration), diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 399712f228dede..ff13a20a6db647 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1365,14 +1365,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS 2 #endif -/** - * @brief Value used when setting or getting the endpoint in a Scene table - * entry. It indicates that the entry is not in use. - */ -#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 */ @@ -1398,14 +1390,15 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; * @brief The maximum number of clusters per scene */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE -#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 3 -#endif +#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 +#endif + /** * @brief The maximum size of a single extension field set for a single cluster */ #ifndef CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER -#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 100 +#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 128 #endif /** diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 8253a9017fbfcc..5ae16fa51f6544 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -40,7 +40,6 @@ typedef uint32_t EventId; typedef uint64_t EventNumber; typedef uint64_t FabricId; typedef uint8_t FabricIndex; -typedef uint8_t SceneIndex; typedef uint32_t FieldId; typedef uint16_t ListIndex; typedef uint16_t LocalizedStringIdentifier; @@ -48,7 +47,6 @@ typedef uint32_t TransactionId; typedef uint16_t KeysetId; typedef uint8_t InteractionModelRevision; typedef uint32_t SubscriptionId; -typedef GroupId SceneGroupID; typedef uint8_t SceneId; constexpr CompressedFabricId kUndefinedCompressedFabricId = 0ULL; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index b4fa1d602bdcca..3348335488df8f 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -198,10 +198,10 @@ class DefaultStorageKeyAllocator } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } + static StorageKeyName FabricSceneDataKey(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/sc/%x", fabric, id); } };