blob: 3a0020c3e4530af29dc42d15f7d4e2d325a93b02 [file]
/*
*
* Copyright (c) 2023-2025 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
// Codegen backward-compat Instance wrappers for OperationalState-derived clusters.
// New code should construct OperationalStateCluster (or a derived class) directly and
// register it with the ServerClusterInterfaceRegistry.
#include "OperationalStateDelegate.h"
#include "OvenCavityOperationalStateCluster.h"
#include "RvcOperationalStateCluster.h"
#include <app/server-cluster/ServerClusterInterfaceRegistry.h>
#include <lib/support/CHIPMem.h>
namespace chip {
namespace app {
namespace Clusters {
namespace OperationalState {
// detail:: base classes guarantee that the cluster + registration storage is initialized
// before Instance receives references to them (base classes initialize before members).
namespace detail {
struct OperationalInstanceBase
{
RegisteredServerCluster<OperationalStateCluster> mCluster;
OperationalInstanceBase(Delegate * aDelegate, EndpointId aEndpointId, const OperationalStateCluster::Config & config = {}) :
mCluster(aEndpointId, aDelegate, config)
{}
};
} // namespace detail
/**
* Backward-compat lifecycle wrapper around OperationalStateCluster.
*
* Provides Init()/Shutdown() for registering/unregistering the cluster with the
* CodegenDataModelProvider, and forwards the full application-facing API.
*
* RvcOperationalState::Instance and OvenCavityOperationalState::Instance derive from this,
* so OperationalState::Instance * can hold any of the three cluster types.
*
* @note New applications should construct OperationalStateCluster directly.
*/
class Instance
{
public:
/**
* Standalone constructor: creates and owns an OperationalStateCluster for the given endpoint.
*/
Instance(Delegate * aDelegate, EndpointId aEndpointId, const OperationalStateCluster::Config & config = {});
~Instance();
CHIP_ERROR Init();
void Shutdown();
// Forwarders to the underlying cluster. Defined out-of-line in CodegenIntegration.cpp so the
// cluster methods are not inlined (and duplicated) into each shim — keeps the back-compat layer small.
CHIP_ERROR SetCurrentPhase(const DataModel::Nullable<uint8_t> & aPhase);
CHIP_ERROR SetOperationalState(uint8_t aOpState);
DataModel::Nullable<uint8_t> GetCurrentPhase() const;
uint8_t GetCurrentOperationalState() const;
void GetCurrentOperationalError(GenericOperationalError & error) const;
void UpdateCountdownTimeFromDelegate();
void OnOperationalErrorDetected(const Structs::ErrorStateStruct::Type & aError);
void OnOperationCompletionDetected(uint8_t aCompletionErrorCode,
const Optional<DataModel::Nullable<uint32_t>> & aTotalOperationalTime = NullOptional,
const Optional<DataModel::Nullable<uint32_t>> & aPausedTime = NullOptional);
void ReportOperationalStateListChange();
void ReportPhaseListChange();
bool IsSupportedPhase(uint8_t aPhase);
bool IsSupportedOperationalState(uint8_t aState);
protected:
/**
* Constructor for derived instances (Rvc, OvenCavity) that supply their own cluster storage.
* The derived class must ensure the cluster and registration outlive this object.
*/
Instance(OperationalStateCluster & cluster, ServerClusterRegistration & registration, Delegate * aDelegate);
OperationalStateCluster & Cluster() { return mCluster; }
const OperationalStateCluster & Cluster() const { return mCluster; }
bool mRegistered = false;
private:
Delegate * mDelegate;
// mOwnedStorage declared before mCluster so it is initialized first in the standalone constructor,
// allowing mCluster to be bound to the storage's cluster object. Held by Platform::UniquePtr so the
// storage lifetime is managed automatically (no manual delete) and the type is non-copyable.
Platform::UniquePtr<detail::OperationalInstanceBase> mOwnedStorage;
OperationalStateCluster & mCluster;
ServerClusterRegistration * mRegPtr;
};
} // namespace OperationalState
namespace RvcOperationalState {
namespace detail {
struct RvcInstanceBase
{
RegisteredServerCluster<RvcOperationalStateCluster> mCluster;
RvcInstanceBase(Delegate * aDelegate, EndpointId aEndpointId,
const OperationalState::OperationalStateCluster::Config & config = {}) :
mCluster(aEndpointId, aDelegate, config)
{}
};
} // namespace detail
class Instance : private detail::RvcInstanceBase, public OperationalState::Instance
{
public:
Instance(Delegate * aDelegate, EndpointId aEndpointId, const OperationalState::OperationalStateCluster::Config & config = {}) :
detail::RvcInstanceBase(aDelegate, aEndpointId, config),
OperationalState::Instance(detail::RvcInstanceBase::mCluster.Cluster(), detail::RvcInstanceBase::mCluster.Registration(),
aDelegate)
{}
};
} // namespace RvcOperationalState
namespace OvenCavityOperationalState {
namespace detail {
struct OvenInstanceBase
{
RegisteredServerCluster<OvenCavityOperationalStateCluster> mCluster;
OvenInstanceBase(OperationalState::Delegate * aDelegate, EndpointId aEndpointId,
const OperationalState::OperationalStateCluster::Config & config = {}) :
mCluster(aEndpointId, aDelegate, config)
{}
};
} // namespace detail
class Instance : private detail::OvenInstanceBase, public OperationalState::Instance
{
public:
Instance(OperationalState::Delegate * aDelegate, EndpointId aEndpointId,
const OperationalState::OperationalStateCluster::Config & config = {}) :
detail::OvenInstanceBase(aDelegate, aEndpointId, config),
OperationalState::Instance(detail::OvenInstanceBase::mCluster.Cluster(), detail::OvenInstanceBase::mCluster.Registration(),
aDelegate)
{}
};
} // namespace OvenCavityOperationalState
} // namespace Clusters
} // namespace app
} // namespace chip