Skip to content

Commit

Permalink
[Darwin] MTRDevice to persist data versions and use for subscription (#…
Browse files Browse the repository at this point in the history
…32153)

* [Darwin] MTRDevice to persist data versions and use for subscription

* Fixed XPC connection bits
  • Loading branch information
jtung-apple authored and pull[bot] committed Mar 3, 2024
1 parent 23d1b4a commit 8c20512
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 72 deletions.
68 changes: 48 additions & 20 deletions src/darwin/Framework/CHIP/MTRBaseDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,21 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
}];
}

static NSDictionary<NSString *, id> * _MakeDataValueDictionary(NSString * type, id _Nullable value, NSNumber * _Nullable dataVersion)
{
if (value && dataVersion) {
return @ { MTRTypeKey : type, MTRValueKey : value, MTRDataVersionKey : dataVersion };
} else if (value) {
return @ { MTRTypeKey : type, MTRValueKey : value };
} else if (dataVersion) {
return @ { MTRTypeKey : type, MTRDataVersionKey : dataVersion };
} else {
return @ { MTRTypeKey : type };
}
}

// Convert TLV data into data-value dictionary as described in MTRDeviceResponseHandler
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data)
NSDictionary<NSString *, id> * _Nullable MTRDecodeDataValueDictionaryFromCHIPTLV(chip::TLV::TLVReader * data, NSNumber * dataVersion)
{
chip::TLV::TLVType dataTLVType = data->GetType();
switch (dataTLVType) {
Expand All @@ -487,8 +500,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV signed integer decoding failed", chip::ErrorStr(err));
return nil;
}
return [NSDictionary dictionaryWithObjectsAndKeys:MTRSignedIntegerValueType, MTRTypeKey, [NSNumber numberWithLongLong:val],
MTRValueKey, nil];
return _MakeDataValueDictionary(MTRSignedIntegerValueType, @(val), dataVersion);
}
case chip::TLV::kTLVType_UnsignedInteger: {
uint64_t val;
Expand All @@ -497,8 +509,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV unsigned integer decoding failed", chip::ErrorStr(err));
return nil;
}
return [NSDictionary dictionaryWithObjectsAndKeys:MTRUnsignedIntegerValueType, MTRTypeKey,
[NSNumber numberWithUnsignedLongLong:val], MTRValueKey, nil];
return _MakeDataValueDictionary(MTRUnsignedIntegerValueType, @(val), dataVersion);
}
case chip::TLV::kTLVType_Boolean: {
bool val;
Expand All @@ -507,24 +518,22 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV boolean decoding failed", chip::ErrorStr(err));
return nil;
}
return [NSDictionary
dictionaryWithObjectsAndKeys:MTRBooleanValueType, MTRTypeKey, [NSNumber numberWithBool:val], MTRValueKey, nil];
return _MakeDataValueDictionary(MTRBooleanValueType, @(val), dataVersion);
}
case chip::TLV::kTLVType_FloatingPointNumber: {
// Try float first
float floatValue;
CHIP_ERROR err = data->Get(floatValue);
if (err == CHIP_NO_ERROR) {
return @ { MTRTypeKey : MTRFloatValueType, MTRValueKey : [NSNumber numberWithFloat:floatValue] };
return _MakeDataValueDictionary(MTRFloatValueType, @(floatValue), dataVersion);
}
double val;
err = data->Get(val);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Error(%s): TLV floating point decoding failed", chip::ErrorStr(err));
return nil;
}
return [NSDictionary
dictionaryWithObjectsAndKeys:MTRDoubleValueType, MTRTypeKey, [NSNumber numberWithDouble:val], MTRValueKey, nil];
return _MakeDataValueDictionary(MTRDoubleValueType, @(val), dataVersion);
}
case chip::TLV::kTLVType_UTF8String: {
CharSpan stringValue;
Expand All @@ -538,7 +547,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV UTF8String value is not actually UTF-8", err.AsString());
return nil;
}
return @ { MTRTypeKey : MTRUTF8StringValueType, MTRValueKey : stringObj };
return _MakeDataValueDictionary(MTRUTF8StringValueType, stringObj, dataVersion);
}
case chip::TLV::kTLVType_ByteString: {
ByteSpan bytesValue;
Expand All @@ -547,10 +556,10 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV ByteString decoding failed", chip::ErrorStr(err));
return nil;
}
return @ { MTRTypeKey : MTROctetStringValueType, MTRValueKey : AsData(bytesValue) };
return _MakeDataValueDictionary(MTROctetStringValueType, AsData(bytesValue), dataVersion);
}
case chip::TLV::kTLVType_Null: {
return [NSDictionary dictionaryWithObjectsAndKeys:MTRNullValueType, MTRTypeKey, nil];
return _MakeDataValueDictionary(MTRNullValueType, nil, dataVersion);
}
case chip::TLV::kTLVType_Structure:
case chip::TLV::kTLVType_Array: {
Expand Down Expand Up @@ -606,7 +615,7 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
MTR_LOG_ERROR("Error(%s): TLV container exiting failed", chip::ErrorStr(err));
return nil;
}
return [NSDictionary dictionaryWithObjectsAndKeys:typeName, MTRTypeKey, array, MTRValueKey, nil];
return _MakeDataValueDictionary(typeName, array, dataVersion);
}
default:
MTR_LOG_ERROR("Error: Unsupported TLV type for conversion: %u", (unsigned) data->GetType());
Expand Down Expand Up @@ -815,7 +824,7 @@ CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const
class BufferedReadClientCallback final : public app::ReadClient::Callback {
public:
using OnSuccessAttributeCallbackType
= std::function<void(const ConcreteAttributePath & aPath, const DecodableValueType & aData)>;
= std::function<void(const ConcreteDataAttributePath & aPath, const DecodableValueType & aData)>;
using OnSuccessEventCallbackType = std::function<void(const EventHeader & aEventHeader, const DecodableValueType & aData)>;
using OnErrorCallbackType = std::function<void(
const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, CHIP_ERROR aError)>;
Expand Down Expand Up @@ -1027,6 +1036,16 @@ - (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attri
params:(MTRReadParams * _Nullable)params
queue:(dispatch_queue_t)queue
completion:(MTRDeviceResponseHandler)completion
{
[self readAttributePaths:attributePaths eventPaths:eventPaths params:params includeDataVersion:NO queue:queue completion:completion];
}

- (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attributePaths
eventPaths:(NSArray<MTREventRequestPath *> * _Nullable)eventPaths
params:(MTRReadParams * _Nullable)params
includeDataVersion:(BOOL)includeDataVersion
queue:(dispatch_queue_t)queue
completion:(MTRDeviceResponseHandler)completion
{
if ((attributePaths == nil || [attributePaths count] == 0) && (eventPaths == nil || [eventPaths count] == 0)) {
// No paths, just return an empty array.
Expand Down Expand Up @@ -1056,11 +1075,20 @@ - (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attri

auto resultArray = [[NSMutableArray alloc] init];
auto onAttributeSuccessCb
= [resultArray](const ConcreteAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) {
[resultArray addObject:@ {
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
MTRDataKey : aData.GetDecodedObject()
}];
= [resultArray, includeDataVersion](const ConcreteDataAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) {
// TODO: move this logic into MTRDataValueDictionaryDecodableType
if (includeDataVersion && aAttributePath.mDataVersion.HasValue()) {
NSDictionary * dataValue = aData.GetDecodedObject();
[resultArray addObject:@{
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
MTRDataKey : _MakeDataValueDictionary(dataValue[MTRTypeKey], dataValue[MTRValueKey], @(aAttributePath.mDataVersion.Value()))
}];
} else {
[resultArray addObject:@ {
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
MTRDataKey : aData.GetDecodedObject()
}];
}
};

auto onEventSuccessCb
Expand Down
12 changes: 11 additions & 1 deletion src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
queue:(dispatch_queue_t)queue
completion:(void (^)(id _Nullable value, NSError * _Nullable error))completion;

/**
* 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.
*/
- (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attributePaths
eventPaths:(NSArray<MTREventRequestPath *> * _Nullable)eventPaths
params:(MTRReadParams * _Nullable)params
includeDataVersion:(BOOL)includeDataVersion
queue:(dispatch_queue_t)queue
completion:(MTRDeviceResponseHandler)completion;

@end

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

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

// Convert a data-value dictionary as described in MTRDeviceResponseHandler into
// TLV Data with an anonymous tag. This method assumes the encoding of the
Expand Down
4 changes: 2 additions & 2 deletions src/darwin/Framework/CHIP/MTRBaseSubscriptionCallback.mm
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@
}

VerifyOrDie((aReadPrepareParams.mDataVersionFilterListSize == 0 && aReadPrepareParams.mpDataVersionFilterList == nullptr)
|| (aReadPrepareParams.mDataVersionFilterListSize == 1 && aReadPrepareParams.mpDataVersionFilterList != nullptr));
|| (aReadPrepareParams.mDataVersionFilterListSize > 0 && aReadPrepareParams.mpDataVersionFilterList != nullptr));
if (aReadPrepareParams.mpDataVersionFilterList != nullptr) {
delete aReadPrepareParams.mpDataVersionFilterList;
delete[] aReadPrepareParams.mpDataVersionFilterList;
}

VerifyOrDie((aReadPrepareParams.mEventPathParamsListSize == 0 && aReadPrepareParams.mpEventPathParamsList == nullptr)
Expand Down
5 changes: 5 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1))
@end

MTR_EXTERN NSString * const MTRPreviousDataKey MTR_NEWLY_AVAILABLE;
MTR_EXTERN NSString * const MTRDataVersionKey MTR_NEWLY_AVAILABLE;

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

Expand Down
Loading

0 comments on commit 8c20512

Please sign in to comment.