30
30
#include < app/util/odd-sized-integers.h>
31
31
#include < app/util/util.h>
32
32
#include < lib/support/CodeUtils.h>
33
+ #include < platform/CHIPDeviceLayer.h>
33
34
#include < platform/DiagnosticDataProvider.h>
34
35
#include < tracing/macros.h>
35
36
37
+ #ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT
38
+ #include < app/clusters/scenes-server/scenes-server.h>
39
+ #endif // MATTER_DM_PLUGIN_SCENES_MANAGEMENT
40
+
36
41
#ifdef MATTER_DM_PLUGIN_ON_OFF
37
42
#include < app/clusters/on-off-server/on-off-server.h>
38
43
#endif // MATTER_DM_PLUGIN_ON_OFF
@@ -109,35 +114,200 @@ CHIP_ERROR ModeSelectAttrAccess::Read(const ConcreteReadAttributePath & aPath, A
109
114
return CHIP_NO_ERROR;
110
115
}
111
116
112
- } // anonymous namespace
113
-
114
- bool emberAfModeSelectClusterChangeToModeCallback (CommandHandler * commandHandler, const ConcreteCommandPath & commandPath,
115
- const ModeSelect::Commands::ChangeToMode::DecodableType & commandData)
117
+ Status ChangeToMode (EndpointId endpointId, uint8_t newMode)
116
118
{
117
119
MATTER_TRACE_SCOPE (" ChangeToMode" , " ModeSelect" );
118
120
ChipLogProgress (Zcl, " ModeSelect: Entering emberAfModeSelectClusterChangeToModeCallback" );
119
- EndpointId endpointId = commandPath.mEndpointId ;
120
- uint8_t newMode = commandData.newMode ;
121
+
121
122
// Check that the newMode matches one of the supported options
122
123
const ModeSelect::Structs::ModeOptionStruct::Type * modeOptionPtr;
123
124
const ModeSelect::SupportedModesManager * gSupportedModeManager = ModeSelect::getSupportedModesManager ();
124
125
if (gSupportedModeManager == nullptr )
125
126
{
126
127
ChipLogError (Zcl, " ModeSelect: SupportedModesManager is NULL" );
127
- commandHandler->AddStatus (commandPath, Status::Failure);
128
- return true ;
128
+ return Status::Failure;
129
129
}
130
130
Status checkSupportedModeStatus = gSupportedModeManager ->getModeOptionByMode (endpointId, newMode, &modeOptionPtr);
131
131
if (Status::Success != checkSupportedModeStatus)
132
132
{
133
133
ChipLogProgress (Zcl, " ModeSelect: Failed to find the option with mode %u" , newMode);
134
- commandHandler->AddStatus (commandPath, checkSupportedModeStatus);
135
- return true ;
134
+ return checkSupportedModeStatus;
136
135
}
137
136
ModeSelect::Attributes::CurrentMode::Set (endpointId, newMode);
138
137
138
+ return Status::Success;
139
+ }
140
+
141
+ } // anonymous namespace
142
+
143
+ #if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS
144
+ static constexpr size_t kModeSelectMaxEnpointCount =
145
+ MATTER_DM_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT;
146
+
147
+ static void timerCallback (System::Layer *, void * callbackContext);
148
+ static void sceneModeSelectCallback (EndpointId endpoint);
149
+ using ModeSelectEndPointPair = scenes::DefaultSceneHandlerImpl::EndpointStatePair<uint8_t >;
150
+ using ModeSelectTransitionTimeInterface =
151
+ scenes::DefaultSceneHandlerImpl::TransitionTimeInterface<kModeSelectMaxEnpointCount ,
152
+ MATTER_DM_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT>;
153
+
154
+ class DefaultModeSelectSceneHandler : public scenes ::DefaultSceneHandlerImpl
155
+ {
156
+ public:
157
+ DefaultSceneHandlerImpl::StatePairBuffer<uint8_t , kModeSelectMaxEnpointCount > mSceneEndpointStatePairs ;
158
+ // As per spec, 1 attribute is scenable in the mode select cluster
159
+ static constexpr uint8_t kScenableAttributeCount = 1 ;
160
+
161
+ DefaultModeSelectSceneHandler () = default ;
162
+ ~DefaultModeSelectSceneHandler () override {}
163
+
164
+ // Default function for the mode select cluster, only puts the mode select cluster ID in the span if supported on the given
165
+ // endpoint
166
+ virtual void GetSupportedClusters (EndpointId endpoint, Span<ClusterId> & clusterBuffer) override
167
+ {
168
+ if (emberAfContainsServer (endpoint, ModeSelect::Id) && clusterBuffer.size () >= 1 )
169
+ {
170
+ clusterBuffer[0 ] = ModeSelect::Id;
171
+ clusterBuffer.reduce_size (1 );
172
+ }
173
+ else
174
+ {
175
+ clusterBuffer.reduce_size (0 );
176
+ }
177
+ }
178
+
179
+ // Default function for mode select cluster, only checks if mode select is enabled on the endpoint
180
+ bool SupportsCluster (EndpointId endpoint, ClusterId cluster) override
181
+ {
182
+ return (cluster == ModeSelect::Id) && (emberAfContainsServer (endpoint, ModeSelect::Id));
183
+ }
184
+
185
+ // / @brief Serialize the Cluster's EFS value
186
+ // / @param [in] endpoint target endpoint
187
+ // / @param [in] cluster target cluster
188
+ // / @param [out] serializedBytes data to serialize into EFS
189
+ // / @return CHIP_NO_ERROR if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT otherwise
190
+ CHIP_ERROR SerializeSave (EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) override
191
+ {
192
+ using AttributeValuePair = ScenesManagement::Structs::AttributeValuePairStruct::Type;
193
+
194
+ uint8_t currentMode;
195
+ // read CurrentMode value
196
+ Status status = Attributes::CurrentMode::Get (endpoint, ¤tMode);
197
+ if (status != Status::Success)
198
+ {
199
+ ChipLogError (Zcl, " ERR: reading CurrentMode 0x%02x" , to_underlying (status));
200
+ return CHIP_ERROR_READ_FAILED;
201
+ }
202
+
203
+ AttributeValuePair pairs[kScenableAttributeCount ];
204
+
205
+ pairs[0 ].attributeID = Attributes::CurrentMode::Id;
206
+ pairs[0 ].valueUnsigned8 .SetValue (currentMode);
207
+
208
+ app::DataModel::List<AttributeValuePair> attributeValueList (pairs);
209
+
210
+ return EncodeAttributeValueList (attributeValueList, serializedBytes);
211
+ }
212
+
213
+ // / @brief Default EFS interaction when applying scene to the ModeSelect Cluster
214
+ // / @param endpoint target endpoint
215
+ // / @param cluster target cluster
216
+ // / @param serializedBytes Data from nvm
217
+ // / @param timeMs transition time in ms
218
+ // / @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise
219
+ CHIP_ERROR ApplyScene (EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes,
220
+ scenes::TransitionTimeMs timeMs) override
221
+ {
222
+ app::DataModel::DecodableList<ScenesManagement::Structs::AttributeValuePairStruct::DecodableType> attributeValueList;
223
+
224
+ VerifyOrReturnError (cluster == ModeSelect::Id, CHIP_ERROR_INVALID_ARGUMENT);
225
+
226
+ ReturnErrorOnFailure (DecodeAttributeValueList (serializedBytes, attributeValueList));
227
+
228
+ size_t attributeCount = 0 ;
229
+ ReturnErrorOnFailure (attributeValueList.ComputeSize (&attributeCount));
230
+ VerifyOrReturnError (attributeCount <= kScenableAttributeCount , CHIP_ERROR_BUFFER_TOO_SMALL);
231
+
232
+ auto pair_iterator = attributeValueList.begin ();
233
+ while (pair_iterator.Next ())
234
+ {
235
+ auto & decodePair = pair_iterator.GetValue ();
236
+ VerifyOrReturnError (decodePair.attributeID == Attributes::CurrentMode::Id, CHIP_ERROR_INVALID_ARGUMENT);
237
+ VerifyOrReturnError (decodePair.valueUnsigned8 .HasValue (), CHIP_ERROR_INVALID_ARGUMENT);
238
+ ReturnErrorOnFailure (mSceneEndpointStatePairs .InsertPair (
239
+ ModeSelectEndPointPair (endpoint, static_cast <uint8_t >(decodePair.valueUnsigned8 .HasValue ()))));
240
+ }
241
+ // Verify that the EFS was completely read
242
+ CHIP_ERROR err = pair_iterator.GetStatus ();
243
+ if (CHIP_NO_ERROR != err)
244
+ {
245
+ mSceneEndpointStatePairs .RemovePair (endpoint);
246
+ return err;
247
+ }
248
+
249
+ VerifyOrReturnError (mTransitionTimeInterface .sceneEventControl (endpoint) != nullptr , CHIP_ERROR_INVALID_ARGUMENT);
250
+ DeviceLayer::SystemLayer ().StartTimer (chip::System::Clock::Milliseconds32 (timeMs), timerCallback,
251
+ mTransitionTimeInterface .sceneEventControl (endpoint));
252
+
253
+ return CHIP_NO_ERROR;
254
+ }
255
+
256
+ private:
257
+ ModeSelectTransitionTimeInterface mTransitionTimeInterface =
258
+ ModeSelectTransitionTimeInterface (ModeSelect::Id, sceneModeSelectCallback);
259
+ };
260
+ static DefaultModeSelectSceneHandler sModeSelectSceneHandler ;
261
+
262
+ static void timerCallback (System::Layer *, void * callbackContext)
263
+ {
264
+ auto control = static_cast <EmberEventControl *>(callbackContext);
265
+ (control->callback )(control->endpoint );
266
+ }
267
+
268
+ /* *
269
+ * @brief This function is a callback to apply the mode that was saved when the ApplyScene was called with a transition time greater
270
+ * than 0.
271
+ *
272
+ * @param endpoint The endpoint ID that the scene mode selection is associated with.
273
+ *
274
+ */
275
+ static void sceneModeSelectCallback (EndpointId endpoint)
276
+ {
277
+ ModeSelectEndPointPair savedState;
278
+ ReturnOnFailure (sModeSelectSceneHandler .mSceneEndpointStatePairs .GetPair (endpoint, savedState));
279
+ ChangeToMode (endpoint, savedState.mValue );
280
+ sModeSelectSceneHandler .mSceneEndpointStatePairs .RemovePair (endpoint);
281
+ }
282
+
283
+ #endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS
284
+
285
+ bool emberAfModeSelectClusterChangeToModeCallback (CommandHandler * commandHandler, const ConcreteCommandPath & commandPath,
286
+ const ModeSelect::Commands::ChangeToMode::DecodableType & commandData)
287
+ {
288
+ ChipLogProgress (Zcl, " ModeSelect: Entering emberAfModeSelectClusterChangeToModeCallback" );
289
+
290
+ uint8_t currentMode = 0 ;
291
+ ModeSelect::Attributes::CurrentMode::Get (commandPath.mEndpointId , ¤tMode);
292
+ #ifdef MATTER_DM_PLUGIN_SCENES_MANAGEMENT
293
+ if (currentMode != commandData.newMode )
294
+ {
295
+ // the scene has been changed (the value of CurrentMode has changed) so
296
+ // the current scene as described in the scene table is invalid
297
+ ScenesManagement::ScenesServer::Instance ().MakeSceneInvalidForAllFabrics (commandPath.mEndpointId );
298
+ }
299
+ #endif // MATTER_DM_PLUGIN_SCENES_MANAGEMENT
300
+
301
+ Status status = ChangeToMode (commandPath.mEndpointId , commandData.newMode );
302
+
303
+ if (Status::Success != status)
304
+ {
305
+ commandHandler->AddStatus (commandPath, status);
306
+ return true ;
307
+ }
308
+
139
309
ChipLogProgress (Zcl, " ModeSelect: ChangeToMode successful" );
140
- commandHandler->AddStatus (commandPath, Status::Success );
310
+ commandHandler->AddStatus (commandPath, status );
141
311
return true ;
142
312
}
143
313
@@ -148,6 +318,10 @@ bool emberAfModeSelectClusterChangeToModeCallback(CommandHandler * commandHandle
148
318
*/
149
319
void emberAfModeSelectClusterServerInitCallback (EndpointId endpointId)
150
320
{
321
+ #if defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS
322
+ ScenesManagement::ScenesServer::Instance ().RegisterSceneHandler (endpointId, &sModeSelectSceneHandler );
323
+ #endif // defined(MATTER_DM_PLUGIN_SCENES_MANAGEMENT) && CHIP_CONFIG_SCENES_USE_DEFAULT_HANDLERS
324
+
151
325
// StartUp behavior relies on CurrentMode StartUpMode attributes being non-volatile.
152
326
if (areStartUpModeAndCurrentModeNonVolatile (endpointId))
153
327
{
@@ -161,6 +335,7 @@ void emberAfModeSelectClusterServerInitCallback(EndpointId endpointId)
161
335
Status status = Attributes::StartUpMode::Get (endpointId, startUpMode);
162
336
if (status == Status::Success && !startUpMode.IsNull ())
163
337
{
338
+
164
339
#ifdef MATTER_DM_PLUGIN_ON_OFF
165
340
// OnMode with Power Up
166
341
// If the On/Off feature is supported and the On/Off cluster attribute StartUpOnOff is present, with a
0 commit comments