From b3915ca7cfa3df2c53736218dc2aeb9bbdfaa7bd Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 1 Nov 2023 15:59:01 -0400 Subject: [PATCH] Added helpers to reduce code copied over when created scene new scene handlers --- src/app/chip_data_model.gni | 3 + .../clusters/on-off-server/on-off-server.cpp | 97 +--------- src/app/clusters/scenes-server/BUILD.gn | 2 + .../scenes-server/SceneHandlerImpl.cpp | 99 ++++++++++ .../clusters/scenes-server/SceneHandlerImpl.h | 179 ++++++++++++++++++ .../clusters/scenes-server/SceneTableImpl.cpp | 81 +------- .../clusters/scenes-server/SceneTableImpl.h | 64 +------ src/app/tests/BUILD.gn | 2 + 8 files changed, 294 insertions(+), 233 deletions(-) create mode 100644 src/app/clusters/scenes-server/SceneHandlerImpl.cpp create mode 100644 src/app/clusters/scenes-server/SceneHandlerImpl.h diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 85cc2025a586dd..cd6afabfc063d4 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -165,6 +165,7 @@ template("chip_data_model") { "${_app_root}/clusters/scenes-server/ExtensionFieldSetsImpl.h", "${_app_root}/clusters/scenes-server/SceneTable.h", "${_app_root}/clusters/scenes-server/SceneTableImpl.h", + "${_app_root}/clusters/scenes-server/SceneHandlerImpl.h", "${_app_root}/clusters/scenes-server/scenes-server.h", "${_app_root}/util/binding-table.cpp", "${_app_root}/util/binding-table.h", @@ -279,6 +280,8 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/${cluster}.cpp", "${_app_root}/clusters/scenes-server/ExtensionFieldSetsImpl.cpp", "${_app_root}/clusters/scenes-server/SceneTableImpl.cpp", + "${_app_root}/clusters/scenes-server/SceneHandlerImpl.cpp", + ] } else if (cluster == "operational-state-server") { sources += [ diff --git a/src/app/clusters/on-off-server/on-off-server.cpp b/src/app/clusters/on-off-server/on-off-server.cpp index bbd35235e99555..7664a7254eb739 100644 --- a/src/app/clusters/on-off-server/on-off-server.cpp +++ b/src/app/clusters/on-off-server/on-off-server.cpp @@ -106,99 +106,12 @@ static constexpr size_t kOnOffMaxEnpointCount = #ifdef EMBER_AF_PLUGIN_SCENES static EmberEventControl sceneHandlerEventControls[kOnOffMaxEnpointCount]; static void sceneOnOffCallback(EndpointId endpoint); +using OnOffEndPointPair = chip::scenes::DefaultSceneHandlerImpl::EndpointStatePair; class DefaultOnOffSceneHandler : public scenes::DefaultSceneHandlerImpl { public: - /// @brief Struct to keep track of the desired state of the OnOff attribute between ApplyScene and - /// transition time expiration - struct EndpointStatePair - { - EndpointStatePair(EndpointId endpoint = kInvalidEndpointId, bool status = false) : mEndpoint(endpoint), mState(status) {} - EndpointId mEndpoint; - bool mState; - }; - - /// @brief Struct holding an array of EndpointStatePair. Handles insertion, get and removal by EndpointID. - /// TODO: Implement generic object to handle this boilerplate array manipulation - struct StatePairBuffer - { - bool IsEmpty() const { return (mPairCount == 0); } - - CHIP_ERROR FindPair(const EndpointId endpoint, uint16_t & found_index) const - { - VerifyOrReturnError(!IsEmpty(), CHIP_ERROR_NOT_FOUND); - for (found_index = 0; found_index < mPairCount; found_index++) - { - if (endpoint == mStatePairBuffer[found_index].mEndpoint) - { - return CHIP_NO_ERROR; - } - } - - return CHIP_ERROR_NOT_FOUND; - } - - CHIP_ERROR InsertPair(const EndpointStatePair & status) - { - uint16_t idx; - CHIP_ERROR err = FindPair(status.mEndpoint, idx); - - if (CHIP_NO_ERROR == err) - { - mStatePairBuffer[idx] = status; - } - else if (mPairCount < MAX_ENDPOINT_COUNT) - { - // if not found, insert at the end - mStatePairBuffer[mPairCount] = status; - mPairCount++; - } - else - { - return CHIP_ERROR_NO_MEMORY; - } - - return CHIP_NO_ERROR; - } - - CHIP_ERROR GetPair(const EndpointId endpoint, EndpointStatePair & status) const - { - uint16_t idx; - ReturnErrorOnFailure(FindPair(endpoint, idx)); - - status = mStatePairBuffer[idx]; - return CHIP_NO_ERROR; - } - - /// @brief Removes Pair and decrements Pair count if the endpoint existed in the array - /// @param endpoint : endpoint id of the pair - CHIP_ERROR RemovePair(const EndpointId endpoint) - { - uint16_t position; - VerifyOrReturnValue(CHIP_NO_ERROR == FindPair(endpoint, position), CHIP_NO_ERROR); - - uint16_t nextPos = static_cast(position + 1); - uint16_t moveNum = static_cast(mPairCount - nextPos); - - // Compress array after removal, if the removed position is not the last - if (moveNum) - { - memmove(&mStatePairBuffer[position], &mStatePairBuffer[nextPos], sizeof(EndpointStatePair) * moveNum); - } - - mPairCount--; - // Clear last occupied position - mStatePairBuffer[mPairCount].mEndpoint = kInvalidEndpointId; - - return CHIP_NO_ERROR; - } - - uint16_t mPairCount; - EndpointStatePair mStatePairBuffer[kOnOffMaxEnpointCount]; - }; - - StatePairBuffer mSceneEndpointStatePairs; + DefaultSceneHandlerImpl::StatePairBuffer mSceneEndpointStatePairs; // As per spec, 1 attribute is scenable in the on off cluster static constexpr uint8_t scenableAttributeCount = 1; @@ -279,7 +192,7 @@ class DefaultOnOffSceneHandler : public scenes::DefaultSceneHandlerImpl auto & decodePair = pair_iterator.GetValue(); VerifyOrReturnError(decodePair.attributeID == Attributes::OnOff::Id, CHIP_ERROR_INVALID_ARGUMENT); ReturnErrorOnFailure( - mSceneEndpointStatePairs.InsertPair(EndpointStatePair(endpoint, static_cast(decodePair.attributeValue)))); + mSceneEndpointStatePairs.InsertPair(OnOffEndPointPair(endpoint, static_cast(decodePair.attributeValue)))); } // Verify that the EFS was completely read CHIP_ERROR err = pair_iterator.GetStatus(); @@ -328,9 +241,9 @@ static DefaultOnOffSceneHandler sOnOffSceneHandler; static void sceneOnOffCallback(EndpointId endpoint) { - DefaultOnOffSceneHandler::EndpointStatePair savedState; + OnOffEndPointPair savedState; ReturnOnFailure(sOnOffSceneHandler.mSceneEndpointStatePairs.GetPair(endpoint, savedState)); - chip::CommandId command = (savedState.mState) ? Commands::On::Id : Commands::Off::Id; + chip::CommandId command = (savedState.mValue) ? Commands::On::Id : Commands::Off::Id; OnOffServer::Instance().setOnOffValue(endpoint, command, false); ReturnOnFailure(sOnOffSceneHandler.mSceneEndpointStatePairs.RemovePair(endpoint)); } diff --git a/src/app/clusters/scenes-server/BUILD.gn b/src/app/clusters/scenes-server/BUILD.gn index 0e34919d8307b8..f55b1544ae9633 100644 --- a/src/app/clusters/scenes-server/BUILD.gn +++ b/src/app/clusters/scenes-server/BUILD.gn @@ -23,6 +23,8 @@ static_library("scenes") { "SceneTable.h", "SceneTableImpl.cpp", "SceneTableImpl.h", + "SceneHandlerImpl.cpp", + "SceneHandlerImpl.h", ] deps = [ "${chip_root}/src/app" ] diff --git a/src/app/clusters/scenes-server/SceneHandlerImpl.cpp b/src/app/clusters/scenes-server/SceneHandlerImpl.cpp new file mode 100644 index 00000000000000..c29d1bbd5d27e8 --- /dev/null +++ b/src/app/clusters/scenes-server/SceneHandlerImpl.cpp @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace chip { +namespace scenes { + +CHIP_ERROR +DefaultSceneHandlerImpl::EncodeAttributeValueList(const List & aVlist, MutableByteSpan & serializedBytes) +{ + TLV::TLVWriter writer; + writer.Init(serializedBytes); + ReturnErrorOnFailure(app::DataModel::Encode(writer, TLV::AnonymousTag(), aVlist)); + serializedBytes.reduce_size(writer.GetLengthWritten()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultSceneHandlerImpl::DecodeAttributeValueList(const ByteSpan & serializedBytes, + DecodableList & aVlist) +{ + TLV::TLVReader reader; + + reader.Init(serializedBytes); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::AnonymousTag())); + ReturnErrorOnFailure(aVlist.Decode(reader)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +DefaultSceneHandlerImpl::SerializeAdd(EndpointId endpoint, const ExtensionFieldSetDecodableType & extensionFieldSet, + MutableByteSpan & serializedBytes) +{ + AttributeValuePairType aVPairs[kMaxAvPair]; + + size_t pairTotal = 0; + // Verify size of list + ReturnErrorOnFailure(extensionFieldSet.attributeValueList.ComputeSize(&pairTotal)); + VerifyOrReturnError(pairTotal <= ArraySize(aVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t pairCount = 0; + auto pair_iterator = extensionFieldSet.attributeValueList.begin(); + while (pair_iterator.Next()) + { + aVPairs[pairCount] = pair_iterator.GetValue(); + pairCount++; + } + ReturnErrorOnFailure(pair_iterator.GetStatus()); + List attributeValueList(aVPairs, pairCount); + + return EncodeAttributeValueList(attributeValueList, serializedBytes); +} + +CHIP_ERROR DefaultSceneHandlerImpl::Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, + ExtensionFieldSetType & extensionFieldSet) +{ + DecodableList attributeValueList; + + ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList)); + + // Verify size of list + size_t pairTotal = 0; + ReturnErrorOnFailure(attributeValueList.ComputeSize(&pairTotal)); + VerifyOrReturnError(pairTotal <= ArraySize(mAVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t pairCount = 0; + auto pair_iterator = attributeValueList.begin(); + while (pair_iterator.Next()) + { + mAVPairs[pairCount] = pair_iterator.GetValue(); + pairCount++; + }; + ReturnErrorOnFailure(pair_iterator.GetStatus()); + + extensionFieldSet.clusterID = cluster; + extensionFieldSet.attributeValueList = mAVPairs; + extensionFieldSet.attributeValueList.reduce_size(pairCount); + + return CHIP_NO_ERROR; +} + +} // namespace scenes +} // namespace chip diff --git a/src/app/clusters/scenes-server/SceneHandlerImpl.h b/src/app/clusters/scenes-server/SceneHandlerImpl.h new file mode 100644 index 00000000000000..6551084389cc16 --- /dev/null +++ b/src/app/clusters/scenes-server/SceneHandlerImpl.h @@ -0,0 +1,179 @@ +/** + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace chip { +namespace scenes { + +using clusterId = chip::ClusterId; + +/// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster +/// The implementation of SerializeSave and ApplyScene were omitted and must be implemented in a way that +/// is compatible with the SerializeAdd output in order to function with the Default Scene Handler. +/// It is worth noting that this implementation is very memory consuming. In the current worst case, +/// (Color control cluster), the Extension Field Set's value pair list TLV occupies 99 bytes of memory +class DefaultSceneHandlerImpl : public scenes::SceneHandler +{ + template + using List = chip::app::DataModel::List; + + template + using DecodableList = chip::app::DataModel::DecodableList; + + using AttributeValuePairType = chip::app::Clusters::Scenes::Structs::AttributeValuePair::Type; + using AttributeValuePairDecodableType = chip::app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType; + using ExtensionFieldSetDecodableType = chip::app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType; + using ExtensionFieldSetType = chip::app::Clusters::Scenes::Structs::ExtensionFieldSet::Type; + +public: + /// @brief Struct meant to map the state of a cluster to a specific endpoint. Meant to be used to apply scenes using a timer for + /// transitionning + /// @tparam ValueType type of the value to map to the endpoint, must implement operator= and operator== for complex types + template + struct EndpointStatePair + { + EndpointStatePair(EndpointId endpoint = kInvalidEndpointId, ValueType value = ValueType{}) : + mEndpoint(endpoint), mValue(value) + {} + EndpointId mEndpoint; + ValueType mValue; + }; + + template + struct StatePairBuffer + { + bool IsEmpty() const { return (mPairCount == 0); } + + CHIP_ERROR FindPair(const EndpointId endpoint, uint16_t & found_index) const + { + VerifyOrReturnError(!IsEmpty(), CHIP_ERROR_NOT_FOUND); + for (found_index = 0; found_index < mPairCount; found_index++) + { + if (endpoint == mStatePairBuffer[found_index].mEndpoint) + { + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_NOT_FOUND; + } + + CHIP_ERROR InsertPair(const EndpointStatePair & status) + { + uint16_t idx; + CHIP_ERROR err = FindPair(status.mEndpoint, idx); + + if (CHIP_NO_ERROR == err) + { + mStatePairBuffer[idx] = status; + } + else if (mPairCount < MaxEndpointCount) + { + // If not found, insert at the end + mStatePairBuffer[mPairCount] = status; + mPairCount++; + } + else + { + return CHIP_ERROR_NO_MEMORY; + } + + return CHIP_NO_ERROR; + } + + CHIP_ERROR GetPair(const EndpointId endpoint, EndpointStatePair & status) const + { + uint16_t idx; + ReturnErrorOnFailure(FindPair(endpoint, idx)); + + status = mStatePairBuffer[idx]; + return CHIP_NO_ERROR; + } + + /// @brief Removes Pair and decrements Pair count if the endpoint existed in the array + /// @param endpoint : endpoint id of the pair + CHIP_ERROR RemovePair(const EndpointId endpoint) + { + uint16_t position; + VerifyOrReturnValue(CHIP_NO_ERROR == FindPair(endpoint, position), CHIP_NO_ERROR); + + uint16_t nextPos = static_cast(position + 1); + uint16_t moveNum = static_cast(mPairCount - nextPos); + + // Compress array after removal, if the removed position is not the last + if (moveNum) + { + memmove(&mStatePairBuffer[position], &mStatePairBuffer[nextPos], sizeof(EndpointStatePair) * moveNum); + } + + mPairCount--; + // Clear the last occupied position + mStatePairBuffer[mPairCount].mEndpoint = kInvalidEndpointId; + + return CHIP_NO_ERROR; + } + + uint16_t mPairCount = 0; + EndpointStatePair mStatePairBuffer[MaxEndpointCount]; + }; + + static constexpr uint8_t kMaxAvPair = CHIP_CONFIG_SCENES_MAX_AV_PAIRS_EFS; + + DefaultSceneHandlerImpl() = default; + ~DefaultSceneHandlerImpl() override{}; + + /// @brief Encodes an attribute value list into a TLV structure and resizes the buffer to the size of the encoded data + /// @param aVlist[in] Attribute value list to encode + /// @param serializedBytes[out] Buffer to fill from the Attribute value list in a TLV format + /// @return CHIP_ERROR + virtual CHIP_ERROR EncodeAttributeValueList(const List & aVlist, MutableByteSpan & serializedBytes); + + /// @brief Decodes an attribute value list from a TLV structure and ensure it fits the member pair buffer + /// @param serializedBytes [in] Buffer to read from + /// @param aVlist [out] Attribute value list to fill from the TLV structure. Only valid while the buffer backing + /// serializedBytes exists and its contents are not modified. + /// @return CHIP_ERROR + virtual CHIP_ERROR DecodeAttributeValueList(const ByteSpan & serializedBytes, + DecodableList & aVlist); + + /// @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 serializedBytes[out] Buffer to fill from the ExtensionFieldSet in command + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not supported, CHIP_ERROR value + /// otherwise + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const ExtensionFieldSetDecodableType & extensionFieldSet, + MutableByteSpan & serializedBytes) override; + + /// @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 serializedBytes data to deserialize into EFS + /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not + /// supported, specific CHIP_ERROR otherwise + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, + ExtensionFieldSetType & extensionFieldSet) override; + +private: + AttributeValuePairType mAVPairs[kMaxAvPair]; +}; + +} // namespace scenes +} // namespace chip diff --git a/src/app/clusters/scenes-server/SceneTableImpl.cpp b/src/app/clusters/scenes-server/SceneTableImpl.cpp index 7f5870f0ecf2b3..64a72687ef67e2 100644 --- a/src/app/clusters/scenes-server/SceneTableImpl.cpp +++ b/src/app/clusters/scenes-server/SceneTableImpl.cpp @@ -22,81 +22,6 @@ namespace chip { namespace scenes { -CHIP_ERROR -DefaultSceneHandlerImpl::EncodeAttributeValueList(const List & aVlist, MutableByteSpan & serializedBytes) -{ - TLV::TLVWriter writer; - writer.Init(serializedBytes); - ReturnErrorOnFailure(app::DataModel::Encode(writer, TLV::AnonymousTag(), aVlist)); - serializedBytes.reduce_size(writer.GetLengthWritten()); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR DefaultSceneHandlerImpl::DecodeAttributeValueList(const ByteSpan & serializedBytes, - DecodableList & aVlist) -{ - TLV::TLVReader reader; - - reader.Init(serializedBytes); - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::AnonymousTag())); - ReturnErrorOnFailure(aVlist.Decode(reader)); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR -DefaultSceneHandlerImpl::SerializeAdd(EndpointId endpoint, const ExtensionFieldSetDecodableType & extensionFieldSet, - MutableByteSpan & serializedBytes) -{ - AttributeValuePairType aVPairs[kMaxAvPair]; - - size_t pairTotal = 0; - // Verify size of list - ReturnErrorOnFailure(extensionFieldSet.attributeValueList.ComputeSize(&pairTotal)); - VerifyOrReturnError(pairTotal <= ArraySize(aVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); - - uint8_t pairCount = 0; - auto pair_iterator = extensionFieldSet.attributeValueList.begin(); - while (pair_iterator.Next()) - { - aVPairs[pairCount] = pair_iterator.GetValue(); - pairCount++; - } - ReturnErrorOnFailure(pair_iterator.GetStatus()); - List attributeValueList(aVPairs, pairCount); - - return EncodeAttributeValueList(attributeValueList, serializedBytes); -} - -CHIP_ERROR DefaultSceneHandlerImpl::Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, - ExtensionFieldSetType & extensionFieldSet) -{ - DecodableList attributeValueList; - - ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList)); - - // Verify size of list - size_t pairTotal = 0; - ReturnErrorOnFailure(attributeValueList.ComputeSize(&pairTotal)); - VerifyOrReturnError(pairTotal <= ArraySize(mAVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); - - uint8_t pairCount = 0; - auto pair_iterator = attributeValueList.begin(); - while (pair_iterator.Next()) - { - mAVPairs[pairCount] = pair_iterator.GetValue(); - pairCount++; - }; - ReturnErrorOnFailure(pair_iterator.GetStatus()); - - extensionFieldSet.clusterID = cluster; - extensionFieldSet.attributeValueList = mAVPairs; - extensionFieldSet.attributeValueList.reduce_size(pairCount); - - return CHIP_NO_ERROR; -} - /// @brief Tags Used to serialize Scenes so they can be stored in flash memory. /// kSceneCount: Number of scenes in a Fabric /// kStorageIDArray: Array of StorageID struct @@ -817,12 +742,12 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) // TODO : Once zap supports the scenable quality, implement a GetSceneableClusterCountFromEndpointType function to avoid // over-allocation uint8_t clusterCount = GetClusterCountFromEndpoint(); - chip::Platform::ScopedMemoryBuffer cBuffer; + chip::Platform::ScopedMemoryBuffer cBuffer; VerifyOrReturnError(cBuffer.Calloc(clusterCount), CHIP_ERROR_NO_MEMORY); clusterCount = GetClustersFromEndpoint(cBuffer.Get(), clusterCount); - Span cSpan(cBuffer.Get(), clusterCount); - for (clusterId cluster : cSpan) + Span cSpan(cBuffer.Get(), clusterCount); + for (ClusterId cluster : cSpan) { ExtensionFieldSet EFS; MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); diff --git a/src/app/clusters/scenes-server/SceneTableImpl.h b/src/app/clusters/scenes-server/SceneTableImpl.h index 9f659fab068f50..144e89c2f78b3e 100644 --- a/src/app/clusters/scenes-server/SceneTableImpl.h +++ b/src/app/clusters/scenes-server/SceneTableImpl.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -40,69 +41,6 @@ static_assert(kMaxScenesPerEndpoint <= CHIP_CONFIG_MAX_SCENES_TABLE_SIZE, static_assert(kMaxScenesPerEndpoint >= 16, "Per spec, kMaxScenesPerEndpoint must be at least 16"); static constexpr uint16_t kMaxScenesPerFabric = (kMaxScenesPerEndpoint - 1) / 2; -using clusterId = chip::ClusterId; - -/// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster -/// The implementation of SerializeSave and ApplyScene were omitted and must be implemented in a way that -/// is compatible with the SerializeAdd output in order to function with the Default Scene Handler. -/// It is worth noting that this implementation is very memory consuming. In the current worst case, -/// (Color control cluster), the Extension Field Set's value pair list TLV occupies 99 bytes of memory -class DefaultSceneHandlerImpl : public scenes::SceneHandler -{ - - template - using List = chip::app::DataModel::List; - - template - using DecodableList = chip::app::DataModel::DecodableList; - - using AttributeValuePairType = chip::app::Clusters::Scenes::Structs::AttributeValuePair::Type; - using AttributeValuePairDecodableType = chip::app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType; - using ExtensionFieldSetDecodableType = chip::app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType; - using ExtensionFieldSetType = chip::app::Clusters::Scenes::Structs::ExtensionFieldSet::Type; - -public: - static constexpr uint8_t kMaxAvPair = CHIP_CONFIG_SCENES_MAX_AV_PAIRS_EFS; - - DefaultSceneHandlerImpl() = default; - ~DefaultSceneHandlerImpl() override{}; - - /// @brief Encodes an attribute value list into a TLV structure and resizes the buffer to the size of the encoded data - /// @param aVlist[in] Attribute value list to encode - /// @param serializedBytes[out] Buffer to fill from the Attribute value list in a TLV format - /// @return CHIP_ERROR - virtual CHIP_ERROR EncodeAttributeValueList(const List & aVlist, MutableByteSpan & serializedBytes); - - /// @brief Decodes an attribute value list from a TLV structure and ensure it fits the member pair buffer - /// @param serializedBytes [in] Buffer to read from - /// @param aVlist [out] Attribute value list to fill from the TLV structure. Only valid while the buffer backing - /// serializedBytes exists and its contents are not modified. - /// @return CHIP_ERROR - virtual CHIP_ERROR DecodeAttributeValueList(const ByteSpan & serializedBytes, - DecodableList & aVlist); - - /// @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 serializedBytes[out] Buffer to fill from the ExtensionFieldSet in command - /// @return CHIP_NO_ERROR if successful, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not supported, CHIP_ERROR value - /// otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const ExtensionFieldSetDecodableType & extensionFieldSet, - MutableByteSpan & serializedBytes) override; - - /// @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 serializedBytes data to deserialize into EFS - /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not - /// supported, specific CHIP_ERROR otherwise - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, - ExtensionFieldSetType & extensionFieldSet) override; - -private: - AttributeValuePairType mAVPairs[kMaxAvPair]; -}; - /** * @brief Implementation of a storage in nonvolatile storage of the scene table. * diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 26c0cb0693c532..b2269f88c3f290 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -98,6 +98,8 @@ source_set("scenes-table-test-srcs") { "${chip_root}/src/app/clusters/scenes-server/SceneTable.h", "${chip_root}/src/app/clusters/scenes-server/SceneTableImpl.cpp", "${chip_root}/src/app/clusters/scenes-server/SceneTableImpl.h", + "${chip_root}/src/app/clusters/scenes-server/SceneHandlerImpl.cpp", + "${chip_root}/src/app/clusters/scenes-server/SceneHandlerImpl.h", ] public_deps = [