Skip to content

Commit 5bb92b6

Browse files
authored
[Darwin] MTRDevice to persist data versions and use for subscription (#32153)
* [Darwin] MTRDevice to persist data versions and use for subscription * Fixed XPC connection bits
1 parent 7cb963e commit 5bb92b6

7 files changed

+251
-72
lines changed

src/darwin/Framework/CHIP/MTRBaseDevice.mm

+48-20
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,21 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
475475
}];
476476
}
477477

478+
static NSDictionary<NSString *, id> * _MakeDataValueDictionary(NSString * type, id _Nullable value, NSNumber * _Nullable dataVersion)
479+
{
480+
if (value && dataVersion) {
481+
return @ { MTRTypeKey : type, MTRValueKey : value, MTRDataVersionKey : dataVersion };
482+
} else if (value) {
483+
return @ { MTRTypeKey : type, MTRValueKey : value };
484+
} else if (dataVersion) {
485+
return @ { MTRTypeKey : type, MTRDataVersionKey : dataVersion };
486+
} else {
487+
return @ { MTRTypeKey : type };
488+
}
489+
}
490+
478491
// Convert TLV data into data-value dictionary as described in MTRDeviceResponseHandler
479-
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data)
492+
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data, NSNumber * dataVersion)
480493
{
481494
chip::TLV::TLVType dataTLVType = data->GetType();
482495
switch (dataTLVType) {
@@ -487,8 +500,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
487500
MTR_LOG_ERROR("Error(%s): TLV signed integer decoding failed", chip::ErrorStr(err));
488501
return nil;
489502
}
490-
return [NSDictionary dictionaryWithObjectsAndKeys:MTRSignedIntegerValueType, MTRTypeKey, [NSNumber numberWithLongLong:val],
491-
MTRValueKey, nil];
503+
return _MakeDataValueDictionary(MTRSignedIntegerValueType, @(val), dataVersion);
492504
}
493505
case chip::TLV::kTLVType_UnsignedInteger: {
494506
uint64_t val;
@@ -497,8 +509,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
497509
MTR_LOG_ERROR("Error(%s): TLV unsigned integer decoding failed", chip::ErrorStr(err));
498510
return nil;
499511
}
500-
return [NSDictionary dictionaryWithObjectsAndKeys:MTRUnsignedIntegerValueType, MTRTypeKey,
501-
[NSNumber numberWithUnsignedLongLong:val], MTRValueKey, nil];
512+
return _MakeDataValueDictionary(MTRUnsignedIntegerValueType, @(val), dataVersion);
502513
}
503514
case chip::TLV::kTLVType_Boolean: {
504515
bool val;
@@ -507,24 +518,22 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
507518
MTR_LOG_ERROR("Error(%s): TLV boolean decoding failed", chip::ErrorStr(err));
508519
return nil;
509520
}
510-
return [NSDictionary
511-
dictionaryWithObjectsAndKeys:MTRBooleanValueType, MTRTypeKey, [NSNumber numberWithBool:val], MTRValueKey, nil];
521+
return _MakeDataValueDictionary(MTRBooleanValueType, @(val), dataVersion);
512522
}
513523
case chip::TLV::kTLVType_FloatingPointNumber: {
514524
// Try float first
515525
float floatValue;
516526
CHIP_ERROR err = data->Get(floatValue);
517527
if (err == CHIP_NO_ERROR) {
518-
return @ { MTRTypeKey : MTRFloatValueType, MTRValueKey : [NSNumber numberWithFloat:floatValue] };
528+
return _MakeDataValueDictionary(MTRFloatValueType, @(floatValue), dataVersion);
519529
}
520530
double val;
521531
err = data->Get(val);
522532
if (err != CHIP_NO_ERROR) {
523533
MTR_LOG_ERROR("Error(%s): TLV floating point decoding failed", chip::ErrorStr(err));
524534
return nil;
525535
}
526-
return [NSDictionary
527-
dictionaryWithObjectsAndKeys:MTRDoubleValueType, MTRTypeKey, [NSNumber numberWithDouble:val], MTRValueKey, nil];
536+
return _MakeDataValueDictionary(MTRDoubleValueType, @(val), dataVersion);
528537
}
529538
case chip::TLV::kTLVType_UTF8String: {
530539
CharSpan stringValue;
@@ -538,7 +547,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
538547
MTR_LOG_ERROR("Error(%s): TLV UTF8String value is not actually UTF-8", err.AsString());
539548
return nil;
540549
}
541-
return @ { MTRTypeKey : MTRUTF8StringValueType, MTRValueKey : stringObj };
550+
return _MakeDataValueDictionary(MTRUTF8StringValueType, stringObj, dataVersion);
542551
}
543552
case chip::TLV::kTLVType_ByteString: {
544553
ByteSpan bytesValue;
@@ -547,10 +556,10 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
547556
MTR_LOG_ERROR("Error(%s): TLV ByteString decoding failed", chip::ErrorStr(err));
548557
return nil;
549558
}
550-
return @ { MTRTypeKey : MTROctetStringValueType, MTRValueKey : AsData(bytesValue) };
559+
return _MakeDataValueDictionary(MTROctetStringValueType, AsData(bytesValue), dataVersion);
551560
}
552561
case chip::TLV::kTLVType_Null: {
553-
return [NSDictionary dictionaryWithObjectsAndKeys:MTRNullValueType, MTRTypeKey, nil];
562+
return _MakeDataValueDictionary(MTRNullValueType, nil, dataVersion);
554563
}
555564
case chip::TLV::kTLVType_Structure:
556565
case chip::TLV::kTLVType_Array: {
@@ -606,7 +615,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
606615
MTR_LOG_ERROR("Error(%s): TLV container exiting failed", chip::ErrorStr(err));
607616
return nil;
608617
}
609-
return [NSDictionary dictionaryWithObjectsAndKeys:typeName, MTRTypeKey, array, MTRValueKey, nil];
618+
return _MakeDataValueDictionary(typeName, array, dataVersion);
610619
}
611620
default:
612621
MTR_LOG_ERROR("Error: Unsupported TLV type for conversion: %u", (unsigned) data->GetType());
@@ -815,7 +824,7 @@ CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const
815824
class BufferedReadClientCallback final : public app::ReadClient::Callback {
816825
public:
817826
using OnSuccessAttributeCallbackType
818-
= std::function<void(const ConcreteAttributePath & aPath, const DecodableValueType & aData)>;
827+
= std::function<void(const ConcreteDataAttributePath & aPath, const DecodableValueType & aData)>;
819828
using OnSuccessEventCallbackType = std::function<void(const EventHeader & aEventHeader, const DecodableValueType & aData)>;
820829
using OnErrorCallbackType = std::function<void(
821830
const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, CHIP_ERROR aError)>;
@@ -1027,6 +1036,16 @@ - (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attri
10271036
params:(MTRReadParams * _Nullable)params
10281037
queue:(dispatch_queue_t)queue
10291038
completion:(MTRDeviceResponseHandler)completion
1039+
{
1040+
[self readAttributePaths:attributePaths eventPaths:eventPaths params:params includeDataVersion:NO queue:queue completion:completion];
1041+
}
1042+
1043+
- (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attributePaths
1044+
eventPaths:(NSArray<MTREventRequestPath *> * _Nullable)eventPaths
1045+
params:(MTRReadParams * _Nullable)params
1046+
includeDataVersion:(BOOL)includeDataVersion
1047+
queue:(dispatch_queue_t)queue
1048+
completion:(MTRDeviceResponseHandler)completion
10301049
{
10311050
if ((attributePaths == nil || [attributePaths count] == 0) && (eventPaths == nil || [eventPaths count] == 0)) {
10321051
// No paths, just return an empty array.
@@ -1056,11 +1075,20 @@ - (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attri
10561075

10571076
auto resultArray = [[NSMutableArray alloc] init];
10581077
auto onAttributeSuccessCb
1059-
= [resultArray](const ConcreteAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) {
1060-
[resultArray addObject:@ {
1061-
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
1062-
MTRDataKey : aData.GetDecodedObject()
1063-
}];
1078+
= [resultArray, includeDataVersion](const ConcreteDataAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) {
1079+
// TODO: move this logic into MTRDataValueDictionaryDecodableType
1080+
if (includeDataVersion && aAttributePath.mDataVersion.HasValue()) {
1081+
NSDictionary * dataValue = aData.GetDecodedObject();
1082+
[resultArray addObject:@{
1083+
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
1084+
MTRDataKey : _MakeDataValueDictionary(dataValue[MTRTypeKey], dataValue[MTRValueKey], @(aAttributePath.mDataVersion.Value()))
1085+
}];
1086+
} else {
1087+
[resultArray addObject:@ {
1088+
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
1089+
MTRDataKey : aData.GetDecodedObject()
1090+
}];
1091+
}
10641092
};
10651093

10661094
auto onEventSuccessCb

src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
185185
queue:(dispatch_queue_t)queue
186186
completion:(void (^)(id _Nullable value, NSError * _Nullable error))completion;
187187

188+
/**
189+
* Same as the public -readAttributePaths:eventPaths:params:queue:completion: except also include the data version in the data-value dictionary in the response dictionary, if the includeDataVersion argument is set to YES.
190+
*/
191+
- (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attributePaths
192+
eventPaths:(NSArray<MTREventRequestPath *> * _Nullable)eventPaths
193+
params:(MTRReadParams * _Nullable)params
194+
includeDataVersion:(BOOL)includeDataVersion
195+
queue:(dispatch_queue_t)queue
196+
completion:(MTRDeviceResponseHandler)completion;
197+
188198
@end
189199

190200
@interface MTRClusterPath ()
@@ -228,7 +238,7 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
228238

229239
// Exported utility function
230240
// Convert TLV data into data-value dictionary as described in MTRDeviceResponseHandler
231-
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data);
241+
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data, NSNumber * _Nullable dataVersion = nil);
232242

233243
// Convert a data-value dictionary as described in MTRDeviceResponseHandler into
234244
// TLV Data with an anonymous tag. This method assumes the encoding of the

src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@
111111
}
112112

113113
VerifyOrDie((aReadPrepareParams.mDataVersionFilterListSize == 0 && aReadPrepareParams.mpDataVersionFilterList == nullptr)
114-
|| (aReadPrepareParams.mDataVersionFilterListSize == 1 && aReadPrepareParams.mpDataVersionFilterList != nullptr));
114+
|| (aReadPrepareParams.mDataVersionFilterListSize > 0 && aReadPrepareParams.mpDataVersionFilterList != nullptr));
115115
if (aReadPrepareParams.mpDataVersionFilterList != nullptr) {
116-
delete aReadPrepareParams.mpDataVersionFilterList;
116+
delete[] aReadPrepareParams.mpDataVersionFilterList;
117117
}
118118

119119
VerifyOrDie((aReadPrepareParams.mEventPathParamsListSize == 0 && aReadPrepareParams.mpEventPathParamsList == nullptr)

src/darwin/Framework/CHIP/MTRDevice.h

+5
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1))
350350
@end
351351

352352
MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE;
353+
MTR_EXTERN NSString * const MTRDataVersionKey MTR_NEWLY_AVAILABLE;
353354

354355
@protocol MTRDeviceDelegate <NSObject>
355356
@required
@@ -366,6 +367,10 @@ MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE;
366367
* In addition to MTRDataKey, each response-value dictionary in the array may also have this key:
367368
*
368369
* MTRPreviousDataKey : Same data-value dictionary format as the object for MTRDataKey. This is included when the previous value is known for an attribute.
370+
*
371+
* The data-value dictionary also contains this key:
372+
*
373+
* MTRDataVersionKey : NSNumber-wrapped uin32_t. Monotonically increaseing data version for the cluster.
369374
*/
370375
- (void)device:(MTRDevice *)device receivedAttributeReport:(NSArray<NSDictionary<NSString *, id> *> *)attributeReport;
371376

0 commit comments

Comments
 (0)