Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 05dc1b5

Browse files
authoredJul 23, 2024··
Merge branch 'master' into feature/app-install-flow-public
2 parents 79ef400 + f6022e4 commit 05dc1b5

17 files changed

+652
-100
lines changed
 

‎.github/workflows/tests.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ jobs:
576576
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_1.py'
577577
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_3.py'
578578
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_4.py'
579+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SC_7_1.py'
579580
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestConformanceSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
580581
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
581582
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestSpecParsingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
@@ -585,6 +586,7 @@ jobs:
585586
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestSpecParsingDeviceType.py'
586587
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestConformanceSupport.py'
587588
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/test_testing/test_IDM_10_4.py'
589+
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/test_testing/test_TC_SC_7_1.py'
588590
589591
- name: Uploading core files
590592
uses: actions/upload-artifact@v4

‎docs/guides/fabric_synchronization_guide.md

+22-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Fabric-Bridge-App example app implements the Aggregator device type with Fabric
1919
Synchronization condition met and demonstrates the end-to-end Fabric
2020
Synchronization feature using dynamic endpoints.
2121

22+
The Fabric-Admin and Fabric-Bridge-App example applications must be executed on
23+
the same physical device and communicate with each other using RPC.
24+
2225
Fabric Synchronization can be triggered from either side. The initiator of the
2326
Fabric Synchronization process, who shares their devices, takes on the
2427
Commissioner role. The recipient of the Fabric Synchronization request, who
@@ -82,11 +85,29 @@ fabricsync enable-auto-sync 1
8285
Pair the Fabric-Source bridge to Fabric-Sync with node ID 1:
8386

8487
```
85-
fabricsync add-bridge 1 <fabric-sink-ip>
88+
fabricsync add-bridge 1 <fabric-source-bridge-ip>
8689
```
8790

8891
### Pair Light Example to Fabric-Source
8992

93+
Since Fabric-Bridge also functions as a Matter server, running it alongside the
94+
Light Example app on the same machine would cause conflicts. Therefore, you need
95+
to run the Matter Light Example app on a separate physical machine from the one
96+
hosting Fabric-Admin and Fabric-Bridge. You can then commission the Matter Light
97+
Example app using Fabric-Admin on the source side.
98+
99+
There is a workaround to avoid conflicts when running multiple Matter server
100+
applications on the same machine, you can use different ports and unique
101+
Key-Value Store (KVS) paths for each app. Here's an example of how to launch a
102+
Light App with custom settings:
103+
104+
Light App with yet another set of different discriminator/passcode, ports and
105+
KVS
106+
107+
```
108+
./out/linux-x64-light-clang/chip-lighting-app --discriminator 3843 --passcode 20202023 --secured-device-port 5543 --unsecured-commissioner-port 5553 --KVS /tmp/chip_kvs_lighting_app
109+
```
110+
90111
Pair the Light Example with node ID 3 using its payload number:
91112

