Skip to content

Commit

Permalink
[Darwin] MTRDevice should not always send reads to device directly (p…
Browse files Browse the repository at this point in the history
…roject-chip#26776)

* [Darwin] MTRDevice should not always send reads to device directly

* Update src/darwin/Framework/CHIP/MTRDevice.mm

Co-authored-by: Boris Zbarsky <[email protected]>

* Update src/darwin/Framework/CHIP/MTRDevice.mm

Co-authored-by: Boris Zbarsky <[email protected]>

* Update src/darwin/Framework/CHIP/MTRDevice.mm

Co-authored-by: Boris Zbarsky <[email protected]>

* Update src/darwin/Framework/CHIP/templates/MTRAttributeUtils-src.zapt

Co-authored-by: Boris Zbarsky <[email protected]>

* Address PR review comments

---------

Co-authored-by: Boris Zbarsky <[email protected]>
jtung-apple and bzbarsky-apple authored May 25, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 76ccf9d commit 49eae3a
Showing 6 changed files with 5,236 additions and 36 deletions.
25 changes: 25 additions & 0 deletions src/darwin/Framework/CHIP/MTRAttributeSpecifiedCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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.
*/

#pragma once

#import <Foundation/Foundation.h>

#include <lib/core/DataModelTypes.h>

BOOL MTRAttributeIsSpecified(chip::ClusterId aClusterId, chip::AttributeId aAttributeId);
217 changes: 182 additions & 35 deletions src/darwin/Framework/CHIP/MTRDevice.mm
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
#import <os/lock.h>

#import "MTRAsyncCallbackWorkQueue.h"
#import "MTRAttributeSpecifiedCheck.h"
#import "MTRBaseDevice_Internal.h"
#import "MTRBaseSubscriptionCallback.h"
#import "MTRCluster.h"
@@ -254,6 +255,13 @@ - (void)nodeMayBeAdvertisingOperational
}
}

// Return YES if there's a valid delegate AND subscription is expected to report value
- (BOOL)_subscriptionAbleToReport
{
// TODO: include period from when first report comes in until establish callback
return (_weakDelegate.strongObject) && (_state == MTRDeviceStateReachable);
}

// assume lock is held
- (void)_changeState:(MTRDeviceState)state
{
@@ -617,52 +625,191 @@ - (void)_setupSubscription
}

#pragma mark Device Interactions

// Helper function to determine whether an attribute has "Changes Omitted" quality, which indicates that past the priming report in
// a subscription, this attribute is not expected to be reported when its value changes
// * TODO: xml+codegen version to replace this hardcoded list.
static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath)
{
switch (attributePath.cluster.unsignedLongValue) {
case MTRClusterEthernetNetworkDiagnosticsID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterEthernetNetworkDiagnosticsAttributePacketRxCountID:
case MTRClusterEthernetNetworkDiagnosticsAttributePacketTxCountID:
case MTRClusterEthernetNetworkDiagnosticsAttributeTxErrCountID:
case MTRClusterEthernetNetworkDiagnosticsAttributeCollisionCountID:
case MTRClusterEthernetNetworkDiagnosticsAttributeOverrunCountID:
case MTRClusterEthernetNetworkDiagnosticsAttributeCarrierDetectID:
case MTRClusterEthernetNetworkDiagnosticsAttributeTimeSinceResetID:
return YES;
default:
return NO;
}
case MTRClusterGeneralDiagnosticsID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterGeneralDiagnosticsAttributeUpTimeID:
case MTRClusterGeneralDiagnosticsAttributeTotalOperationalHoursID:
return YES;
default:
return NO;
}
case MTRClusterThreadNetworkDiagnosticsID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterThreadNetworkDiagnosticsAttributeOverrunCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeDetachedRoleCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeChildRoleCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRouterRoleCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeLeaderRoleCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeAttachAttemptCountID:
case MTRClusterThreadNetworkDiagnosticsAttributePartitionIdChangeCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeBetterPartitionAttachAttemptCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeParentChangeCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxTotalCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxUnicastCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxBroadcastCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxAckRequestedCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxAckedCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxNoAckRequestedCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxDataCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxDataPollCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxBeaconCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxBeaconRequestCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxOtherCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxRetryCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxDirectMaxRetryExpiryCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxIndirectMaxRetryExpiryCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxErrCcaCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxErrAbortCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeTxErrBusyChannelCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxTotalCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxUnicastCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxBroadcastCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxDataCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxDataPollCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxBeaconCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxBeaconRequestCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxOtherCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxAddressFilteredCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxDestAddrFilteredCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxDuplicatedCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrNoFrameCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrUnknownNeighborCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrInvalidSrcAddrCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrSecCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrFcsCountID:
case MTRClusterThreadNetworkDiagnosticsAttributeRxErrOtherCountID:
return YES;
default:
return NO;
}
case MTRClusterWiFiNetworkDiagnosticsID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterWiFiNetworkDiagnosticsAttributeRssiID:
case MTRClusterWiFiNetworkDiagnosticsAttributeBeaconLostCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributeBeaconRxCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributePacketMulticastRxCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributePacketMulticastTxCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributePacketUnicastRxCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributePacketUnicastTxCountID:
case MTRClusterWiFiNetworkDiagnosticsAttributeCurrentMaxRateID:
case MTRClusterWiFiNetworkDiagnosticsAttributeOverrunCountID:
return YES;
default:
return NO;
}
case MTRClusterOperationalCredentialsID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterOperationalCredentialsAttributeNOCsID:
case MTRClusterOperationalCredentialsAttributeTrustedRootCertificatesID:
return YES;
default:
return NO;
}
case MTRClusterPowerSourceID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterPowerSourceAttributeWiredAssessedInputVoltageID:
case MTRClusterPowerSourceAttributeWiredAssessedInputFrequencyID:
case MTRClusterPowerSourceAttributeWiredAssessedCurrentID:
case MTRClusterPowerSourceAttributeBatVoltageID:
case MTRClusterPowerSourceAttributeBatPercentRemainingID:
case MTRClusterPowerSourceAttributeBatTimeRemainingID:
case MTRClusterPowerSourceAttributeBatTimeToFullChargeID:
case MTRClusterPowerSourceAttributeBatChargingCurrentID:
return YES;
default:
return NO;
}
case MTRClusterTimeSynchronizationID:
switch (attributePath.attribute.unsignedLongValue) {
case MTRClusterTimeSynchronizationAttributeUTCTimeID:
case MTRClusterTimeSynchronizationAttributeLocalTimeID:
return YES;
default:
return NO;
}
default:
return NO;
}
}

