forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathICDManager.h
333 lines (292 loc) · 14.7 KB
/
ICDManager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*
*
* Copyright (c) 2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app/icd/server/ICDServerConfig.h>
#include <app-common/zap-generated/cluster-enums.h>
#include <app/AppConfig.h>
#include <app/SubscriptionsInfoProvider.h>
#include <app/TestEventTriggerDelegate.h>
#include <app/icd/server/ICDConfigurationData.h>
#include <app/icd/server/ICDNotifier.h>
#include <app/icd/server/ICDStateObserver.h>
#include <credentials/FabricTable.h>
#include <crypto/SessionKeystore.h>
#include <lib/support/BitFlags.h>
#include <messaging/ExchangeMgr.h>
#include <platform/CHIPDeviceConfig.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <system/SystemClock.h>
#if CHIP_CONFIG_ENABLE_ICD_CIP
#include <app/icd/server/ICDCheckInSender.h> // nogncheck
#include <app/icd/server/ICDMonitoringTable.h> // nogncheck
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
namespace chip {
namespace Crypto {
using SymmetricKeystore = SessionKeystore;
}
} // namespace chip
namespace chip {
namespace app {
// Forward declaration of TestICDManager to allow it to be friend with ICDManager
// Used in unit tests
class TestICDManager;
/**
* @brief ICD Manager is responsible of processing the events and triggering the correct action for an ICD
*/
class ICDManager : public ICDListener, public TestEventTriggerHandler
{
public:
/**
* @brief This structure is used for the creation an ObjectPool of ICDStateObserver pointers
*/
struct ObserverPointer
{
ObserverPointer(ICDStateObserver * obs) : mObserver(obs) {}
~ObserverPointer() { mObserver = nullptr; }
ICDStateObserver * mObserver;
};
enum class OperationalState : uint8_t
{
IdleMode,
ActiveMode,
};
/**
* @brief This enum class represents all ICDStateObserver callbacks available from the
* mStateObserverPool for the ICDManager.
*
* EnterActiveMode, TransitionToIdle and EnterIdleMode will always be called as a trio in the same order.
* Each event will only be called once per cycle.
* EnterActiveMode will always be called first, when the ICD has transitioned to ActiveMode.
* TransitionToIdle will always be second. This event will only be called the first time there is
* `ICD_ACTIVE_TIME_JITTER_MS` remaining to the ActiveMode timer.
* When this event is called, the ICD is still in ActiveMode.
* If the ActiveMode timer is increased due to the TransitionToIdle event, the event will not be called a second time in
* a given cycle.
* OnEnterIdleMode will always the third event and indicates that the ICD has transitioned to IdleMode.
*
* The ICDModeChange event can occur independently from the EnterActiveMode, TransitionToIdle and EnterIdleMode.
* It will typically happen at the ICDManager init when a client is already registered with the ICD before the
* OnEnterIdleMode event or when a client sends a register command after the OnEnterActiveMode event. Nothing prevents
* the ICDModeChange event from happening multiple times per cycle or while the ICD is in IdleMode.
*
* See src/app/icd/server/ICDStateObserver.h for more information on the APIs each event triggers
*/
enum class ObserverEventType : uint8_t
{
EnterActiveMode,
EnterIdleMode,
TransitionToIdle,
ICDModeChange,
};
/**
* @brief Verifier template function
* This type can be used to implement specific verifiers that can be used in the CheckInMessagesWouldBeSent function.
* The goal is to avoid having multiple functions that implement the iterator loop with only the check changing.
*
* @return true: if at least one Check-In message would be sent
* false: No Check-In messages would be sent
*/
using ShouldCheckInMsgsBeSentFunction = bool(FabricIndex aFabricIndex, NodeId subjectID);
ICDManager() = default;
~ICDManager() = default;
void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeyStore,
Messaging::ExchangeManager * exchangeManager, SubscriptionsInfoProvider * subInfoProvider);
void Shutdown();
/**
* @brief SupportsFeature verifies if a given FeatureMap bit is enabled
*
* @param[in] feature FeatureMap bit to verify
*
* @return true: if the FeatureMap bit is enabled in the ICDM cluster attribute.
* false: if the FeatureMap bit is not enabled in the ICDM cluster attribute.
* if we failed to read the FeatureMap attribute.
*/
bool SupportsFeature(Clusters::IcdManagement::Feature feature);
ICDConfigurationData::ICDMode GetICDMode() { return ICDConfigurationData::GetInstance().GetICDMode(); };
/**
* @brief Adds the referenced observer in parameters to the mStateObserverPool
* A maximum of CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE observers can be concurrently registered
*
* @return The pointer to the pool object, or null if it could not be added.
*/
ObserverPointer * RegisterObserver(ICDStateObserver * observer);
/**
* @brief Remove the referenced observer in parameters from the mStateObserverPool
* If the observer is not present in the object pool, we do nothing
*/
void ReleaseObserver(ICDStateObserver * observer);
/**
* @brief Ensures that the remaining Active Mode duration is at least the smaller of 30000 milliseconds and stayActiveDuration.
*
* @param[in] stayActiveDuration The duration (in milliseconds) requested by the client to stay in Active Mode
* @return The duration (in milliseconds) the device will stay in Active Mode
*/
uint32_t StayActiveRequest(uint32_t stayActiveDuration);
/**
* @brief TestEventTriggerHandler for the ICD feature set
*
* @param[in] eventTrigger Event trigger to handle.
*
* @return CHIP_ERROR CHIP_NO_ERROR - No erros during the processing
* CHIP_ERROR_INVALID_ARGUMENT - eventTrigger isn't a valid value
*/
CHIP_ERROR HandleEventTrigger(uint64_t eventTrigger) override;
#if CHIP_CONFIG_ENABLE_ICD_CIP
/**
* @brief Trigger the ICDManager to send Check-In message if necessary
*
* @param[in] function to use to determine if we need to send check-in messages
*/
void TriggerCheckInMessages(const std::function<ShouldCheckInMsgsBeSentFunction> & function);
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
/**
* @brief Set mSubCheckInBootCheckExecuted to true
* Function allows the InteractionModelEngine to notify the ICDManager that the boot up subscription resumption has been
* completed.
*/
void SetBootUpResumeSubscriptionExecuted() { mIsBootUpResumeSubscriptionExecuted = true; };
#endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
void SetTestFeatureMapValue(uint32_t featureMap) { mFeatureMap = featureMap; };
#if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
bool GetIsBootUpResumeSubscriptionExecuted() { return mIsBootUpResumeSubscriptionExecuted; };
#endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
#endif
// Implementation of ICDListener functions.
// Callers must origin from the chip task context or hold the ChipStack lock.
void OnNetworkActivity() override;
void OnKeepActiveRequest(KeepActiveFlags request) override;
void OnActiveRequestWithdrawal(KeepActiveFlags request) override;
void OnICDManagementServerEvent(ICDManagementEvents event) override;
void OnSubscriptionReport() override;
private:
friend class TestICDManager;
/**
* @brief UpdateICDMode evaluates in which mode the ICD can be in; SIT or LIT mode.
* If the current operating mode does not match the evaluated operating mode, function updates the ICDMode and triggers
* all necessary operations.
* For a SIT ICD, this function does nothing.
* For a LIT ICD, the function checks if the ICD has a registration in the ICDMonitoringTable to determine which ICDMode
* the ICD must be in.
*/
void UpdateICDMode();
/**
* @brief UpdateOperationState updates the OperationState of the ICD to the requested one.
* IdleMode -> IdleMode : No actions are necessary, do nothing.
* IdleMode -> ActiveMode : Transition the device to ActiveMode, start the ActiveMode timer and trigger all necessary
* operations. These operations could be : Send Check-In messages
* Send subscription reports
* Process user actions
* ActiveMode -> ActiveMode : Increase remaining ActiveMode timer to one ActiveModeThreshold.
* If ActiveModeThreshold is 0, do nothing.
* ActiveMode -> IdleMode : Transition ICD to IdleMode and start the IdleMode timer.
*
* @param state requested OperationalState for the ICD to transition to
*/
void UpdateOperationState(OperationalState state);
/**
* @brief Set or Remove a keep ActiveMode requirement for the given flag
* If state is true and the ICD is in IdleMode, transition the ICD to ActiveMode
* If state is false and the ICD is in ActiveMode, check whether we can transition the ICD to IdleMode.
* If we can, transition the ICD to IdleMode.
*
* @param flag KeepActiveFlag to remove or add
* @param state true: adding a flag requirement
* false: removing a flag requirement
*/
void SetKeepActiveModeRequirements(KeepActiveFlags flag, bool state);
/**
* @brief Associates the ObserverEventType parameters to the correct
* ICDStateObservers function and calls it for all observers in the mStateObserverPool
*/
void postObserverEvent(ObserverEventType event);
/**
* @brief Hepler function that extends the ActiveMode timer as well as the Active Mode Jitter timer for the transition to
* idle mode event.
*/
void ExtendActiveMode(System::Clock::Milliseconds16 extendDuration);
/**
* @brief Timer callback function for when the IdleMode timer expires
*
* @param appState pointer to the ICDManager
*/
static void OnIdleModeDone(System::Layer * aLayer, void * appState);
/**
* @brief Timer callback function for when the ActiveMode timer expires
*
* @param appState pointer to the ICDManager
*/
static void OnActiveModeDone(System::Layer * aLayer, void * appState);
/**
* @brief Timer Callback function called shortly before the device enters idle mode to allow checks to be made.
* This is currently only called once to prevent entering in a loop if some events re-trigger this check (for instance if
* a check for subscriptions before entering idle mode leads to emiting a report, we will re-enter UpdateOperationState
* and check again for subscription, etc.)
*
* @param appState pointer to the ICDManager
*/
static void OnTransitionToIdle(System::Layer * aLayer, void * appState);
#if CHIP_CONFIG_ENABLE_ICD_CIP
/**
* @brief Function triggers all necessary Check-In messages to be sent.
*
* @note For each ICDMonitoring entry, we check if should send a Check-In message with
* ShouldCheckInMsgsBeSentAtActiveModeFunction. If we should, we allocate an ICDCheckInSender which tries to send a
* Check-In message to the registered client.
*/
void SendCheckInMsgs();
/**
* @brief See function implementation in .cpp for details on this function.
*/
bool ShouldCheckInMsgsBeSentAtActiveModeFunction(FabricIndex aFabricIndex, NodeId subjectID);
/**
* @brief Function checks if at least one client registration would require a Check-In message
*
* @param[in] function function to use to determine if a Check-In message would be sent for a given registration
*
* @return true At least one registration would require an Check-In message if we were entering ActiveMode.
* @return false None of the registration would require a Check-In message either because there are no registration or
* because they all have associated subscriptions.
*/
bool CheckInMessagesWouldBeSent(const std::function<ShouldCheckInMsgsBeSentFunction> & function);
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
KeepActiveFlags mKeepActiveFlags{ 0 };
// Initialize mOperationalState to ActiveMode so the init sequence at bootup triggers the IdleMode behaviour first.
OperationalState mOperationalState = OperationalState::ActiveMode;
bool mTransitionToIdleCalled = false;
ObjectPool<ObserverPointer, CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE> mStateObserverPool;
uint8_t mOpenExchangeContextCount = 0;
#if CHIP_CONFIG_ENABLE_ICD_CIP
uint8_t mCheckInRequestCount = 0;
#if !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
bool mIsBootUpResumeSubscriptionExecuted = false;
#endif // !CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION && CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
Messaging::ExchangeManager * mExchangeManager = nullptr;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
SubscriptionsInfoProvider * mSubInfoProvider = nullptr;
ObjectPool<ICDCheckInSender, (CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC * CHIP_CONFIG_MAX_FABRICS)> mICDSenderPool;
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST
// feature map that can be changed at runtime for testing purposes
uint32_t mFeatureMap = 0;
#endif
};
} // namespace app
} // namespace chip