Skip to content

Commit

Permalink
[IM] Use DataModel::Encode in EncodeScalarAttributeWritePayload for c…
Browse files Browse the repository at this point in the history
…omplex types (#10386)

* [IM] Use DataModel::Encode in EncodeScalarAttributeWritePayload for
complex types

* Rename EncodeScalarAttributeWritePayload to EncodeAttributeWritePayload

* Add unit test

* Run Codegen
  • Loading branch information
erjiaqing authored and pull[bot] committed Nov 3, 2021
1 parent 833d45b commit 9290547
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 391 deletions.
6 changes: 4 additions & 2 deletions src/app/WriteClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <app/MessageDef/AttributeDataList.h>
#include <app/MessageDef/AttributeStatusIB.h>
#include <app/MessageDef/WriteRequest.h>
#include <app/data-model/Encode.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPTLVDebug.hpp>
#include <lib/support/CodeUtils.h>
Expand Down Expand Up @@ -183,14 +184,15 @@ class WriteClientHandle
* Encode an attribute value that can be directly encoded using TLVWriter::Put
*/
template <class T>
CHIP_ERROR EncodeScalarAttributeWritePayload(const chip::app::AttributePathParams & attributePath, T value)
CHIP_ERROR EncodeAttributeWritePayload(const chip::app::AttributePathParams & attributePath, const T & value)
{
chip::TLV::TLVWriter * writer = nullptr;

VerifyOrReturnError(mpWriteClient != nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorOnFailure(mpWriteClient->PrepareAttribute(attributePath));
VerifyOrReturnError((writer = mpWriteClient->GetAttributeDataElementTLVWriter()) != nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorOnFailure(writer->Put(chip::TLV::ContextTag(chip::app::AttributeDataElement::kCsTag_Data), value));
ReturnErrorOnFailure(
DataModel::Encode(*writer, chip::TLV::ContextTag(chip::app::AttributeDataElement::kCsTag_Data), value));
ReturnErrorOnFailure(mpWriteClient->FinishAttribute());

return CHIP_NO_ERROR;
Expand Down
80 changes: 80 additions & 0 deletions src/app/tests/TestWriteInteraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
*/

#include <app-common/zap-generated/cluster-objects.h>
#include <app/InteractionModelEngine.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPTLV.h>
Expand Down Expand Up @@ -43,6 +44,9 @@ chip::TransportMgrBase gTransportManager;
chip::Test::LoopbackTransport gLoopback;
chip::Test::IOContext gIOContext;

uint8_t attributeDataTLV[CHIP_CONFIG_DEFAULT_UDP_MTU_SIZE];
size_t attributeDataTLVLen = 0;

using TestContext = chip::Test::MessagingContext;
TestContext sContext;

Expand All @@ -55,6 +59,7 @@ class TestWriteInteraction
static void TestWriteClient(nlTestSuite * apSuite, void * apContext);
static void TestWriteHandler(nlTestSuite * apSuite, void * apContext);
static void TestWriteRoundtrip(nlTestSuite * apSuite, void * apContext);
static void TestWriteRoundtripWithClusterObjects(nlTestSuite * apSuite, void * apContext);

private:
static void AddAttributeDataElement(nlTestSuite * apSuite, void * apContext, WriteClientHandle & aWriteClient);
Expand Down Expand Up @@ -257,6 +262,10 @@ void TestWriteInteraction::TestWriteHandler(nlTestSuite * apSuite, void * apCont

CHIP_ERROR WriteSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVReader & aReader, WriteHandler * aWriteHandler)
{
TLV::TLVWriter writer;
writer.Init(attributeDataTLV);
writer.CopyElement(TLV::AnonymousTag, aReader);
attributeDataTLVLen = writer.GetLengthWritten();
return aWriteHandler->AddAttributeStatusCode(
AttributePathParams(aClusterInfo.mNodeId, aClusterInfo.mEndpointId, aClusterInfo.mClusterId, aClusterInfo.mFieldId,
aClusterInfo.mListIndex, AttributePathParams::Flags::kFieldIdValid),
Expand All @@ -279,6 +288,76 @@ class RoundtripDelegate : public chip::app::InteractionModelDelegate
bool mGotResponse = false;
};

void TestWriteInteraction::TestWriteRoundtripWithClusterObjects(nlTestSuite * apSuite, void * apContext)
{
TestContext & ctx = *static_cast<TestContext *>(apContext);

CHIP_ERROR err = CHIP_NO_ERROR;

Messaging::ReliableMessageMgr * rm = ctx.GetExchangeManager().GetReliableMessageMgr();
// Shouldn't have anything in the retransmit table when starting the test.
NL_TEST_ASSERT(apSuite, rm->TestGetCountRetransTable() == 0);

RoundtripDelegate delegate;
auto * engine = chip::app::InteractionModelEngine::GetInstance();
err = engine->Init(&ctx.GetExchangeManager(), &delegate);
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);

app::WriteClientHandle writeClient;
err = engine->NewWriteClient(writeClient);
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);

System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);

AttributePathParams attributePathParams;
attributePathParams.mNodeId = 1;
attributePathParams.mEndpointId = 2;
attributePathParams.mClusterId = 3;
attributePathParams.mFieldId = 4;
attributePathParams.mFlags.Set(AttributePathParams::Flags::kFieldIdValid);

const uint8_t byteSpanData[] = { 0xde, 0xad, 0xbe, 0xef };
const char charSpanData[] = "a simple test string";

app::Clusters::TestCluster::Structs::SimpleStruct::Type dataTx;
dataTx.a = 12;
dataTx.b = true;
dataTx.d = chip::ByteSpan(byteSpanData);
// Spec A.11.2 strings SHALL NOT include a terminating null character to mark the end of a string.
dataTx.e = chip::Span<const char>(charSpanData, strlen(charSpanData));

writeClient.EncodeAttributeWritePayload(attributePathParams, dataTx);
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);

NL_TEST_ASSERT(apSuite, !delegate.mGotResponse);

SessionHandle session = ctx.GetSessionBobToAlice();

err = writeClient.SendWriteRequest(ctx.GetAliceNodeId(), ctx.GetFabricIndex(), Optional<SessionHandle>::Value(session));
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);

NL_TEST_ASSERT(apSuite, delegate.mGotResponse);

{
app::Clusters::TestCluster::Structs::SimpleStruct::Type dataRx;
TLV::TLVReader reader;
reader.Init(attributeDataTLV, attributeDataTLVLen);
reader.Next();
NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == DataModel::Decode(reader, dataRx));
NL_TEST_ASSERT(apSuite, dataRx.a == dataTx.a);
NL_TEST_ASSERT(apSuite, dataRx.b == dataTx.b);
NL_TEST_ASSERT(apSuite, dataRx.d.data_equal(dataTx.d));
// Equals to dataRx.e.size() == dataTx.e.size() && memncmp(dataRx.e.data(), dataTx.e.data(), dataTx.e.size()) == 0
NL_TEST_ASSERT(apSuite, dataRx.e.data_equal(dataTx.e));
}

