Skip to content

Commit e3701e6

Browse files
Implement MTRBaseCluster invokes on top of MTRBaseDevice.
This gets rid of command bridge code and shares code a lot better.
1 parent 68d69cb commit e3701e6

12 files changed

+5146
-10202
lines changed

src/darwin/Framework/CHIP/MTRBaseClusterUtils.h

-36
Original file line numberDiff line numberDiff line change
@@ -392,40 +392,4 @@ class MTRInvokeCallback : public chip::app::CommandSender::Callback {
392392
bool mCalledCallback = false;
393393
};
394394

395-
/**
396-
* timedInvokeTimeoutMs, if provided, is how long the server will wait for us to
397-
* send the invoke after we sent the Timed Request message.
398-
*
399-
* invokeTimeout, if provided, will have possible MRP latency added to it and
400-
* the result is how long we will wait for the server to respond.
401-
*/
402-
template <typename BridgeType, typename RequestDataType>
403-
CHIP_ERROR MTRStartInvokeInteraction(BridgeType * _Nonnull bridge, const RequestDataType & requestData,
404-
chip::Messaging::ExchangeManager & exchangeManager, const chip::SessionHandle & session,
405-
typename BridgeType::SuccessCallbackType successCb, MTRErrorCallback failureCb, chip::EndpointId endpoint,
406-
chip::Optional<uint16_t> timedInvokeTimeoutMs, chip::Optional<chip::System::Clock::Timeout> invokeTimeout)
407-
{
408-
auto callback = chip::Platform::MakeUnique<MTRInvokeCallback<BridgeType, typename RequestDataType::ResponseType>>(
409-
bridge, successCb, failureCb);
410-
VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY);
411-
412-
auto commandSender
413-
= chip::Platform::MakeUnique<chip::app::CommandSender>(callback.get(), &exchangeManager, timedInvokeTimeoutMs.HasValue());
414-
VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY);
415-
416-
chip::app::CommandPathParams commandPath(endpoint, 0, RequestDataType::GetClusterId(), RequestDataType::GetCommandId(),
417-
chip::app::CommandPathFlags::kEndpointIdValid);
418-
ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, requestData, timedInvokeTimeoutMs));
419-
420-
if (invokeTimeout.HasValue()) {
421-
invokeTimeout.SetValue(session->ComputeRoundTripTimeout(invokeTimeout.Value()));
422-
}
423-
ReturnErrorOnFailure(commandSender->SendCommandRequest(session, invokeTimeout));
424-
425-
callback->AdoptCommandSender(std::move(commandSender));
426-
callback.release();
427-
428-
return CHIP_NO_ERROR;
429-
};
430-
431395
NS_ASSUME_NONNULL_END

src/darwin/Framework/CHIP/MTRBaseDevice.mm

+50
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#import "MTRSetupPayload_Internal.h"
3232
#import "NSDataSpanConversion.h"
3333
#import "NSStringSpanConversion.h"
34+
#import "zap-generated/MTRCommandPayloads_Internal.h"
3435

3536
#include "app/ConcreteAttributePath.h"
3637
#include "app/ConcreteCommandPath.h"
@@ -1308,6 +1309,55 @@ - (void)_invokeCommandWithEndpointID:(NSNumber *)endpointID
13081309
std::move(*bridge).DispatchAction(self);
13091310
}
13101311