- (NSDictionary<NSString *, id> *)readAttributeWithEndpointID:(NSNumber *)endpointID
clusterID:(NSNumber *)clusterID
attributeID:(NSNumber *)attributeID
params:(MTRReadParams *)params
{
NSString * logPrefix = [NSString stringWithFormat:@"%@ read %@ %@ %@", self, endpointID, clusterID, attributeID];
// Create work item, set ready handler to perform task, then enqueue the work
MTRAsyncCallbackQueueWorkItem * workItem = [[MTRAsyncCallbackQueueWorkItem alloc] initWithQueue:self.queue];
MTRAsyncCallbackReadyHandler readyHandler = ^(MTRDevice * device, NSUInteger retryCount) {
MTR_LOG_DEFAULT("%@ dequeueWorkItem %@", logPrefix, self->_asyncCallbackWorkQueue);
MTRBaseDevice * baseDevice = [self newBaseDevice];
[baseDevice
readAttributesWithEndpointID:endpointID
clusterID:clusterID
attributeID:attributeID
params:params
queue:self.queue
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error) {
if (values) {
// Since the format is the same data-value dictionary, this looks like an attribute
// report
MTR_LOG_INFO("%@ completion values %@", logPrefix, values);
[self _handleAttributeReport:values];
}

// TODO: better retry logic
if (error && (retryCount < 2)) {
MTR_LOG_ERROR(
"%@ completion error %@ retryWork %lu", logPrefix, error, (unsigned long) retryCount);
[workItem retryWork];
} else {
MTR_LOG_DEFAULT("%@ completion error %@ endWork", logPrefix, error);
[workItem endWork];
}
}];
};
workItem.readyHandler = readyHandler;
MTR_LOG_DEFAULT("%@ enqueueWorkItem %@", logPrefix, _asyncCallbackWorkQueue);
[_asyncCallbackWorkQueue enqueueWorkItem:workItem];

// Return current known / expected value right away
MTRAttributePath * attributePath = [MTRAttributePath attributePathWithEndpointID:endpointID
clusterID:clusterID
attributeID:attributeID];

BOOL attributeIsSpecified = MTRAttributeIsSpecified(clusterID.unsignedIntValue, attributeID.unsignedIntValue);
BOOL hasChangesOmittedQuality = AttributeHasChangesOmittedQuality(attributePath);

// Return current known / expected value right away
NSDictionary<NSString *, id> * attributeValueToReturn = [self _attributeValueDictionaryForAttributePath:attributePath];

