@@ -212,24 +212,9 @@ - (BOOL)isEqual:(id)object
212
212
@end
213
213
214
214
@interface MTRDevice ()
215
- // protects against concurrent time updates by guarding timeUpdateScheduled flag which manages time updates scheduling,
216
- // and protects device calls to setUTCTime and setDSTOffset. This can't just be replaced with "lock", because the time
217
- // update code calls public APIs like readAttributeWithEndpointID:.. (which attempt to take "lock") while holding
218
- // whatever lock protects the time sync bits.
219
- @property (nonatomic , readonly ) os_unfair_lock timeSyncLock;
220
215
221
216
@property (nonatomic ) chip::FabricIndex fabricIndex;
222
217
223
- // TODO: instead of all the BOOL properties that are some facet of the state, move to internal state machine that has (at least):
224
- // Actively receiving report
225
- // Actively receiving priming report
226
-
227
- @property (nonatomic ) MTRInternalDeviceState internalDeviceState;
228
-
229
- @property (nonatomic ) BOOL timeUpdateScheduled;
230
-
231
- @property (nonatomic ) NSMutableDictionary * temporaryMetaDataCache;
232
-
233
218
@end
234
219
235
220
// Declaring selector so compiler won't complain about testing and calling it in _handleReportEnd
@@ -316,7 +301,6 @@ - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControlle
316
301
{
317
302
if (self = [super init ]) {
318
303
_lock = OS_UNFAIR_LOCK_INIT;
319
- _timeSyncLock = OS_UNFAIR_LOCK_INIT;
320
304
_descriptionLock = OS_UNFAIR_LOCK_INIT;
321
305
_nodeID = [nodeID copy ];
322
306
_fabricIndex = controller.fabricIndex ;
@@ -325,7 +309,6 @@ - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControlle
325
309
= dispatch_queue_create (" org.csa-iot.matter.framework.device.workqueue" , DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
326
310
_asyncWorkQueue = [[MTRAsyncWorkQueue alloc ] initWithContext: self ];
327
311
_state = MTRDeviceStateUnknown;
328
- _internalDeviceState = MTRInternalDeviceStateUnsubscribed;
329
312
if (controller.controllerDataStore ) {
330
313
_persistedClusterData = [[NSCache alloc ] init ];
331
314
} else {
@@ -365,189 +348,6 @@ + (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControll
365
348
return [controller deviceForNodeID: nodeID];
366
349
}
367
350
368
- #pragma mark - Time Synchronization
369
-
370
- - (void )_setTimeOnDevice
371
- {
372
- NSDate * now = [NSDate date ];
373
- // If no date available, error
374
- if (!now) {
375
- MTR_LOG_ERROR (" %@ Could not retrieve current date. Unable to setUTCTime on endpoints." , self);
376
- return ;
377
- }
378
-
379
- uint64_t matterEpochTimeMicroseconds = 0 ;
380
- if (!DateToMatterEpochMicroseconds (now, matterEpochTimeMicroseconds)) {
381
- MTR_LOG_ERROR (" %@ Could not convert NSDate (%@) to Matter Epoch Time. Unable to setUTCTime on endpoints." , self, now);
382
- return ;
383
- }
384
-
385
- // Set Time on each Endpoint with a Time Synchronization Cluster Server
386
- NSArray <NSNumber *> * endpointsToSync = [self _endpointsWithTimeSyncClusterServer ];
387
- for (NSNumber * endpoint in endpointsToSync) {
388
- MTR_LOG_DEBUG (" %@ Setting Time on Endpoint %@" , self, endpoint);
389
- [self _setUTCTime: matterEpochTimeMicroseconds withGranularity: MTRTimeSynchronizationGranularityMicrosecondsGranularity forEndpoint: endpoint];
390
-
391
- // Check how many DST offsets this endpoint supports.
392
- auto dstOffsetsMaxSizePath = [MTRAttributePath attributePathWithEndpointID: endpoint clusterID: @(MTRClusterIDTypeTimeSynchronizationID) attributeID: @(MTRAttributeIDTypeClusterTimeSynchronizationAttributeDSTOffsetListMaxSizeID)];
393
- auto dstOffsetsMaxSize = [self readAttributeWithEndpointID: dstOffsetsMaxSizePath.endpoint clusterID: dstOffsetsMaxSizePath.cluster attributeID: dstOffsetsMaxSizePath.attribute params: nil ];
394
- if (dstOffsetsMaxSize == nil ) {
395
- // This endpoint does not support TZ, so won't support SetDSTOffset.
396
- MTR_LOG (" %@ Unable to SetDSTOffset on endpoint %@, since it does not support the TZ feature" , self, endpoint);
397
- continue ;
398
- }
399
- auto attrReport = [[MTRAttributeReport alloc ] initWithResponseValue: @{
400
- MTRAttributePathKey : dstOffsetsMaxSizePath,
401
- MTRDataKey : dstOffsetsMaxSize,
402
- }
403
- error: nil ];
404
- uint8_t maxOffsetCount;
405
- if (attrReport == nil ) {
406
- MTR_LOG_ERROR (" %@ DSTOffsetListMaxSize value on endpoint %@ is invalid. Defaulting to 1." , self, endpoint);
407
- maxOffsetCount = 1 ;
408
- } else {
409
- NSNumber * maxOffsetCountAsNumber = attrReport.value ;
410
- maxOffsetCount = maxOffsetCountAsNumber.unsignedCharValue ;
411
- if (maxOffsetCount == 0 ) {
412
- MTR_LOG_ERROR (" %@ DSTOffsetListMaxSize value on endpoint %@ is 0, which is not allowed. Defaulting to 1." , self, endpoint);
413
- maxOffsetCount = 1 ;
414
- }
415
- }
416
- auto * dstOffsets = MTRComputeDSTOffsets (maxOffsetCount);
417
- if (dstOffsets == nil ) {
418
- MTR_LOG_ERROR (" %@ Could not retrieve DST offset information. Unable to setDSTOffset on endpoint %@." , self, endpoint);
419
- continue ;
420
- }
421
-
422
- [self _setDSTOffsets: dstOffsets forEndpoint: endpoint];
423
- }
424
- }
425
-
426
- - (void )_scheduleNextUpdate : (UInt64 )nextUpdateInSeconds
427
- {
428
- mtr_weakify (self);
429
- dispatch_after (dispatch_time (DISPATCH_TIME_NOW, (int64_t ) (nextUpdateInSeconds * NSEC_PER_SEC)), self.queue , ^{
430
- MTR_LOG_DEBUG (" %@ Timer expired, start Device Time Update" , self);
431
- mtr_strongify (self);
432
- if (self) {
433
- [self _performScheduledTimeUpdate ];
434
- } else {
435
- MTR_LOG_DEBUG (" %@ MTRDevice no longer valid. No Timer Scheduled will be scheduled for a Device Time Update." , self);
436
- return ;
437
- }
438
- });
439
- self.timeUpdateScheduled = YES ;
440
- MTR_LOG_DEBUG (" %@ Timer Scheduled for next Device Time Update, in %llu seconds" , self, nextUpdateInSeconds);
441
- }
442
-
443
- // Time Updates are a day apart (this can be changed in the future)
444
- #define MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC (24 * 60 * 60 )
445
- // assume lock is held
446
- - (void )_updateDeviceTimeAndScheduleNextUpdate
447
- {
448
- os_unfair_lock_assert_owner (&self->_timeSyncLock );
449
- if (self.timeUpdateScheduled ) {
450
- MTR_LOG_DEBUG (" %@ Device Time Update already scheduled" , self);
451
- return ;
452
- }
453
-
454
- [self _setTimeOnDevice ];
455
- [self _scheduleNextUpdate: MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC];
456
- }
457
-
458
- - (void )_performScheduledTimeUpdate
459
- {
460
- std::lock_guard lock (_timeSyncLock);
461
- // Device needs to still be reachable
462
- if (self.state != MTRDeviceStateReachable) {
463
- MTR_LOG_DEBUG (" %@ Device is not reachable, canceling Device Time Updates." , self);
464
- return ;
465
- }
466
- // Device must not be invalidated
467
- if (!self.timeUpdateScheduled ) {
468
- MTR_LOG_DEBUG (" %@ Device Time Update is no longer scheduled, MTRDevice may have been invalidated." , self);
469
- return ;
470
- }
471
- self.timeUpdateScheduled = NO ;
472
- [self _updateDeviceTimeAndScheduleNextUpdate ];
473
- }
474
-
475
- - (NSArray <NSNumber *> *)_endpointsWithTimeSyncClusterServer
476
- {
477
- NSArray <NSNumber *> * endpointsOnDevice;
478
- {
479
- std::lock_guard lock (_lock);
480
- endpointsOnDevice = [self _endpointList ];
481
- }
482
-
483
- NSMutableArray <NSNumber *> * endpointsWithTimeSyncCluster = [[NSMutableArray <NSNumber *> alloc] init ];
484
- for (NSNumber * endpoint in endpointsOnDevice) {
485
- // Get list of server clusters on endpoint
486
- auto clusterList = [self readAttributeWithEndpointID: endpoint clusterID: @(MTRClusterIDTypeDescriptorID) attributeID: @(MTRAttributeIDTypeClusterDescriptorAttributeServerListID) params: nil ];
487
- NSArray <NSNumber *> * clusterArray = [self arrayOfNumbersFromAttributeValue: clusterList];
488
-
489
- if (clusterArray && [clusterArray containsObject: @(MTRClusterIDTypeTimeSynchronizationID)]) {
490
- [endpointsWithTimeSyncCluster addObject: endpoint];
491
- }
492
- }
493
- MTR_LOG_DEBUG (" %@ Device has following endpoints with Time Sync Cluster Server: %@" , self, endpointsWithTimeSyncCluster);
494
- return endpointsWithTimeSyncCluster;
495
- }
496
-
497
- - (void )_setUTCTime : (UInt64 )matterEpochTime withGranularity : (uint8_t )granularity forEndpoint : (NSNumber *)endpoint
498
- {
499
- MTR_LOG_DEBUG (" %@ _setUTCTime with matterEpochTime: %llu, endpoint %@" , self, matterEpochTime, endpoint);
500
- MTRTimeSynchronizationClusterSetUTCTimeParams * params = [[MTRTimeSynchronizationClusterSetUTCTimeParams
501
- alloc ] init ];
502
- params.utcTime = @(matterEpochTime);
503
- params.granularity = @(granularity);
504
- auto setUTCTimeResponseHandler = ^(id _Nullable response, NSError * _Nullable error) {
505
- if (error) {
506
- MTR_LOG_ERROR (" %@ _setUTCTime failed on endpoint %@, with parameters %@, error: %@" , self, endpoint, params, error);
507
- }
508
- };
509
-
510
- [self _invokeKnownCommandWithEndpointID: endpoint
511
- clusterID: @(MTRClusterIDTypeTimeSynchronizationID)
512
- commandID: @(MTRCommandIDTypeClusterTimeSynchronizationCommandSetUTCTimeID)
513
- commandPayload: params
514
- expectedValues: nil
515
- expectedValueInterval: nil
516
- timedInvokeTimeout: nil
517
- serverSideProcessingTimeout: params.serverSideProcessingTimeout
518
- responseClass: nil
519
- queue: self .queue
520
- completion: setUTCTimeResponseHandler];
521
- }
522
-
523
- - (void )_setDSTOffsets : (NSArray <MTRTimeSynchronizationClusterDSTOffsetStruct *> *)dstOffsets forEndpoint : (NSNumber *)endpoint
524
- {
525
- MTR_LOG_DEBUG (" %@ _setDSTOffsets with offsets: %@, endpoint %@" ,
526
- self, dstOffsets, endpoint);
527
-
528
- MTRTimeSynchronizationClusterSetDSTOffsetParams * params = [[MTRTimeSynchronizationClusterSetDSTOffsetParams
529
- alloc ] init ];
530
- params.dstOffset = dstOffsets;
531
-
532
- auto setDSTOffsetResponseHandler = ^(id _Nullable response, NSError * _Nullable error) {
533
- if (error) {
534
- MTR_LOG_ERROR (" %@ _setDSTOffsets failed on endpoint %@, with parameters %@, error: %@" , self, endpoint, params, error);
535
- }
536
- };
537
-
538
- [self _invokeKnownCommandWithEndpointID: endpoint
539
- clusterID: @(MTRClusterIDTypeTimeSynchronizationID)
540
- commandID: @(MTRCommandIDTypeClusterTimeSynchronizationCommandSetDSTOffsetID)
541
- commandPayload: params
542
- expectedValues: nil
543
- expectedValueInterval: nil
544
- timedInvokeTimeout: nil
545
- serverSideProcessingTimeout: params.serverSideProcessingTimeout
546
- responseClass: nil
547
- queue: self .queue
548
- completion: setDSTOffsetResponseHandler];
549
- }
550
-
551
351
- (NSMutableArray <NSNumber *> *)arrayOfNumbersFromAttributeValue : (MTRDeviceDataValueDictionary)dataDictionary
552
352
{
553
353
if (![MTRArrayValueType isEqual: dataDictionary[MTRTypeKey]]) {
@@ -756,14 +556,6 @@ - (void)_callFirstDelegateSynchronouslyWithBlock:(void (^)(id<MTRDeviceDelegate>
756
556
}
757
557
#endif
758
558
759
- #ifdef DEBUG
760
- - (MTRInternalDeviceState)_getInternalState
761
- {
762
- std::lock_guard lock (self->_lock );
763
- return _internalDeviceState;
764
- }
765
- #endif
766
-
767
559
- (BOOL )deviceUsesThread
768
560
{
769
561
std::lock_guard lock (_lock);
0 commit comments