Skip to content

Commit

Permalink
Use templated reads/writes. (#12127)
Browse files Browse the repository at this point in the history
  • Loading branch information
austinh0 authored Nov 23, 2021
1 parent 6eba258 commit 2e85d48
Show file tree
Hide file tree
Showing 23 changed files with 8,335 additions and 2,007 deletions.
31 changes: 28 additions & 3 deletions src/app/zap-templates/templates/chip/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,35 @@ function chip_has_clusters(options)
* @param {*} options
*/
function chip_server_global_responses(options)
{
return asBlocks.call(this, getServerGlobalAttributeResponses(), options);
}

async function if_in_global_responses(options)
{
const attribute = this.response.arguments[0];
const globalResponses = await getServerGlobalAttributeResponses();
const responseTypeExists = globalResponses.find(
// Some fields of item/attribute here may be undefined.
item => item.isList == attribute.isList && item.isStruct == attribute.isStruct && item.chipType == attribute.chipType
&& item.isNullable == attribute.isNullable && item.isOptional == attribute.isOptional)

if (responseTypeExists)
{
return options.fn(this);
}
else
{
return options.inverse(this);
}
}

function getServerGlobalAttributeResponses()
{
const sorter = (a, b) => a.chipCallback.name.localeCompare(b.chipCallback.name, 'en', { numeric : true });

const reducer = (unique, item) => {
const { type, size, isList, chipCallback, chipType } = item.response.arguments[0];
const { type, size, isList, isOptional, isNullable, chipCallback, chipType } = item.response.arguments[0];

// List-typed elements have a dedicated callback
if (isList) {
Expand All @@ -167,11 +191,11 @@ function chip_server_global_responses(options)
return unique;
}

return [...unique, { chipCallback, chipType, size } ];
return [...unique, { chipCallback, chipType, size, isOptional, isNullable } ];
};

const filter = attributes => attributes.reduce(reducer, []).sort(sorter);
return asBlocks.call(this, Clusters.getAttributesByClusterSide('server').then(filter), options);
return Clusters.getAttributesByClusterSide('server').then(filter);
}

/**
Expand Down Expand Up @@ -381,3 +405,4 @@ exports.chip_server_cluster_attributes = chip_server_clust
exports.chip_server_has_list_attributes = chip_server_has_list_attributes;
exports.chip_available_cluster_commands = chip_available_cluster_commands;
exports.if_chip_enum = if_chip_enum;
exports.if_in_global_responses = if_in_global_responses;
11 changes: 11 additions & 0 deletions src/controller/java/templates/CHIPCallbackTypes.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@
#include <app-common/zap-generated/cluster-objects.h>

typedef void (*CHIPDefaultSuccessCallbackType)(void *, const chip::app::DataModel::NullObjectType &);
typedef void (*CHIPDefaultWriteSuccessCallbackType)(void *);
typedef void (*CHIPDefaultFailureCallbackType)(void *, EmberAfStatus);

{{#chip_client_clusters}}
{{#chip_cluster_responses}}
typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}CallbackType)(void *, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType &);
{{/chip_cluster_responses}}

{{! TODO: global response types?}}

{{#chip_server_cluster_attributes}}
{{#if isList}}
typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType)(void *, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo::DecodableType &);
{{else}}
typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType)(void *, chip::app::Clusters::{{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo::DecodableArgType);
{{/if}}
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}
{{/if}}
19 changes: 9 additions & 10 deletions src/controller/java/templates/CHIPClusters-JNI.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,14 @@ JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, {{asLowerCamelCase name}})
{{! TODO: Lists not supported in attribute writes yet. }}
{{#unless isList}}

JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase name}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, {{asJniBasicType type false}} value)
JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase name}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, {{asJniBasicType type true}} value)
{
chip::DeviceLayer::StackLock lock;
using TypeInfo = chip::app::Clusters::{{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
TypeInfo::Type cppValue;

{{>encode_value target="cppValue" source="value"}}

std::unique_ptr<CHIPDefaultSuccessCallback, void (*)(CHIPDefaultSuccessCallback *)> onSuccess(Platform::New<CHIPDefaultSuccessCallback>(callback), Platform::Delete<CHIPDefaultSuccessCallback>);
VerifyOrReturn(onSuccess.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY));

Expand All @@ -94,15 +99,9 @@ JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase na
{{asCamelCased ../name false}}Cluster * cppCluster = reinterpret_cast<{{asCamelCased ../name false}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE));

{{#if (isOctetString type)}}
JniByteArray jniArr(env, value);
err = cppCluster->WriteAttribute{{asUpperCamelCase name}}(onSuccess->Cancel(), onFailure->Cancel(), chip::ByteSpan((const uint8_t*) jniArr.data(), jniArr.size()));
{{else if (isCharString type)}}
JniUtfString valueStr(env, value);
err = cppCluster->WriteAttribute{{asUpperCamelCase name}}(onSuccess->Cancel(), onFailure->Cancel(), chip::CharSpan(valueStr.c_str(), strlen(valueStr.c_str())));
{{else}}
err = cppCluster->WriteAttribute{{asUpperCamelCase name}}(onSuccess->Cancel(), onFailure->Cancel(), static_cast<{{chipType}}>(value));
{{/if}}
auto successFn = chip::Callback::Callback<CHIPDefaultWriteSuccessCallbackType>::FromCancelable(onSuccess->Cancel());
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());
err = cppCluster->WriteAttribute<TypeInfo>(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall);
VerifyOrReturn(err == CHIP_NO_ERROR, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error writing attribute", err));

onSuccess.release();
Expand Down
22 changes: 14 additions & 8 deletions src/controller/java/templates/CHIPClustersRead-JNI.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, read{{asUpperCamelCase name}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback)
{
chip::DeviceLayer::StackLock lock;
{{#if isList}}
std::unique_ptr<CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback, void (*)(CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback *)> onSuccess(
chip::Platform::New<CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback>(callback), chip::Platform::Delete<CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback>);
{{else}}
std::unique_ptr<CHIP{{chipCallback.name}}AttributeCallback, void (*)(CHIP{{chipCallback.name}}AttributeCallback *)> onSuccess(chip::Platform::New<CHIP{{chipCallback.name}}AttributeCallback>(callback{{#if (isString type)}},
{{#if (isOctetString type)}}true{{else}}false{{/if}}{{/if}}), chip::Platform::Delete<CHIP{{chipCallback.name}}AttributeCallback>);
{{/if}}
using TypeInfo = chip::app::Clusters::{{asUpperCamelCase ../name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;

{{~#*inline "callbackName"}}
{{#if_in_global_responses}}
CHIP{{chipCallback.name}}AttributeCallback
{{else}}
CHIP{{asCamelCased parent.name false}}{{asCamelCased name false}}AttributeCallback
{{/if_in_global_responses}}
{{/inline}}

std::unique_ptr<{{>callbackName}}, void (*)({{>callbackName}} *)> onSuccess(chip::Platform::New<{{>callbackName}}>(callback, false), chip::Platform::Delete<{{>callbackName}}>);
VerifyOrReturn(onSuccess.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY));

std::unique_ptr<chip::CHIPDefaultFailureCallback, void (*)(chip::CHIPDefaultFailureCallback *)> onFailure(chip::Platform::New<chip::CHIPDefaultFailureCallback>(callback), chip::Platform::Delete<chip::CHIPDefaultFailureCallback>);
Expand All @@ -35,7 +39,9 @@ JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, read{{asUpperCamelCase nam
chip::Controller::{{asCamelCased ../name false}}Cluster * cppCluster = reinterpret_cast<chip::Controller::{{asCamelCased ../name false}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE));

err = cppCluster->ReadAttribute{{asCamelCased name false}}(onSuccess->Cancel(), onFailure->Cancel());
auto successFn = chip::Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType>::FromCancelable(onSuccess->Cancel());
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());
err = cppCluster->ReadAttribute<TypeInfo>(onSuccess->mContext, successFn->mCall, failureFn->mCall);
VerifyOrReturn(err == CHIP_NO_ERROR, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error reading attribute", err));

onSuccess.release();
Expand Down
4 changes: 2 additions & 2 deletions src/controller/java/templates/CHIPInvokeCallbacks-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ void CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callbac
// Java callback is allowed to be null, exit early if this is the case.
VerifyOrReturn(javaCallbackRef != nullptr);

err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#chip_cluster_response_arguments}}{{#if isArray}}{{else if isOptional}}Ljava/util/Optional;{{else if (isOctetString type)}}[B{{else if (isShortString type)}}Ljava/lang/String;{{else}}{{asJniSignature type true}}{{/if}}{{/chip_cluster_response_arguments}})V", &javaMethod);
err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#chip_cluster_response_arguments}}{{#if isArray}}{{else if isOptional}}Ljava/util/Optional;{{else if (isOctetString type)}}[B{{else if (isCharString type)}}Ljava/lang/String;{{else}}{{asJniSignature type true}}{{/if}}{{/chip_cluster_response_arguments}})V", &javaMethod);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Error invoking Java callback: %s", ErrorStr(err)));

{{#chip_cluster_response_arguments}}
{{>decode_value}}
{{>decode_value source=(concat "dataResponse." (asLowerCamelCase name)) target=(asSymbol label)}}
{{/chip_cluster_response_arguments}}

env->CallVoidMethod(javaCallbackRef, javaMethod{{#chip_cluster_response_arguments}}, {{asSymbol label}}{{/chip_cluster_response_arguments}});
Expand Down
37 changes: 33 additions & 4 deletions src/controller/java/templates/CHIPReadCallbacks-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ void CHIP{{chipCallback.name}}AttributeCallback::CallbackFn(void * context, {{ch

{{#chip_client_clusters}}
{{#chip_server_cluster_attributes}}
{{#if isList}}

{{! NOTE: Some of our helpers rely on broken ZAP APIs that sniff for "isArray"
when we are just trying to work with the type of an array element. Fix
Expand All @@ -92,8 +91,10 @@ void CHIP{{chipCallback.name}}AttributeCallback::CallbackFn(void * context, {{ch
{{~#*inline "asUnboxedJniSignatureForEntry"}}{{> asUnboxedJniSignature isArray=false}}{{/inline~}}
{{~#*inline "asBoxedJavaBasicType"}}{{asJavaBasicTypeForZclType type true}}{{/inline~}}
{{~#*inline "asBoxedJavaBasicTypeForEntry"}}{{>asBoxedJavaBasicType isArray=false}}{{/inline~}}
CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback(jobject javaCallback) :
chip::Callback::Callback<{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeCallback>(CallbackFn, this)
{{#if_in_global_responses}}
{{else}}
CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback(jobject javaCallback, bool keepAlive) :
chip::Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType>(CallbackFn, this), keepAlive(keepAlive)
{
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
if (env == nullptr) {
Expand All @@ -116,7 +117,9 @@ CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::
}
env->DeleteGlobalRef(javaCallbackRef);
}
{{/if_in_global_responses}}

{{#if isList}}
void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list)
{
chip::DeviceLayer::StackUnlock unlock;
Expand All @@ -126,7 +129,7 @@ void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallb

VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env"));

std::unique_ptr<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback> cppCallback(reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback *>(context));
std::unique_ptr<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback, decltype(&maybeDestroy)> cppCallback(reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback *>(context), maybeDestroy);

// It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback.
javaCallbackRef = cppCallback.get()->javaCallbackRef;
Expand Down Expand Up @@ -311,6 +314,32 @@ void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallb
env->ExceptionClear();
env->CallVoidMethod(javaCallbackRef, javaMethod, arrayListObj);
}
{{else}}
{{#if_in_global_responses}}
{{else}}
void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} value)
{
chip::DeviceLayer::StackUnlock unlock;
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
jobject javaCallbackRef;

VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env"));
std::unique_ptr<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback, decltype(&maybeDestroy)> cppCallback(reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback *>(context), maybeDestroy);

// It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback.
javaCallbackRef = cppCallback.get()->javaCallbackRef;
VerifyOrReturn(javaCallbackRef != nullptr, ChipLogProgress(Zcl, "Early return from attribute callback since Java callback is null"));

jmethodID javaMethod;
err = chip::JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#if isArray}}{{else if isStruct}}{{else if isOptional}}Ljava/util/Optional;{{else if (isOctetString type)}}[B{{else if (isCharString type)}}Ljava/lang/String;{{else}}{{asJniSignature type true}}{{/if}})V", &javaMethod);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Could not find onSuccess() method"));

{{>decode_value source="value" target="javaValue"}}

env->CallVoidMethod(javaCallbackRef, javaMethod, javaValue);
}
{{/if_in_global_responses}}
{{/if}}
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}
Expand Down
25 changes: 17 additions & 8 deletions src/controller/java/templates/CHIPReadCallbacks.zapt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{{> header}}
{{#if (chip_has_client_clusters)}}
#include <zap-generated/CHIPClientCallbacks.h>
#include "CHIPCallbackTypes.h"

#include <jni.h>
#include <zap-generated/CHIPClientCallbacks.h>

{{#chip_server_global_responses}}
class CHIP{{chipCallback.name}}AttributeCallback : public chip::Callback::Callback<{{chipCallback.name}}AttributeCallback> {
Expand All @@ -14,7 +15,7 @@ public:
static void maybeDestroy(CHIP{{chipCallback.name}}AttributeCallback * callback) {
if (!callback->keepAlive) {
callback->Cancel();
delete callback;
chip::Platform::Delete<CHIP{{chipCallback.name}}AttributeCallback>(callback);
}
}

Expand All @@ -24,26 +25,34 @@ private:
jobject javaCallbackRef;
bool keepAlive;
};

{{/chip_server_global_responses}}

{{#chip_client_clusters}}
{{#chip_server_cluster_attributes}}
{{#if isList}}
class CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback : public chip::Callback::Callback<{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}ListAttributeCallback>
{{#if_in_global_responses}}
{{else}}
class CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback : public chip::Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}AttributeCallbackType>
{
public:
CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback(jobject javaCallback);
CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback(jobject javaCallback, bool keepAlive = false);

~CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback();

static void CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list);
static void maybeDestroy(CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback * callback) {
if (!callback->keepAlive) {
callback->Cancel();
chip::Platform::Delete<CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback>(callback);
}
}

static void CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} {{#if isList}}list{{else}}value{{/if}});

private:
jobject javaCallbackRef;
bool keepAlive;
};
{{/if_in_global_responses}}

{{/if}}
{{/chip_server_cluster_attributes}}
{{/chip_client_clusters}}

Expand Down
Loading

0 comments on commit 2e85d48

Please sign in to comment.