1312+
- (void)_invokeKnownCommandWithEndpointID:(NSNumber *)endpointID
1313+
clusterID:(NSNumber *)clusterID
1314+
commandID:(NSNumber *)commandID
1315+
commandPayload:(id)commandPayload
1316+
timedInvokeTimeout:(NSNumber * _Nullable)timeout
1317+
serverSideProcessingTimeout:(NSNumber * _Nullable)serverSideProcessingTimeout
1318+
responseClass:(Class _Nullable)responseClass
1319+
queue:(dispatch_queue_t)queue
1320+
completion:(void (^)(id _Nullable response, NSError * _Nullable error))completion
1321+
{
1322+
if (![commandPayload respondsToSelector:@selector(_encodeAsDataValue:)]) {
1323+
dispatch_async(queue, ^{
1324+
completion(nil, [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT]);
1325+
});
1326+
return;
1327+
}
1328+
1329+
NSError * encodingError;
1330+
auto * commandFields = [commandPayload _encodeAsDataValue:&encodingError];
1331+
if (commandFields == nil) {
1332+
dispatch_async(queue, ^{
1333+
completion(nil, encodingError);
1334+
});
1335+
return;
1336+
}
1337+
1338+
auto responseHandler = ^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
1339+
id _Nullable response = nil;
1340+
if (error == nil) {
1341+
if (values.count != 1) {
1342+
error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeSchemaMismatch userInfo:nil];
1343+
} else if (responseClass != nil) {
1344+
response = [[responseClass alloc] initWithResponseValue:values[0] error:&error];
1345+
}
1346+
}
1347+
completion(response, error);
1348+
};
1349+
1350+
[self _invokeCommandWithEndpointID:endpointID
1351+
clusterID:clusterID
1352+
commandID:commandID
1353+
commandFields:commandFields
1354+
timedInvokeTimeout:timeout
1355+
serverSideProcessingTimeout:serverSideProcessingTimeout
1356+
queue:queue
1357+
completion:responseHandler];
1358+
1359+
}
1360+
13111361
- (void)subscribeToAttributesWithEndpointID:(NSNumber * _Nullable)endpointID
13121362
clusterID:(NSNumber * _Nullable)clusterID
13131363
attributeID:(NSNumber * _Nullable)attributeID

src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h

+18
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,24 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
111111
queue:(dispatch_queue_t)queue
112112
completion:(MTRDeviceResponseHandler)completion;
113113

114+
/**
115+
* Like the public invokeCommandWithEndpointID but:
116+
*
117+
* 1) Allows passing through a serverSideProcessingTimeout.
118+
* 2) Expects one of the command payload structs as commandPayload
119+
* 3) On success, returns an instance of responseClass via the completion (or
120+
* nil if there is no responseClass, which indicates a status-only command).
121+
*/
122+
- (void)_invokeKnownCommandWithEndpointID:(NSNumber *)endpointID
123+
clusterID:(NSNumber *)clusterID
124+
commandID:(NSNumber *)commandID
125+
commandPayload:(id)commandPayload
126+
timedInvokeTimeout:(NSNumber * _Nullable)timeout
127+
serverSideProcessingTimeout:(NSNumber * _Nullable)serverSideProcessingTimeout
128+
responseClass:(Class _Nullable)responseClass
129+
queue:(dispatch_queue_t)queue
130+
completion:(void (^)(id _Nullable response, NSError * _Nullable error))completion;
131+
114132
@end
115133

116134
@interface MTRClusterPath ()

src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt

+32-54
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#import "NSStringSpanConversion.h"
1515
#import "NSDataSpanConversion.h"
1616

