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

[Android] Use templated reads and writes #12127

Merged
merged 1 commit into from
Nov 23, 2021
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
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