Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the AttributeList attribute. #12660

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/app/AttributePathParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct AttributePathParams
//
// TODO: (#11420) This class is overlapped with ClusterInfo class, need to do a clean up.
AttributePathParams(EndpointId aEndpointId, ClusterId aClusterId) :
AttributePathParams(aEndpointId, aClusterId, ClusterInfo::kInvalidAttributeId, kInvalidListIndex)
AttributePathParams(aEndpointId, aClusterId, kInvalidAttributeId, kInvalidListIndex)
{}

AttributePathParams(EndpointId aEndpointId, ClusterId aClusterId, AttributeId aAttributeId) :
Expand Down Expand Up @@ -61,13 +61,13 @@ struct AttributePathParams
bool IsValidAttributePath() const { return HasWildcardListIndex() || !HasWildcardAttributeId(); }

inline bool HasWildcardEndpointId() const { return mEndpointId == kInvalidEndpointId; }
inline bool HasWildcardClusterId() const { return mClusterId == ClusterInfo::kInvalidClusterId; }
inline bool HasWildcardAttributeId() const { return mAttributeId == ClusterInfo::kInvalidAttributeId; }
inline bool HasWildcardClusterId() const { return mClusterId == kInvalidClusterId; }
inline bool HasWildcardAttributeId() const { return mAttributeId == kInvalidAttributeId; }
inline bool HasWildcardListIndex() const { return mListIndex == kInvalidListIndex; }

EndpointId mEndpointId = kInvalidEndpointId;
ClusterId mClusterId = ClusterInfo::kInvalidClusterId;
AttributeId mAttributeId = ClusterInfo::kInvalidAttributeId;
ClusterId mClusterId = kInvalidClusterId;
AttributeId mAttributeId = kInvalidAttributeId;
ListIndex mListIndex = kInvalidListIndex;
};
} // namespace app
Expand Down
11 changes: 0 additions & 11 deletions src/app/ClusterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,6 @@ namespace app {
// Note: The change will happen after #11171 with a better linked list.
struct ClusterInfo
{
private:
// Allow AttributePathParams access these constants.
friend struct AttributePathParams;
friend struct EventPathParams;

// The ClusterId, AttributeId and EventId are MEIs,
// 0xFFFF is not a valid manufacturer code, thus 0xFFFF'FFFF is not a valid MEI
static constexpr ClusterId kInvalidClusterId = 0xFFFF'FFFF;
static constexpr AttributeId kInvalidAttributeId = 0xFFFF'FFFF;
static constexpr EventId kInvalidEventId = 0xFFFF'FFFF;

public:
bool IsAttributePathSupersetOf(const ClusterInfo & other) const
{
Expand Down
8 changes: 4 additions & 4 deletions src/app/EventPathParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ struct EventPathParams
bool IsValidEventPath() const { return !(HasWildcardClusterId() && !HasWildcardEventId()); }

inline bool HasWildcardEndpointId() const { return mEndpointId == kInvalidEndpointId; }
inline bool HasWildcardClusterId() const { return mClusterId == ClusterInfo::kInvalidClusterId; }
inline bool HasWildcardEventId() const { return mEventId == ClusterInfo::kInvalidEventId; }
inline bool HasWildcardClusterId() const { return mClusterId == kInvalidClusterId; }
inline bool HasWildcardEventId() const { return mEventId == kInvalidEventId; }

EndpointId mEndpointId = kInvalidEndpointId;
ClusterId mClusterId = ClusterInfo::kInvalidClusterId;
EventId mEventId = ClusterInfo::kInvalidEventId;
ClusterId mClusterId = kInvalidClusterId;
EventId mEventId = kInvalidEventId;
};
} // namespace app
} // namespace chip
10 changes: 5 additions & 5 deletions src/app/tests/TestClusterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ void TestAttributePathIncludedDifferentClusterId(nlTestSuite * apSuite, void * a
}

