Skip to content

Commit cb43d2a

Browse files
Closure Control Cluster Server Code Implementatio
1 parent a529202 commit cb43d2a

File tree

5 files changed

+427
-1
lines changed

5 files changed

+427
-1
lines changed

src/app/chip_data_model.gni

+5
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,11 @@ template("chip_data_model") {
451451
"${_app_root}/clusters/${cluster}/ArlEncoder.cpp",
452452
"${_app_root}/clusters/${cluster}/ArlEncoder.h",
453453
]
454+
} else if (cluster == "closure-control-server") {
455+
sources += [
456+
"${_app_root}/clusters/${cluster}/${cluster}.cpp",
457+
"${_app_root}/clusters/${cluster}/${cluster}.h",
458+
]
454459
} else {
455460
sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ]
456461
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
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

Comments
 (0)