// By now we should have closed all exchanges and sent all pending acks, so
// there should be no queued-up things in the retransmit table.
NL_TEST_ASSERT(apSuite, rm->TestGetCountRetransTable() == 0);

engine->Shutdown();
}

void TestWriteInteraction::TestWriteRoundtrip(nlTestSuite * apSuite, void * apContext)
{
TestContext & ctx = *static_cast<TestContext *>(apContext);
Expand Down Expand Up @@ -332,6 +411,7 @@ const nlTest sTests[] =
NL_TEST_DEF("CheckWriteClient", chip::app::TestWriteInteraction::TestWriteClient),
NL_TEST_DEF("CheckWriteHandler", chip::app::TestWriteInteraction::TestWriteHandler),
NL_TEST_DEF("CheckWriteRoundtrip", chip::app::TestWriteInteraction::TestWriteRoundtrip),
NL_TEST_DEF("TestWriteRoundtripWithClusterObjects", chip::app::TestWriteInteraction::TestWriteRoundtripWithClusterObjects),
NL_TEST_SENTINEL()
};
// clang-format on
Expand Down
2 changes: 1 addition & 1 deletion src/app/zap-templates/templates/app/CHIPClusters-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ CHIP_ERROR {{asUpperCamelCase parent.name}}Cluster::WriteAttribute{{asUpperCamel
attributePath.mFlags.Set(chip::app::AttributePathParams::Flags::kFieldIdValid);

ReturnErrorOnFailure(app::InteractionModelEngine::GetInstance()->NewWriteClient(handle));
ReturnErrorOnFailure(handle.EncodeScalarAttributeWritePayload(attributePath, value));
ReturnErrorOnFailure(handle.EncodeAttributeWritePayload(attributePath, value));

return mDevice->SendWriteAttributeRequest(std::move(handle), onSuccessCallback, onFailureCallback);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ CHIP_ERROR {{asUpperCamelCase parent.name}}ClusterTest::WriteAttribute{{asUpperC
attributePath.mFlags.Set(chip::app::AttributePathParams::Flags::kFieldIdValid);

ReturnErrorOnFailure(app::InteractionModelEngine::GetInstance()->NewWriteClient(handle));
ReturnErrorOnFailure(handle.EncodeScalarAttributeWritePayload(attributePath, {{asLowerCamelCase name}}));
ReturnErrorOnFailure(handle.EncodeAttributeWritePayload(attributePath, {{asLowerCamelCase name}}));

return mDevice->SendWriteAttributeRequest(std::move(handle), onSuccessCallback, onFailureCallback);
}
Expand Down
Loading

0 comments on commit 9290547

Please sign in to comment.