Skip to content

Commit

Permalink
Added scene handler to mode select cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
lpbeliveau-silabs committed Oct 31, 2023
1 parent 5218c3b commit 31f6544
Showing 1 changed file with 132 additions and 0 deletions.
132 changes: 132 additions & 0 deletions src/app/clusters/mode-select-server/mode-select-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include <app/clusters/on-off-server/on-off-server.h>
#endif // EMBER_AF_PLUGIN_ON_OFF

#ifdef EMBER_AF_PLUGIN_SCENES
#include <app/clusters/scenes-server/scenes-server.h>
#endif // EMBER_AF_PLUGIN_SCENES

using namespace std;
using namespace chip;
using namespace chip::app;
Expand Down Expand Up @@ -95,6 +99,118 @@ CHIP_ERROR ModeSelectAttrAccess::Read(const ConcreteReadAttributePath & aPath, A

} // anonymous namespace

#ifdef EMBER_AF_PLUGIN_SCENES

static constexpr size_t kModeSelectMaxEnpointCount =
EMBER_AF_MODE_SELECT_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT;
class DefaultModeSelectSceneHandler : public scenes::DefaultSceneHandlerImpl
{
public:
// As per spec, 1 attribute is scenable in the mode select cluster
static constexpr uint8_t scenableAttributeCount = 1;

DefaultModeSelectSceneHandler() = default;
~DefaultModeSelectSceneHandler() override {}

// Default function for the mode select cluster, only puts the mode select cluster ID in the span if supported on the given
// endpoint
virtual void GetSupportedClusters(EndpointId endpoint, Span<ClusterId> & clusterBuffer) override
{
ClusterId * buffer = clusterBuffer.data();
if (emberAfContainsServer(endpoint, ModeSelect::Id) && clusterBuffer.size() >= 1)
{
buffer[0] = ModeSelect::Id;
clusterBuffer.reduce_size(1);
}
else
{
clusterBuffer.reduce_size(0);
}
}

// Default function for mode select cluster, only checks if mode select is enabled on the endpoint
bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override
{
return (cluster == ModeSelect::Id) && (emberAfContainsServer(endpoint, ModeSelect::Id));
}

/// @brief Serialize the Cluster's EFS value
/// @param endpoint target endpoint
/// @param cluster target cluster
/// @param serializedBytes data to serialize into EFS
/// @return CHIP_NO_ERROR if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT otherwise
CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) override
{
using AttributeValuePair = Scenes::Structs::AttributeValuePair::Type;

uint8_t currentMode;
// read CurrentMode value
EmberAfStatus status = Attributes::CurrentMode::Get(endpoint, &currentMode);
if (status != EMBER_ZCL_STATUS_SUCCESS)
{
ChipLogError(Zcl, "ERR: reading CurrentMode %x", status);
return CHIP_ERROR_READ_FAILED;
}

AttributeValuePair pairs[scenableAttributeCount];

pairs[0].attributeID = Attributes::CurrentMode::Id;
pairs[0].attributeValue = currentMode;

app::DataModel::List<AttributeValuePair> attributeValueList(pairs);

return EncodeAttributeValueList(attributeValueList, serializedBytes);
}

/// @brief Default EFS interaction when applying scene to the ModeSelect Cluster
/// @param endpoint target endpoint
/// @param cluster target cluster
/// @param serializedBytes Data from nvm
/// @param timeMs transition time in ms
/// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise
CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes,
scenes::TransitionTimeMs timeMs) override
{
app::DataModel::DecodableList<Scenes::Structs::AttributeValuePair::DecodableType> attributeValueList;

VerifyOrReturnError(cluster == CurrentMode::Id, CHIP_ERROR_INVALID_ARGUMENT);

ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList));

size_t attributeCount = 0;
ReturnErrorOnFailure(attributeValueList.ComputeSize(&attributeCount));
VerifyOrReturnError(attributeCount <= scenableAttributeCount, CHIP_ERROR_BUFFER_TOO_SMALL);

auto pair_iterator = attributeValueList.begin();
while (pair_iterator.Next())
{
auto & decodePair = pair_iterator.GetValue();
VerifyOrReturnError(decodePair.attributeID == Attributes::CurrentMode::Id, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(
mSceneEndpointStatePairs.InsertPair(EndpointStatePair(endpoint, static_cast<bool>(decodePair.attributeValue))));
}
// Verify that the EFS was completely read
CHIP_ERROR err = pair_iterator.GetStatus();
if (CHIP_NO_ERROR != err)
{
mSceneEndpointStatePairs.RemovePair(endpoint);
return err;
}

// TODO : Implement timer callback and pass level to it
// CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(delayMs), timerCallback,
// reinterpret_cast<void *>(static_cast<uintptr_t>(endpoint)));

return CHIP_NO_ERROR;
}

private:
// TODO : Implement timer callback function here
};
static DefaultModeSelectSceneHandler sModeSelectSceneHandler;

#endif // EMBER_AF_PLUGIN_SCENES

bool emberAfModeSelectClusterChangeToModeCallback(CommandHandler * commandHandler, const ConcreteCommandPath & commandPath,
const ModeSelect::Commands::ChangeToMode::DecodableType & commandData)
{
Expand All @@ -113,6 +229,15 @@ bool emberAfModeSelectClusterChangeToModeCallback(CommandHandler * commandHandle
}
ModeSelect::Attributes::CurrentMode::Set(endpointId, newMode);

// TODO : Compare with previous mode before invalidating scene?
#ifdef EMBER_AF_PLUGIN_SCENES
// the scene has been changed (the value of on/off has changed) so
// the current scene as described in the attribute table is invalid,
// so mark it as invalid (just writes the valid/invalid attribute)

Scenes::ScenesServer::Instance().MakeSceneInvalid(endpoint);
#endif // EMBER_AF_PLUGIN_SCENES

ChipLogProgress(Zcl, "ModeSelect: ChangeToMode successful");
commandHandler->AddStatus(commandPath, Status::Success);
return true;
Expand All @@ -138,6 +263,13 @@ void emberAfModeSelectClusterServerInitCallback(EndpointId endpointId)
EmberAfStatus status = Attributes::StartUpMode::Get(endpointId, startUpMode);
if (status == EMBER_ZCL_STATUS_SUCCESS && !startUpMode.IsNull())
{

#ifdef EMBER_AF_PLUGIN_SCENES
// TODO: Complete init and add getSceneHandler for the cluster
// Registers Scene handlers for the On/Off cluster on the server
// app::Clusters::Scenes::ScenesServer::Instance().RegisterSceneHandler(endpoint, handler);
#endif // EMBER_AF_PLUGIN_SCENES

#ifdef EMBER_AF_PLUGIN_ON_OFF
// OnMode with Power Up
// If the On/Off feature is supported and the On/Off cluster attribute StartUpOnOff is present, with a
Expand Down

0 comments on commit 31f6544

Please sign in to comment.