Skip to content

Commit

Permalink
Reduce the amount of code generated for MTRClusters. (#28594)
Browse files Browse the repository at this point in the history
1. Push endpoint property up to MTRCluster, instead of having it be on every
   MTRCluster* and MTRBaseCluster* instance.
2. Instead of duplicating all the command bridge code for MTRCluster* commands,
   just instantiate the relevant MTRBaseCluster and delegate to it.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Feb 1, 2024
1 parent 1cbe65d commit 2004059
Show file tree
Hide file tree
Showing 10 changed files with 8,410 additions and 16,519 deletions.
5 changes: 4 additions & 1 deletion src/darwin/Framework/CHIP/MTRCluster.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
using namespace ::chip;

@implementation MTRCluster
- (instancetype)initWithQueue:(dispatch_queue_t)queue
- (instancetype)initWithEndpointID:(NSNumber *)endpointID queue:(dispatch_queue_t)queue;
{
if (self = [super init]) {
// TODO consider range-checking the incoming number to make sure it's
// actually in the EndpointId range
_endpoint = endpointID.unsignedShortValue;
_callbackQueue = queue;
}
return self;
Expand Down
5 changes: 4 additions & 1 deletion src/darwin/Framework/CHIP/MTRCluster_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
#import "zap-generated/MTRBaseClusters.h"

#include <app/ReadPrepareParams.h>
#include <lib/core/DataModelTypes.h>

NS_ASSUME_NONNULL_BEGIN

@interface MTRCluster ()
@property (readonly, nonatomic) dispatch_queue_t callbackQueue;
- (instancetype _Nullable)initWithQueue:(dispatch_queue_t)queue;
@property (nonatomic, readonly) chip::EndpointId endpoint;

- (instancetype)initWithEndpointID:(NSNumber *)endpointID queue:(dispatch_queue_t)queue;
- (chip::ByteSpan)asByteSpan:(NSData *)value;
- (chip::CharSpan)asCharSpan:(NSString *)value;
@end
Expand Down
13 changes: 5 additions & 8 deletions src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,12 @@ using chip::System::Clock::Seconds16;

- (instancetype)initWithDevice:(MTRBaseDevice *)device endpointID:(NSNumber *)endpointID queue:(dispatch_queue_t)queue
{
if (self = [super initWithQueue:queue]) {
if (self = [super initWithEndpointID:endpointID queue:queue]) {
if (device == nil) {
return nil;
}

_device = device;
{{!TODO consider range-checking the incoming number to make sure it's
actually in the uint16_t range}}
_endpoint = [endpointID unsignedShortValue];
}
return self;
}
Expand Down Expand Up @@ -122,7 +119,7 @@ MTR{{cluster}}Cluster{{command}}Params
{{/last}}
{{/zcl_command_arguments}}

return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self->_endpoint, timedInvokeTimeoutMs, invokeTimeout);
return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self.endpoint, timedInvokeTimeoutMs, invokeTimeout);
});
std::move(*bridge).DispatchAction(self.device);
}
Expand Down Expand Up @@ -156,7 +153,7 @@ MTR{{cluster}}Cluster{{command}}Params
using TypeInfo = {{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
return MTRReadAttribute<MTR{{>attribute_data_callback_name}}CallbackBridge,
{{asObjectiveCClass type parent.name}},
TypeInfo::DecodableType>(params, completion, self.callbackQueue, self.device, self->_endpoint, TypeInfo::GetClusterId(), TypeInfo::GetAttributeId());
TypeInfo::DecodableType>(params, completion, self.callbackQueue, self.device, self.endpoint, TypeInfo::GetClusterId(), TypeInfo::GetAttributeId());
}

{{#if isWritableAttribute}}
Expand Down Expand Up @@ -196,7 +193,7 @@ MTR{{cluster}}Cluster{{command}}Params
TypeInfo::Type cppValue;
{{>encode_value target="cppValue" source="value" cluster=parent.name errorCode="return CHIP_ERROR_INVALID_ARGUMENT;" depth=0}}

chip::Controller::ClusterBase cppCluster(exchangeManager, session, self->_endpoint);
chip::Controller::ClusterBase cppCluster(exchangeManager, session, self.endpoint);
return cppCluster.WriteAttribute<TypeInfo>(cppValue, bridge, successCb, failureCb, timedWriteTimeout);
});
std::move(*bridge).DispatchAction(self.device);
Expand All @@ -209,7 +206,7 @@ subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptio
reportHandler:(void (^)({{asObjectiveCClass type parent.name}} * _Nullable value, NSError * _Nullable error))reportHandler
{
using TypeInfo = {{asUpperCamelCase parent.name}}::Attributes::{{asUpperCamelCase name}}::TypeInfo;
MTRSubscribeAttribute<MTR{{>attribute_data_callback_name}}CallbackSubscriptionBridge, {{asObjectiveCClass type parent.name}}, TypeInfo::DecodableType>(params, subscriptionEstablished, reportHandler, self.callbackQueue, self.device, self->_endpoint, TypeInfo::GetClusterId(), TypeInfo::GetAttributeId());
MTRSubscribeAttribute<MTR{{>attribute_data_callback_name}}CallbackSubscriptionBridge, {{asObjectiveCClass type parent.name}}, TypeInfo::DecodableType>(params, subscriptionEstablished, reportHandler, self.callbackQueue, self.device, self.endpoint, TypeInfo::GetClusterId(), TypeInfo::GetAttributeId());
}

+ (void) read{{>attribute}}WithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)({{asObjectiveCClass type parent.name}} * _Nullable value, NSError * _Nullable error))completion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
{{#if (isSupported (asUpperCamelCase name preserveAcronyms=true))}}
@interface MTRBaseCluster{{asUpperCamelCase name preserveAcronyms=true}} ()
@property (nonatomic, strong, readonly) MTRBaseDevice * device;
@property (nonatomic, assign, readonly) chip::EndpointId endpoint;
@end
{{/if}}

Expand Down
105 changes: 41 additions & 64 deletions src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{{> header excludeZapComment=true}}

#import <Foundation/Foundation.h>
#import <Matter/MTRBaseClusters.h>

#import "MTRAsyncCallbackWorkQueue.h"
#import "MTRBaseClusterUtils.h"
Expand Down Expand Up @@ -49,14 +50,11 @@ static void MTRClustersLogCompletion(NSString *logPrefix, id value, NSError *err

- (instancetype)initWithDevice:(MTRDevice *)device endpointID:(NSNumber *)endpointID queue:(dispatch_queue_t)queue
{
if (self = [super initWithQueue:queue]) {
if (self = [super initWithEndpointID:endpointID queue:queue]) {
if (device == nil) {
return nil;
}

{{!TODO consider range-checking the incoming number to make sure it's
actually in the uint16_t range}}
_endpoint = [endpointID unsignedShortValue];
_device = device;
}
return self;
Expand Down Expand Up @@ -90,6 +88,20 @@ MTRClusterIDType{{cluster}}ID
MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
{{/unless}}
{{/inline}}
{{#*inline "baseCluster"}}
{{#if (isSupported cluster command=command)}}
MTRBaseCluster{{cluster}}
{{else}}
MTRBaseCluster{{compatClusterNameRemapping parent.name}}
{{/if}}
{{/inline}}
{{#*inline "completionName"}}
{{#if (isSupported cluster command=command)}}
completion
{{else}}
completionHandler
{{/if}}
{{/inline}}
{{#unless hasArguments}}
- (void){{asLowerCamelCase name}}WithExpectedValues:(NSArray<NSDictionary<NSString *, id> *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:({{>command_completion_type command=.}})completion
{
Expand All @@ -98,73 +110,38 @@ MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
{{/unless}}
- (void){{asLowerCamelCase name}}WithParams: ({{> paramsType}} * {{#unless commandHasRequiredField}}_Nullable{{/unless}})params expectedValues:(NSArray<NSDictionary<NSString *, id> *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:({{>command_completion_type command=.}})completion
{
NSString * logPrefix = [NSString stringWithFormat:@"MTRDevice command %u %u %u %u", self.device.deviceController.fabricIndex, _endpoint, (unsigned int){{> clusterId}}, (unsigned int){{> commandId}}];
NSString * logPrefix = [NSString stringWithFormat:@"MTRDevice command %u %u %u %u", self.device.deviceController.fabricIndex, self.endpoint, (unsigned int){{> clusterId}}, (unsigned int){{> commandId}}];
// Make a copy of params before we go async.
params = [params copy];
NSNumber *timedInvokeTimeoutMsParam = params.timedInvokeTimeoutMs;
if (timedInvokeTimeoutMsParam) {
timedInvokeTimeoutMsParam = MTRClampedNumber(timedInvokeTimeoutMsParam, @(1), @(UINT16_MAX));
}
MTRAsyncCallbackQueueWorkItem * workItem = [[MTRAsyncCallbackQueueWorkItem alloc] initWithQueue:self.device.queue];
MTRAsyncCallbackReadyHandler readyHandler = ^(MTRDevice * device, NSUInteger retryCount) {
MTRClustersLogDequeue(logPrefix, self.device.asyncCallbackWorkQueue);
MTRBaseDevice *baseDevice = [[MTRBaseDevice alloc] initWithNodeID:self.device.nodeID controller:self.device.deviceController];
auto * bridge = new MTR{{>callbackName}}CallbackBridge(self.device.queue,
^(id _Nullable value, NSError * _Nullable error) {
auto * baseDevice = [[MTRBaseDevice alloc] initWithNodeID:self.device.nodeID controller:self.device.deviceController];
auto * cluster = [[{{> baseCluster}} alloc] initWithDevice:baseDevice endpointID:@(self.endpoint) queue:self.device.queue];
[cluster {{asLowerCamelCase name}}WithParams:params {{> completionName}}:
{{#if hasSpecificResponse}}
^(MTR{{cluster}}Cluster{{asUpperCamelCase responseName preserveAcronyms=true}}Params * _Nullable value, NSError * _Nullable error) {
MTRClustersLogCompletion(logPrefix, value, error);
dispatch_async(self.callbackQueue, ^{
{{#if hasSpecificResponse}}
{{! This treats completion as taking an id for the data. This is
not great from a type-safety perspective, of course. }}
completion(value, error);
{{else}}
{{! For now, don't change the bridge API; instead just use an adapter
to invoke our completion handler. This is not great from a
type-safety perspective, of course. }}
completion(error);
{{/if}}
{{! This treats completion as taking an id for the data. This is
not great from a type-safety perspective, of course. }}
completion(value, error);
});
[workItem endWork];
},
^(ExchangeManager & exchangeManager, const SessionHandle & session, {{>callbackName}}CallbackType successCb, MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) {
auto * typedBridge = static_cast<MTR{{>callbackName}}CallbackBridge *>(bridge);
Optional<uint16_t> timedInvokeTimeoutMs;
Optional<Timeout> invokeTimeout;
ListFreer listFreer;
{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type request;
if (timedInvokeTimeoutMsParam != nil) {
timedInvokeTimeoutMs.SetValue(timedInvokeTimeoutMsParam.unsignedShortValue);
}
if (params != nil) {
if (params.serverSideProcessingTimeout != nil) {
// Clamp to a number of seconds that will not overflow 32-bit
// int when converted to ms.
auto * serverSideProcessingTimeout = MTRClampedNumber(params.serverSideProcessingTimeout, @(0), @(UINT16_MAX));
invokeTimeout.SetValue(Seconds16(serverSideProcessingTimeout.unsignedShortValue));
}
}
{{#if mustUseTimedInvoke}}
if (!timedInvokeTimeoutMs.HasValue()) {
timedInvokeTimeoutMs.SetValue(10000);
}
{{/if}}
{{#zcl_command_arguments}}
{{#first}}
{{#unless parent.commandHasRequiredField}}
if (params != nil) {
{{/unless}}
{{/first}}
{{>encode_value target=(concat "request." (asLowerCamelCase label)) source=(concat "params." (asStructPropertyName label)) cluster=parent.parent.name errorCode="return CHIP_ERROR_INVALID_ARGUMENT;" depth=0}}
{{#last}}
{{#unless parent.commandHasRequiredField}}
}
{{/unless}}
{{/last}}
{{/zcl_command_arguments}}

return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self->_endpoint, timedInvokeTimeoutMs, invokeTimeout);
});
std::move(*bridge).DispatchAction(baseDevice);
}
{{else}}
^(NSError * _Nullable error) {
MTRClustersLogCompletion(logPrefix, nil, error);
dispatch_async(self.callbackQueue, ^{
{{! For now, don't change the bridge API; instead just use an adapter
to invoke our completion handler. This is not great from a
type-safety perspective, of course. }}
completion(error);
});
[workItem endWork];
}
{{/if}}
];
};
workItem.readyHandler = readyHandler;
MTRClustersLogEnqueue(logPrefix, self.device.asyncCallbackWorkQueue);
Expand Down Expand Up @@ -198,7 +175,7 @@ MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
{{#*inline "cluster"}}{{asUpperCamelCase parent.name preserveAcronyms=true}}{{/inline}}
{{#*inline "attribute"}}Attribute{{asUpperCamelCase name preserveAcronyms=true}}{{/inline}}
- (NSDictionary<NSString *, id> *)read{{>attribute}}WithParams:(MTRReadParams * _Nullable)params {
return [self.device readAttributeWithEndpointID:@(_endpoint) clusterID:@(MTRClusterIDType{{>cluster}}ID) attributeID:@(MTRAttributeIDTypeCluster{{>cluster}}{{>attribute}}ID) params:params];
return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDType{{>cluster}}ID) attributeID:@(MTRAttributeIDTypeCluster{{>cluster}}{{>attribute}}ID) params:params];
}

{{#if isWritableAttribute}}
Expand All @@ -216,7 +193,7 @@ MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
}
{{/if}}

[self.device writeAttributeWithEndpointID:@(_endpoint) clusterID:@(MTRClusterIDType{{>cluster}}ID) attributeID:@(MTRAttributeIDTypeCluster{{>cluster}}{{>attribute}}ID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout];
[self.device writeAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDType{{>cluster}}ID) attributeID:@(MTRAttributeIDTypeCluster{{>cluster}}{{>attribute}}ID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout];
}

{{/if}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

{{#if (isSupported (asUpperCamelCase name preserveAcronyms=true))}}
@interface MTRCluster{{asUpperCamelCase name preserveAcronyms=true}} ()
@property (nonatomic, readonly) uint16_t endpoint;
@property (nonatomic, readonly) MTRDevice *device;
@end
{{/if}}
Expand Down
Loading

0 comments on commit 2004059

Please sign in to comment.