blob: 1b7dbc0e9c34c5eb6e3d0a38ddacf0668e932480 [file] [log] [blame]
/**
*
* Copyright (c) 2025 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.
*/
#include "identify-server.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app-common/zap-generated/ids/Commands.h>
#include <app/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <app/InteractionModelEngine.h>
#include <app/clusters/identify-server/IdentifyCluster.h>
#include <app/server-cluster/DefaultServerCluster.h>
#include <app/util/generic-callbacks.h>
#include <data-model-providers/codegen/ClusterIntegration.h>
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
#include <data-model-providers/codegen/CodegenProcessingConfig.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/TimerDelegate.h>
#include <platform/DefaultTimerDelegate.h>
#include <tracing/macros.h>
namespace {
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters::Identify;
using chip::app::Clusters::IdentifyCluster;
using chip::app::Clusters::IdentifyDelegate;
using chip::Protocols::InteractionModel::Status;
Identify * firstLegacyIdentify = nullptr;
DefaultTimerDelegate sDefaultTimerDelegate;
Identify * GetLegacyIdentifyInstance(EndpointId endpoint)
{
Identify * current = firstLegacyIdentify;
while (current != nullptr && current->mCluster.Cluster().GetPaths()[0].mEndpointId != endpoint)
{
current = current->nextIdentify;
}
return current;
}
class IdentifyLegacyDelegate : public IdentifyDelegate
{
public:
void OnIdentifyStart(IdentifyCluster & cluster) override
{
Identify * identify = GetLegacyIdentifyInstance(cluster.GetPaths()[0].mEndpointId);
if (identify != nullptr)
{
identify->mActive = true;
if (identify->mOnIdentifyStart)
{
identify->mOnIdentifyStart(identify);
}
}
}
void OnIdentifyStop(IdentifyCluster & cluster) override
{
Identify * identify = GetLegacyIdentifyInstance(cluster.GetPaths()[0].mEndpointId);
if (identify != nullptr)
{
identify->mActive = false;
if (identify->mOnIdentifyStop)
{
identify->mOnIdentifyStop(identify);
}
}
}
void OnTriggerEffect(IdentifyCluster & cluster) override
{
Identify * identify = GetLegacyIdentifyInstance(cluster.GetPaths()[0].mEndpointId);
if (identify != nullptr)
{
identify->mCurrentEffectIdentifier = cluster.GetEffectIdentifier();
identify->mEffectVariant = cluster.GetEffectVariant();
if (identify->mOnEffectIdentifier)
{
identify->mOnEffectIdentifier(identify);
}
}
}
bool IsTriggerEffectEnabled() const override { return true; }
};
IdentifyLegacyDelegate gLegacyDelegate;
inline void RegisterLegacyIdentify(Identify * inst)
{
inst->nextIdentify = firstLegacyIdentify;
firstLegacyIdentify = inst;
}
inline void UnregisterLegacyIdentify(Identify * inst)
{
if (firstLegacyIdentify == inst)
{
firstLegacyIdentify = firstLegacyIdentify->nextIdentify;
}
else if (firstLegacyIdentify != nullptr)
{
Identify * previous = firstLegacyIdentify;
Identify * current = firstLegacyIdentify->nextIdentify;
while (current != nullptr && current != inst)
{
previous = current;
current = current->nextIdentify;
}
if (current != nullptr)
{
previous->nextIdentify = current->nextIdentify;
}
}
}
} // namespace
IdentifyCluster * FindIdentifyClusterOnEndpoint(EndpointId endpointId)
{
Identify * legacyInstance = GetLegacyIdentifyInstance(endpointId);
if (legacyInstance != nullptr)
{
return &legacyInstance->mCluster.Cluster();
}
return nullptr;
}
Identify::Identify(EndpointId endpoint, onIdentifyStartCb onIdentifyStart, onIdentifyStopCb onIdentifyStop,
IdentifyTypeEnum identifyType, onEffectIdentifierCb onEffectIdentifier, EffectIdentifierEnum effectIdentifier,
EffectVariantEnum effectVariant, chip::TimerDelegate * timerDelegate) :
mOnIdentifyStart(onIdentifyStart),
mOnIdentifyStop(onIdentifyStop), mIdentifyType(identifyType), mOnEffectIdentifier(onEffectIdentifier),
mCurrentEffectIdentifier(effectIdentifier), mEffectVariant(effectVariant),
mCluster(chip::app::Clusters::IdentifyCluster::Config(endpoint, timerDelegate ? *timerDelegate : sDefaultTimerDelegate)
.WithIdentifyType(identifyType)
.WithDelegate(&gLegacyDelegate)
.WithEffectIdentifier(effectIdentifier)
.WithEffectVariant(effectVariant))
{
RegisterLegacyIdentify(this);
// CodegenDataModelProvider::Instance() is a Meyer’s singleton so it's safe to call this here without worrying about
// intialization order. It's also OK to Register() the cluster in the provider even if the endpoint is not yet started up. It
// will be started up when the endpoint is started and a context is set.
RETURN_SAFELY_IGNORED CodegenDataModelProvider::Instance().Registry().Register(mCluster.Registration());
};
Identify::~Identify()
{
RETURN_SAFELY_IGNORED CodegenDataModelProvider::Instance().Registry().Unregister(&mCluster.Cluster());
UnregisterLegacyIdentify(this);
}
void MatterIdentifyClusterInitCallback(EndpointId endpointId)
{
#if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
if (GetLegacyIdentifyInstance(endpointId) != nullptr &&
CodegenDataModelProvider::Instance().Registry().Get({ endpointId, Clusters::Identify::Id }) == nullptr)
{
ChipLogError(AppServer, "Warning: unexpected state. Failed to find Identify cluster registration for endpoint %u",
endpointId);
}
#endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
}
void MatterIdentifyClusterShutdownCallback(EndpointId, MatterClusterShutdownType) {}
// Legacy PluginServer callback stubs
void MatterIdentifyPluginServerInitCallback() {}
void MatterIdentifyPluginServerShutdownCallback() {}