Skip to content

Commit

Permalink
Address review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
yufengwangca committed Nov 11, 2021
1 parent e208d50 commit b8852b5
Show file tree
Hide file tree
Showing 5 changed files with 523 additions and 446 deletions.
45 changes: 29 additions & 16 deletions src/app/AttributeAccessInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <app/ConcreteAttributePath.h>
#include <app/MessageDef/AttributeDataIB.h>
#include <app/data-model/Decode.h>
#include <app/data-model/Encode.h>
#include <app/data-model/List.h> // So we can encode lists
#include <app/data-model/TagBoundEncoder.h>
Expand Down Expand Up @@ -101,6 +102,25 @@ class AttributeValueEncoder : protected TagBoundEncoder
const FabricIndex mAccessingFabricIndex;
};

class AttributeValueDecoder
{
public:
AttributeValueDecoder(TLV::TLVReader & aReader) : mReader(aReader) {}

template <typename T>
CHIP_ERROR Decode(T & aArg)
{
mTriedDecode = true;
return DataModel::Decode(mReader, aArg);
}

bool TriedDecode() const { return mTriedDecode; }

private:
TLV::TLVReader & mReader;
bool mTriedDecode = false;
};

class AttributeAccessInterface
{
public:
Expand Down Expand Up @@ -130,23 +150,16 @@ class AttributeAccessInterface
/**
* Callback for writing attributes.
*
* @param [in] aPath indicates which exact data is being write.
* @param [in] aTLVReader A pointer to a TLVReader, which should point to the beginning
* of this AttributeDataElement to write.
* @param [out] aDataWrite whether we actually tried to write data. If
* this function returns success and aDataWrite is
* false, the AttributeAccessInterface did not try
* to write any data. In this case, normal attribute
* access will happen for the write. This may involve
* writing to the attribute store or external attribute
* callbacks.
* @param [in] aPath indicates which exact data is being written.
* @param [in] aDecoder the AttributeValueDecoder to use for decoding the
* data. If this function returns scucess and no attempt is
* made to decode data using aDecoder, the
* AttributeAccessInterface did not try to write any data. In
* this case, normal attribute access will happen for the write.
* This may involve writing to the attribute store or external
* attribute callbacks.
*/
virtual CHIP_ERROR Write(const ConcreteAttributePath & aPath, TLV::TLVReader & aReader, bool * aDataWrite)
{
*aDataWrite = false;

return CHIP_NO_ERROR;
}
virtual CHIP_ERROR Write(const ConcreteAttributePath & aPath, AttributeValueDecoder & aDecoder) { return CHIP_NO_ERROR; }

/**
* Mechanism for keeping track of a chain of AttributeAccessInterfaces.
Expand Down
88 changes: 51 additions & 37 deletions src/app/clusters/test-cluster-server/test-cluster-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,35 +40,50 @@ using namespace chip::app::Clusters::TestCluster;
using namespace chip::app::Clusters::TestCluster::Commands;
using namespace chip::app::Clusters::TestCluster::Attributes;

constexpr uint8_t kAttributeListLength = 4;
// The number of elements in the test attribute list
constexpr uint8_t kAttributeListLength = 4;

// The maximum length of the test attribute list element in bytes
constexpr uint8_t kAttributeEntryLength = 6;

namespace {

class OctetStringData
{
public:
uint8_t * Data() { return mDataBuf; }
size_t Length() const { return mDataLen; }
void SetLength(size_t size) { mDataLen = size; }

private:
uint8_t mDataBuf[kAttributeEntryLength];
size_t mDataLen = 0;
};

class TestAttrAccess : public AttributeAccessInterface
{
public:
// Register for the Test Cluster cluster on all endpoints.
TestAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), TestCluster::Id) {}

CHIP_ERROR Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
CHIP_ERROR Write(const ConcreteAttributePath & aPath, TLV::TLVReader & aReader, bool * aDataWrite) override;
CHIP_ERROR Write(const ConcreteAttributePath & aPath, AttributeValueDecoder & aDecoder) override;

private:
CHIP_ERROR ReadListInt8uAttribute(AttributeValueEncoder & aEncoder);
CHIP_ERROR WriteListInt8uAttribute(TLV::TLVReader & aReader);
CHIP_ERROR WriteListInt8uAttribute(AttributeValueDecoder & aDecoder);
CHIP_ERROR ReadListOctetStringAttribute(AttributeValueEncoder & aEncoder);
CHIP_ERROR WriteListOctetStringAttribute(TLV::TLVReader & aReader);
CHIP_ERROR WriteListOctetStringAttribute(AttributeValueDecoder & aDecoder);
CHIP_ERROR ReadListStructOctetStringAttribute(AttributeValueEncoder & aEncoder);
CHIP_ERROR WriteListStructOctetStringAttribute(TLV::TLVReader & aReader);
CHIP_ERROR WriteListStructOctetStringAttribute(AttributeValueDecoder & aDecoder);
CHIP_ERROR ReadListNullablesAndOptionalsStructAttribute(AttributeValueEncoder & aEncoder);
CHIP_ERROR WriteListNullablesAndOptionalsStructAttribute(TLV::TLVReader & aReader);
CHIP_ERROR WriteListNullablesAndOptionalsStructAttribute(AttributeValueDecoder & aDecoder);
};

TestAttrAccess gAttrAccess;
uint8_t gListUint8Data[kAttributeListLength];
char gListOctetStringData[kAttributeListLength][kAttributeEntryLength];
char gListOperationalCert[kAttributeListLength][kAttributeEntryLength];
OctetStringData gListOctetStringData[kAttributeListLength];
OctetStringData gListOperationalCert[kAttributeListLength];
Structs::TestListStructOctet::Type listStructOctetStringData[kAttributeListLength];

CHIP_ERROR TestAttrAccess::Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder)
Expand All @@ -95,26 +110,23 @@ CHIP_ERROR TestAttrAccess::Read(const ConcreteAttributePath & aPath, AttributeVa
return CHIP_NO_ERROR;
}

CHIP_ERROR TestAttrAccess::Write(const ConcreteAttributePath & aPath, TLV::TLVReader & aReader, bool * aDataWrite)
CHIP_ERROR TestAttrAccess::Write(const ConcreteAttributePath & aPath, AttributeValueDecoder & aDecoder)
{
*aDataWrite = true;

switch (aPath.mAttributeId)
{
case ListInt8u::Id: {
return WriteListInt8uAttribute(aReader);
return WriteListInt8uAttribute(aDecoder);
}
case ListOctetString::Id: {
return WriteListOctetStringAttribute(aReader);
return WriteListOctetStringAttribute(aDecoder);
}
case ListStructOctetString::Id: {
return WriteListStructOctetStringAttribute(aReader);
return WriteListStructOctetStringAttribute(aDecoder);
}
case ListNullablesAndOptionalsStruct::Id: {
return WriteListNullablesAndOptionalsStructAttribute(aReader);
return WriteListNullablesAndOptionalsStructAttribute(aDecoder);
}
default: {
*aDataWrite = false;
break;
}
}
Expand All @@ -133,45 +145,42 @@ CHIP_ERROR TestAttrAccess::ReadListInt8uAttribute(AttributeValueEncoder & aEncod
});
}

CHIP_ERROR TestAttrAccess::WriteListInt8uAttribute(TLV::TLVReader & aReader)
CHIP_ERROR TestAttrAccess::WriteListInt8uAttribute(AttributeValueDecoder & aDecoder)
{
DataModel::DecodableList<uint8_t> list;
ListInt8u::TypeInfo::DecodableType list;

ReturnErrorOnFailure(DataModel::Decode(aReader, list));
ReturnErrorOnFailure(aDecoder.Decode(list));

uint8_t index = 0;
auto iter = list.begin();
while (iter.Next())
{
auto & entry = iter.GetValue();
gListUint8Data[index++] = entry;
}
auto & entry = iter.GetValue();

if (iter.GetStatus() != CHIP_NO_ERROR)
{
return CHIP_ERROR_INVALID_DATA_LIST;
VerifyOrReturnError(index < kAttributeListLength, CHIP_ERROR_BUFFER_TOO_SMALL);
gListUint8Data[index++] = entry;
}

return CHIP_NO_ERROR;
return iter.GetStatus();
}

CHIP_ERROR TestAttrAccess::ReadListOctetStringAttribute(AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([](const TagBoundEncoder & encoder) -> CHIP_ERROR {
for (uint8_t index = 0; index < kAttributeListLength; index++)
{
ByteSpan span(Uint8::from_char(gListOctetStringData[index]), strlen(gListOctetStringData[index]));
ByteSpan span(gListOctetStringData[index].Data(), gListOctetStringData[index].Length());
ReturnErrorOnFailure(encoder.Encode(span));
}
return CHIP_NO_ERROR;
});
}

CHIP_ERROR TestAttrAccess::WriteListOctetStringAttribute(TLV::TLVReader & aReader)
CHIP_ERROR TestAttrAccess::WriteListOctetStringAttribute(AttributeValueDecoder & aDecoder)
{
DataModel::DecodableList<ByteSpan> list;
ListOctetString::TypeInfo::DecodableType list;

ReturnErrorOnFailure(DataModel::Decode(aReader, list));
ReturnErrorOnFailure(aDecoder.Decode(list));

uint8_t index = 0;
auto iter = list.begin();
Expand All @@ -180,7 +189,9 @@ CHIP_ERROR TestAttrAccess::WriteListOctetStringAttribute(TLV::TLVReader & aReade
const auto & entry = iter.GetValue();

VerifyOrReturnError(index < kAttributeListLength, CHIP_ERROR_BUFFER_TOO_SMALL);
Platform::CopyString(gListOctetStringData[index], sizeof(gListOctetStringData[index]), entry);
VerifyOrReturnError(entry.size() <= kAttributeEntryLength, CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(gListOctetStringData[index].Data(), entry.data(), entry.size());
gListOctetStringData[index].SetLength(entry.size());
index++;
}

Expand All @@ -202,11 +213,11 @@ CHIP_ERROR TestAttrAccess::ReadListStructOctetStringAttribute(AttributeValueEnco
});
}

CHIP_ERROR TestAttrAccess::WriteListStructOctetStringAttribute(TLV::TLVReader & aReader)
CHIP_ERROR TestAttrAccess::WriteListStructOctetStringAttribute(AttributeValueDecoder & aDecoder)
{
DataModel::DecodableList<Structs::TestListStructOctet::Type> list;
ListStructOctetString::TypeInfo::DecodableType list;

ReturnErrorOnFailure(DataModel::Decode(aReader, list));
ReturnErrorOnFailure(aDecoder.Decode(list));

uint8_t index = 0;
auto iter = list.begin();
Expand All @@ -215,10 +226,13 @@ CHIP_ERROR TestAttrAccess::WriteListStructOctetStringAttribute(TLV::TLVReader &
const auto & entry = iter.GetValue();

VerifyOrReturnError(index < kAttributeListLength, CHIP_ERROR_BUFFER_TOO_SMALL);
Platform::CopyString(gListOperationalCert[index], sizeof(gListOperationalCert[index]), entry.operationalCert);
VerifyOrReturnError(entry.operationalCert.size() <= kAttributeEntryLength, CHIP_ERROR_BUFFER_TOO_SMALL);
memcpy(gListOperationalCert[index].Data(), entry.operationalCert.data(), entry.operationalCert.size());
gListOperationalCert[index].SetLength(entry.operationalCert.size());

listStructOctetStringData[index].fabricIndex = entry.fabricIndex;
listStructOctetStringData[index].operationalCert =
ByteSpan(Uint8::from_char(gListOperationalCert[index]), strlen(gListOperationalCert[index]));
ByteSpan(gListOperationalCert[index].Data(), gListOperationalCert[index].Length());
index++;
}

Expand All @@ -241,7 +255,7 @@ CHIP_ERROR TestAttrAccess::ReadListNullablesAndOptionalsStructAttribute(Attribut
});
}

CHIP_ERROR TestAttrAccess::WriteListNullablesAndOptionalsStructAttribute(TLV::TLVReader & aReader)
CHIP_ERROR TestAttrAccess::WriteListNullablesAndOptionalsStructAttribute(AttributeValueDecoder & aDecoder)
{
// TODO Add yaml test case for NullablesAndOptionalsStruct list
return CHIP_NO_ERROR;
Expand Down
7 changes: 3 additions & 4 deletions src/app/util/ember-compatibility-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,12 +508,11 @@ CHIP_ERROR WriteSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVReader & a
AttributeAccessInterface * attrOverride = findAttributeAccessOverride(aClusterInfo.mEndpointId, aClusterInfo.mClusterId);
if (attrOverride != nullptr)
{
bool dataWrite;
ConcreteAttributePath path(aClusterInfo.mEndpointId, aClusterInfo.mClusterId, aClusterInfo.mAttributeId);
AttributeValueDecoder valueDecoder(aReader);
ReturnErrorOnFailure(attrOverride->Write(path, valueDecoder));

ReturnErrorOnFailure(attrOverride->Write(path, aReader, &dataWrite));

if (dataWrite)
if (valueDecoder.TriedDecode())
{
return apWriteHandler->AddStatus(attributePathParams, Protocols::InteractionModel::Status::Success);
}
Expand Down
Loading

0 comments on commit b8852b5

Please sign in to comment.