diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 7c85bc7fa8d0ec..3e9a2232ad4660 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -129,7 +129,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); - uint8_t nextPos = position++; + uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 98c7548694e8c7..be4688a9010126 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -56,40 +56,52 @@ class SceneHandler SceneHandler(){}; virtual ~SceneHandler() = default; + /// @brief Gets the list of supported clusters for an endpoint + /// @param endpoint target endpoint + /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than + /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES + virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; + + /// @brief Returns whether or not a cluster is supported on an endpoint + /// @param endpoint Target Endpoint ID + /// @param cluster Target Cluster ID + /// @return true if supported, false if not supported 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 serialysedBytes Buffer for ExtensionFieldSet in command + /// @param serialisedBytes Buffer for ExtensionFieldSet in command /// @param extensionFieldSet ExtensionFieldSets provided by the AddScene Command - /// @return - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialysedBytes, + /// @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; - /// @brief From command SaveScene, retrieves ExtensionField from nvm - /// @param endpoint - /// @param cluster - /// @param serialysedBytes - /// @return - virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialysedBytes) = 0; + /// @brief From command StoreScene, retrieves ExtensionField from nvm, it is the functions responsability to resize the mutable + /// span if necessary, a number of byte equal to the span will be stored in memory + /// @param endpoint Target Endpoint + /// @param cluster Target Cluster + /// @param serialisedBytes Output buffer, data needs to be writen in there and size adjusted if smaller than + /// kMaxFieldsPerCluster + /// @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 /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to set in command - /// @param serialysedBytes ExtensionFieldSet stored in NVM + /// @param cluster Cluster ID to save + /// @param serialisedBytes ExtensionFieldSet stored in NVM /// @param extensionFieldSet ExtensionFieldSet in command format - /// @return - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, 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 serialysedBytes ExtensionFieldSet stored in NVM + /// @param serialisedBytes ExtensionFieldSet stored in NVM /// @param timeMs Transition time in ms to apply the scene - /// @return - virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, TransitionTimeMs timeMs) = 0; + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; }; class SceneTable @@ -318,21 +330,50 @@ class SceneTable virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; - // Iterators - using SceneEntryIterator = CommonIterator; + // SceneHandlers + virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; + virtual CHIP_ERROR UnregisterHandler(uint8_t position) = 0; - virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + // Extension field sets operation + virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; + virtual CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) = 0; // Fabrics virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; + // Iterators + using SceneEntryIterator = CommonIterator; + + virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + // Handlers - SceneHandler * mHandlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES] = { nullptr }; - uint8_t handlerNum = 0; + virtual bool HandlerListEmpty() { return (handlerNum == 0); } + virtual bool HandlerListFull() { return (handlerNum >= kMaxSceneHandlers); } + virtual uint8_t GetHandlerNum() { return this->handlerNum; } -protected: - const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; + SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; + uint8_t handlerNum = 0; }; +/** + * Instance getter for the global SceneTable. + * + * Callers have to externally synchronize usage of this function. + * + * @return The global Scene Table + */ +SceneTable * GetSceneTable(); + +/** + * Instance setter for the global Scene Table. + * + * Callers have to externally synchronize usage of this function. + * + * The `provider` can be set to nullptr if the owner is done with it fully. + * + * @param[in] provider pointer to the Scene Table global instance to use + */ +void SetSceneTable(SceneTable * provider); + } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 0c4ac6b1da2c7d..df68536f763265 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -443,12 +443,12 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); - uint8_t nextPos = position++; + uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(SceneHandler *) * moveNum); + memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); this->handlerNum--; // Clear last occupied position @@ -457,20 +457,27 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene, clusterId cluster) +CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { - ExtensionFieldsSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < this->handlerNum; i++) { + clusterId cArray[kMaxClusterPerScenes]; + Span cSpan(cArray); if (this->mHandlers[i] != nullptr) { - EFS.mID = cluster; - ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, cluster, EFSSpan)); - EFS.mUsedBytes = (uint8_t) EFSSpan.size(); - ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); + 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); + + EFS.mID = cArray[j]; + ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); + EFS.mUsedBytes = (uint8_t) EFSSpan.size(); + ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); + } } } } @@ -585,16 +592,16 @@ void DefaultSceneTableImpl::SceneEntryIteratorImpl::Release() namespace { -DefaultSceneTableImpl * gSceneTable = nullptr; +SceneTable * gSceneTable = nullptr; } // namespace -DefaultSceneTableImpl * GetSceneTable() +SceneTable * GetSceneTable() { return gSceneTable; } -void SetSceneTable(DefaultSceneTableImpl * provider) +void SetSceneTable(SceneTable * provider) { gSceneTable = provider; } diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index aac47870632db4..42576779900d29 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -44,10 +44,10 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @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 serialyzedBytes Mutable Byte span to hold EFS data from command + /// @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 & serialyzedBytes, + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) override { app::DataModel::List attributeValueList; @@ -88,7 +88,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler attributeValueList = mAVPairs; attributeValueList.reduce_size(pairCount); - writer.Init(serialyzedBytes); + writer.Init(serialisedBytes); 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)), @@ -101,9 +101,9 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @brief Simulates taking data from nvm and loading it in a command object if the cluster is supported by the endpoint /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes data to deserialize into EFS + /// @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 & serialyzedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { app::DataModel::DecodableList attributeValueList; @@ -117,7 +117,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler VerifyOrReturnError(SupportsCluster(endpoint, cluster), CHIP_ERROR_INVALID_ARGUMENT); extensionFieldSet.clusterID = cluster; - reader.Init(serialyzedBytes); + reader.Init(serialisedBytes); ReturnErrorOnFailure(reader.Next()); ReturnErrorOnFailure(reader.EnterContainer(outer)); ReturnErrorOnFailure(reader.Next()); @@ -183,12 +183,12 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; // SceneHandlers - CHIP_ERROR RegisterHandler(SceneHandler * handler); - CHIP_ERROR UnregisterHandler(uint8_t position); + CHIP_ERROR RegisterHandler(SceneHandler * handler) override; + CHIP_ERROR UnregisterHandler(uint8_t position) override; // Extension field sets operation - CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene, clusterId cluster); - CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id); + CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; + CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) override; // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; @@ -196,10 +196,6 @@ class DefaultSceneTableImpl : public SceneTable // Iterators SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; - bool HandlerListEmpty() { return (handlerNum == 0); } - bool HandlerListFull() { return (handlerNum >= CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES); } - uint8_t GetHandlerNum() { return this->handlerNum; } - protected: class SceneEntryIteratorImpl : public SceneEntryIterator { @@ -222,24 +218,5 @@ class DefaultSceneTableImpl : public SceneTable ObjectPool mSceneEntryIterators; }; // class DefaultSceneTableImpl -/** - * Instance getter for the global SceneTable. - * - * Callers have to externally synchronize usage of this function. - * - * @return The global Scene Table - */ -DefaultSceneTableImpl * GetSceneTable(); - -/** - * Instance setter for the global Scene Table. - * - * Callers have to externally synchronize usage of this function. - * - * The `provider` can be set to nullptr if the owner is done with it fully. - * - * @param[in] provider pointer to the Scene Table global instance to use - */ -void SetSceneTable(DefaultSceneTableImpl * provider); } // namespace scenes } // namespace chip diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 527fb349bc8a6d..4f0813f9d9cb82 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -24,6 +24,8 @@ #include using namespace chip; + +using SceneTable = scenes::SceneTable; using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; using SceneTableImpl = scenes::DefaultSceneTableImpl; using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; @@ -119,6 +121,24 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl 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) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } + else if (endpoint == TEST_ENDPOINT2) + { + 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 { @@ -145,9 +165,9 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @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 serialyzedBytes data to serialize into EFS + /// @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 & serialyzedBytes) override + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -157,13 +177,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + 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(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(27); // Used memory for Level Control TLV break; default: break; @@ -175,13 +195,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + 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(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(99); // Used memory for Color Control TLV break; default: break; @@ -194,11 +214,11 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// "cluster" /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes Data from nvm + /// @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 & serialyzedBytes, TransitionTimeMs timeMs) override + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -208,13 +228,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case LV_CTR_CID: - if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -230,13 +250,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case CC_CTR_CID: - if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -254,16 +274,61 @@ static chip::TestPersistentStorageDelegate testStorage; static SceneTableImpl sSceneTable; static TestSceneHandler sHandler; -void ResetSceneTable(SceneTableImpl * sceneTable) +void ResetSceneTable(SceneTable * sceneTable) { sceneTable->RemoveFabric(kFabric1); sceneTable->RemoveFabric(kFabric2); } +void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) +{ + SceneTable * sceneTable = scenes::GetSceneTable(); + TestSceneHandler tmpHandler[scenes::kMaxSceneHandlers]; + + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == i); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); + } + + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == scenes::kMaxSceneHandlers); + // Removal at begining + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == 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]); + + // Removal at the middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(3)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 2)); + // Confirm array was compressed and last position is now null + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 2]); + + // Removal at the middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(scenes::kMaxSceneHandlers - 3)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 3)); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 3]); + + // Emptying Handler array + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); + } + + // Verify the handler num has been updated properly + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == 0); + + // Verify all array is empty + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); + } +} + void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); - ClusterId tempCluster = 0; + SceneTable * sceneTable = chip::scenes::GetSceneTable(); + ClusterId tempCluster = 0; app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; @@ -409,7 +474,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // 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)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -425,7 +490,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // 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)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for level control previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -441,7 +506,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // 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)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for color control previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -457,31 +522,23 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) void TestStoreScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); // Reset test ResetSceneTable(sceneTable); // Populate scene1's EFS (Endpoint1) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene1, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1)); // Populate scene2's EFS (Endpoint1) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene2, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2)); // Populate scene3's EFS (Endpoint2) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene3, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3)); // Populate scene3's EFS (Endpoint2) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene4, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4)); SceneTableEntry scene; @@ -495,7 +552,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene7)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene8)); - // Too many scenes 1 fabric + // Too many scenes for 1 fabric NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_LIST_LENGTH == sceneTable->SetSceneTableEntry(kFabric1, scene9)); // Not Found @@ -530,7 +587,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -554,7 +611,7 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) void TestIterateScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -590,7 +647,7 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -681,7 +738,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) void TestFabricScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); // Reset test @@ -757,7 +814,7 @@ int TestSetup(void * inContext) */ int TestTeardown(void * inContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); if (nullptr != sceneTable) { sceneTable->Finish(); @@ -767,12 +824,14 @@ int TestTeardown(void * inContext) } int TestSceneTable() { - static nlTest sTests[] = { NL_TEST_DEF("TestStoreScenes", TestHandlerFunctions), + static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestHandlerRegistration), + NL_TEST_DEF("TestHandlerFunctions", TestHandlerFunctions), NL_TEST_DEF("TestStoreScenes", TestStoreScenes), NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + NL_TEST_SENTINEL() }; nlTestSuite theSuite = { diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index a8706eaaf0638b..26bfb84bd55e62 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -26,6 +26,7 @@ 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; @@ -72,12 +73,27 @@ static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { public: - static constexpr uint8_t kMaxValueSize = 4; - static constexpr uint8_t kMaxAvPair = 15; - 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) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } + else if (endpoint == TEST_ENDPOINT2) + { + 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 { @@ -104,9 +120,9 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @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 serialyzedBytes data to serialize into EFS + /// @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 & serialyzedBytes) override + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -116,13 +132,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + 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(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(27); // Used memory for Level Control TLV break; default: break; @@ -134,13 +150,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + 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(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(99); // Used memory for Color Control TLV break; default: break; @@ -153,11 +169,11 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// "cluster" /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes Data from nvm + /// @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 & serialyzedBytes, TransitionTimeMs timeMs) override + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -167,13 +183,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case LV_CTR_CID: - if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -189,13 +205,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case CC_CTR_CID: - if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -211,7 +227,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl static TestSceneHandler sHandler; -CHIP_ERROR scene_handler_test(SceneTableImpl * provider) +CHIP_ERROR scene_handler_test(SceneTable * provider) { ClusterId tempCluster = 0; @@ -387,7 +403,7 @@ CHIP_ERROR scene_handler_test(SceneTableImpl * provider) return CHIP_NO_ERROR; }; -CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) +CHIP_ERROR scene_store_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry) { SceneTableEntry temp; @@ -400,7 +416,7 @@ CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, return CHIP_NO_ERROR; } -CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, +CHIP_ERROR scene_iterator_test(SceneTable * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, const SceneTableEntry & entry2, const SceneTableEntry & entry3) { SceneTableEntry temp; @@ -428,8 +444,8 @@ CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_ind return CHIP_NO_ERROR; } -CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry1, - SceneTableEntry & entry2, SceneTableEntry & entry3) +CHIP_ERROR scene_remove_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry1, SceneTableEntry & entry2, + SceneTableEntry & entry3) { SceneTableEntry temp; @@ -458,7 +474,7 @@ CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index return CHIP_NO_ERROR; } -CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) +CHIP_ERROR TestSceneData(SceneTable * provider, FabricIndex fabric_index) { CHIP_ERROR err = CHIP_NO_ERROR; // Scene storage ID @@ -476,16 +492,13 @@ CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) SceneTableEntry scene2(sceneId2, sceneData2); SceneTableEntry scene3(sceneId3, sceneData3); - LogErrorOnFailure(scene_handler_test(provider)); - - err = provider->SceneSaveEFS(scene1, ON_OFF_CID); - LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene1, LV_CTR_CID); + err = scene_handler_test(provider); LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene3, ON_OFF_CID); + err = provider->SceneSaveEFS(scene1); LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene3, CC_CTR_CID); + + err = provider->SceneSaveEFS(scene3); LogErrorOnFailure(err); // Tests