From ed6eb71cbc5b49fb034262a1b0510872beca9fc1 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 5 Jun 2023 18:05:25 -0400 Subject: [PATCH] Added Encode and Decode helper functions for SceneHandlers to avoid code dupplication --- .../clusters/scenes-server/SceneTableImpl.h | 111 +++++++++++------- src/app/tests/TestSceneTable.cpp | 3 + 2 files changed, 69 insertions(+), 45 deletions(-) diff --git a/src/app/clusters/scenes-server/SceneTableImpl.h b/src/app/clusters/scenes-server/SceneTableImpl.h index 7298f60a310e79..ed037f48778b45 100644 --- a/src/app/clusters/scenes-server/SceneTableImpl.h +++ b/src/app/clusters/scenes-server/SceneTableImpl.h @@ -46,89 +46,110 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler 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 app::DataModel::List & aVlist, + MutableByteSpan & serializedBytes) + { + TLV::TLVWriter writer; + TLV::TLVType outer; + writer.Init(serializedBytes); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList), aVlist)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + serializedBytes.reduce_size(writer.GetLengthWritten()); + + return CHIP_NO_ERROR; + } + + /// @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 + /// @return CHIP_ERROR + virtual CHIP_ERROR DecodeAttributeValueList( + const ByteSpan & serializedBytes, + app::DataModel::DecodableList & aVlist) + { + TLV::TLVReader reader; + TLV::TLVType outer; + size_t pairTotal = 0; + + reader.Init(serializedBytes); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + ReturnErrorOnFailure(reader.Next( + TLV::kTLVType_Array, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList))); + aVlist.Decode(reader); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + // Verify size of list + ReturnErrorOnFailure(aVlist.ComputeSize(&pairTotal)); + VerifyOrReturnError(pairTotal <= ArraySize(mAVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + + return CHIP_NO_ERROR; + } + /// @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 serialisedBytes[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 + /// @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 app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, MutableByteSpan & serializedBytes) override { - app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; - TLV::TLVWriter writer; - TLV::TLVType outer; - size_t pairTotal = 0; - uint8_t pairCount = 0; + app::Clusters::Scenes::Structs::AttributeValuePair::Type aVPairs[kMaxAvPair]; + size_t pairTotal = 0; // Verify size of list ReturnErrorOnFailure(extensionFieldSet.attributeValueList.ComputeSize(&pairTotal)); - VerifyOrReturnError(pairTotal <= ArraySize(mAVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(pairTotal <= ArraySize(aVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + uint8_t pairCount = 0; auto pair_iterator = extensionFieldSet.attributeValueList.begin(); while (pair_iterator.Next()) { - aVPair = pair_iterator.GetValue(); - mAVPairs[pairCount].attributeID = aVPair.attributeID; - mAVPairs[pairCount].attributeValue = aVPair.attributeValue; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair = pair_iterator.GetValue(); + aVPairs[pairCount].attributeID = aVPair.attributeID; + aVPairs[pairCount].attributeValue = aVPair.attributeValue; pairCount++; } ReturnErrorOnFailure(pair_iterator.GetStatus()); - - app::DataModel::List attributeValueList; - attributeValueList = mAVPairs; + app::DataModel::List attributeValueList(aVPairs); attributeValueList.reduce_size(pairCount); - writer.Init(serializedBytes); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList), - attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - - return CHIP_NO_ERROR; + return EncodeAttributeValueList(attributeValueList, serializedBytes); } /// @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 serialisedBytes data to deserialize into EFS + /// @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 & serialisedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { app::DataModel::DecodableList attributeValueList; - app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType decodePair; - TLV::TLVReader reader; - TLV::TLVType outer; - size_t pairTotal = 0; - uint8_t pairCount = 0; - - extensionFieldSet.clusterID = cluster; - reader.Init(serialisedBytes); - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); - ReturnErrorOnFailure(reader.EnterContainer(outer)); - ReturnErrorOnFailure(reader.Next( - TLV::kTLVType_Array, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList))); - attributeValueList.Decode(reader); - - // Verify size of list - ReturnErrorOnFailure(attributeValueList.ComputeSize(&pairTotal)); - VerifyOrReturnError(pairTotal <= ArraySize(mAVPairs), CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList)); + uint8_t pairCount = 0; auto pair_iterator = attributeValueList.begin(); while (pair_iterator.Next()) { - decodePair = pair_iterator.GetValue(); - mAVPairs[pairCount].attributeID = decodePair.attributeID; - mAVPairs[pairCount].attributeValue = decodePair.attributeValue; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType decodePair = pair_iterator.GetValue(); + mAVPairs[pairCount].attributeID = decodePair.attributeID; + mAVPairs[pairCount].attributeValue = decodePair.attributeValue; pairCount++; }; ReturnErrorOnFailure(pair_iterator.GetStatus()); - ReturnErrorOnFailure(reader.ExitContainer(outer)); + extensionFieldSet.clusterID = cluster; extensionFieldSet.attributeValueList = mAVPairs; extensionFieldSet.attributeValueList.reduce_size(pairCount); diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 25808686828d16..b94c9b487850ac 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -571,6 +571,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); memset(buffer, 0, buff_span.size()); + buff_span = MutableByteSpan(buffer); // Setup the Level Control Extension field set in the expected state from a command reader.Init(LC_list); @@ -587,6 +588,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); memset(buffer, 0, buff_span.size()); + buff_span = MutableByteSpan(buffer); // Setup the Color control Extension field set in the expected state from a command reader.Init(CC_list); @@ -603,6 +605,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); memset(buffer, 0, buff_span.size()); + buff_span = MutableByteSpan(buffer); // Verify Deserializing is properly filling out output extension field set for on off NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint1, kOnOffClusterId));