92113
```

‎scripts/setup/constraints.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ mobly==1.12.1
128128
# via -r requirements.all.txt
129129
msgpack==1.0.4
130130
# via cachecontrol
131-
mypy==0.971
131+
mypy==1.10.1
132132
# via -r requirements.all.txt
133133
mypy-extensions==1.0.0
134134
# via mypy

‎scripts/setup/requirements.all.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ appdirs
3838
coloredlogs
3939
watchdog
4040
build==0.8.0
41-
mypy==0.971
41+
mypy==1.10.1
4242
mypy-protobuf==3.5.0
4343
protobuf==4.24.4
4444
types-protobuf==4.24.0.2
@@ -50,4 +50,3 @@ colorama
5050

5151
# update tornado for pw_watch
5252
tornado
53-

‎src/app/tests/suites/certification/Test_TC_S_2_2.yaml

+16-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,20 @@ tests:
8181
value: maxScenesMinusOne / 2
8282

8383
- label:
84-
"Step 0a :TH sends KeySetWrite command in the GroupKeyManagement
84+
"Step 0a :TH reads attribute {ServerList} from the Descriptor cluster
85+
of the endpoint that implements the Scenes Management server on the
86+
DUT. DUT responds with a list of server clusters containing the groups
87+
cluster."
88+
cluster: "Descriptor"
89+
command: "readAttribute"
90+
attribute: "ServerList"
91+
response:
92+
constraints:
93+
type: list
94+
contains: [4]
95+
96+
- label:
97+
"Step 0b :TH sends KeySetWrite command in the GroupKeyManagement
8598
cluster to DUT using a key that is pre-installed on the TH.
8699
GroupKeySet fields are as follows:"
87100
cluster: "Group Key Management"
@@ -103,7 +116,7 @@ tests:
103116
}
104117

105118
- label:
106-
"Step 0b: TH binds GroupIds 0x0001 and 0x0002 with GroupKeySetID
119+
"Step 0c: TH binds GroupIds 0x0001 and 0x0002 with GroupKeySetID
107120
0x01a1 in the GroupKeyMap attribute list on GroupKeyManagement cluster
108121
by writing the GroupKeyMap attribute with two entries as follows:"
109122
cluster: "Group Key Management"
@@ -117,7 +130,7 @@ tests:
117130
{ FabricIndex: 1, GroupId: G2, GroupKeySetID: 0x01a1 },
118131
]
119132

120-
- label: "Step 0c: TH sends a RemoveAllGroups command to DUT."
133+
- label: "Step 0d: TH sends a RemoveAllGroups command to DUT."
121134
PICS: G.S.C04.Rsp
122135
cluster: "Groups"
123136
endpoint: endpoint

‎src/darwin/Framework/CHIP/MTRDevice.mm

+84-4
Original file line numberDiff line numberDiff line change
@@ -908,12 +908,17 @@ - (void)invalidate
908908
_reattemptingSubscription = NO;
909909

910910
[_deviceController asyncDispatchToMatterQueue:^{
911+
MTR_LOG("%@ invalidate disconnecting ReadClient and SubscriptionCallback", self);
912+
911913
// Destroy the read client and callback (has to happen on the Matter
912914
// queue, to avoid deleting objects that are being referenced), to
913915
// tear down the subscription. We will get no more callbacks from
914916
// the subscrption after this point.
915917
std::lock_guard lock(self->_lock);
916918
self->_currentReadClient = nullptr;
919+
if (self->_currentSubscriptionCallback) {
920+
delete self->_currentSubscriptionCallback;
921+
}
917922
self->_currentSubscriptionCallback = nullptr;
918923

919924
[self _changeInternalState:MTRInternalDeviceStateUnsubscribed];
@@ -940,6 +945,7 @@ - (void)nodeMayBeAdvertisingOperational
940945
// whether it might be.
941946
- (void)_triggerResubscribeWithReason:(NSString *)reason nodeLikelyReachable:(BOOL)nodeLikelyReachable
942947
{
948+
MTR_LOG("%@ _triggerResubscribeWithReason called with reason %@", self, reason);
943949
assertChipStackLockedByCurrentThread();
944950

945951
// We might want to trigger a resubscribe on our existing ReadClient. Do
@@ -1235,6 +1241,12 @@ - (void)_handleSubscriptionEstablished
12351241
- (void)_handleSubscriptionError:(NSError *)error
12361242
{
12371243
std::lock_guard lock(_lock);
1244+
[self _doHandleSubscriptionError:error];
1245+
}
1246+
1247+
- (void)_doHandleSubscriptionError:(NSError *)error
1248+
{
1249+
os_unfair_lock_assert_owner(&_lock);
12381250

12391251
[self _changeInternalState:MTRInternalDeviceStateUnsubscribed];
12401252
_unreportedEvents = nil;
@@ -1400,6 +1412,12 @@ - (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs
14001412
- (void)_handleSubscriptionReset:(NSNumber * _Nullable)retryDelay
14011413
{
14021414
std::lock_guard lock(_lock);
1415+
[self _doHandleSubscriptionReset:retryDelay];
1416+
}
1417+
1418+
- (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay
1419+
{
1420+
os_unfair_lock_assert_owner(&_lock);
14031421

14041422
// If we are here, then either we failed to establish initial CASE, or we
14051423
// failed to send the initial SubscribeRequest message, or our ReadClient
@@ -1471,7 +1489,7 @@ - (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason
14711489
return;
14721490
}
14731491

1474-
MTR_LOG("%@ reattempting subscription", self);
1492+
MTR_LOG("%@ reattempting subscription with reason %@", self, reason);
14751493
self.reattemptingSubscription = NO;
14761494
[self _setupSubscriptionWithReason:reason];
14771495
}
@@ -2100,6 +2118,22 @@ - (void)unitTestClearClusterData
21002118
}
21012119
#endif
21022120

2121+
- (void)_reconcilePersistedClustersWithStorage
2122+
{
2123+
os_unfair_lock_assert_owner(&self->_lock);
2124+
2125+
NSMutableSet * clusterPathsToRemove = [NSMutableSet set];
2126+
for (MTRClusterPath * clusterPath in _persistedClusters) {
2127+
MTRDeviceClusterData * data = [_deviceController.controllerDataStore getStoredClusterDataForNodeID:_nodeID endpointID:clusterPath.endpoint clusterID:clusterPath.cluster];
2128+
if (!data) {
2129+
[clusterPathsToRemove addObject:clusterPath];
2130+
}
2131+
}
2132+
2133+
MTR_LOG_ERROR("%@ Storage missing %lu / %lu clusters - reconciling in-memory records", self, static_cast<unsigned long>(clusterPathsToRemove.count), static_cast<unsigned long>(_persistedClusters.count));
2134+
[_persistedClusters minusSet:clusterPathsToRemove];
2135+
}
2136+
21032137
- (nullable MTRDeviceClusterData *)_clusterDataForPath:(MTRClusterPath *)clusterPath
21042138
{
21052139
os_unfair_lock_assert_owner(&self->_lock);
@@ -2132,8 +2166,16 @@ - (nullable MTRDeviceClusterData *)_clusterDataForPath:(MTRClusterPath *)cluster
21322166

21332167
// Page in the stored value for the data.
21342168
MTRDeviceClusterData * data = [_deviceController.controllerDataStore getStoredClusterDataForNodeID:_nodeID endpointID:clusterPath.endpoint clusterID:clusterPath.cluster];
2169+
MTR_LOG("%@ cluster path %@ cache miss - load from storage success %@", self, clusterPath, YES_NO(data));
21352170
if (data != nil) {
21362171
[_persistedClusterData setObject:data forKey:clusterPath];
2172+
} else {
2173+
// If clusterPath is in _persistedClusters and the data store returns nil for it, then the in-memory cache is now not dependable, and subscription should be reset and reestablished to reload cache from device
2174+
2175+
// First make sure _persistedClusters is consistent with storage, so repeated calls don't immediately re-trigger this
2176+
[self _reconcilePersistedClustersWithStorage];
2177+
2178+
[self _resetSubscriptionWithReasonString:[NSString stringWithFormat:@"Data store has no data for cluster %@", clusterPath]];
21372179
}
21382180

21392181
return data;
@@ -2303,13 +2345,43 @@ - (void)_stopConnectivityMonitoring
23032345
}
23042346
}
23052347

2348+
- (void)_resetSubscriptionWithReasonString:(NSString *)reasonString
2349+
{
2350+
os_unfair_lock_assert_owner(&self->_lock);
2351+
MTR_LOG_ERROR("%@ %@ - resetting subscription", self, reasonString);
2352+
2353+
[_deviceController asyncDispatchToMatterQueue:^{
2354+
MTR_LOG("%@ subscription reset disconnecting ReadClient and SubscriptionCallback", self);
2355+
2356+
std::lock_guard lock(self->_lock);
2357+
self->_currentReadClient = nullptr;
2358+
if (self->_currentSubscriptionCallback) {
2359+
delete self->_currentSubscriptionCallback;
2360+
}
2361+
self->_currentSubscriptionCallback = nullptr;
2362+
2363+
[self _doHandleSubscriptionError:nil];
2364+
// Use nil reset delay so that this keeps existing backoff timing
2365+
[self _doHandleSubscriptionReset:nil];
2366+
}
2367+
errorHandler:nil];
2368+
}
2369+
2370+
#ifdef DEBUG
2371+
- (void)unitTestResetSubscription
2372+
{
2373+
std::lock_guard lock(self->_lock);
2374+
[self _resetSubscriptionWithReasonString:@"Unit test reset subscription"];
2375+
}
2376+
#endif
2377+
23062378
// assume lock is held
23072379
- (void)_setupSubscriptionWithReason:(NSString *)reason
23082380
{
23092381
os_unfair_lock_assert_owner(&self->_lock);
23102382

23112383
if (![self _subscriptionsAllowed]) {
2312-
MTR_LOG("%@ _setupSubscription: Subscriptions not allowed. Do not set up subscription", self);
2384+
MTR_LOG("%@ _setupSubscription: Subscriptions not allowed. Do not set up subscription (reason: %@)", self, reason);
23132385
return;
23142386
}
23152387

@@ -2328,6 +2400,7 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
23282400

23292401
// for now just subscribe once
23302402
if (!NeedToStartSubscriptionSetup(_internalDeviceState)) {
2403+
MTR_LOG("%@ setupSubscription: no need to subscribe due to internal state %lu (reason: %@)", self, static_cast<unsigned long>(_internalDeviceState), reason);
23312404
return;
23322405
}
23332406

@@ -3758,14 +3831,21 @@ - (void)_storePersistedDeviceData
37583831
}
37593832

37603833
#ifdef DEBUG
3761-
- (MTRDeviceClusterData *)_getClusterDataForPath:(MTRClusterPath *)path
3834+
- (MTRDeviceClusterData *)unitTestGetClusterDataForPath:(MTRClusterPath *)path
37623835
{
37633836
std::lock_guard lock(_lock);
37643837

37653838
return [[self _clusterDataForPath:path] copy];
37663839
}
37673840

3768-
- (BOOL)_clusterHasBeenPersisted:(MTRClusterPath *)path
3841+
- (NSSet<MTRClusterPath *> *)unitTestGetPersistedClusters
3842+
{
3843+
std::lock_guard lock(_lock);
3844+
3845+
return [_persistedClusters copy];
3846+
}
3847+
3848+
- (BOOL)unitTestClusterHasBeenPersisted:(MTRClusterPath *)path
37693849
{
37703850
std::lock_guard lock(_lock);
37713851

0 commit comments

Comments
 (0)
Please sign in to comment.