Skip to content

Commit

Permalink
Switch YAML tests to using templated ReadAttribute.
Browse files Browse the repository at this point in the history
This will let us handle reading nullables (and structs once we can
have struct-typed attributes) propely.
  • Loading branch information
bzbarsky-apple committed Nov 10, 2021
1 parent 22e3e9d commit 79bd4d6
Show file tree
Hide file tree
Showing 8 changed files with 5,452 additions and 4,916 deletions.
11 changes: 11 additions & 0 deletions examples/chip-tool/templates/partials/test_cluster.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ class {{filename}}: public TestCommand
{{#unless isWait}}
{{#unless isCommand}}
{{#unless isWriteAttribute}}
{{#unless isReadAttribute}}
chip::Callback::Callback<void (*) ({{>failureArguments}})> {{>failureCallback}} { {{>failureResponse}}, this };
chip::Callback::Callback<void (*) ({{>successArguments}})> {{>successCallback}} { {{>successResponse}}, this };
{{/unless}}
{{/unless}}
{{/unless}}
{{/unless}}
{{/unless}}
{{/chip_tests_items}}

{{#chip_tests_items}}
Expand All @@ -78,6 +80,11 @@ class {{filename}}: public TestCommand
{
(static_cast<{{filename}} *>(context))->OnFailureResponse_{{index}}(chip::to_underlying(status));
}
{{else if isReadAttribute}}
static void {{>failureResponse}}(void * context, EmberAfStatus status)
{
(static_cast<{{filename}} *>(context))->OnFailureResponse_{{index}}(chip::to_underlying(status));
}
{{else}}
static void {{>failureResponse}}({{> failureArguments}})
{
Expand Down Expand Up @@ -160,6 +167,10 @@ class {{filename}}: public TestCommand
{{#*inline "failureResponse"}}OnFailureCallback_{{index}}{{/inline}}
{{#*inline "successResponse"}}OnSuccessCallback_{{index}}{{/inline}}
{{#if async}}ReturnErrorOnFailure({{else}}return {{/if}}cluster.WriteAttribute<chip::app::Clusters::{{asUpperCamelCase cluster}}::Attributes::{{asUpperCamelCase attribute}}::TypeInfo>({{#chip_tests_item_parameters}}{{asLowerCamelCase name}}Argument, {{/chip_tests_item_parameters}}this, {{>successResponse}}, {{>failureResponse}}){{#if async}}){{/if}};
{{else if isReadAttribute}}
{{#*inline "failureResponse"}}OnFailureCallback_{{index}}{{/inline}}
{{#*inline "successResponse"}}OnSuccessCallback_{{index}}{{/inline}}
{{#if async}}ReturnErrorOnFailure({{else}}return {{/if}}cluster.ReadAttribute<chip::app::Clusters::{{asUpperCamelCase cluster}}::Attributes::{{asUpperCamelCase attribute}}::TypeInfo>({{#chip_tests_item_parameters}}{{asLowerCamelCase name}}Argument, {{/chip_tests_item_parameters}}this, {{>successResponse}}, {{>failureResponse}}){{#if async}}){{/if}};
{{else}}
{{~#*inline "commandName"}}{{asUpperCamelCase commandName}}{{#if isAttribute}}Attribute{{asUpperCamelCase attribute}}{{/if}}{{/inline}}
{{#if async}}ReturnErrorOnFailure({{else}}return {{/if}}cluster.{{>commandName}}({{>successCallback}}.Cancel(){{#unless isWaitForReport}}, {{>failureCallback}}.Cancel(){{/unless}}{{#chip_tests_item_parameters}}, {{asLowerCamelCase name}}Argument{{/chip_tests_item_parameters}}){{#if async}}){{/if}};
Expand Down
2 changes: 1 addition & 1 deletion src/app/tests/suites/TestDescriptorCluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ tests:
command: "readAttribute"
attribute: "Device List"
response:
value: [{ deviceTypeId: 1, revision: 1 }]
value: [{ type: 0, revision: 1 }]

- label: "Read attribute Server list"
command: "readAttribute"
Expand Down
2 changes: 2 additions & 0 deletions src/app/zap-templates/templates/app/cluster-objects.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ namespace {{asUpperCamelCase label}} {
{{#if entryType}}
using Type = {{zapTypeToEncodableClusterObjectType entryType forceNotOptional=true}};
using DecodableType = {{zapTypeToDecodableClusterObjectType entryType forceNotOptional=true}};
using DecodableArgType = {{zapTypeToDecodableClusterObjectType entryType forceNotOptional=true isArgument=true}};
{{else}}
using Type = {{zapTypeToEncodableClusterObjectType type forceNotOptional=true}};
using DecodableType = {{zapTypeToDecodableClusterObjectType type forceNotOptional=true}};
using DecodableArgType = {{zapTypeToDecodableClusterObjectType type forceNotOptional=true isArgument=true}};
{{/if}}

static constexpr ClusterId GetClusterId() { return Clusters::{{asUpperCamelCase parent.name}}::Id; }
Expand Down
40 changes: 40 additions & 0 deletions src/controller/CHIPCluster.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <app/DeviceProxy.h>
#include <app/util/error-mapping.h>
#include <controller/InvokeInteraction.h>
#include <controller/ReadInteraction.h>
#include <controller/WriteInteraction.h>

namespace chip {
Expand All @@ -40,6 +41,9 @@ using CommandResponseSuccessCallback = void(void * context, const T & responseOb
using CommandResponseFailureCallback = void(void * context, EmberAfStatus status);
using WriteResponseSuccessCallback = void (*)(void * context);
using WriteResponseFailureCallback = void (*)(void * context, EmberAfStatus status);
template <typename T>
using ReadResponseSuccessCallback = void (*)(void * context, T responseData);
using ReadResponseFailureCallback = void (*)(void * context, EmberAfStatus status);

class DLL_EXPORT ClusterBase
{
Expand Down Expand Up @@ -102,6 +106,42 @@ class DLL_EXPORT ClusterBase
failureCb);
}

/**
* Read an attribute and get a type-safe callback with the attribute value.
*/
template <typename AttributeInfo>
CHIP_ERROR ReadAttribute(void * context, ReadResponseSuccessCallback<typename AttributeInfo::DecodableArgType> successCb,
ReadResponseFailureCallback failureCb)
{
return ReadAttribute<typename AttributeInfo::DecodableType, typename AttributeInfo::DecodableArgType>(
context, AttributeInfo::GetClusterId(), AttributeInfo::GetAttributeId(), successCb, failureCb);
}

template <typename DecodableType, typename DecodableArgType>
CHIP_ERROR ReadAttribute(void * context, ClusterId clusterId, AttributeId attributeId,
ReadResponseSuccessCallback<DecodableArgType> successCb, ReadResponseFailureCallback failureCb)
{
VerifyOrReturnError(mDevice != nullptr, CHIP_ERROR_INCORRECT_STATE);

auto onSuccessCb = [context, successCb](const app::ConcreteAttributePath & commandPath, const DecodableType & aData) {
if (successCb != nullptr)
{
successCb(context, aData);
}
};

auto onFailureCb = [context, failureCb](const app::ConcreteAttributePath * commandPath, app::StatusIB status,
CHIP_ERROR aError) {
if (failureCb != nullptr)
{
failureCb(context, app::ToEmberAfStatus(status.mStatus));
}
};

return Controller::ReadAttribute<DecodableType>(mDevice->GetExchangeManager(), mDevice->GetSecureSession().Value(),
mEndpoint, clusterId, attributeId, onSuccessCb, onFailureCb);
}

protected:
ClusterBase(uint16_t cluster) : mClusterId(cluster) {}

Expand Down
29 changes: 23 additions & 6 deletions src/controller/ReadInteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ namespace Controller {
* GetAttributeId() methods is expected to work.
*
*/
template <typename AttributeTypeInfo>

/**
* To avoid instantiating all the complicated code on a per-attribute basis, we
* have a helper that's just templated on the type.
*/
template <typename DecodableAttributeType>
CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle sessionHandle, EndpointId endpointId,
typename TypedReadCallback<AttributeTypeInfo>::OnSuccessCallbackType onSuccessCb,
typename TypedReadCallback<AttributeTypeInfo>::OnErrorCallbackType onErrorCb)
ClusterId clusterId, AttributeId attributeId,
typename TypedReadCallback<DecodableAttributeType>::OnSuccessCallbackType onSuccessCb,
typename TypedReadCallback<DecodableAttributeType>::OnErrorCallbackType onErrorCb)
{
app::AttributePathParams attributePath(endpointId, AttributeTypeInfo::GetClusterId(), AttributeTypeInfo::GetAttributeId());
app::AttributePathParams attributePath(endpointId, clusterId, attributeId);
app::ReadPrepareParams readParams(sessionHandle);
app::ReadClient * readClient = nullptr;
app::InteractionModelEngine * engine = app::InteractionModelEngine::GetInstance();
Expand All @@ -50,11 +56,12 @@ CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const Sessio
readParams.mpAttributePathParamsList = &attributePath;
readParams.mAttributePathParamsListSize = 1;

auto onDone = [](app::ReadClient * apReadClient, TypedReadCallback<AttributeTypeInfo> * callback) {
auto onDone = [](app::ReadClient * apReadClient, TypedReadCallback<DecodableAttributeType> * callback) {
chip::Platform::Delete(callback);
};

auto callback = chip::Platform::MakeUnique<TypedReadCallback<AttributeTypeInfo>>(onSuccessCb, onErrorCb, onDone);
auto callback = chip::Platform::MakeUnique<TypedReadCallback<DecodableAttributeType>>(clusterId, attributeId, onSuccessCb,
onErrorCb, onDone);
VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY);

ReturnErrorOnFailure(engine->NewReadClient(&readClient, app::ReadClient::InteractionType::Read, callback.get()));
Expand All @@ -75,5 +82,15 @@ CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const Sessio
return err;
}

template <typename AttributeTypeInfo>
CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const SessionHandle sessionHandle, EndpointId endpointId,
typename TypedReadCallback<typename AttributeTypeInfo::DecodableType>::OnSuccessCallbackType onSuccessCb,
typename TypedReadCallback<typename AttributeTypeInfo::DecodableType>::OnErrorCallbackType onErrorCb)
{
return ReadAttribute<typename AttributeTypeInfo::DecodableType>(aExchangeMgr, sessionHandle, endpointId,
AttributeTypeInfo::GetClusterId(),
AttributeTypeInfo::GetAttributeId(), onSuccessCb, onErrorCb);
}

} // namespace Controller
} // namespace chip
18 changes: 10 additions & 8 deletions src/controller/TypedReadCallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,31 @@ namespace Controller {
* 2. Automatic decoding of attribute data provided in the TLVReader by InteractionModelDelegate::OnReportData into a decoded
* cluster object.
*/
template <typename AttributeTypeInfo>
template <typename DecodableAttributeType>
class TypedReadCallback final : public app::ReadClient::Callback
{
public:
using OnSuccessCallbackType =
std::function<void(const app::ConcreteAttributePath & aPath, const typename AttributeTypeInfo::DecodableType & aData)>;
std::function<void(const app::ConcreteAttributePath & aPath, const DecodableAttributeType & aData)>;
using OnErrorCallbackType = std::function<void(const app::ConcreteAttributePath * aPath,
Protocols::InteractionModel::Status aIMStatus, CHIP_ERROR aError)>;
using OnDoneCallbackType = std::function<void(app::ReadClient * client, TypedReadCallback * callback)>;

TypedReadCallback(OnSuccessCallbackType aOnSuccess, OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone) :
mOnSuccess(aOnSuccess), mOnError(aOnError), mOnDone(aOnDone)
TypedReadCallback(ClusterId aClusterId, AttributeId aAttributeId, OnSuccessCallbackType aOnSuccess,
OnErrorCallbackType aOnError, OnDoneCallbackType aOnDone) :
mClusterId(aClusterId),
mAttributeId(aAttributeId), mOnSuccess(aOnSuccess), mOnError(aOnError), mOnDone(aOnDone)
{}

private:
void OnAttributeData(const app::ReadClient * apReadClient, const app::ConcreteAttributePath & aPath, TLV::TLVReader * apData,
const app::StatusIB & status) override
{
CHIP_ERROR err = CHIP_NO_ERROR;
typename AttributeTypeInfo::DecodableType value;
DecodableAttributeType value;

VerifyOrExit(status.mStatus == Protocols::InteractionModel::Status::Success, err = CHIP_ERROR_IM_STATUS_CODE_RECEIVED);
VerifyOrExit(aPath.mClusterId == AttributeTypeInfo::GetClusterId() &&
aPath.mAttributeId == AttributeTypeInfo::GetAttributeId(),
CHIP_ERROR_SCHEMA_MISMATCH);
VerifyOrExit(aPath.mClusterId == mClusterId && aPath.mAttributeId == mAttributeId, err = CHIP_ERROR_SCHEMA_MISMATCH);
VerifyOrExit(apData != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);

err = app::DataModel::Decode(*apData, value);
Expand Down Expand Up @@ -90,6 +90,8 @@ class TypedReadCallback final : public app::ReadClient::Callback

void OnDone(app::ReadClient * apReadClient) override { mOnDone(apReadClient, this); }

ClusterId mClusterId;
AttributeId mAttributeId;
OnSuccessCallbackType mOnSuccess;
OnErrorCallbackType mOnError;
OnDoneCallbackType mOnDone;
Expand Down
Loading

0 comments on commit 79bd4d6

Please sign in to comment.