Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2023 Project CHIP Authors 4 : * All rights reserved. 5 : * 6 : * Licensed under the Apache License, Version 2.0 (the "License"); 7 : * you may not use this file except in compliance with the License. 8 : * You may obtain a copy of the License at 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 12 : * Unless required by applicable law or agreed to in writing, software 13 : * distributed under the License is distributed on an "AS IS" BASIS, 14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 : * See the License for the specific language governing permissions and 16 : * limitations under the License. 17 : */ 18 : 19 : #pragma once 20 : 21 : #include <app/reporting/ReportScheduler.h> 22 : 23 : namespace chip { 24 : namespace app { 25 : namespace reporting { 26 : 27 : /** 28 : * @class ReportSchedulerImpl 29 : * 30 : * @brief This class extends ReportScheduler and provides a scheduling logic for the CHIP Interaction Model Reporting Engine. 31 : * 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. 34 : * 35 : * All ReadHandlers Observers callbacks rely on the node pool to create or find the node associated to the ReadHandler that 36 : * triggered the callback and will use the FindReadHandlerNode() method to do so. 37 : * 38 : * ## Scheduling Logic 39 : * 40 : * This class implements a scheduling logic that calculates the next report timeout based on the current system timestamp, the state 41 : * of the ReadHandlers associated with the scheduler nodes and the min and max intervals of the ReadHandlers. 42 : * 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. 46 : */ 47 : class ReportSchedulerImpl : public ReportScheduler 48 : { 49 : public: 50 : using Timeout = System::Clock::Timeout; 51 : 52 : ReportSchedulerImpl(TimerDelegate * aTimerDelegate); 53 0 : ~ReportSchedulerImpl() override { UnregisterAllHandlers(); } 54 : 55 : // ICDStateObserver 56 : 57 : /** 58 : * @brief When the ICD changes to Idle, no action is taken in this implementation. 59 : */ 60 0 : void OnTransitionToIdle() override{}; 61 : 62 : /** 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. 65 : * 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. 68 : */ 69 : void OnEnterActiveMode() override; 70 : 71 : /** 72 : * @brief When the ICD changes operation mode, no action is taken in this implementation. 73 : */ 74 0 : void OnICDModeChange() override{}; 75 : 76 : // ReadHandlerObserver 77 : 78 : /** 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. 82 : * 83 : * @note This method sets a now Timestamp that is used to calculate the next report timeout. 84 : */ 85 : void OnSubscriptionEstablished(ReadHandler * aReadHandler) final; 86 : 87 : /** 88 : * @brief When a ReadHandler becomes reportable, recalculate and reschedule the report. 89 : * 90 : * @note This method sets a now Timestamp that is used to calculate the next report timeout. 91 : */ 92 : void OnBecameReportable(ReadHandler * aReadHandler) final; 93 : 94 : /** 95 : * @brief When a ReadHandler report is sent, recalculate and reschedule the report. 96 : * 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 : * 100 : * @note This method sets a now Timestamp that is used to calculate the next report timeout. 101 : */ 102 : void OnSubscriptionReportSent(ReadHandler * aReadHandler) final; 103 : 104 : /** 105 : * @brief When a ReadHandler is destroyed, remove the node from the scheduler node pool and cancel the timer associated to it. 106 : */ 107 : void OnReadHandlerDestroyed(ReadHandler * aReadHandler) override; 108 : 109 : virtual bool IsReportScheduled(ReadHandler * aReadHandler); 110 : 111 : void ReportTimerCallback() override; 112 : 113 : protected: 114 : /** 115 : * @brief Schedule a report for the ReadHandler associated to the node. 116 : * 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. 119 : * 120 : * @param[in] timeout The timeout to schedule the report. 121 : * @param[in] node The node associated to the ReadHandler. 122 : * @param[in] now The current system timestamp. 123 : * 124 : * @return CHIP_ERROR CHIP_NO_ERROR on success, timer related error code otherwise (This can only fail on starting the timer) 125 : */ 126 : virtual CHIP_ERROR ScheduleReport(Timeout timeout, ReadHandlerNode * node, const Timestamp & now); 127 : void CancelReport(ReadHandler * aReadHandler); 128 : virtual void UnregisterAllHandlers(); 129 : 130 : private: 131 : friend class chip::app::reporting::TestReportScheduler; 132 : 133 : /** 134 : * @brief Find the next timer when a report should be scheduled for a ReadHandler. 135 : * 136 : * @param[out] timeout The timeout to calculate. 137 : * @param[in] aNode The node associated to the ReadHandler. 138 : * @param[in] now The current system timestamp. 139 : * 140 : * @return CHIP_ERROR CHIP_NO_ERROR on success or CHIP_ERROR_INVALID_ARGUMENT if aNode is not in the pool. 141 : * 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. 147 : */ 148 : virtual CHIP_ERROR CalculateNextReportTimeout(Timeout & timeout, ReadHandlerNode * aNode, const Timestamp & now); 149 : }; 150 : 151 : } // namespace reporting 152 : } // namespace app 153 : } // namespace chip