Skip to content

Commit 377947b

Browse files
Chime server (project-chip#35892)
* Added Chime Server * Generated using ./scripts/tools/zap_regen_all.py * Restyled by whitespace * Restyled by clang-format * Addressed review comments, storing attributes in server now * (re)Generated using ./scripts/tools/zap_regen_all.py * playChimeSound -> PlayChimeSound * Changed entries in zcl files * (re)Generate using ./scripts/tools/zap_regen_all.py * Restyled by clang-format * (re)Generated by ./scripts/tools/zap_regen_all.py --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent b3223b6 commit 377947b

File tree

10 files changed

+480
-111
lines changed

10 files changed

+480
-111
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/****************************************************************************'
19+
* @file
20+
* @brief Implementation for the Chime Server Cluster
21+
***************************************************************************/
22+
23+
#include "chime-server.h"
24+
25+
#include <app/AttributeAccessInterfaceRegistry.h>
26+
#include <app/CommandHandlerInterfaceRegistry.h>
27+
#include <app/ConcreteAttributePath.h>
28+
#include <app/SafeAttributePersistenceProvider.h>
29+
#include <protocols/interaction_model/StatusCode.h>
30+
31+
using namespace chip;
32+
using namespace chip::app;
33+
using namespace chip::app::Clusters::Chime;
34+
using namespace chip::app::Clusters::Chime::Attributes;
35+
using chip::Protocols::InteractionModel::Status;
36+
using ChimeSoundStructType = Structs::ChimeSoundStruct::Type;
37+
38+
namespace chip {
39+
namespace app {
40+
namespace Clusters {
41+
42+
ChimeServer::ChimeServer(EndpointId endpointId, ChimeDelegate & delegate) :
43+
AttributeAccessInterface(MakeOptional(endpointId), Chime::Id), CommandHandlerInterface(MakeOptional(endpointId), Chime::Id),
44+
mDelegate(delegate), mActiveChimeID(0), mEnabled(true)
45+
{
46+
mDelegate.SetChimeServer(this);
47+
}
48+
49+
ChimeServer::~ChimeServer()
50+
{
51+
// null out the ref to us on the delegate
52+
mDelegate.SetChimeServer(nullptr);
53+
54+
// unregister
55+
CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this);
56+
AttributeAccessInterfaceRegistry::Instance().Unregister(this);
57+
}
58+
59+
CHIP_ERROR ChimeServer::Init()
60+
{
61+
LoadPersistentAttributes();
62+
63+
VerifyOrReturnError(AttributeAccessInterfaceRegistry::Instance().Register(this), CHIP_ERROR_INTERNAL);
64+
ReturnErrorOnFailure(CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(this));
65+
return CHIP_NO_ERROR;
66+
}
67+
68+
void ChimeServer::LoadPersistentAttributes()
69+
{
70+
// Load Active Chime ID
71+
uint8_t storedActiveChimeID;
72+
CHIP_ERROR err = GetSafeAttributePersistenceProvider()->ReadScalarValue(
73+
ConcreteAttributePath(GetEndpointId(), Chime::Id, ActiveChimeID::Id), storedActiveChimeID);
74+
if (err == CHIP_NO_ERROR)
75+
{
76+
mActiveChimeID = storedActiveChimeID;
77+
}
78+
else
79+
{
80+
// otherwise defaults
81+
ChipLogDetail(Zcl, "Chime: Unable to load the ActiveChimeID attribute from the KVS. Defaulting to %u", mActiveChimeID);
82+
}
83+
84+
// Load Enabled
85+
bool storedEnabled;
86+
err = GetSafeAttributePersistenceProvider()->ReadScalarValue(ConcreteAttributePath(GetEndpointId(), Chime::Id, Enabled::Id),
87+
storedEnabled);
88+
if (err == CHIP_NO_ERROR)
89+
{
90+
mEnabled = storedEnabled;
91+
}
92+
else
93+
{
94+
// otherwise take the default
95+
ChipLogDetail(Zcl, "Chime: Unable to load the Enabled attribute from the KVS. Defaulting to %u", mEnabled);
96+
}
97+
}
98+
99+
// AttributeAccessInterface
100+
CHIP_ERROR ChimeServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
101+
{
102+
VerifyOrDie(aPath.mClusterId == Chime::Id);
103+
104+
switch (aPath.mAttributeId)
105+
{
106+
case ActiveChimeID::Id:
107+
ReturnErrorOnFailure(aEncoder.Encode(mActiveChimeID));
108+
break;
109+
case Enabled::Id:
110+
ReturnErrorOnFailure(aEncoder.Encode(mEnabled));
111+
break;
112+
case InstalledChimeSounds::Id:
113+
ChimeServer * cs = this;
114+
CHIP_ERROR err =
115+
aEncoder.EncodeList([cs](const auto & encoder) -> CHIP_ERROR { return cs->EncodeSupportedChimeSounds(encoder); });
116+
return err;
117+
}
118+
119+
return CHIP_NO_ERROR;
120+
}
121+
122+
uint8_t ChimeServer::GetActiveChimeID() const
123+
{
124+
return mActiveChimeID;
125+
}
126+
127+
bool ChimeServer::GetEnabled() const
128+
{
129+
return mEnabled;
130+
}
131+
132+
// helper method to get the Chime Sounds one by one and encode into a list
133+
CHIP_ERROR ChimeServer::EncodeSupportedChimeSounds(const AttributeValueEncoder::ListEncodeHelper & encoder)
134+
{
135+
136+
for (uint8_t i = 0; true; i++)
137+
{
138+
ChimeSoundStructType chimeSound;
139+
140+
// Get the chime sound
141+
// We pass in a MutableCharSpan to avoid any ownership issues - Delegate needs to use
142+
// CopyCharSpanToMutableCharSpan to copy data in
143+
char buffer[kMaxChimeSoundNameSize];
144+
MutableCharSpan name(buffer);
145+
auto err = mDelegate.GetChimeSoundByIndex(i, chimeSound.chimeID, name);
146+
147+
// return if we've run off the end of the Chime Sound List on the delegate
148+
if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED)
149+
{
150+
return CHIP_NO_ERROR;
151+
}
152+
153+
ReturnErrorOnFailure(err);
154+
155+
// set the name on the struct
156+
chimeSound.name = name;
157+
158+
// and now encode the struct
159+
ReturnErrorOnFailure(encoder.Encode(chimeSound));
160+
}
161+
return CHIP_NO_ERROR;
162+
}
163+
164+
// helper method to check if the chimeID param is supported by the delegate
165+
bool ChimeServer::IsSupportedChimeID(uint8_t chimeID)
166+
{
167+
uint8_t supportedChimeID;
168+
for (uint8_t i = 0; mDelegate.GetChimeIDByIndex(i, supportedChimeID) != CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; i++)
169+
{
170+
if (supportedChimeID == chimeID)
171+
{
172+
return true;
173+
}
174+
}
175+
176+
ChipLogDetail(Zcl, "Cannot find a supported ChimeID with value %u", chimeID);
177+
return false;
178+
}
179+
180+
CHIP_ERROR ChimeServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
181+
{
182+
VerifyOrDie(aPath.mClusterId == Chime::Id);
183+
Status status;
184+
185+
switch (aPath.mAttributeId)
186+
{
187+
case ActiveChimeID::Id: {
188+
uint8_t newValue;
189+
ReturnErrorOnFailure(aDecoder.Decode(newValue));
190+
status = SetActiveChimeID(newValue);
191+
return StatusIB(status).ToChipError();
192+
}
193+
case Enabled::Id: {
194+
bool newValue;
195+
ReturnErrorOnFailure(aDecoder.Decode(newValue));
196+
status = SetEnabled(newValue);
197+
return StatusIB(status).ToChipError();
198+
}
199+
200+
default:
201+
// Unknown attribute
202+
return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
203+
}
204+
}
205+
206+
Status ChimeServer::SetActiveChimeID(uint8_t chimeID)
207+
{
208+
if (!IsSupportedChimeID(chimeID))
209+
{
210+
return Protocols::InteractionModel::Status::ConstraintError;
211+
}
212+
213+
bool activeIDChanged = !(mActiveChimeID == chimeID);
214+
if (activeIDChanged)
215+
{
216+
mActiveChimeID = chimeID;
217+
218+
// Write new value to persistent storage.
219+
auto endpointId = GetEndpointId();
220+
ConcreteAttributePath path = ConcreteAttributePath(endpointId, Chime::Id, ActiveChimeID::Id);
221+
GetSafeAttributePersistenceProvider()->WriteScalarValue(path, mActiveChimeID);
222+
223+
// and mark as dirty
224+
MatterReportingAttributeChangeCallback(path);
225+
}
226+
return Protocols::InteractionModel::Status::Success;
227+
}
228+
229+
Status ChimeServer::SetEnabled(bool Enabled)
230+
{
231+
bool enableChanged = !(mEnabled == Enabled);
232+
233+
if (enableChanged)
234+
{
235+
mEnabled = Enabled;
236+
237+
// Write new value to persistent storage.
238+
auto endpointId = GetEndpointId();
239+
ConcreteAttributePath path = ConcreteAttributePath(endpointId, Chime::Id, Enabled::Id);
240+
GetSafeAttributePersistenceProvider()->WriteScalarValue(path, mEnabled);
241+
242+
// and mark as dirty
243+
MatterReportingAttributeChangeCallback(path);
244+
}
245+
246+
return Protocols::InteractionModel::Status::Success;
247+
}
248+
249+
void ChimeServer::InvokeCommand(HandlerContext & ctx)
250+
{
251+
switch (ctx.mRequestPath.mCommandId)
252+
{
253+
case Commands::PlayChimeSound::Id:
254+
CommandHandlerInterface::HandleCommand<Commands::PlayChimeSound::DecodableType>(
255+
ctx, [this](HandlerContext & ctx, const auto & req) { HandlePlayChimeSound(ctx, req); });
256+
break;
257+
}
258+
}
259+
260+
void ChimeServer::HandlePlayChimeSound(HandlerContext & ctx, const Commands::PlayChimeSound::DecodableType & req)
261+
{
262+
263+
ChipLogDetail(Zcl, "Chime: PlayChimeSound");
264+
265+
// call the delegate to play the chime
266+
Status status = mDelegate.PlayChimeSound();
267+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status);
268+
}
269+
270+
} // namespace Clusters
271+
} // namespace app
272+
} // namespace chip
273+
274+
/** @brief Chime Cluster Server Init
275+
*
276+
* Server Init
277+
*
278+
*/
279+
void MatterChimePluginServerInitCallback() {}

0 commit comments

Comments
 (0)