blob: b8b591bda24fda82e36b6eb8145ad9a9e25cf307 [file]
/*
*
* Copyright (c) 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.
*/
#include <app/clusters/electrical-energy-measurement-server/CodegenIntegration.h>
#include <protocols/interaction_model/StatusCode.h>
#include <app/EventLogging.h>
#include <app/reporting/reporting.h>
#include <app/util/attribute-storage.h>
#include <app/util/config.h>
#include <data-model-providers/codegen/CodegenDataModelProvider.h>
#include <data-model-providers/codegen/CodegenProcessingConfig.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <zap-generated/gen_config.h>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Attributes;
using namespace chip::app::Clusters::ElectricalEnergyMeasurement::Structs;
namespace {
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * EEMFirstInstance = nullptr;
inline void RegisterLegacyEEM(SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * inst)
{
inst->mpNext = EEMFirstInstance;
EEMFirstInstance = inst;
}
inline void UnregisterLegacyEEM(SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * inst)
{
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * current = EEMFirstInstance;
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * previous = nullptr;
while (current != nullptr)
{
if (current == inst)
{
if (previous == nullptr)
{
// Removing first element
EEMFirstInstance = current->mpNext;
}
else
{
previous->mpNext = current->mpNext;
}
break;
}
previous = current;
current = current->mpNext;
}
}
// Default empty accuracy used at construction time; real values are set later via SetMeasurementAccuracy.
const MeasurementAccuracyStruct::Type kDefaultAccuracy = {};
} // namespace
namespace chip {
namespace app {
namespace Clusters {
namespace ElectricalEnergyMeasurement {
ElectricalEnergyMeasurementAttrAccess::ElectricalEnergyMeasurementAttrAccess(BitMask<Feature> aFeature,
BitMask<OptionalAttributes> aOptionalAttrs,
EndpointId endpointId) :
mCluster(ElectricalEnergyMeasurementCluster::Config{
.endpointId = endpointId,
.featureFlags = aFeature,
.optionalAttributes = aOptionalAttrs,
.accuracyStruct = kDefaultAccuracy,
})
{
mClusterListNode.mValue = &mCluster.Cluster();
}
const ElectricalEnergyMeasurement::MeasurementData * MeasurementDataForEndpoint(EndpointId endpointId)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnValue(cluster != nullptr, nullptr);
return cluster->GetMeasurementData();
}
CHIP_ERROR SetMeasurementAccuracy(EndpointId endpointId, const MeasurementAccuracyStruct::Type & accuracy)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnError(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
return cluster->SetMeasurementAccuracy(accuracy);
}
CHIP_ERROR SetCumulativeReset(EndpointId endpointId, const Optional<CumulativeEnergyResetStruct::Type> & cumulativeReset)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnError(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
return cluster->SetCumulativeEnergyReset(cumulativeReset);
}
bool NotifyCumulativeEnergyMeasured(EndpointId endpointId, const Optional<EnergyMeasurementStruct::Type> & energyImported,
const Optional<EnergyMeasurementStruct::Type> & energyExported)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnValue(cluster != nullptr, false);
VerifyOrReturnValue(cluster->Features().Has(Feature::kCumulativeEnergy), false);
cluster->CumulativeEnergySnapshot(energyImported, energyExported);
return true;
}
bool NotifyPeriodicEnergyMeasured(EndpointId endpointId, const Optional<EnergyMeasurementStruct::Type> & energyImported,
const Optional<EnergyMeasurementStruct::Type> & energyExported)
{
ElectricalEnergyMeasurementCluster * cluster = FindElectricalEnergyMeasurementClusterOnEndpoint(endpointId);
VerifyOrReturnValue(cluster != nullptr, false);
VerifyOrReturnValue(cluster->Features().Has(Feature::kPeriodicEnergy), false);
cluster->PeriodicEnergySnapshot(energyImported, energyExported);
return true;
}
CHIP_ERROR ElectricalEnergyMeasurementAttrAccess::Init()
{
CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Register(mCluster.Registration());
RegisterLegacyEEM(&mClusterListNode);
if (err != CHIP_NO_ERROR)
{
#if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
ChipLogError(AppServer, "Failed to register cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
mCluster.Cluster().GetPaths()[0].mEndpointId, ChipLogValueMEI(ElectricalEnergyMeasurement::Id), err.Format());
#endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
}
return err;
}
void ElectricalEnergyMeasurementAttrAccess::Shutdown()
{
CHIP_ERROR err = CodegenDataModelProvider::Instance().Registry().Unregister(&mCluster.Cluster());
if (err != CHIP_NO_ERROR)
{
#if CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
ChipLogError(AppServer, "Failed to unregister cluster %u/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
mCluster.Cluster().GetPaths()[0].mEndpointId, ChipLogValueMEI(ElectricalEnergyMeasurement::Id), err.Format());
#endif // CHIP_CODEGEN_CONFIG_ENABLE_CODEGEN_INTEGRATION_LOOKUP_ERRORS
}
UnregisterLegacyEEM(&mClusterListNode);
}
bool ElectricalEnergyMeasurementAttrAccess::HasFeature(Feature aFeature) const
{
return mCluster.Cluster().Features().Has(aFeature);
}
bool ElectricalEnergyMeasurementAttrAccess::SupportsOptAttr(OptionalAttributes aOptionalAttrs) const
{
// Convert from OptionalAttributes enum to AttributeId and check OptionalAttributesSet from cluster
switch (aOptionalAttrs)
{
case OptionalAttributes::kOptionalAttributeCumulativeEnergyReset:
return mCluster.Cluster().OptionalAttributes().IsSet(CumulativeEnergyReset::Id);
default:
return false;
}
}
ElectricalEnergyMeasurementCluster * FindElectricalEnergyMeasurementClusterOnEndpoint(EndpointId endpointId)
{
SingleLinkedListNode<ElectricalEnergyMeasurementCluster *> * current = EEMFirstInstance;
while (current != nullptr)
{
if (current->mValue != nullptr && current->mValue->GetPaths()[0].mEndpointId == endpointId)
{
return current->mValue;
}
current = current->mpNext;
}
return nullptr;
}
} // namespace ElectricalEnergyMeasurement
} // namespace Clusters
} // namespace app
} // namespace chip