Skip to content

Commit e52724f

Browse files
[Report Scheduler] Documentation update (project-chip#31430)
* Adressed comments regarding grammar and clarity of the ReportScheduler's documentation * Applied suggestion about resolved instead of removed
1 parent aee267d commit e52724f

5 files changed

+129
-87
lines changed

src/app/reporting/ReportScheduler.h

+34-27
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class TimerContext
5151
*
5252
* It inherits the ReadHandler::Observer class to be notified of reportability changes in the ReadHandlers.
5353
* It inherits the ICDStateObserver class to allow the implementation to generate reports based on the changes in ICD devices state,
54-
* such as going from idle to active and vice-versa.
54+
* such as going from idle to active mode and vice-versa.
5555
*
5656
* @note The logic for how and when to schedule reports is implemented in the subclasses of ReportScheduler, such as
5757
* ReportSchedulerImpl and SyncronizedReportSchedulerImpl.
@@ -70,7 +70,7 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
7070
/// @brief Start a timer for a given context. The report scheduler must always cancel an existing timer for a context (using
7171
/// CancelTimer) before starting a new one for that context.
7272
/// @param context context to pass to the timer callback.
73-
/// @param aTimeout time in miliseconds before the timer expires
73+
/// @param aTimeout time in milliseconds before the timer expires
7474
virtual CHIP_ERROR StartTimer(TimerContext * context, System::Clock::Timeout aTimeout) = 0;
7575
/// @brief Cancel a timer for a given context
7676
/// @param context used to identify the timer to cancel
@@ -82,25 +82,34 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
8282
/**
8383
* @class ReadHandlerNode
8484
*
85-
* @brief This class is in charge of determining when a ReadHandler is reportable depending on the monotonic timestamp of the
86-
* system and the intervals of the ReadHandler. It inherits the TimerContext class to allow it to be used as a context for a
87-
* TimerDelegate so the TimerDelegate can call the TimerFired method when the timer expires.
85+
* @brief This class is responsible for determining when a ReadHandler is reportable depending on the monotonic timestamp of
86+
* the system and the intervals of the ReadHandler. It inherits the TimerContext class to allow it to be used as a context for
87+
* a TimerDelegate so that the TimerDelegate can call the TimerFired method when the timer expires.
8888
*
89-
* The Logic to determine if a ReadHandler is reportable at a precise timestamp is as follows:
90-
* 1: The ReadHandler is in the CanStartReporting state
91-
* 2: The minimal interval since last report has elapsed
92-
* 3: The maximal interval since last report has elapsed or the ReadHandler is dirty
93-
* If the three conditions are met, the ReadHandler is reportable.
89+
* Three conditions that can prevent the ReadHandler from being reportable:
90+
* 1: The ReadHandler is not in the CanStartReporting state:
91+
* This condition can be resolved by setting the CanStartReporting flag on the ReadHandler
9492
*
95-
* Additionnal flags have been provided for specific use cases:
93+
* 2: The minimal interval since the last report has not elapsed
94+
* This condition can be resolved after enough time has passed since the last report or by setting the EngineRunScheduled
95+
* flag
9696
*
97-
* CanbeSynced: Mechanism to allow the ReadHandler to emit a report if another readHandler is ReportableNow.
98-
* This flag can substitute the maximal interval condition or the dirty condition. It is currently only used by the
99-
* SynchronizedReportScheduler.
97+
* 3: The maximal interval since the last report has not elapsed and the ReadHandler is not dirty:
98+
* This condition can be resolved after enough time has passed since the last report to reach the max interval, by the
99+
* ReadHandler becoming dirty or by setting the CanBeSynced flag and having another ReadHandler needing to report.
100+
*
101+
* Once the 3 conditions are met, the ReadHandler is considered reportable.
102+
*
103+
* Flags:
104+
*
105+
* CanBeSynced: Mechanism to allow the ReadHandler to emit a report if another readHandler is ReportableNow.
106+
* This flag is currently only used by the SynchronizedReportScheduler to allow firing reports of ReadHandlers at the same
107+
* time.
100108
*
101109
* EngineRunScheduled: Mechanism to ensure that the reporting engine will see the ReadHandler as reportable if a timer fires.
102-
* This flag can substitute the minimal interval condition or the maximal interval condition. The goal is to allow for
103-
* reporting when timers fire earlier than the minimal timestamp du to mechanism such as NTP clock adjustments.
110+
* This flag is used to confirm that the next report timer has fired for a ReadHandler, thus allowing reporting when timers
111+
* fire earlier than the minimal timestamp due to mechanisms such as NTP clock adjustments.
112+
*
104113
*/
105114
class ReadHandlerNode : public TimerContext
106115
{
@@ -125,12 +134,12 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
125134
ReadHandler * GetReadHandler() const { return mReadHandler; }
126135

127136
/// @brief Check if the Node is reportable now, meaning its readhandler was made reportable by attribute dirtying and
128-
/// handler state, and minimal time interval since last report has elapsed, or the maximal time interval since last
137+
/// handler state, and minimal time interval since the last report has elapsed, or the maximal time interval since the last
129138
/// report has elapsed.
130-
/// @note If a handler has been flaged as scheduled for engine run, it will be reported regardless of the timestamps. This
131-
/// is done to guarantee that the reporting engine will see the handler as reportable if a timer fires, even if it fires
132-
/// early.
133-
/// @param now current time to use for the check, user must ensure to provide a valid time for this to be reliable
139+
/// @note If a handler has been flagged as scheduled for an engine run, it will be reported regardless of the timestamps.
140+
/// This is done to guarantee that the reporting engine will see the handler as reportable if a timer fires, even if it
141+
/// fires early.
142+
/// @param now current time to use for the check, the user must ensure to provide a valid time for this to be reliable
134143
bool IsReportableNow(const Timestamp & now) const
135144
{
136145
return (mReadHandler->CanStartReporting() &&
@@ -149,8 +158,8 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
149158

150159
/// @brief Set the interval timestamps for the node based on the read handler reporting intervals
151160
/// @param aReadHandler read handler to get the intervals from
152-
/// @param now current time to calculate the mMin and mMax timestamps, user must ensure to provide a valid time for this to
153-
/// be reliable
161+
/// @param now current time to calculate the mMin and mMax timestamps, the user must ensure to provide a valid time for this
162+
/// to be reliable
154163
void SetIntervalTimeStamps(ReadHandler * aReadHandler, const Timestamp & now)
155164
{
156165
uint16_t minInterval, maxInterval;
@@ -178,9 +187,7 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
178187
};
179188

180189
ReportScheduler(TimerDelegate * aTimerDelegate) : mTimerDelegate(aTimerDelegate) {}
181-
/**
182-
* Interface to act on changes in the ReadHandler reportability
183-
*/
190+
184191
virtual ~ReportScheduler() = default;
185192

186193
virtual void ReportTimerCallback() = 0;
@@ -225,7 +232,7 @@ class ReportScheduler : public ReadHandler::Observer, public ICDStateObserver
225232

226233
/// @brief Find the ReadHandlerNode for a given ReadHandler pointer
227234
/// @param [in] aReadHandler ReadHandler pointer to look for in the ReadHandler nodes list
228-
/// @return Node Address if node was found, nullptr otherwise
235+
/// @return Node Address if the node was found, nullptr otherwise
229236
ReadHandlerNode * FindReadHandlerNode(const ReadHandler * aReadHandler)
230237
{
231238
ReadHandlerNode * foundNode = nullptr;

src/app/reporting/ReportSchedulerImpl.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ void ReportSchedulerImpl::OnSubscriptionReportSent(ReadHandler * aReadHandler)
9292

9393
Timestamp now = mTimerDelegate->GetCurrentMonotonicTimestamp();
9494

95+
// This method is called after the report is sent, so the ReadHandler is no longer reportable, and thus CanBeSynced and
96+
// EngineRunScheduled of the node associated with the ReadHandler are set to false here.
9597
node->SetCanBeSynced(false);
9698
node->SetIntervalTimeStamps(aReadHandler, now);
9799
Milliseconds32 newTimeout;

src/app/reporting/ReportSchedulerImpl.h

+44-31
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,33 @@ namespace reporting {
2929
*
3030
* @brief This class extends ReportScheduler and provides a scheduling logic for the CHIP Interaction Model Reporting Engine.
3131
*
32-
* It is reponsible for implementing the ReadHandler and ICD observers callbacks to the Scheduler can take actions whenever a
33-
* ReadHandler event occurs or the ICD changes modes.
32+
* It is responsible for implementing the ReadHandler and ICD observers callbacks so the Scheduler can take action whenever a
33+
* ReadHandler event occurs or the ICD mode change occurs.
3434
*
35-
* All ReadHandlers Observers callbacks rely on the node pool to create or find the node associated to the ReadHandler that
35+
* All ReadHandlers Observers callbacks rely on the node pool to create or find the node associated with the ReadHandler that
3636
* triggered the callback and will use the FindReadHandlerNode() method to do so.
3737
*
3838
* ## Scheduling Logic
3939
*
4040
* This class implements a scheduling logic that calculates the next report timeout based on the current system timestamp, the state
4141
* of the ReadHandlers associated with the scheduler nodes and the min and max intervals of the ReadHandlers.
4242
*
43-
* @note This class mimics the original scheduling in which the ReadHandlers would schedule themselves. The key difference is that
44-
* this implementation only relies on a single timer from the scheduling moment rather than having a timer expiring on the min
45-
* interval that would trigger the start of a second timer expiring on the max interval.
43+
* The logic is as follows:
44+
*
45+
* - When a ReadHandler is created for a subscription, the scheduler adds a node and registers it in the scheduler node pool.
46+
*
47+
* - Each node can schedule a report independently from the other nodes, and thus each node has its timer.
48+
*
49+
* - The timeout of each node timer is calculated when its associated ReadHandler becomes reportable, when a report is sent for
50+
* the ReadHandler.
51+
*
52+
* - The scheduler calculates the next report timeout of each node timer based on the current system timestamp and the state of the
53+
* ReadHandlers. If the ReadHandler is not reportable, the timeout is the difference between the next max interval and now. If the
54+
* ReadHandler is reportable, the timeout is the difference between the next min interval and now. If that min interval is in the
55+
* past, the scheduler directly calls the TimerFired() method instead of starting a timer.
56+
*
57+
*
58+
4659
*/
4760
class ReportSchedulerImpl : public ReportScheduler
4861
{
@@ -55,32 +68,35 @@ class ReportSchedulerImpl : public ReportScheduler
5568
// ICDStateObserver
5669

5770
/**
58-
* @brief When the ICD changes to Idle, no action is taken in this implementation.
71+
* @brief This implementation is not attempting any synchronization on external events as each Node is scheduled independently
72+
* solely based on its ReadHandler's state. Therefore, no synchronization action on the ICDState is needed in this
73+
* implementation.
5974
*/
6075
void OnTransitionToIdle() override{};
6176

6277
/**
63-
* @brief When the ICD changes to Active, this implementation will trigger a report emission on each ReadHandler that is not
64-
* blocked on its min interval.
78+
* @brief When the ICD transitions to Active mode, this implementation will trigger a report emission on each ReadHandler that
79+
* is not blocked by its min interval.
6580
*
66-
* @note Most action triggering a change to the Active mode already trigger a report emission, so this method is optionnal as it
67-
* might be redundant.
81+
* @note Most of the actions that trigger a change to the Active mode already trigger a report emission (e.g. Event or Attribute
82+
* change), so this method is optional as it might be redundant.
6883
*/
6984
void OnEnterActiveMode() override;
7085

7186
/**
72-
* @brief When the ICD changes operation mode, no action is taken in this implementation.
87+
* @brief Similar to the OnTransitionToIdle() method, this implementation does not attempt any synchronization on ICD events,
88+
* therefore no action is needed on the ICDModeChange() method.
7389
*/
7490
void OnICDModeChange() override{};
7591

7692
// ReadHandlerObserver
7793

7894
/**
79-
* @brief When a ReadHandler is added, adds a node and register it in the scheduler node pool. Scheduling the report here is
80-
* un-necessary since the ReadHandler will call MoveToState(HandlerState::CanStartReporting);, which will call
81-
* OnBecameReportable() and schedule the report.
95+
* @brief When a ReadHandler is created for a subscription, the scheduler adds a node and registers it in the scheduler node
96+
* pool. Scheduling the report here is unnecessary since the ReadHandler will call
97+
* MoveToState(HandlerState::CanStartReporting);, which will call OnBecameReportable() and schedule a report.
8298
*
83-
* @note This method sets a now Timestamp that is used to calculate the next report timeout.
99+
* @note This method sets a timestamp to the call time that is used as an input parameter by the ScheduleReport method.
84100
*/
85101
void OnSubscriptionEstablished(ReadHandler * aReadHandler) final;
86102

@@ -94,9 +110,6 @@ class ReportSchedulerImpl : public ReportScheduler
94110
/**
95111
* @brief When a ReadHandler report is sent, recalculate and reschedule the report.
96112
*
97-
* @note This method is called after the report is sent, so the ReadHandler is no longer reportable, and thus CanBeSynced and
98-
* EngineRunScheduled of the node associated to the ReadHandler are set to false in this method.
99-
*
100113
* @note This method sets a now Timestamp that is used to calculate the next report timeout.
101114
*/
102115
void OnSubscriptionReportSent(ReadHandler * aReadHandler) final;
@@ -106,22 +119,27 @@ class ReportSchedulerImpl : public ReportScheduler
106119
*/
107120
void OnReadHandlerDestroyed(ReadHandler * aReadHandler) override;
108121

122+
/**
123+
* @brief Checks if a report is scheduled for the ReadHandler by checking if the timer is active.
124+
*
125+
* @note If the CalculateNextReportTimeout outputs 0, the TimerFired() will be called directly instead of starting a timer,
126+
* so this method will return false.
127+
*/
109128
virtual bool IsReportScheduled(ReadHandler * aReadHandler);
110129

111130
void ReportTimerCallback() override;
112131

113132
protected:
114133
/**
115-
* @brief Schedule a report for the ReadHandler associated to the node.
134+
* @brief Schedule a report for the ReadHandler associated with a ReadHandlerNode.
116135
*
117-
* If a report is already scheduled for the ReadHandler, cancel it and schedule a new one.
118-
* If the timeout is 0, directly calls the TimerFired() method of the node instead of scheduling a report.
136+
* @note If a report is already scheduled for the ReadHandler, this method will cancel it and schedule a new one.
119137
*
120138
* @param[in] timeout The timeout to schedule the report.
121-
* @param[in] node The node associated to the ReadHandler.
139+
* @param[in] node The node associated with the ReadHandler.
122140
* @param[in] now The current system timestamp.
123141
*
124-
* @return CHIP_ERROR CHIP_NO_ERROR on success, timer related error code otherwise (This can only fail on starting the timer)
142+
* @return CHIP_ERROR CHIP_NO_ERROR on success, timer-related error code otherwise (This can only fail on starting the timer)
125143
*/
126144
virtual CHIP_ERROR ScheduleReport(Timeout timeout, ReadHandlerNode * node, const Timestamp & now);
127145
void CancelReport(ReadHandler * aReadHandler);
@@ -131,19 +149,14 @@ class ReportSchedulerImpl : public ReportScheduler
131149
friend class chip::app::reporting::TestReportScheduler;
132150

133151
/**
134-
* @brief Find the next timer when a report should be scheduled for a ReadHandler.
152+
* @brief Find the next timestamp when a report should be scheduled for a ReadHandler.
135153
*
136-
* @param[out] timeout The timeout to calculate.
154+
* @param[out] timeout The timeout calculated from the "now" timestamp provided as an input parameter.
137155
* @param[in] aNode The node associated to the ReadHandler.
138156
* @param[in] now The current system timestamp.
139157
*
140158
* @return CHIP_ERROR CHIP_NO_ERROR on success or CHIP_ERROR_INVALID_ARGUMENT if aNode is not in the pool.
141159
*
142-
* The logic is as follows:
143-
* - If the ReadHandler is reportable now, the timeout is 0.
144-
* - If the ReadHandler is reportable, but the current timestamp is earlier thant the next min interval's timestamp, the timeout
145-
* is the delta between the next min interval and now.
146-
* - If the ReadHandler is not reportable, the timeout is the difference between the next max interval and now.
147160
*/
148161
virtual CHIP_ERROR CalculateNextReportTimeout(Timeout & timeout, ReadHandlerNode * aNode, const Timestamp & now);
149162
};

0 commit comments

Comments
 (0)