1
+ /*
2
+ * Copyright (c) 2025 Project CHIP Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include " closure-control-server.h"
18
+
19
+ #include < app/AttributeAccessInterface.h>
20
+ #include < app/AttributeAccessInterfaceRegistry.h>
21
+ #include < app/CommandHandlerInterfaceRegistry.h>
22
+ #include < app/ConcreteAttributePath.h>
23
+ #include < app/InteractionModelEngine.h>
24
+ #include < app/util/attribute-storage.h>
25
+
26
+ using namespace chip ;
27
+ using namespace chip ::app;
28
+ using namespace chip ::app::DataModel;
29
+ using namespace chip ::app::Clusters;
30
+ using namespace chip ::app::Clusters::ClosureControl;
31
+ using namespace chip ::app::Clusters::ClosureControl::Attributes;
32
+ using namespace chip ::app::Clusters::ClosureControl::Commands;
33
+ using chip::Protocols::InteractionModel::Status;
34
+
35
+ namespace chip {
36
+ namespace app {
37
+ namespace Clusters {
38
+ namespace ClosureControl {
39
+
40
+ CHIP_ERROR Instance::Init ()
41
+ {
42
+ ReturnErrorOnFailure (CommandHandlerInterfaceRegistry::Instance ().RegisterCommandHandler (this ));
43
+ VerifyOrReturnError (AttributeAccessInterfaceRegistry::Instance ().Register (this ), CHIP_ERROR_INCORRECT_STATE);
44
+
45
+ return CHIP_NO_ERROR;
46
+ }
47
+
48
+ void Instance::Shutdown ()
49
+ {
50
+ CommandHandlerInterfaceRegistry::Instance ().UnregisterCommandHandler (this );
51
+ AttributeAccessInterfaceRegistry::Instance ().Unregister (this );
52
+ }
53
+
54
+ bool Instance::HasFeature (Feature aFeature) const
55
+ {
56
+ return mFeature .Has (aFeature);
57
+ }
58
+
59
+ bool Instance::SupportsOptAttr (OptionalAttributes aOptionalAttrs) const
60
+ {
61
+ return mOptionalAttrs .Has (aOptionalAttrs);
62
+ }
63
+
64
+ // AttributeAccessInterface
65
+ CHIP_ERROR Instance::Read (const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
66
+ {
67
+ VerifyOrDie (aPath.mClusterId == ClosureControl::Id);
68
+
69
+ switch (aPath.mAttributeId )
70
+ {
71
+ case CountdownTime::Id:
72
+ if (SupportsOptAttr (OptionalAttributes::kCountdownTime ))
73
+ {
74
+ return aEncoder.Encode (mDelegate .GetCountdownTime ());
75
+ }
76
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
77
+ case MainState::Id:
78
+ return aEncoder.Encode (mDelegate .GetMainState ());
79
+ case CurrentErrorList::Id:
80
+ return aEncoder.EncodeList ([this ](const auto & encoder) -> CHIP_ERROR { return this ->EncodeCurrentErrorList (encoder); });
81
+ case OverallState::Id:
82
+ return aEncoder.Encode (mDelegate .GetOverallState ());
83
+ case OverallTarget::Id:
84
+ return aEncoder.Encode (mDelegate .GetOverallTarget ());
85
+ case RestingProcedure::Id:
86
+ if (HasFeature (Feature::kFallback ))
87
+ {
88
+ return aEncoder.Encode (mDelegate .GetRestingProcedure ());
89
+ }
90
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
91
+ case TriggerCondition::Id:
92
+ if (HasFeature (Feature::kFallback ))
93
+ {
94
+ return aEncoder.Encode (mDelegate .GetTriggerCondition ());
95
+ }
96
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
97
+ case TriggerPosition::Id:
98
+ if (HasFeature (Feature::kFallback ))
99
+ {
100
+ return aEncoder.Encode (mDelegate .GetTriggerPosition ());
101
+ }
102
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
103
+ case WaitingDelay::Id:
104
+ if (HasFeature (Feature::kFallback ))
105
+ {
106
+ return aEncoder.Encode (mDelegate .GetWaitingDelay ());
107
+ }
108
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
109
+ case KickoffTimer::Id:
110
+ if (HasFeature (Feature::kFallback ))
111
+ {
112
+ return aEncoder.Encode (mDelegate .GetKickoffTimer ());
113
+ }
114
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
115
+ /* FeatureMap - is held locally */
116
+ case FeatureMap::Id:
117
+ return aEncoder.Encode (mFeature );
118
+ // TODO CHECK CLUSTER REVISION
119
+ }
120
+ /* Allow all other unhandled attributes to fall through to Ember */
121
+ return CHIP_NO_ERROR;
122
+ }
123
+
124
+ CHIP_ERROR Instance::EncodeCurrentErrorList (const AttributeValueEncoder::ListEncodeHelper & encoder)
125
+ {
126
+ CHIP_ERROR err = CHIP_NO_ERROR;
127
+
128
+ ReturnErrorOnFailure (mDelegate .StartCurrentErrorListRead ());
129
+ for (size_t i = 0 ; true ; i++)
130
+ {
131
+ ClosureErrorEnum error;
132
+
133
+ err = mDelegate .GetCurrentErrorListAtIndex (i, error);
134
+ if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED)
135
+ {
136
+ // Convert end of list to CHIP_NO_ERROR
137
+ err = CHIP_NO_ERROR;
138
+ goto exit ;
139
+ }
140
+
141
+ // Check if another error occurred before trying to encode
142
+ SuccessOrExit (err);
143
+
144
+ err = encoder.Encode (error);
145
+ SuccessOrExit (err);
146
+ }
147
+
148
+ exit :
149
+ // Tell the delegate the read is complete
150
+ err = mDelegate .EndCurrentErrorListRead ();
151
+ return err;
152
+ }
153
+
154
+ CHIP_ERROR Instance::Write (const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
155
+ {
156
+ switch (aPath.mAttributeId )
157
+ {
158
+ default :
159
+ // Unknown attribute; return error. None of the other attributes for
160
+ // this cluster are writable, so should not be ending up in this code to
161
+ // start with.
162
+ return CHIP_IM_GLOBAL_STATUS (UnsupportedAttribute);
163
+ }
164
+ }
165
+
166
+ // CommandHandlerInterface
167
+ void Instance::InvokeCommand (HandlerContext & handlerContext)
168
+ {
169
+ using namespace Commands ;
170
+
171
+ switch (handlerContext.mRequestPath .mCommandId )
172
+ {
173
+ case Stop::Id:
174
+ if (!HasFeature (Feature::kInstantaneous ))
175
+ {
176
+ HandleCommand<Stop::DecodableType>(
177
+ handlerContext, [this ](HandlerContext & ctx, const auto & commandData) { HandleStop (ctx, commandData); });
178
+ }
179
+ else
180
+ {
181
+ handlerContext.mCommandHandler .AddStatus (handlerContext.mRequestPath , Status::UnsupportedCommand);
182
+ }
183
+ return ;
184
+ case MoveTo::Id:
185
+ HandleCommand<MoveTo::DecodableType>(
186
+ handlerContext, [this ](HandlerContext & ctx, const auto & commandData) { HandleMoveTo (ctx, commandData); });
187
+ return ;
188
+ case Calibrate::Id:
189
+ if (HasFeature (Feature::kCalibration ))
190
+ {
191
+ HandleCommand<Calibrate::DecodableType>(
192
+ handlerContext, [this ](HandlerContext & ctx, const auto & commandData) { HandleCalibrate (ctx, commandData); });
193
+ }
194
+ else
195
+ {
196
+ handlerContext.mCommandHandler .AddStatus (handlerContext.mRequestPath , Status::UnsupportedCommand);
197
+ }
198
+ return ;
199
+ case ConfigureFallback::Id:
200
+ if (HasFeature (Feature::kFallback ))
201
+ {
202
+ HandleCommand<ConfigureFallback::DecodableType>(
203
+ handlerContext, [this ](HandlerContext & ctx, const auto & commandData) { HandleConfigureFallback (ctx, commandData); });
204
+ }
205
+ else
206
+ {
207
+ handlerContext.mCommandHandler .AddStatus (handlerContext.mRequestPath , Status::UnsupportedCommand);
208
+ }
209
+ return ;
210
+ case CancelFallback::Id:
211
+ if (HasFeature (Feature::kFallback ))
212
+ {
213
+ HandleCommand<CancelFallback::DecodableType>(
214
+ handlerContext, [this ](HandlerContext & ctx, const auto & commandData) { HandleCancelFallback (ctx, commandData); });
215
+ }
216
+ else
217
+ {
218
+ handlerContext.mCommandHandler .AddStatus (handlerContext.mRequestPath , Status::UnsupportedCommand);
219
+ }
220
+ return ;
221
+ }
222
+ }
223
+
224
+ void Instance::HandleStop (HandlerContext & ctx, const Commands::Stop::DecodableType & commandData)
225
+ {
226
+ // No parameters for this command
227
+ // Call the delegate
228
+ Status status = mDelegate .Stop ();
229
+
230
+ ctx.mCommandHandler .AddStatus (ctx.mRequestPath , status);
231
+ }
232
+
233
+ void Instance::HandleMoveTo (HandlerContext & ctx, const Commands::MoveTo::DecodableType & commandData)
234
+ {
235
+ const Optional<TagPositionEnum> tag = commandData.tag ;
236
+ const Optional<TagLatchEnum> latch = commandData.latch ;
237
+ const Optional<Globals::ThreeLevelAutoEnum> speed = commandData.speed ;
238
+
239
+ // Call the delegate
240
+ Status status = mDelegate .MoveTo (tag, latch, speed);
241
+
242
+ ctx.mCommandHandler .AddStatus (ctx.mRequestPath , status);
243
+ }
244
+
245
+ void Instance::HandleCalibrate (HandlerContext & ctx, const Commands::Calibrate::DecodableType & commandData)
246
+ {
247
+ // No parameters for this command
248
+ // Call the delegate
249
+ Status status = mDelegate .Calibrate ();
250
+
251
+ ctx.mCommandHandler .AddStatus (ctx.mRequestPath , status);
252
+ }
253
+
254
+ void Instance::HandleConfigureFallback (HandlerContext & ctx, const Commands::ConfigureFallback::DecodableType & commandData)
255
+ {
256
+ const Optional<RestingProcedureEnum> restingProcedure = commandData.restingProcedure ;
257
+ const Optional<TriggerConditionEnum> triggerCondition = commandData.triggerCondition ;
258
+ const Optional<TriggerPositionEnum> triggerPosition = commandData.triggerPosition ;
259
+ const Optional<uint32_t > waitingDelay = commandData.waitingDelay ;
260
+
261
+ // Call the delegate
262
+ Status status = mDelegate .ConfigureFallback (restingProcedure, triggerCondition, triggerPosition, waitingDelay);
263
+
264
+ ctx.mCommandHandler .AddStatus (ctx.mRequestPath , status);
265
+ }
266
+
267
+ void Instance::HandleCancelFallback (HandlerContext & ctx, const Commands::CancelFallback::DecodableType & commandData)
268
+ {
269
+ // No parameters for this command
270
+ // Call the delegate
271
+ Status status = mDelegate .CancelFallback ();
272
+
273
+ ctx.mCommandHandler .AddStatus (ctx.mRequestPath , status);
274
+ }
275
+
276
+ } // namespace ClosureControl
277
+ } // namespace Clusters
278
+ } // namespace app
279
+ } // namespace chip
280
+
281
+ // -----------------------------------------------------------------------------
282
+ // Plugin initialization
283
+
284
+ void MatterClosureControlPluginServerInitCallback () {}
0 commit comments