Skip to content

Commit

Permalink
Switch attributes writes on Darwin to support all types. (#11820)
Browse files Browse the repository at this point in the history
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Nov 4, 2022
1 parent 9d7faef commit f707f92
Show file tree
Hide file tree
Showing 21 changed files with 6,528 additions and 2,125 deletions.
4 changes: 4 additions & 0 deletions src/darwin/Framework/CHIP.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
2F79A67726CE6672006377B0 /* im-client-callbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F79A67626CE6672006377B0 /* im-client-callbacks.cpp */; };
2FD775552695557E00FF4B12 /* error-mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD775542695557E00FF4B12 /* error-mapping.cpp */; };
5129BCFD26A9EE3300122DDF /* CHIPError.h in Headers */ = {isa = PBXBuildFile; fileRef = 5129BCFC26A9EE3300122DDF /* CHIPError.h */; settings = {ATTRIBUTES = (Public, ); }; };
5145F81027435A5500225B60 /* CHIPListUtils_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5145F80F27435A5400225B60 /* CHIPListUtils_internal.h */; };
51B22C1E2740CB0A008D5055 /* CHIPStructsObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B22C1D2740CB0A008D5055 /* CHIPStructsObjc.h */; settings = {ATTRIBUTES = (Public, ); }; };
51B22C222740CB1D008D5055 /* CHIPCommandPayloadsObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B22C212740CB1D008D5055 /* CHIPCommandPayloadsObjc.h */; settings = {ATTRIBUTES = (Public, ); }; };
51B22C262740CB32008D5055 /* CHIPStructsObjc.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51B22C252740CB32008D5055 /* CHIPStructsObjc.mm */; };
Expand Down Expand Up @@ -145,6 +146,7 @@
2F79A67626CE6672006377B0 /* im-client-callbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "im-client-callbacks.cpp"; path = "../../../app/util/im-client-callbacks.cpp"; sourceTree = "<group>"; };
2FD775542695557E00FF4B12 /* error-mapping.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "error-mapping.cpp"; path = "../../../app/util/error-mapping.cpp"; sourceTree = "<group>"; };
5129BCFC26A9EE3300122DDF /* CHIPError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CHIPError.h; path = CHIP/CHIPError.h; sourceTree = "<group>"; };
5145F80F27435A5400225B60 /* CHIPListUtils_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHIPListUtils_internal.h; sourceTree = "<group>"; };
51B22C1D2740CB0A008D5055 /* CHIPStructsObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CHIPStructsObjc.h; path = "zap-generated/CHIPStructsObjc.h"; sourceTree = "<group>"; };
51B22C212740CB1D008D5055 /* CHIPCommandPayloadsObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CHIPCommandPayloadsObjc.h; path = "zap-generated/CHIPCommandPayloadsObjc.h"; sourceTree = "<group>"; };
51B22C252740CB32008D5055 /* CHIPStructsObjc.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CHIPStructsObjc.mm; path = "zap-generated/CHIPStructsObjc.mm"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -273,6 +275,7 @@
B202528F2459E34F00F97062 /* CHIP */ = {
isa = PBXGroup;
children = (
5145F80F27435A5400225B60 /* CHIPListUtils_internal.h */,
1ED276E326C5832500547A89 /* CHIPCluster.h */,
1ED276E126C5812A00547A89 /* CHIPCluster.mm */,
2C5EEEF4268A85C400CAE3D3 /* CHIPDeviceConnectionBridge.h */,
Expand Down Expand Up @@ -364,6 +367,7 @@
B2E0D7B5245B0B5C003C5B48 /* CHIPQRCodeSetupPayloadParser.h in Headers */,
1EC4CE6425CC276600D7304F /* CHIPClustersObjc.h in Headers */,
2C5EEEF6268A85C400CAE3D3 /* CHIPDeviceConnectionBridge.h in Headers */,
5145F81027435A5500225B60 /* CHIPListUtils_internal.h in Headers */,
2C8C8FC0253E0C2100797F05 /* CHIPPersistentStorageDelegateBridge.h in Headers */,
998F286F26D55EC5001846C6 /* CHIPP256KeypairBridge.h in Headers */,
2C222ADF255C811800E446B9 /* CHIPDevice_Internal.h in Headers */,
Expand Down
65 changes: 65 additions & 0 deletions src/darwin/Framework/CHIP/CHIPListUtils_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef CHIP_LISTUTILS_INTERNAL_H
#define CHIP_LISTUTILS_INTERNAL_H

#include <set>
#include <type_traits>

template <typename T>
struct ListMemberTypeGetter
{
};
template <typename T>
struct ListMemberTypeGetter<chip::app::DataModel::List<T>>
{
// We use List<const ...> in data model data structures, so consumers can
// use const data. Just grab the type with the const stripped off.
using Type = std::remove_const_t<T>;
};

struct ListHolderBase
{
// Just here so we can delete an instance to trigger the subclass destructor.
virtual ~ListHolderBase() {}
};

template <typename T>
struct ListHolder : ListHolderBase
{
ListHolder(size_t N) { mList = new T[N]; }
~ListHolder() { delete[] mList; }
T * mList;
};

struct ListFreer
{
~ListFreer()
{
for (auto listHolder : mListHolders)
{
delete listHolder;
}
}

void add(ListHolderBase * listHolder) { mListHolders.insert(listHolder); }

std::set<ListHolderBase *> mListHolders;
};

#endif /* CHIP_LISTUTILS_INTERNAL_H */
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#import "CHIPCommandPayloadsObjc.h"

{{#>CHIPCallbackBridge partial-type="" }}DefaultSuccessCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge partial-type="CommandStatus"}}CommandSuccessCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge partial-type="Octet_String"}}OctetStringAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge partial-type="Char_String" }}CharStringAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge partial-type="Boolean" }}BooleanAttributeCallback{{/CHIPCallbackBridge}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include <app/data-model/DecodableList.h>
#include <app-common/zap-generated/cluster-objects.h>

typedef void (*CHIPDefaultSuccessCallbackType)(void *, const chip::app::DataModel::NullObjectType &);
typedef void (*CommandSuccessCallback)(void *, const chip::app::DataModel::NullObjectType &);
using CHIPCommandSuccessCallbackType = CommandSuccessCallback;
typedef void (*CHIPDefaultSuccessCallbackType)(void *);
typedef void (*CHIPDefaultFailureCallbackType)(void *, EmberAfStatus);

{{#chip_client_clusters}}
Expand All @@ -17,6 +19,7 @@ typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase nam
{{/chip_client_clusters}}

{{#>CHIPCallbackBridge header="1" partial-type="" }}DefaultSuccessCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge header="1" partial-type="CommandStatus"}}CommandSuccessCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge header="1" partial-type="Octet_String"}}OctetStringAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge header="1" partial-type="Char_String" }}CharStringAttributeCallback{{/CHIPCallbackBridge}}
{{#>CHIPCallbackBridge header="1" partial-type="Boolean" }}BooleanAttributeCallback{{/CHIPCallbackBridge}}
Expand Down
64 changes: 11 additions & 53 deletions src/darwin/Framework/CHIP/templates/CHIPClustersObjc-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,14 @@
#import "CHIPDevice_Internal.h"
#import "CHIPStructsObjc.h"
#import "CHIPCommandPayloadsObjc.h"
#import "CHIPListUtils_internal.h"

#include <set>
#include <type_traits>

using chip::Callback::Callback;
using chip::Callback::Cancelable;
using namespace chip::app::Clusters;

template<typename T> struct ListMemberTypeGetter {};
template<typename T> struct ListMemberTypeGetter<chip::app::DataModel::List<T>> {
// We use List<const ...> in data model data structures, so consumers can
// use const data. Just grab the type with the const stripped off.
using Type = std::remove_const_t<T>;
};

struct ListHolderBase {
// Just here so we can delete an instance to trigger the subclass destructor.
virtual ~ListHolderBase() {}
};

template<typename T>
struct ListHolder : ListHolderBase {
ListHolder(size_t N) {
mList = new T[N];
}
~ListHolder() {
delete [] mList;
}
T * mList;
};

struct ListFreer {
~ListFreer() {
for (auto listHolder : mListHolders) {
delete listHolder;
}
}

void add(ListHolderBase * listHolder) {
mListHolders.insert(listHolder);
}

std::set<ListHolderBase *> mListHolders;
};

{{#chip_client_clusters}}
@implementation CHIP{{asUpperCamelCase name}}

Expand All @@ -64,13 +27,13 @@ struct ListFreer {
}

{{#chip_cluster_commands}}
{{#*inline "callbackName"}}{{#if hasSpecificResponse}}{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase responseName}}{{else}}DefaultSuccess{{/if}}{{/inline}}
{{#*inline "callbackName"}}{{#if hasSpecificResponse}}{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase responseName}}{{else}}CommandSuccess{{/if}}{{/inline}}
- (void){{asLowerCamelCase name}}:(CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Payload * _Nonnull)payload responseHandler:(ResponseHandler)responseHandler
{
ListFreer listFreer;
{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type request;
{{#chip_cluster_command_arguments}}
{{>encode_value target=(concat "request." (asLowerCamelCase label)) source=(concat "payload." (asUpperCamelCase label)) cluster=parent.parent.name}}
{{>encode_value target=(concat "request." (asLowerCamelCase label)) source=(concat "payload." (asUpperCamelCase label)) cluster=parent.parent.name errorCode="return;" depth=0}}
{{/chip_cluster_command_arguments}}

new CHIP{{>callbackName}}CallbackBridge(self.callbackQueue, responseHandler, ^(Cancelable * success, Cancelable * failure) {
Expand All @@ -93,21 +56,16 @@ struct ListFreer {

{{#if isWritableAttribute}}
{{#*inline "callbackName"}}DefaultSuccess{{/inline}}
{{#*inline "callbackParams"}},
{{#if_chip_enum type}}
static_cast<{{chipType}}>(value)
{{else if (isOctetString type)}}
[self asByteSpan:value]
{{else if (isCharString type)}}
[self asCharSpan:value]
{{else}}
value
{{/if_chip_enum}}
{{/inline}}
- (void)write{{>attribute}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler
- (void)write{{>attribute}}WithValue:({{asObjectiveCType type parent.name}})value responseHandler:(ResponseHandler)responseHandler
{
new CHIP{{>callbackName}}CallbackBridge(self.callbackQueue, responseHandler, ^(Cancelable * success, Cancelable * failure) {
return self.cppCluster.Write{{>attribute}}(success, failure{{>callbackParams}});
ListFreer listFreer;
using TypeInfo = {{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
TypeInfo::Type cppValue;
{{>encode_value target="cppValue" source="value" cluster=parent.name errorCode="return CHIP_ERROR_INVALID_ARGUMENT;" depth=0}}
auto successFn = Callback<CHIP{{>callbackName}}CallbackType>::FromCancelable(success);
auto failureFn = Callback<CHIPDefaultFailureCallbackType>::FromCancelable(failure);
return self.cppCluster.WriteAttribute<TypeInfo>(cppValue, successFn->mContext, successFn->mCall, failureFn->mCall);
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/templates/CHIPClustersObjc.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
{{#*inline "attribute"}}Attribute{{asUpperCamelCase name}}{{/inline}}
- (void)read{{>attribute}}WithResponseHandler:(ResponseHandler)responseHandler;
{{#if isWritableAttribute}}
- (void)write{{>attribute}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler;
- (void)write{{>attribute}}WithValue:({{asObjectiveCType type parent.name}})value responseHandler:(ResponseHandler)responseHandler;
{{/if}}
{{#if isReportableAttribute}}
- (void) subscribe{{>attribute}}WithMinInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval responseHandler:(ResponseHandler)responseHandler;
Expand Down
28 changes: 13 additions & 15 deletions src/darwin/Framework/CHIP/templates/CHIPTestClustersObjc-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
#import "CHIPCluster_internal.h"
#import "CHIPDevice.h"
#import "CHIPDevice_Internal.h"
#import "CHIPListUtils_internal.h"

#import "zap-generated/tests/CHIPClustersTest.h"
#import "zap-generated/CHIPTestClustersObjc.h"

#include <type_traits>

using chip::Callback::Callback;
using chip::Callback::Cancelable;
using namespace chip::app::Clusters;

{{#chip_client_clusters}}

Expand All @@ -27,28 +32,21 @@ using chip::Callback::Cancelable;

{{#chip_server_cluster_attributes}}
{{#unless isWritableAttribute}}
{{#unless isList}}
{{#unless isStruct}}
{{#*inline "attribute"}}Attribute{{asUpperCamelCase name}}{{/inline}}
{{#*inline "callbackName"}}DefaultSuccess{{/inline}}
{{#*inline "callbackParams"}},
{{#if (isOctetString type)}}
[self asByteSpan:value]
{{else if (isCharString type)}}
[self asCharSpan:value]
{{else}}
value
{{/if}}
{{/inline}}
- (void)write{{>attribute}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler
- (void)write{{>attribute}}WithValue:({{asObjectiveCType type parent.name}})value responseHandler:(ResponseHandler)responseHandler
{
new CHIP{{>callbackName}}CallbackBridge(self.callbackQueue, responseHandler, ^(Cancelable * success, Cancelable * failure) {
return self.cppCluster.Write{{>attribute}}(success, failure{{>callbackParams}});
ListFreer listFreer;
using TypeInfo = {{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
TypeInfo::Type cppValue;
{{>encode_value target="cppValue" source="value" cluster=parent.name errorCode="return CHIP_ERROR_INVALID_ARGUMENT;" depth=0}}
auto successFn = Callback<CHIP{{>callbackName}}CallbackType>::FromCancelable(success);
auto failureFn = Callback<CHIPDefaultFailureCallbackType>::FromCancelable(failure);
return self.cppCluster.WriteAttribute<TypeInfo>(cppValue, successFn->mContext, successFn->mCall, failureFn->mCall);
});
}

{{/unless}}
{{/unless}}
{{/unless}}
{{/chip_server_cluster_attributes}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ NS_ASSUME_NONNULL_BEGIN

{{#chip_server_cluster_attributes}}
{{#unless isWritableAttribute}}
{{#unless isList}}
{{#unless isStruct}}
- (void)writeAttribute{{asUpperCamelCase name}}WithValue:({{asObjectiveCBasicType type}})value responseHandler:(ResponseHandler)responseHandler;
{{/unless}}
{{/unless}}
- (void)writeAttribute{{asUpperCamelCase name}}WithValue:({{asObjectiveCType type parent.name}})value responseHandler:(ResponseHandler)responseHandler;
{{/unless}}
{{/chip_server_cluster_attributes}}

Expand Down
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/templates/clusters-tests.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ CHIPDevice * GetConnectedDevice()
CHIP{{asUpperCamelCase parent.name}} * cluster = [[CHIP{{asUpperCamelCase parent.name}} alloc] initWithDevice:device endpoint:{{asExpectedEndpointForCluster (asUpperCamelCase parent.name)}} queue:queue];
XCTAssertNotNil(cluster);

{{asObjectiveCBasicType type}} value = {{asTestValue}};
{{asObjectiveCType type parent.name}} value = {{asTestValue}};
[cluster writeAttribute{{asUpperCamelCase name}}WithValue:value responseHandler:^(NSError * err, NSDictionary * values) {
NSLog(@"{{asUpperCamelCase parent.name}} {{asUpperCamelCase name}} Error: %@", err);
XCTAssertEqual(err.code, 0);
Expand Down
8 changes: 7 additions & 1 deletion src/darwin/Framework/CHIP/templates/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function asTestValue()
} else if (StringHelper.isCharString(this.type)) {
return '@"Test"';
} else {
return this.min || this.max || 0;
return `@(${this.min || this.max || 0})`;
}
}

Expand Down Expand Up @@ -163,6 +163,11 @@ async function arrayElementObjectiveCClass(type, cluster, options)
return asObjectiveCClass.call(this, type, cluster, options);
}

function incrementDepth(depth)
{
return depth + 1;
}

//
// Module exports
//
Expand All @@ -174,3 +179,4 @@ exports.asTestValue = asTestValue;
exports.asObjectiveCClass = asObjectiveCClass;
exports.asObjectiveCType = asObjectiveCType;
exports.arrayElementObjectiveCClass = arrayElementObjectiveCClass;
exports.incrementDepth = incrementDepth;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public:
static void OnSuccessFn(void * context
{{#if (isStrEqual partial-type "Command")}}
, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType & data
{{else if (isStrEqual partial-type "CommandStatus")}}
, const chip::app::DataModel::NullObjectType &
{{else if (isStrEqual partial-type "List")}}
, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list
{{else if partial-type}}
Expand All @@ -22,6 +24,8 @@ public:
void CHIP{{> @partial-block}}Bridge::OnSuccessFn(void * context
{{#if (isStrEqual partial-type "Command")}}
, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType & data
{{else if (isStrEqual partial-type "CommandStatus")}}
, const chip::app::DataModel::NullObjectType &
{{else if (isStrEqual partial-type "List")}}
, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list
{{else if partial-type}}
Expand Down Expand Up @@ -88,6 +92,8 @@ void CHIP{{> @partial-block}}Bridge::OnSuccessFn(void * context
DispatchSuccess(context, @{ @"value": [NSData dataWithBytes: value.data() length: value.size()] });
{{else if (isCharString partial-type)}}
DispatchSuccess(context, @{ @"value": [[NSString alloc] initWithBytes:value.data() length:value.size() encoding:NSUTF8StringEncoding] });
{{else if (isStrEqual partial-type "CommandStatus")}}
DispatchSuccess(context, nil);
{{else if partial-type}}
DispatchSuccess(context, @{ @"value": [NSNumber numberWith{{asObjectiveCNumberType name partial-type false}}:value] });
{{else}}
Expand Down
Loading

0 comments on commit f707f92

Please sign in to comment.