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: Pass event timestamp to MTRDeviceDelegate #24858

Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Address PR comments
jtung-apple committed Feb 4, 2023
commit 27bc928a5d2d8bc1ece1af5ac25d8cc4df04db9a
25 changes: 15 additions & 10 deletions src/darwin/Framework/CHIP/MTRBaseDevice.h
Original file line number Diff line number Diff line change
@@ -429,20 +429,26 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
@property (nonatomic, readonly, copy, nullable) NSError * error;
@end

typedef NS_ENUM(NSUInteger, MTREventTimeType) { MTREventTimeTypeSystemUpTime = 0, MTREventTimeTypeTimestampDate };
typedef NS_ENUM(NSUInteger, MTREventTimeType) {
MTREventTimeTypeSystemUpTime = 0,
MTREventTimeTypeTimestampDate
} MTR_NEWLY_AVAILABLE;

typedef NS_ENUM(NSUInteger, MTREventPriority) {
MTREventPriorityDebug = 0,
MTREventPriorityInfo = 1,
MTREventPriorityCritical = 2
} MTR_NEWLY_AVAILABLE;

@interface MTREventReport : NSObject
@property (nonatomic, readonly, copy) MTREventPath * path;
@property (nonatomic, readonly, copy) NSNumber * eventNumber; // EventNumber type (uint64_t)
@property (nonatomic, readonly, copy) NSNumber * priority; // PriorityLevel type (uint8_t)
@property (nonatomic, readonly, copy) NSNumber * priority; // PriorityLevel type (MTREventPriority)

// Either systemUpTime or timestampDate will be valid depending on eventTimeType
@property (nonatomic, readonly) MTREventTimeType eventTimeType;
MTR_NEWLY_AVAILABLE;
@property (nonatomic, readonly) NSTimeInterval systemUpTime;
MTR_NEWLY_AVAILABLE;
@property (nonatomic, readonly, copy, nullable) NSDate * timestampDate;
MTR_NEWLY_AVAILABLE;
@property (nonatomic, readonly) MTREventTimeType eventTimeType MTR_NEWLY_AVAILABLE;
@property (nonatomic, readonly) NSTimeInterval systemUpTime MTR_NEWLY_AVAILABLE;
@property (nonatomic, readonly, copy, nullable) NSDate * timestampDate MTR_NEWLY_AVAILABLE;

// An instance of one of the event payload interfaces.
@property (nonatomic, readonly, copy) id value;
@@ -554,8 +560,7 @@ MTR_NEWLY_AVAILABLE;
@end

@interface MTREventReport (Deprecated)
@property (nonatomic, readonly, copy) NSNumber * timestamp;
MTR_NEWLY_DEPRECATED("Please use timestampDate and systemUpTime")
@property (nonatomic, readonly, copy) NSNumber * timestamp MTR_NEWLY_DEPRECATED("Please use timestampDate and systemUpTime");
@end