/*
{ClusterInfo::kInvalidEndpointId, ClusterInfo::kInvalidClusterId, ClusterInfo::kInvalidEventId},
{ClusterInfo::kInvalidEndpointId, MockClusterId(1), ClusterInfo::kInvalidEventId},
{ClusterInfo::kInvalidEndpointId, MockClusterId(1), MockEventId(1)},
{kMockEndpoint1, ClusterInfo::kInvalidClusterId, ClusterInfo::kInvalidEventId},
{kMockEndpoint1, MockClusterId(1), ClusterInfo::kInvalidEventId},
{kInvalidEndpointId, kInvalidClusterId, kInvalidEventId},
{kInvalidEndpointId, MockClusterId(1), kInvalidEventId},
{kInvalidEndpointId, MockClusterId(1), MockEventId(1)},
{kMockEndpoint1, kInvalidClusterId, kInvalidEventId},
{kMockEndpoint1, MockClusterId(1), kInvalidEventId},
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
{kMockEndpoint1, MockClusterId(1), MockEventId(1)},
*/
chip::app::ClusterInfo validEventpaths[6];
Expand Down
29 changes: 29 additions & 0 deletions src/app/tests/suites/TestBasicInformation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,32 @@ tests:
attribute: "location"
arguments:
value: ""

- label: "Read AttributeList value"
command: "readAttribute"
attribute: "AttributeList"
response:
value:
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
0xFFFB,
0xFFFD,
]
118 changes: 98 additions & 20 deletions src/app/util/ember-compatibility-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,84 @@ CHIP_ERROR SendFailureStatus(const ConcreteAttributePath & aPath, AttributeRepor
return aAttributeReport.EndOfAttributeReportIB().GetError();
}

// This reader should never actually be registered; we do manual dispatch to it
// for the one attribute it handles.
class MandatoryGlobalAttributeReader : public AttributeAccessInterface
{
public:
MandatoryGlobalAttributeReader(const EmberAfCluster * aCluster) :
AttributeAccessInterface(MakeOptional(kInvalidEndpointId), kInvalidClusterId), mCluster(aCluster)
{}

protected:
const EmberAfCluster * mCluster;
};

class AttributeListReader : public MandatoryGlobalAttributeReader
{
public:
AttributeListReader(const EmberAfCluster * aCluster) : MandatoryGlobalAttributeReader(aCluster) {}

CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
};

CHIP_ERROR AttributeListReader::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
// The id of AttributeList is not in the attribute metadata.
// TODO: This does not play nicely with wildcard reads. Need to fix ZAP to
// put it in the metadata, or fix wildcard expansion to add it.
mrjerryjohns marked this conversation as resolved.
Show resolved Hide resolved
return aEncoder.EncodeList([this](const auto & encoder) {
constexpr AttributeId ourId = Clusters::Globals::Attributes::AttributeList::Id;
const size_t count = mCluster->attributeCount;
bool addedOurId = false;
for (size_t i = 0; i < count; ++i)
{
AttributeId id = mCluster->attributes[i].attributeId;
if (!addedOurId && id > ourId)
mrjerryjohns marked this conversation as resolved.
Show resolved Hide resolved
{
ReturnErrorOnFailure(encoder.Encode(ourId));
addedOurId = true;
}
ReturnErrorOnFailure(encoder.Encode(id));
}
if (!addedOurId)
{
ReturnErrorOnFailure(encoder.Encode(ourId));
}
return CHIP_NO_ERROR;
});
}

// Helper function for trying to read an attribute value via an
// AttributeAccessInterface. On failure, the read has failed. On success, the
// aTriedEncode outparam is set to whether the AttributeAccessInterface tried to encode a value.
CHIP_ERROR ReadViaAccessInterface(FabricIndex aAccessingFabricIndex, const ConcreteReadAttributePath & aPath,
AttributeReportIBs::Builder & aAttributeReports,
AttributeValueEncoder::AttributeEncodeState * aEncoderState,
AttributeAccessInterface * aAccessInterface, bool * aTriedEncode)
{
// TODO: We should probably clone the writer and convert failures here
// into status responses, unless our caller already does that.
AttributeValueEncoder::AttributeEncodeState state =
(aEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *aEncoderState);
AttributeValueEncoder valueEncoder(aAttributeReports, aAccessingFabricIndex, aPath, kTemporaryDataVersion, state);
CHIP_ERROR err = aAccessInterface->Read(aPath, valueEncoder);

if (err != CHIP_NO_ERROR)
{
// If the err is not CHIP_NO_ERROR, means the encoding was aborted, then the valueEncoder may save its state.
// The state is used by list chunking feature for now.
if (aEncoderState != nullptr)
{
*aEncoderState = valueEncoder.GetState();
}
return err;
}

*aTriedEncode = valueEncoder.TriedEncode();
return CHIP_NO_ERROR;
}

} // anonymous namespace

