Skip to content

Commit

Permalink
Added Encode and Decode helper functions for SceneHandlers to avoid c…
Browse files Browse the repository at this point in the history
…ode dupplication
  • Loading branch information
lpbeliveau-silabs committed Jun 5, 2023
1 parent 9828293 commit ed6eb71
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 45 deletions.
111 changes: 66 additions & 45 deletions src/app/clusters/scenes-server/SceneTableImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<app::Clusters::Scenes::Structs::AttributeValuePair::Type> & 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<app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType> & 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<app::Clusters::Scenes::Structs::AttributeValuePair::Type> attributeValueList;
attributeValueList = mAVPairs;
app::DataModel::List<app::Clusters::Scenes::Structs::AttributeValuePair::Type> 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<app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType> 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);

Expand Down
3 changes: 3 additions & 0 deletions src/app/tests/TestSceneTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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));
Expand Down

0 comments on commit ed6eb71

Please sign in to comment.