Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
jtung-apple marked this conversation as resolved.
Show resolved Hide resolved
{
if (value && dataVersion) {
return @ { MTRTypeKey : type, MTRValueKey : value, MTRDataVersionKey : dataVersion };
jtung-apple marked this conversation as resolved.
Show resolved Hide resolved
} 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last arg should be annotated nullable, no?

{
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);
jtung-apple marked this conversation as resolved.
Show resolved Hide resolved

// 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"increasing".

Also, "monotonically increasing" is somewhere between "misleading" and "wrong". We should not claim it's increasing in our API documentation. It can easily decrease.

*/
- (void)device:(MTRDevice *)device receivedAttributeReport:(NSArray<NSDictionary<NSString *, id> *> *)attributeReport;

Expand Down
Loading
Loading