Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chime Cluster Definition and server code #35729

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ jobs:
src/app/zap-templates/zcl/data-model/chip/chip-ota.xml \
src/app/zap-templates/zcl/data-model/chip/chip-types.xml \
src/app/zap-templates/zcl/data-model/chip/channel-cluster.xml \
src/app/zap-templates/zcl/data-model/chip/chime-cluster.xml \
src/app/zap-templates/zcl/data-model/chip/clusters-extensions.xml \
src/app/zap-templates/zcl/data-model/chip/color-control-cluster.xml \
src/app/zap-templates/zcl/data-model/chip/commissioner-control-cluster.xml \
Expand Down
1 change: 1 addition & 0 deletions scripts/rules.matterlint
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ load "../src/app/zap-templates/zcl/data-model/chip/boolean-state-cluster.xml";
load "../src/app/zap-templates/zcl/data-model/chip/actions-cluster.xml";
load "../src/app/zap-templates/zcl/data-model/chip/bridged-device-basic-information.xml";
load "../src/app/zap-templates/zcl/data-model/chip/channel-cluster.xml";
load "../src/app/zap-templates/zcl/data-model/chip/chime-cluster.xml";
load "../src/app/zap-templates/zcl/data-model/chip/chip-ota.xml";
load "../src/app/zap-templates/zcl/data-model/chip/chip-types.xml";
load "../src/app/zap-templates/zcl/data-model/chip/clusters-extensions.xml";
Expand Down
169 changes: 169 additions & 0 deletions src/app/clusters/chime-server/chime-server.cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, the implementation would be a separate PR from adding the XML.

Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
*
* Copyright (c) 2024 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.
*/

/****************************************************************************'
* @file
* @brief Implementation for the Chime Server Cluster
***************************************************************************/


#include "chime-server.h"

#include <app/AttributeAccessInterfaceRegistry.h>
#include <app/CommandHandlerInterfaceRegistry.h>
#include <app/ConcreteAttributePath.h>
#include <app/InteractionModelEngine.h>
#include <app/util/attribute-storage.h>
#include <app/util/util.h>
#include <protocols/interaction_model/StatusCode.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::DataModel;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::Chime;
using namespace chip::app::Clusters::Chime::Attributes;
using chip::Protocols::InteractionModel::Status;