17+
#include <app-common/zap-generated/cluster-objects.h>
1718
#include <controller/CHIPCluster.h>
1819
#include <lib/support/CHIPListUtils.h>
1920
#include <platform/CHIPDeviceLayer.h>
@@ -53,7 +54,6 @@ using chip::System::Clock::Seconds16;
5354
{{! This is used as the implementation for both the new-name and old-name bits, so check for both here. }}
5455
{{#if (or (isSupported cluster command=command)
5556
(isSupported (compatClusterNameRemapping parent.name) command=(compatCommandNameRemapping parent.name name)))}}
56-
{{#*inline "callbackName"}}{{#if hasSpecificResponse}}{{cluster}}Cluster{{asUpperCamelCase responseName preserveAcronyms=true}}{{else}}CommandSuccess{{/if}}{{/inline}}
5757
{{#*inline "paramsType"}}
5858
{{#unless (isSupported cluster command=command)}}
5959
MTR{{compatClusterNameRemapping parent.name}}Cluster{{compatCommandNameRemapping parent.name name}}Params
@@ -69,61 +69,39 @@ MTR{{cluster}}Cluster{{command}}Params
6969
{{/unless}}
7070
- (void){{asLowerCamelCase name}}WithParams: ({{> paramsType}} * {{#unless commandHasRequiredField}}_Nullable{{/unless}})params completion:({{>command_completion_type command=.}})completion
7171
{
72-
// Make a copy of params before we go async.
73-
params = [params copy];
74-
auto * bridge = new MTR{{>callbackName}}CallbackBridge(self.callbackQueue,
75-
{{#if hasSpecificResponse}}
76-
{{! This treats completion as taking an id for the data. This is
77-
not great from a type-safety perspective, of course. }}
78-
completion,
79-
{{else}}
80-
{{! For now, don't change the bridge API; instead just use an adapter
81-
to invoke our completion handler. This is not great from a
82-
type-safety perspective, of course. }}
83-
^(id _Nullable value, NSError * _Nullable error) {
84-
completion(error);
85-
},
86-
{{/if}}
87-
^(ExchangeManager & exchangeManager, const SessionHandle & session, {{>callbackName}}CallbackType successCb, MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) {
88-
auto * typedBridge = static_cast<MTR{{>callbackName}}CallbackBridge *>(bridge);
89-
Optional<uint16_t> timedInvokeTimeoutMs;
90-
Optional<Timeout> invokeTimeout;
91-
ListFreer listFreer;
92-
{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type request;
93-
if (params != nil) {
94-
if (params.timedInvokeTimeoutMs != nil) {
95-
params.timedInvokeTimeoutMs = MTRClampedNumber(params.timedInvokeTimeoutMs, @(1), @(UINT16_MAX));
96-
timedInvokeTimeoutMs.SetValue(params.timedInvokeTimeoutMs.unsignedShortValue);
97-
}
98-
if (params.serverSideProcessingTimeout != nil) {
99-
// Clamp to a number of seconds that will not overflow 32-bit
100-
// int when converted to ms.
101-
auto * serverSideProcessingTimeout = MTRClampedNumber(params.serverSideProcessingTimeout, @(0), @(UINT16_MAX));
102-
invokeTimeout.SetValue(Seconds16(serverSideProcessingTimeout.unsignedShortValue));
103-
}
104-
}
105-
{{#if mustUseTimedInvoke}}
106-
if (!timedInvokeTimeoutMs.HasValue()) {
107-
timedInvokeTimeoutMs.SetValue(10000);
108-
}
72+
if (params == nil) {
73+
params = [[{{> paramsType}} alloc] init];
74+
}
75+
76+
auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) {
77+
{{#if hasSpecificResponse}}
78+
completion(response, error);
79+
{{else}}
80+
completion(error);
10981
{{/if}}
110-
{{#zcl_command_arguments}}
111-
{{#first}}
112-
{{#unless parent.commandHasRequiredField}}
113-
if (params != nil) {
114-
{{/unless}}
115-
{{/first}}
116-
{{>encode_value target=(concat "request." (asLowerCamelCase label)) source=(concat "params." (asStructPropertyName label)) cluster=parent.parent.name errorCode="return CHIP_ERROR_INVALID_ARGUMENT;" depth=0}}
117-
{{#last}}
118-
{{#unless parent.commandHasRequiredField}}
119-
}
120-
{{/unless}}
121-
{{/last}}
122-
{{/zcl_command_arguments}}
82+
};
12383

124-
return MTRStartInvokeInteraction(typedBridge, request, exchangeManager, session, successCb, failureCb, self.endpoint, timedInvokeTimeoutMs, invokeTimeout);
125-
});
126-
std::move(*bridge).DispatchAction(self.device);
84+
auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs;
85+
{{#if mustUseTimedInvoke}}
86+
if (timedInvokeTimeoutMs == nil) {
87+
timedInvokeTimeoutMs = @(10000);
88+
}
89+
{{/if}}
90+
91+
using RequestType = {{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type;
92+
[self.device _invokeKnownCommandWithEndpointID:@(self.endpoint)
93+
clusterID:@(RequestType::GetClusterId())
94+
commandID:@(RequestType::GetCommandId())
95+
commandPayload:params
96+
timedInvokeTimeout:timedInvokeTimeoutMs
97+
serverSideProcessingTimeout:params.serverSideProcessingTimeout
98+
{{#if hasSpecificResponse}}
99+
responseClass:MTR{{cluster}}Cluster{{asUpperCamelCase responseName preserveAcronyms=true}}Params.class
100+
{{else}}
101+
responseClass:nil
102+
{{/if}}
103+
queue:self.callbackQueue
104+
completion:responseHandler];
127105
}
128106
{{/if}}
129107
{{/inline}}

src/darwin/Framework/CHIP/templates/MTRCallbackBridge-src.zapt

-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include <lib/support/TypeTraits.h>
1111

1212
{{#>MTRCallbackBridge partial-type="Status" }}DefaultSuccessCallback{{/MTRCallbackBridge}}
13-
{{#>MTRCallbackBridge partial-type="CommandStatus" }}CommandSuccessCallback{{/MTRCallbackBridge}}
1413
{{#>MTRCallbackBridge type="Octet_String" isNullable=false ns="chip"}}OctetStringAttributeCallback{{/MTRCallbackBridge}}
1514
{{#>MTRCallbackBridge type="Octet_String" isNullable=true ns="chip"}}NullableOctetStringAttributeCallback{{/MTRCallbackBridge}}
1615
{{#>MTRCallbackBridge type="Char_String" isNullable=false ns="chip"}}CharStringAttributeCallback{{/MTRCallbackBridge}}
@@ -57,14 +56,6 @@
5756
{{/zcl_attributes_server}}
5857
{{/zcl_clusters}}
5958

60-
{{#zcl_clusters}}
61-
{{#zcl_command_responses}}
62-
{{#if (isSupported (asUpperCamelCase ../name preserveAcronyms=true) command=(asUpperCamelCase name preserveAcronyms=true))}}
63-
{{#>MTRCallbackBridge partial-type="Command" }}{{asUpperCamelCase ../../name preserveAcronyms=true}}Cluster{{asUpperCamelCase ../name preserveAcronyms=true}}Callback{{/MTRCallbackBridge}}
64-
{{/if}}
65-
{{/zcl_command_responses}}
66-
{{/zcl_clusters}}
67-
6859
{{#zcl_clusters}}
6960
{{#zcl_enums}}
7061
{{#if (isSupported (asUpperCamelCase parent.name preserveAcronyms=true) enum=(asUpperCamelCase name preserveAcronyms=true))}}

src/darwin/Framework/CHIP/templates/MTRCallbackBridge.zapt

-19
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,11 @@
88
#include <app/util/im-client-callbacks.h>
99
#include <app-common/zap-generated/cluster-objects.h>
1010

11-
typedef void (*CommandSuccessCallback)(void *, const chip::app::DataModel::NullObjectType &);
12-
using CommandSuccessCallbackType = CommandSuccessCallback;
1311
typedef void (*DefaultSuccessCallbackType)(void *);
1412

1513
typedef void (*VendorIdAttributeCallback)(void *, chip::VendorId);
1614
typedef void (*NullableVendorIdAttributeCallback)(void *, const chip::app::DataModel::Nullable<chip::VendorId> &);
1715

18-
{{#zcl_clusters}}
19-
{{#zcl_command_responses}}
20-
{{#if (isSupported (asUpperCamelCase parent.name preserveAcronyms=true) command=(asUpperCamelCase name preserveAcronyms=true))}}
21-
typedef void (*{{asUpperCamelCase parent.name preserveAcronyms=true}}Cluster{{asUpperCamelCase name preserveAcronyms=true}}CallbackType)(void *, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType &);
22-
{{/if}}
23-
{{/zcl_command_responses}}
24-
{{/zcl_clusters}}
25-
2616
{{#zcl_clusters}}
2717
{{#zcl_enums}}
2818
{{#if (isSupported (asUpperCamelCase parent.name preserveAcronyms=true) enum=(asUpperCamelCase name preserveAcronyms=true))}}
@@ -50,7 +40,6 @@ typedef void (*{{asUpperCamelCase parent.name preserveAcronyms=true}}{{asUpperCa
5040
{{/zcl_clusters}}
5141

5242
{{#>MTRCallbackBridge header="1" partial-type="Status" }}DefaultSuccessCallback{{/MTRCallbackBridge}}
53-
{{#>MTRCallbackBridge header="1" partial-type="CommandStatus" }}CommandSuccessCallback{{/MTRCallbackBridge}}
5443
{{#>MTRCallbackBridge header="1" type="Octet_String" isNullable=false ns="chip"}}OctetStringAttributeCallback{{/MTRCallbackBridge}}
5544
{{#>MTRCallbackBridge header="1" type="Octet_String" isNullable=true ns="chip"}}NullableOctetStringAttributeCallback{{/MTRCallbackBridge}}
5645
{{#>MTRCallbackBridge header="1" type="Char_String" isNullable=false ns="chip"}}CharStringAttributeCallback{{/MTRCallbackBridge}}
@@ -97,14 +86,6 @@ typedef void (*{{asUpperCamelCase parent.name preserveAcronyms=true}}{{asUpperCa
9786
{{/zcl_attributes_server}}
9887
{{/zcl_clusters}}
9988

100-
{{#zcl_clusters}}
101-
{{#zcl_command_responses}}
102-
{{#if (isSupported (asUpperCamelCase parent.name preserveAcronyms=true) command=(asUpperCamelCase name preserveAcronyms=true))}}
103-
{{#>MTRCallbackBridge header="1" partial-type="Command" provisional=(isProvisional (asUpperCamelCase parent.name preserveAcronyms=true) command=(asUpperCamelCase name preserveAcronyms=true))}}{{asUpperCamelCase ../../name preserveAcronyms=true}}Cluster{{asUpperCamelCase ../name preserveAcronyms=true}}Callback{{/MTRCallbackBridge}}
104-
{{/if}}
105-
{{/zcl_command_responses}}
106-
{{/zcl_clusters}}
107-
10889
{{#zcl_clusters}}
10990
{{#zcl_enums}}
11091
{{#if (isSupported (asUpperCamelCase parent.name preserveAcronyms=true) enum=(asUpperCamelCase name preserveAcronyms=true))}}

src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt

+5-16
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
#import "MTRCommandPayloadsObjc.h"
1212
#import "MTRLogging_Internal.h"
1313

14+
#include <app-common/zap-generated/cluster-objects.h>
1415
#include <platform/CHIPDeviceLayer.h>
16+
1517
#include <type_traits>
1618

1719
using chip::Callback::Callback;
@@ -54,20 +56,6 @@ MTR{{compatClusterNameRemapping parent.name}}Cluster{{compatCommandNameRemapping
5456
MTR{{cluster}}Cluster{{command}}Params
5557
{{/unless}}
5658
{{/inline}}
57-
{{#*inline "clusterId"}}
58-
{{#unless (isSupported cluster command=command)}}
59-
{{asMEI ../manufacturerCode ../code}}
60-
{{else}}
61-
MTRClusterIDType{{cluster}}ID
62-
{{/unless}}
63-
{{/inline}}
64-
{{#*inline "commandId"}}
65-
{{#unless (isSupported cluster command=command)}}
66-
{{asMEI manufacturerCode code}}
67-
{{else}}
68-
MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
69-
{{/unless}}
70-
{{/inline}}
7159
{{#unless hasArguments}}
7260
- (void){{asLowerCamelCase name}}WithExpectedValues:(NSArray<NSDictionary<NSString *, id> *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:({{>command_completion_type command=.}})completion
7361
{
@@ -95,9 +83,10 @@ MTRCommandIDTypeCluster{{cluster}}Command{{command}}ID
9583
}
9684
{{/if}}
9785

86+
using RequestType = {{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type;
9887
[self.device _invokeKnownCommandWithEndpointID:@(self.endpoint)
99-
clusterID:@({{> clusterId}})
100-
commandID:@({{> commandId}})
88+
clusterID:@(RequestType::GetClusterId())
89+
commandID:@(RequestType::GetCommandId())
10190
commandPayload:params
10291
expectedValues:expectedValues
10392
expectedValueInterval:expectedValueIntervalMs

0 commit comments

Comments
 (0)