diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 05b49a0d615e03..0ee7e155481427 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -110,7 +110,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fiel return CHIP_ERROR_NO_MEMORY; } -CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) const { VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_BUFFER_TOO_SMALL); diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 7d9622e33f56df..4d822af3410df8 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -136,7 +136,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets uint8_t GetFieldSetCount() const override { return mFieldSetsCount; }; CHIP_ERROR InsertFieldSet(const ExtensionFieldSet & field); - CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position); + CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position) const; CHIP_ERROR RemoveFieldAtPosition(uint8_t position); // implementation diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d1ea719231c44e..eb60cf7827131b 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -39,16 +40,15 @@ static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; 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_SCENE_HANDLERS; - /// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the /// 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 +/// +/// @note If more than one handler is implemented for a specific pair, ONLY THE FIRST HANDLER FOR THAT SPECIFIC +/// PAIR will get called on executing extension field sets related ations on the scene table. +class SceneHandler : public IntrusiveListNodeBase<> { public: SceneHandler(){}; @@ -258,13 +258,13 @@ class SceneTable 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; + virtual void RegisterHandler(SceneHandler * handler) = 0; + virtual void UnregisterHandler(SceneHandler * handler) = 0; + virtual void 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; + virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; + virtual CHIP_ERROR SceneApplyEFS(const SceneTableEntry & scene) = 0; // Fabrics virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; @@ -276,11 +276,11 @@ class SceneTable // Handlers virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } - virtual bool HandlerListFull() { return (mNumHandlers >= kMaxSceneHandlers); } virtual uint8_t GetHandlerNum() { return this->mNumHandlers; } - SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; - uint8_t mNumHandlers = 0; + // SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; + IntrusiveList mHandlerList; + uint8_t mNumHandlers = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index e502f57a530290..98276b3c17d995 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -314,6 +315,7 @@ CHIP_ERROR DefaultSceneTableImpl::Init(PersistentStorageDelegate * storage) void DefaultSceneTableImpl::Finish() { + UnregisterAllHandlers(); mSceneEntryIterators.ReleaseAll(); } @@ -329,6 +331,7 @@ CHIP_ERROR DefaultSceneTableImpl::SetSceneTableEntry(FabricIndex fabric_index, c return fabric.SaveScene(mStorage, entry); } + CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) { FabricSceneData fabric(fabric_index); @@ -343,6 +346,7 @@ CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, S return CHIP_NO_ERROR; } + CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) { FabricSceneData fabric(fabric_index); @@ -371,105 +375,64 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa return fabric.RemoveScene(mStorage, scene.mStorageId); } -/// @brief Register a handler in the handler list +/// @brief Register a handler in the handler linked list /// @param handler Cluster specific handler for extension field sets interaction -/// @return CHIP_NO_ERROR if handler was registered, CHIP_ERROR_NO_MEMORY if the handler list is full -CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) +void DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - uint8_t firstEmptyPosition = kInvalidPosition; - for (uint8_t i = 0; i < kMaxSceneHandlers; i++) - { - if (this->mHandlers[i] == handler) - { - this->mHandlers[i] = handler; - return CHIP_NO_ERROR; - } - if (this->mHandlers[i] == nullptr && firstEmptyPosition == kInvalidPosition) - { - firstEmptyPosition = i; - } - } - - // if found, insert at found position, otherwise at first free possition, otherwise return error - if (firstEmptyPosition < kMaxSceneHandlers) - { - this->mHandlers[firstEmptyPosition] = handler; - this->mNumHandlers++; - return CHIP_NO_ERROR; - } - - return CHIP_ERROR_NO_MEMORY; + mHandlerList.PushFront(handler); + mNumHandlers++; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) +void DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) { - uint8_t position = kInvalidPosition; - // Verify list is populated and handler is not null - VerifyOrReturnValue(!this->HandlerListEmpty() && !(handler == nullptr), CHIP_NO_ERROR); - - // Finds the position of the Handler to unregister - for (uint8_t i = 0; i < this->mNumHandlers; i++) - { - if (this->mHandlers[i] == handler) - { - position = i; - break; - } - } - - // Verify Handler was found - VerifyOrReturnValue(position < kMaxSceneHandlers, CHIP_NO_ERROR); - - uint8_t nextPos = static_cast(position + 1); - uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); - - // TODO: Implement general array management methods - // Compress array after removal - if (moveNum) - { - memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); - } - - this->mNumHandlers--; - // Clear last occupied position - this->mHandlers[mNumHandlers] = nullptr; - - return CHIP_NO_ERROR; + VerifyOrReturn(!this->HandlerListEmpty() && !(handler == nullptr)); + mHandlerList.Remove(handler); + mNumHandlers--; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandlers() +void DefaultSceneTableImpl::UnregisterAllHandlers() { - for (uint8_t i = 0; i < this->mNumHandlers; i++) + while (!mHandlerList.Empty()) { - ReturnErrorOnFailure(this->UnregisterHandler(this->mHandlers[0])); + IntrusiveList::Iterator foo = mHandlerList.begin(); + SceneHandler * handle = &(*foo); + mHandlerList.Remove((handle)); + mNumHandlers--; } - - return CHIP_NO_ERROR; } +/// @brief Gets the field sets for the clusters implemented on a specific endpoint and store them in an EFS (extension field set). +/// Does so by going through the SceneHandler list and calling the first handler the list find for each specific clusters. +/// @param scene Scene in which the EFS gets populated CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { + if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < this->mNumHandlers; i++) + uint8_t clusterCount = 0; + clusterId cArray[kMaxClusterPerScenes]; + Span cSpan(cArray); + clusterCount = GetClustersFromEndpoint(scene.mStorageId.mEndpointId, cArray, kMaxClusterPerScenes); + cSpan.reduce_size(clusterCount); + for (clusterId cluster : cSpan) { - clusterId cArray[kMaxClusterPerScenes]; - Span cSpan(cArray); - if (this->mHandlers[i] != nullptr) + ExtensionFieldSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); + EFS.mID = cluster; + + IntrusiveList::Iterator iter = mHandlerList.begin(); + while (iter != mHandlerList.end()) { - this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); - for (clusterId cluster : cSpan) + if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) { - ExtensionFieldSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); - - EFS.mID = cluster; - ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); + ReturnErrorOnFailure(iter->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); EFS.mUsedBytes = static_cast(EFSSpan.size()); ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); + break; } + iter++; } } } @@ -477,18 +440,16 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) +/// @brief Retrieves the values of extension field sets on a scene and applies them to each cluster on the endpoint of the scene. +/// Does so by iterating through mHandlerList for each cluster in the EFS and calling the FIRST handler found that supports the +/// cluster. Does so by going through the SceneHandler list and calling the first handler the list find for each specific clusters. +/// @param scene Scene providing the EFSs (extension field sets) +CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(const SceneTableEntry & scene) { - FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index); ExtensionFieldSet EFS; TransitionTimeMs time; clusterId cluster; - ReturnErrorOnFailure(fabric.Load(mStorage)); - VerifyOrReturnError(fabric.Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(scene.Load(mStorage)); - if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldSetCount(); i++) @@ -500,9 +461,14 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!EFS.IsEmpty()) { - for (uint8_t j = 0; j < this->mNumHandlers; j++) + IntrusiveList::Iterator iter = mHandlerList.begin(); + while (iter != mHandlerList.end()) { - ReturnErrorOnFailure(this->mHandlers[j]->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); + if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) + { + ReturnErrorOnFailure(iter->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); + break; + } } } } @@ -529,6 +495,13 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) return fabric.Delete(mStorage); } +/// @brief wrapper function around emberAfGetClustersFromEndpoint to allow testing, shimed in test configuration because +/// emberAfGetClusterFromEndpoint relies on , which relies on zap generated files +uint8_t DefaultSceneTableImpl::GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen) +{ + return emberAfGetClustersFromEndpoint(endpoint, clusterList, listLen, true); +} + DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntries(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index e80e68a9d3145a..87edee4bb425a1 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -200,13 +200,14 @@ class DefaultSceneTableImpl : public SceneTable 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 UnregisterAllHandlers() override; + void RegisterHandler(SceneHandler * handler) override; + void UnregisterHandler(SceneHandler * handler) override; + void UnregisterAllHandlers() override; // Extension field sets operation + CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; - CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) override; + CHIP_ERROR SceneApplyEFS(const SceneTableEntry & scene) override; // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; @@ -215,6 +216,9 @@ class DefaultSceneTableImpl : public SceneTable SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) override; protected: + // wrapper function around emberAfGetClustersFromEndpoint to allow override when testing + virtual uint8_t GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen); + class SceneEntryIteratorImpl : public SceneEntryIterator { public: diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 507f4b2882d570..d77162909ee5e6 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -50,7 +50,6 @@ static_library("server") { public_deps = [ "${chip_root}/src/app", - "${chip_root}/src/app/clusters/scenes", "${chip_root}/src/lib/address_resolve", "${chip_root}/src/lib/dnssd", "${chip_root}/src/messaging", diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 229ec7ac963be5..b80c3ca8f45b11 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -162,8 +162,6 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) mGroupsProvider = initParams.groupDataProvider; SetGroupDataProvider(mGroupsProvider); - mSceneTable = initParams.sceneTable; - mTestEventTriggerDelegate = initParams.testEventTriggerDelegate; deviceInfoprovider = DeviceLayer::GetDeviceInfoProvider(); @@ -537,8 +535,6 @@ KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStor PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore; Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore; Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider; -// TODO: complete scene cluster implementation before uncommenting -// scenes::DefaultSceneTableImpl CommonCaseDeviceServerInitParams::sSceneTable; IgnoreCertificateValidityPolicy CommonCaseDeviceServerInitParams::sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION SimpleSessionResumptionStorage CommonCaseDeviceServerInitParams::sSessionResumptionStorage; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 18d2d2b948f55f..8a0b872cd36ec9 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -91,7 +89,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -118,8 +116,6 @@ struct ServerInitParams // Group data provider: MUST be injected. Used to maintain critical keys such as the Identity // Protection Key (IPK) for CASE. Must be initialized before being provided. Credentials::GroupDataProvider * groupDataProvider = nullptr; - // Scene Table: optionnal, required if Scene Cluster implemented - scenes::SceneTable * sceneTable = nullptr; // Session keystore: MUST be injected. Used to derive and manage lifecycle of symmetric keys. Crypto::SessionKeystore * sessionKeystore = nullptr; // Access control delegate: MUST be injected. Used to look up access control rules. Must be @@ -209,7 +205,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -260,11 +256,6 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams ReturnErrorOnFailure(sGroupDataProvider.Init()); this->groupDataProvider = &sGroupDataProvider; - // TODO: complete scene cluster implementation before uncommenting - // Scene Table - // this->sceneTable = &sSceneTable; - // this->sceneTable->Init(this->persistentStorageDelegate); - #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION ReturnErrorOnFailure(sSessionResumptionStorage.Init(this->persistentStorageDelegate)); this->sessionResumptionStorage = &sSessionResumptionStorage; @@ -298,8 +289,6 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams static PersistentStorageOperationalKeystore sPersistentStorageOperationalKeystore; static Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; static Credentials::GroupDataProviderImpl sGroupDataProvider; - // TODO: complete scene cluster implementation before uncommenting - // static scenes::DefaultSceneTableImpl sSceneTable; static IgnoreCertificateValidityPolicy sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION static SimpleSessionResumptionStorage sSessionResumptionStorage; @@ -344,43 +333,92 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() { return mFabrics; } - - CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } + FabricTable & GetFabricTable() + { + return mFabrics; + } - Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } + CASESessionManager * GetCASESessionManager() + { + return &mCASESessionManager; + } - SessionManager & GetSecureSessionManager() { return mSessions; } + Messaging::ExchangeManager & GetExchangeManager() + { + return mExchangeMgr; + } - SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } + SessionManager & GetSecureSessionManager() + { + return mSessions; + } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } + SessionResumptionStorage * GetSessionResumptionStorage() + { + return mSessionResumptionStorage; + } - TransportMgrBase & GetTransportManager() { return mTransports; } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() + { + return mSubscriptionResumptionStorage; + } - Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + TransportMgrBase & GetTransportManager() + { + return mTransports; + } - scenes::SceneTable * GetSceneTable() { return mSceneTable; } + Credentials::GroupDataProvider * GetGroupDataProvider() + { + return mGroupsProvider; + } - Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + Crypto::SessionKeystore * GetSessionKeystore() const + { + return mSessionKeystore; + } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } + Ble::BleLayer * GetBleLayerObject() + { + return mBleLayer; + } #endif - CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } + CommissioningWindowManager & GetCommissioningWindowManager() + { + return mCommissioningWindowManager; + } - PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } + PersistentStorageDelegate & GetPersistentStorage() + { + return *mDeviceStorage; + } - app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } + app::FailSafeContext & GetFailSafeContext() + { + return mFailSafeContext; + } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() + { + return mTestEventTriggerDelegate; + } - Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } + Crypto::OperationalKeystore * GetOperationalKeystore() + { + return mOperationalKeystore; + } - Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } + Credentials::OperationalCertificateStore * GetOpCertStore() + { + return mOpCertStore; + } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() + { + return mAttributePersister; + } /** * This function causes the ShutDown event to be generated async on the @@ -397,7 +435,10 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() { return sServer; } + static Server & GetInstance() + { + return sServer; + } private: Server() = default; @@ -578,7 +619,6 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; - scenes::SceneTable * mSceneTable = nullptr; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 999691688c86f2..f64f0f58fe5154 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -91,7 +91,9 @@ source_set("scenes-table-test-srcs") { ] public_deps = [ + "${chip_root}/src/app", "${chip_root}/src/app/common:cluster-objects", + "${chip_root}/src/app/util/mock:mock_ember", "${chip_root}/src/lib/core", ] } diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index dc4049b11e0cbe..27abf69b7659b6 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -368,10 +368,26 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } }; +class TestSceneTableImpl : public SceneTableImpl +{ + uint8_t GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen) override + { + if (listLen >= 3) + { + clusterList[0] = kOnOffClusterId; + clusterList[1] = kLevelControlClusterId; + clusterList[2] = kColorControlClusterId; + return 3; + } + + return 0; + } +}; + // Storage static chip::TestPersistentStorageDelegate testStorage; // Scene -static SceneTableImpl sSceneTable; +static TestSceneTableImpl sSceneTable; static TestSceneHandler sHandler; void ResetSceneTable(SceneTable * sceneTable) @@ -383,56 +399,41 @@ void ResetSceneTable(SceneTable * sceneTable) void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; - TestSceneHandler tmpHandler[scenes::kMaxSceneHandlers]; + TestSceneHandler tmpHandler[scenes::kMaxClusterPerScenes]; - for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + for (uint8_t i = 0; i < scenes::kMaxClusterPerScenes; i++) { NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); + sceneTable->RegisterHandler(&tmpHandler[i]); } // Hanlder order in table : [H0, H1, H2] - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxClusterPerScenes); // Removal at beginning - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[0])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[0]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Re-insert - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[0])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); - // Hanlder order in table : [H1, H2, H0] + sceneTable->RegisterHandler(&tmpHandler[0]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); + // Hanlder order in table : [H0, H1, H2] // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Re-insert - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + sceneTable->RegisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); // Hanlder order in table : [H1, H0, H2] // Removal at the end - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Emptying Handler array - 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])); - } + sceneTable->UnregisterAllHandlers(); // Verify the handler num has been updated properly NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == 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) @@ -533,7 +534,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) CC_buffer_serialized_length = writer.GetLengthWritten(); // Test Registering SceneHandler - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&sHandler)); + sceneTable->RegisterHandler(&sHandler); NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 1); // Setup the On Off Extension field set in the expected state from a command @@ -678,19 +679,19 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene1.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene2.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene3.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene4.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); @@ -700,7 +701,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene7); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene8); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene8.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); } void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 09b43f614136c7..95e12dad065da5 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -61,11 +61,11 @@ EndpointId endpoints[] = { kMockEndpoint1, kMockEndpoint2, kMockEndpoint3 }; uint16_t clusterIndex[] = { 0, 2, 5 }; uint8_t clusterCount[] = { 2, 3, 4 }; ClusterId clusters[] = { MockClusterId(1), MockClusterId(2), MockClusterId(1), MockClusterId(2), MockClusterId(3), - MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; + MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; uint16_t attributeIndex[] = { 0, 2, 5, 7, 11, 16, 19, 25, 27 }; uint16_t attributeCount[] = { 2, 3, 2, 4, 5, 3, 6, 2, 2 }; AttributeId attributes[] = { - // clang-format off + // clang-format off Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, MockAttributeId(1), Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, @@ -84,14 +84,14 @@ bool mockAttribute1 = true; int16_t mockAttribute2 = 42; uint64_t mockAttribute3 = 0xdeadbeef0000cafe; uint8_t mockAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; } // namespace @@ -184,6 +184,24 @@ chip::Optional emberAfGetNthClusterId(chip::EndpointId endpoint return chip::Optional(clusters[clusterIndex[emberAfIndexFromEndpoint(endpoint)] + n]); } +// Returns number of clusters put into the passed cluster list +// for the given endpoint and client/server polarity +uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server) +{ + uint8_t cluster_Count = emberAfClusterCount(endpoint, server); + uint8_t i; + + if (cluster_Count > listLen) + { + cluster_Count = listLen; + } + for (i = 0; i < cluster_Count; i++) + { + clusterList[i] = emberAfGetNthClusterId(endpoint, i, server).Value(); + } + return cluster_Count; +} + chip::Optional emberAfGetServerAttributeIdByIndex(chip::EndpointId endpoint, chip::ClusterId cluster, uint16_t index) { diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index ef1d5bd64a16b3..96de94294d1df4 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1393,13 +1393,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 #endif -/** - * @brief The maximum number of handlers used for extension field sets per scene. - */ -#ifndef CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS -#define CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS 3 -#endif - /** * @brief The maximum size of a single extension field set for a single cluster */ diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index bee51293b22ef2..84dcb15379e6ef 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -198,7 +198,7 @@ class DefaultStorageKeyAllocator } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - static StorageKeyName FabricSceneDataKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } + static StorageKeyName FabricSceneDataKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/sc", fabric); } static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { return StorageKeyName::Formatted("f/%x/sc/%x", fabric, id);