namespace chip {
namespace app {
namespace Clusters {

ChimeServer::ChimeServer(EndpointId endpointId, ChimeDelegate & delegate) :
AttributeAccessInterface(MakeOptional(endpointId), Chime::Id),
CommandHandlerInterface(MakeOptional(endpointId), Chime::Id), mDelegate(delegate)
{
mDelegate.SetChimeServer(this);
}

ChimeServer::~ChimeServer()
{
AttributeAccessInterfaceRegistry::Instance().Unregister(this);
CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this);
}


CHIP_ERROR ChimeServer::Init()
{
VerifyOrReturnError(AttributeAccessInterfaceRegistry::Instance().Register(this), CHIP_ERROR_INTERNAL);
ReturnErrorOnFailure(CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(this));
return CHIP_NO_ERROR;
}

// AttributeAccessInterface
CHIP_ERROR ChimeServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
VerifyOrDie(aPath.mClusterId == Chime::Id);

switch (aPath.mAttributeId)
{
case InstalledChimeSounds::Id:
return aEncoder.Encode(mDelegate.GetInstalledChimeSounds());

case ActiveChimeSoundId::Id:
return aEncoder.Encode(mDelegate.GetActiveChimeSoundId());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if the simple things that can be stored in the cluster were stored there, so we can mark things dirty properly on changes.


case Enabled::Id:
return aEncoder.Encode(mDelegate.GetEnabled());
}

return CHIP_NO_ERROR;
}

CHIP_ERROR ChimeServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
{
VerifyOrDie(aPath.mClusterId == Chime::Id);

switch (aPath.mAttributeId)
{
case ActiveChimeSoundId::Id: {
uint8_t newValue;
ReturnErrorOnFailure(aDecoder.Decode(newValue));
ReturnErrorOnFailure(SetActiveChimeSoundId(newValue));
return CHIP_NO_ERROR;

}
case Enabled::Id: {
bool newValue;
ReturnErrorOnFailure(aDecoder.Decode(newValue));
ReturnErrorOnFailure(mDelegate.SetEnabled(newValue));
return CHIP_NO_ERROR;
}

default:
// Unknown attribute
return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
}

}

CHIP_ERROR ChimeServer::SetActiveChimeSoundId(uint8_t soundId)
{
uint8_t currentSoundId = mDelegate.GetActiveChimeSoundId();
bool activeSoundIdChanged = !(currentSoundId == soundId);

VerifyOrReturnError(activeSoundIdChanged, CHIP_NO_ERROR);
VerifyOrDie(mDelegate.SetActiveChimeSoundId(soundId) == CHIP_NO_ERROR);
MatterReportingAttributeChangeCallback(GetEndpointId(), Chime::Id, ActiveChimeSoundId::Id);

return CHIP_NO_ERROR;
}

CHIP_ERROR ChimeServer::SetEnabled(bool enabled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but the write path is not calling this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's an error

{
bool currentlyEnabled = mDelegate.GetEnabled();
bool enableChanged = !(currentlyEnabled == enabled);

VerifyOrReturnError(enableChanged, CHIP_NO_ERROR);
VerifyOrDie(mDelegate.SetEnabled(enabled) == CHIP_NO_ERROR);
MatterReportingAttributeChangeCallback(GetEndpointId(), Chime::Id, Enabled ::Id);

return CHIP_NO_ERROR;
}

void ChimeServer::InvokeCommand(HandlerContext & ctx)
{
switch (ctx.mRequestPath.mCommandId)
{
case Commands::PlayChimeSound::Id:
CommandHandlerInterface::HandleCommand<Commands::PlayChimeSound::DecodableType>(
ctx, [this](HandlerContext & ctx, const auto & req) { HandlePlayChimeSound(ctx, req); });
break;
}
}

void ChimeServer::HandlePlayChimeSound(HandlerContext & ctx, const Commands::PlayChimeSound::DecodableType & req)
{

ChipLogDetail(Zcl, "Chime: PlayChimeSound");

// call the delegate to play the chime
Status status = mDelegate.playChimeSound();
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status);
}

} // namespace Clusters
} // namespace app
} // namespace chip

/** @brief Chime Cluster Server Init
*
* Server Init
*
*/
void MatterChimePluginServerInitCallback(){}
111 changes: 111 additions & 0 deletions src/app/clusters/chime-server/chime-server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* 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-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandlerInterface.h>
#include <app/ConcreteAttributePath.h>
#include <app/InteractionModelEngine.h>
#include <app/MessageDef/StatusIB.h>
#include <app/reporting/reporting.h>
#include <app/util/attribute-storage.h>
#include <lib/core/CHIPError.h>
#include <protocols/interaction_model/StatusCode.h>

namespace chip {
namespace app {
namespace Clusters {

class ChimeDelegate;


class ChimeServer : private AttributeAccessInterface, private CommandHandlerInterface
{
public:

ChimeServer(EndpointId endpointId, ChimeDelegate & delegate);
~ChimeServer();

CHIP_ERROR Init();

private:
ChimeDelegate & mDelegate;

EndpointId GetEndpointId() { return AttributeAccessInterface::GetEndpointId().Value(); }

// AttributeAccessInterface
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override;
CHIP_ERROR SetActiveChimeSoundId(uint8_t chimeSoundId);
CHIP_ERROR SetEnabled(bool enabled);

// CommandHandlerInterface
void InvokeCommand(HandlerContext & ctx) override;

void HandlePlayChimeSound(HandlerContext & ctx, const Chime::Commands::PlayChimeSound::DecodableType & req);

};

/** @brief
* Defines methods for implementing application-specific logic for the Chime Cluster.
*/
class ChimeDelegate
{
public:
ChimeDelegate() = default;

virtual ~ChimeDelegate() = default;

// Get Attribute Methods
virtual DataModel::List<const Chime::Structs::ChimeSoundStruct::Type>& GetInstalledChimeSounds() = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the lifetime of the buffer backing that list? How does the delegate know to not deallocate it?

Also, it it intentional that this implementation does not allow chunking the list?

virtual uint8_t GetActiveChimeSoundId() = 0;
virtual bool GetEnabled() = 0;


// Set Attribute Methods
virtual CHIP_ERROR SetActiveChimeSoundId(uint8_t chimeSoundId) = 0;
virtual CHIP_ERROR SetEnabled(bool enabled) = 0;

// Commands
/**
* @brief Delegate should implement a handler to play the currently active chime sound.
* It should report Status::Success if successful and may
* return other Status codes if it fails
*/
virtual Protocols::InteractionModel::Status playChimeSound() = 0;




private:
friend class ChimeServer;

ChimeServer * mChimeServer = nullptr;

void SetChimeServer(ChimeServer * chimeServer) { mChimeServer = chimeServer; }

protected:
ChimeServer * GetChimeServer() const { return mChimeServer; }
};

} // namespace Clusters
} // namespace app
} // namespace chip