CHIP_ERROR ReadSingleClusterData(FabricIndex aAccessingFabricIndex, const ConcreteReadAttributePath & aPath,
Expand All @@ -260,6 +338,22 @@ CHIP_ERROR ReadSingleClusterData(FabricIndex aAccessingFabricIndex, const Concre
"Reading attribute: Cluster=" ChipLogFormatMEI " Endpoint=%" PRIx16 " AttributeId=" ChipLogFormatMEI,
ChipLogValueMEI(aPath.mClusterId), aPath.mEndpointId, ChipLogValueMEI(aPath.mAttributeId));

if (aPath.mAttributeId == Clusters::Globals::Attributes::AttributeList::Id)
{
// This is not in our attribute metadata, so we just check for this
// endpoint+cluster existing.
EmberAfCluster * cluster = emberAfFindCluster(aPath.mEndpointId, aPath.mClusterId, CLUSTER_MASK_SERVER);
if (cluster)
{
AttributeListReader reader(cluster);
bool ignored; // Our reader always tries to encode
return ReadViaAccessInterface(aAccessingFabricIndex, aPath, aAttributeReports, apEncoderState, &reader, &ignored);
}

// else to save codesize just fall through and do the metadata search
// (which we know will fail and error out);
}

EmberAfAttributeMetadata * attributeMetadata =
emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId, CLUSTER_MASK_SERVER, 0);

Expand All @@ -277,27 +371,11 @@ CHIP_ERROR ReadSingleClusterData(FabricIndex aAccessingFabricIndex, const Concre
// The AttributeValueEncoder may encode more than one AttributeReportIB for the list chunking feature.
if (attrOverride != nullptr)
{
// TODO: We should probably clone the writer and convert failures here
// into status responses, unless our caller already does that.
AttributeValueEncoder::AttributeEncodeState state =
(apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState);
AttributeValueEncoder valueEncoder(aAttributeReports, aAccessingFabricIndex,
ConcreteAttributePath(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId),
kTemporaryDataVersion, state);
CHIP_ERROR err = attrOverride->Read(aPath, valueEncoder);

if (err != CHIP_NO_ERROR)
{
// If the err is not CHIP_NO_ERROR, means the encoding was aborted, then the valueEncoder may save its state.
// The state is used by list chunking feature for now.
if (apEncoderState != nullptr)
{
*apEncoderState = valueEncoder.GetState();
}
return err;
}
bool triedEncode;
ReturnErrorOnFailure(
ReadViaAccessInterface(aAccessingFabricIndex, aPath, aAttributeReports, apEncoderState, attrOverride, &triedEncode));

if (valueEncoder.TriedEncode())
if (triedEncode)
{
return CHIP_NO_ERROR;
}
Expand Down
1 change: 1 addition & 0 deletions src/app/zap-templates/templates/app/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const ChipTypesHelper = require('../../common/ChipTypesHelper.js');
// This list of attributes is taken from section '11.2. Global Attributes' of the
// Data Model specification.
const kGlobalAttributes = [
0xfffb, // AttributeList
0xfffc, // ClusterRevision
0xfffd, // FeatureMap
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ limitations under the License.
<attribute side="server" code="0xFFFD" define="CLUSTER_REVISION_SERVER" type="int16u" default="1" >ClusterRevision</attribute>
<attribute side="client" code="0xFFFC" define="FEATURE_MAP_CLIENT" type="bitmap32" default="0" optional="true">FeatureMap</attribute>
<attribute side="server" code="0xFFFC" define="FEATURE_MAP_SERVER" type="bitmap32" default="0" optional="true">FeatureMap</attribute>
<attribute side="server" code="0xFFFB" define="ATTRIBUTE_LIST_SERVER" type="array" entryType="attrib_id">AttributeList</attribute>

</global>
</configurator>
Loading