// Send read request to device if any of the following are true:
// 1. The attribute is not in the specification (so we don't know whether hasChangesOmittedQuality can be trusted).
// 2. Subscription not in a state we can expect reports
// 3. There is subscription but attribute has Changes Omitted quality
// 4. Cache has no entry
// TODO: add option for BaseSubscriptionCallback to report during priming, to reduce when case 4 is hit
if (!attributeIsSpecified || ![self _subscriptionAbleToReport] || hasChangesOmittedQuality || !attributeValueToReturn) {
// Create work item, set ready handler to perform task, then enqueue the work
MTRAsyncCallbackQueueWorkItem * workItem = [[MTRAsyncCallbackQueueWorkItem alloc] initWithQueue:self.queue];
MTRAsyncCallbackReadyHandler readyHandler = ^(MTRDevice * device, NSUInteger retryCount) {
MTR_LOG_DEFAULT("%@ dequeueWorkItem %@", logPrefix, self->_asyncCallbackWorkQueue);
MTRBaseDevice * baseDevice = [self newBaseDevice];
[baseDevice readAttributesWithEndpointID:endpointID
clusterID:clusterID
attributeID:attributeID
params:params
queue:self.queue
completion:^(NSArray<NSDictionary<NSString *, id> *> * _Nullable values,
NSError * _Nullable error) {
if (values) {
// Since the format is the same data-value dictionary, this looks like an
// attribute report
MTR_LOG_INFO("%@ completion values %@", logPrefix, values);
[self _handleAttributeReport:values];
}

// TODO: better retry logic
if (error && (retryCount < 2)) {
MTR_LOG_ERROR("%@ completion error %@ retryWork %lu", logPrefix, error,
(unsigned long) retryCount);
[workItem retryWork];
} else {
MTR_LOG_DEFAULT("%@ completion error %@ endWork", logPrefix, error);
[workItem endWork];
}
}];
};
workItem.readyHandler = readyHandler;
MTR_LOG_DEFAULT("%@ enqueueWorkItem %@", logPrefix, _asyncCallbackWorkQueue);
[_asyncCallbackWorkQueue enqueueWorkItem:workItem];
}

return attributeValueToReturn;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{{> header excludeZapComment=true}}

#import "MTRAttributeSpecifiedCheck.h"

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

using namespace chip;
using namespace chip::app;