NS_ASSUME_NONNULL_END
28 changes: 14 additions & 14 deletions src/darwin/Framework/CHIP/MTRBaseDevice.mm
Original file line number Diff line number Diff line change
@@ -2050,24 +2050,25 @@ @interface MTREventReport () {
@implementation MTREventReport
- (instancetype)initWithPath:(const chip::app::ConcreteEventPath &)path
eventNumber:(NSNumber *)eventNumber
priority:(NSNumber *)priority
timestampType:(NSNumber *)timestampType
timestampValue:(NSNumber *)timestampValue
priority:(PriorityLevel)priority
timestamp:(const Timestamp &)timestamp
value:(id _Nullable)value
error:(NSError * _Nullable)error;
error:(NSError * _Nullable)error
{
if (self = [super init]) {
_path = [[MTREventPath alloc] initWithPath:path];
_eventNumber = eventNumber;
_priority = priority;
_timestampValue = timestampValue;
if ((Timestamp::Type) timestampType.unsignedIntegerValue == Timestamp::Type::kSystem) {
if (!MTRPriorityLevelIsValid(priority)) {
return nil;
}
_priority = @(MTREventPriorityForValidPriorityLevel(priority));
_timestampValue = @(timestamp.mValue);
if (timestamp.IsSystem()) {
_eventTimeType = MTREventTimeTypeSystemUpTime;
_systemUpTime = MTRTimeIntervalForEventTimestampValue(timestampValue.unsignedLongLongValue);
} else if ((Timestamp::Type) timestampType.unsignedIntegerValue == Timestamp::Type::kSystem) {
_systemUpTime = MTRTimeIntervalForEventTimestampValue(timestamp.mValue);
} else if (timestamp.IsEpoch()) {
_eventTimeType = MTREventTimeTypeTimestampDate;
_timestampDate =
[NSDate dateWithTimeIntervalSince1970:MTRTimeIntervalForEventTimestampValue(timestampValue.unsignedLongLongValue)];
_timestampDate = [NSDate dateWithTimeIntervalSince1970:MTRTimeIntervalForEventTimestampValue(timestamp.mValue)];
} else {
return nil;
}
@@ -2116,9 +2117,8 @@ - (NSNumber *)timestamp

[mEventReports addObject:[[MTREventReport alloc] initWithPath:aEventHeader.mPath
eventNumber:@(aEventHeader.mEventNumber)
priority:@((uint8_t) aEventHeader.mPriorityLevel)
timestampType:@((NSUInteger) aEventHeader.mTimestamp.mType)
timestampValue:@(aEventHeader.mTimestamp.mValue)
priority:aEventHeader.mPriorityLevel
timestamp:aEventHeader.mTimestamp
value:value
error:error]];
}
6 changes: 3 additions & 3 deletions src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
#include <app/ConcreteCommandPath.h>
#include <app/ConcreteEventPath.h>
#include <app/DeviceProxy.h>
#include <app/EventLoggingTypes.h>

@class MTRDeviceController;

@@ -99,9 +100,8 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
@interface MTREventReport ()
- (instancetype)initWithPath:(const chip::app::ConcreteEventPath &)path
eventNumber:(NSNumber *)eventNumber
priority:(NSNumber *)priority
timestampType:(NSNumber *)timestampType
timestampValue:(NSNumber *)timestampValue
priority:(chip::app::PriorityLevel)priority
timestamp:(const chip::app::Timestamp &)timestamp
value:(id _Nullable)value
error:(NSError * _Nullable)error;
@end
19 changes: 10 additions & 9 deletions src/darwin/Framework/CHIP/MTRDevice.h
Original file line number Diff line number Diff line change
@@ -65,10 +65,12 @@ typedef NS_ENUM(NSUInteger, MTRDeviceState) {
/**
* The estimated device system start time.
*
* A device can reports its events with either calendar time or time since system start time. When events are reported with time
* A device can report its events with either calendar time or time since system start time. When events are reported with time
* since system start time, this property will return an estimation of the device system start time. Because a device may report
* timestamp this way due to the lack of a wall clock, system start time can only be estimated based on event receive time and the
* timestamp value, and this estimation may change over time, but only toward an earlier date.
* timestamps this way due to the lack of a wall clock, system start time can only be estimated based on event receive time and the
* timestamp value, and this estimation may change over time.
*
* Device reboots may also cause the estimated device start time to jump forward.
*
* If events are always reported with calendar time, then this property will return nil.
*/
@@ -208,14 +210,13 @@ extern NSString * const MTREventTimestampDateKey MTR_NEWLY_AVAILABLE;
* In addition to the MTREventPathKey and MTRDataKey containing the path and event values, eventReport also contains
* these keys:
*
* MTREventNumberKey : NSNumber-wrapped uint64_t value.
* MTREventPriorityKey : NSNumber-wrapped uint8_t value.
* MTREventTimeTypeKey : NSNumber-wrapped MTREventTimeType value.
* MTREventSystemUpTimeKey : NSNumber-wrapped NSTimeInterval value.
* MTREventTimestampDateKey : NSDate object.
* MTREventNumberKey : NSNumber-wrapped uint64_t value. Monotonically increasing, but consecutive events may not have
* consecutive numbers. MTREventPriorityKey : NSNumber-wrapped MTREventPriority value. MTREventTimeTypeKey : NSNumber-wrapped
* MTREventTimeType value. MTREventSystemUpTimeKey : NSNumber-wrapped NSTimeInterval value. MTREventTimestampDateKey : NSDate
* object.
*
* Only one of MTREventTimestampDateKey and MTREventSystemUpTimeKey will be present, depending on the value for
* MTREvenTimeTypeKey.
* MTREventTimeTypeKey.
*/
- (void)device:(MTRDevice *)device receivedEventReport:(NSArray<NSDictionary<NSString *, id> *> *)eventReport;

41 changes: 39 additions & 2 deletions src/darwin/Framework/CHIP/MTRDevice.mm
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
#import "MTRBaseDevice_Internal.h"
#import "MTRBaseSubscriptionCallback.h"
#import "MTRCluster.h"
#import "MTRClusterConstants.h"
#import "MTRDeviceController_Internal.h"
#import "MTRDevice_Internal.h"
#import "MTRError_Internal.h"
@@ -110,6 +111,11 @@ - (id)strongObject

NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue)
{
// Note: The event timestamp value as written in the spec is in microseconds, but the released 1.0 SDK implemented it in
// milliseconds. The following issue was filed to address the inconsistency:
// https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/6236
// For consistency with the released behavior, calculations here will be done in milliseconds.

// First convert the event timestamp value (in milliseconds) to NSTimeInterval - to minimize potential loss of precision
jtung-apple marked this conversation as resolved.
Show resolved Hide resolved
// of uint64 => NSTimeInterval (double), convert whole seconds and remainder separately and then combine
NSTimeInterval eventTimestampValueSeconds = (NSTimeInterval)(timeValue / chip::kMillisecondsPerSecond);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
@@ -120,6 +126,23 @@ NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue)
return eventTimestampValue;
}

BOOL MTRPriorityLevelIsValid(chip::app::PriorityLevel priorityLevel)
{
return (priorityLevel >= chip::app::PriorityLevel::Debug) && (priorityLevel <= chip::app::PriorityLevel::Critical);
}

MTREventPriority MTREventPriorityForValidPriorityLevel(chip::app::PriorityLevel priorityLevel)
{
switch (priorityLevel) {
case chip::app::PriorityLevel::Debug:
return MTREventPriorityDebug;
case chip::app::PriorityLevel::Info:
return MTREventPriorityInfo;
default:
return MTREventPriorityCritical;
}
}

#pragma mark - SubscriptionCallback class declaration
using namespace chip;
using namespace chip::app;
@@ -365,9 +388,17 @@ - (void)_handleEventReport:(NSArray<NSDictionary<NSString *, id> *> *)eventRepor
{
os_unfair_lock_lock(&self->_lock);

// If event time is of MTREventTimeTypeSystemUpTime type, then update estimated start time as needed
NSDate * oldEstimatedStartTime = _estimatedStartTime;
for (NSDictionary<NSString *, id> * eventDict in eventReport) {
// Whenever a StartUp event is received, reset the estimated start time
MTREventPath * eventPath = eventDict[MTREventPathKey];
BOOL isStartUpEvent = (eventPath.cluster.unsignedLongValue == MTRClusterIDTypeBasicInformationID)
&& (eventPath.event.unsignedLongValue == MTRClusterBasicEventStartUpID);
jtung-apple marked this conversation as resolved.
Show resolved Hide resolved
if (isStartUpEvent) {
_estimatedStartTime = nil;
}

// If event time is of MTREventTimeTypeSystemUpTime type, then update estimated start time as needed
NSNumber * eventTimeTypeNumber = eventDict[MTREventTimeTypeKey];
if (!eventTimeTypeNumber) {
MTR_LOG_ERROR("Event %@ missing event time type", eventDict);
@@ -1014,11 +1045,17 @@ - (void)invokeCommandWithEndpointID:(NSNumber *)endpointID
return;
}

if (!MTRPriorityLevelIsValid(aEventHeader.mPriorityLevel)) {
MTR_LOG_INFO("%@ Unsupported event priority %u - ignoring", eventPath, (unsigned int) aEventHeader.mPriorityLevel);
ReportError(CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
return;
}

[mEventReports addObject:@{
MTREventPathKey : eventPath,
MTRDataKey : value,
MTREventNumberKey : @(aEventHeader.mEventNumber),
MTREventPriorityKey : @((uint8_t) aEventHeader.mPriorityLevel),
MTREventPriorityKey : @(MTREventPriorityForValidPriorityLevel(aEventHeader.mPriorityLevel)),
MTREventTimeTypeKey : eventTimeType,
timestampKey : timestampValue
}];
4 changes: 4 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice_Internal.h
Original file line number Diff line number Diff line change
@@ -54,4 +54,8 @@ NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max);
#pragma mark - Utility for time conversion
NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue);

#pragma mark - Utility for event priority conversion
BOOL MTRPriorityLevelIsValid(chip::app::PriorityLevel priorityLevel);
MTREventPriority MTREventPriorityForValidPriorityLevel(chip::app::PriorityLevel);

NS_ASSUME_NONNULL_END