1 change: 1 addition & 0 deletions src/app/common/templates/config-data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ CommandHandlerInterfaceOnlyClusters:
- RVC Operational State
- Sample MEI
- Microwave Oven Control
- Chime
- Energy EVSE
- Energy EVSE Mode
- Device Energy Management
Expand Down
57 changes: 57 additions & 0 deletions src/app/zap-templates/zcl/data-model/chip/chime-cluster.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0"?>
<!--
Copyright (c) 2024 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.
-->
<configurator>
<domain name="CHIP"/>

<struct name="ChimeSoundStruct" apiMaturity="provisional">
<cluster code="0x0556"/>
<item name="ChimeId" type="int8u"/>
<item name="Name" type="char_string" max="48"/>
</struct>

<cluster apiMaturity="provisional">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the spec for this? I don't see it in the Matter appclusters spec on "master"....

It's impossible to review this XML without the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's in the Cameras branch

<name>Chime</name>
<domain>Camera</domain>
<code>0x0556</code>
<define>CHIME_CLUSTER</define>
<description>Attributes and commands to configure and play Chime sounds</description>

<!-- cluster revision -->
<globalAttribute side="either" code="0xFFFD" value="1"/>

<attribute side="server" code="0x0000" define="CHIME_INSTALLED_CHIME_SOUNDS" type="array" entryType="ChimeSoundStruct" min="1" max="255" writable="false" optional="false">
<description>InstalledChimeSounds</description>
<access op="read" privilege="view"/>
</attribute>
<attribute side="server" code="0x0001" define="CHIME_ACTIVE_CHIME_SOUND_ID" type="int8u" default="0x00" optional="false">
<description>ActiveChimeSoundId</description>
<access op="read" privilege="view"/>
<access op="write" privilege="operate"/>
</attribute>
<attribute side="server" code="0x0002" define="CHIME_ENABLED" type="boolean" default="1" optional="false">
<description>Enabled</description>
<access op="read" privilege="view"/>
<access op="write" privilege="operate"/>
</attribute>

<command source="client" code="0x00" name="PlayChimeSound" optional="false">
<description>Plays the currently active chime sound.</description>
<access op="invoke" privilege="operate"/>
</command>

</cluster>
</configurator>
2 changes: 2 additions & 0 deletions src/app/zap-templates/zcl/zcl-with-test-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"bridged-device-basic-information.xml",
"chip-ota.xml",
"channel-cluster.xml",
"chime-cluster.xml",
"clusters-extensions.xml",
"color-control-cluster.xml",
"commissioner-control-cluster.xml",
Expand Down Expand Up @@ -191,6 +192,7 @@
"MaxPathsPerInvoke"
],
"Bridged Device Basic Information": ["ProductAppearance"],
"Chime": ["ActiveChimeSoundId", "Enabled"],
"Descriptor": ["ClusterRevision", "FeatureMap"],
"Device Energy Management": [
"ESAType",
Expand Down
2 changes: 2 additions & 0 deletions src/app/zap-templates/zcl/zcl.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"bridged-device-basic-information.xml",
"chip-ota.xml",
"channel-cluster.xml",
"chime-cluster.xml",
"clusters-extensions.xml",
"color-control-cluster.xml",
"commissioner-control-cluster.xml",
Expand Down Expand Up @@ -185,6 +186,7 @@
"MaxPathsPerInvoke"
],
"Bridged Device Basic Information": ["ProductAppearance"],
"Chime": ["ActiveChimeSoundId", "Enabled"],
"Descriptor": ["ClusterRevision", "FeatureMap"],
"Device Energy Management": [
"ESAType",
Expand Down
Loading
Loading