{{#zcl_clusters}}
{{#if (isSupported (asUpperCamelCase name preserveAcronyms=true))}}
static BOOL AttributeIsSpecifiedIn{{asUpperCamelCase name preserveAcronyms=true}}Cluster(AttributeId aAttributeId)
{
using namespace Clusters::{{asUpperCamelCase name}};
switch (aAttributeId) {
{{#zcl_attributes_server}}
{{#if (isSupported (asUpperCamelCase ../name preserveAcronyms=true) attribute=(asUpperCamelCase name preserveAcronyms=true))}}
case Attributes::{{asUpperCamelCase name}}::Id: {
return YES;
}
{{/if}}
{{/zcl_attributes_server}}
default: {
return NO;
}
}
}
{{/if}}
{{/zcl_clusters}}

BOOL MTRAttributeIsSpecified(ClusterId aClusterId, AttributeId aAttributeId)
{
switch (aClusterId)
{
{{#zcl_clusters}}
{{#if (isSupported (asUpperCamelCase name preserveAcronyms=true))}}
case Clusters::{{asUpperCamelCase name}}::Id: {
return AttributeIsSpecifiedIn{{asUpperCamelCase name preserveAcronyms=true}}Cluster(aAttributeId);
}
{{/if}}
{{/zcl_clusters}}
default: {
return NO;
}
}
}
7 changes: 6 additions & 1 deletion src/darwin/Framework/CHIP/templates/templates.json
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@
},
{
"path": "MTRCommandPayloadsObjc-src.zapt",
"name": "Objc reflections of MTR command payloads header",
"name": "Objc reflections of MTR command payloads",
"output": "src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm"
},
{
@@ -132,6 +132,11 @@
"path": "MTRClusterConstants.zapt",
"name": "Constants for cluster IDs",
"output": "src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h"
},
{
"path": "MTRAttributeSpecifiedCheck-src.zapt",
"name": "Function to check if attribute is specified",
"output": "src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm"
}
]
}
4,966 changes: 4,966 additions & 0 deletions src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/darwin/Framework/Matter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -200,6 +200,8 @@
7596A8512878709F004DAE0E /* MTRAsyncCallbackQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7596A8502878709F004DAE0E /* MTRAsyncCallbackQueueTests.m */; };
7596A85528788557004DAE0E /* MTRClusters.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7596A85228788557004DAE0E /* MTRClusters.mm */; };
7596A85728788557004DAE0E /* MTRClusters.h in Headers */ = {isa = PBXBuildFile; fileRef = 7596A85428788557004DAE0E /* MTRClusters.h */; settings = {ATTRIBUTES = (Public, ); }; };
75B765C12A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 75B765C02A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h */; };
75B765C32A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm in Sources */ = {isa = PBXBuildFile; fileRef = 75B765C22A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm */; };
88EBF8CE27FABDD500686BC1 /* MTRDeviceAttestationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EBF8CB27FABDD500686BC1 /* MTRDeviceAttestationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
88EBF8CF27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 88EBF8CC27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm */; };
88EBF8D027FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EBF8CD27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h */; };
@@ -488,6 +490,9 @@
7596A8502878709F004DAE0E /* MTRAsyncCallbackQueueTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRAsyncCallbackQueueTests.m; sourceTree = "<group>"; };
7596A85228788557004DAE0E /* MTRClusters.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRClusters.mm; sourceTree = "<group>"; };
7596A85428788557004DAE0E /* MTRClusters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRClusters.h; sourceTree = "<group>"; };
75B765BF2A1D70F80014719B /* MTRAttributeSpecifiedCheck-src.zapt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "MTRAttributeSpecifiedCheck-src.zapt"; sourceTree = "<group>"; };
75B765C02A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRAttributeSpecifiedCheck.h; sourceTree = "<group>"; };
75B765C22A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttributeSpecifiedCheck.mm; sourceTree = "<group>"; };
88EBF8CB27FABDD500686BC1 /* MTRDeviceAttestationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationDelegate.h; sourceTree = "<group>"; };
88EBF8CC27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceAttestationDelegateBridge.mm; sourceTree = "<group>"; };
88EBF8CD27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationDelegateBridge.h; sourceTree = "<group>"; };
@@ -818,6 +823,7 @@
children = (
1EC3238C271999E2002A8BF0 /* cluster-objects.cpp */,
513DDB892761F6F900DAA01A /* MTRAttributeTLVValueDecoder.mm */,
75B765C22A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm */,
1EC4CE6325CC276600D7304F /* MTRBaseClusters.h */,
7596A83D28751220004DAE0E /* MTRBaseClusters_Internal.h */,
1EC4CE5925CC26E900D7304F /* MTRBaseClusters.mm */,
@@ -857,6 +863,7 @@
children = (
3D843723294984AF0070D20A /* templates.json */,
3D84371C294984AF0070D20A /* MTRAttributeTLVValueDecoder-src.zapt */,
75B765BF2A1D70F80014719B /* MTRAttributeSpecifiedCheck-src.zapt */,
3D843719294984AF0070D20A /* MTRBaseClusters.zapt */,
3D84371B294984AF0070D20A /* MTRBaseClusters_Internal.zapt */,
3D843724294984AF0070D20A /* MTRBaseClusters-src.zapt */,
@@ -927,6 +934,7 @@
27A53C1527FBC6920053F131 /* MTRAttestationTrustStoreBridge.h */,
27A53C1627FBC6920053F131 /* MTRAttestationTrustStoreBridge.mm */,
513DDB852761F69300DAA01A /* MTRAttributeTLVValueDecoder_Internal.h */,
75B765C02A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h */,
51E4D120291D0EB400C8C535 /* MTRBaseClusterUtils.h */,
2C222ADE255C811800E446B9 /* MTRBaseDevice_Internal.h */,
2C222ACE255C620600E446B9 /* MTRBaseDevice.h */,
@@ -1135,6 +1143,7 @@
51B22C222740CB1D008D5055 /* MTRCommandPayloadsObjc.h in Headers */,
51B22C1E2740CB0A008D5055 /* MTRStructsObjc.h in Headers */,
2CB7163B252E8A7B0026E2BB /* MTRDeviceControllerDelegateBridge.h in Headers */,
75B765C12A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h in Headers */,
5ACDDD7A27CD129700EFD68A /* MTRClusterStateCacheContainer.h in Headers */,
5A6FEC9227B5669C00F25F42 /* MTRDeviceControllerOverXPC.h in Headers */,
5117DD3929A931AE00FFA1AA /* MTROperationalBrowser.h in Headers */,
@@ -1402,6 +1411,7 @@
998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */,
5136661428067D550025EDAE /* MTRDeviceControllerFactory.mm in Sources */,
51B22C2A2740CB47008D5055 /* MTRCommandPayloadsObjc.mm in Sources */,
75B765C32A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm in Sources */,
AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */,
3D84374B29498BAE0070D20A /* privilege-storage.cpp in Sources */,
7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */,

0 comments on commit 49eae3a

Please sign in to comment.