blob: f1d0d60833c8e00d44ec4de329f633f64da83549 [file]
/*
*
* Copyright (c) 2026 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.
*/
#pragma once
#include <app/data-model/Nullable.h>
#include <app/server-cluster/OptionalAttributeSet.h>
#include <clusters/PowerSource/Attributes.h>
#include <clusters/PowerSource/Enums.h>
#include <lib/support/ScopedMemoryBuffer.h>
#include <lib/support/Span.h>
#include <lib/support/TimerDelegate.h>
#include <atomic>
#include <bitset>
#include <functional>
#include <type_traits>
namespace chip::app::Clusters::PowerSource::detail {
using DataModel::Nullable;
constexpr size_t kBitSetSize = 16;
using BitSetType = std::bitset<kBitSetSize>;
struct MandatoryModule
{
PowerSourceStatusEnum status{};
uint8_t order{};
CharSpan description{};
protected:
Span<const EndpointId> endpointList{};
};
struct WiredMandatoryModule
{
WiredCurrentTypeEnum wiredCurrentType{};
};
struct BatteryMandatoryModule
{
BatChargeLevelEnum batChargeLevel{};
bool batReplacementNeeded{};
BatReplaceabilityEnum batReplaceability{};
};
struct ReplaceableMandatoryModule
{
CharSpan batReplacementDescription{};
uint8_t batQuantity{};
};
struct RechargeableMandatoryModule
{
BatChargeStateEnum batChargeState{};
bool batFunctionalWhileCharging{};
};
template <bool used>
struct WiredAssessedInputVoltageModule
{
};
template <>
struct WiredAssessedInputVoltageModule<true>
{
Nullable<uint32_t> wiredAssessedInputVoltage{};
};
template <bool used>
struct WiredAssessedInputFrequencyModule
{
};
template <>
struct WiredAssessedInputFrequencyModule<true>
{
Nullable<uint16_t> wiredAssessedInputFrequency{};
};
template <bool used>
struct WiredAssessedCurrentModule
{
};
template <>
struct WiredAssessedCurrentModule<true>
{
Nullable<uint32_t> wiredAssessedCurrent{};
};
template <bool used>
struct WiredNominalVoltageModule
{
};
template <>
struct WiredNominalVoltageModule<true>
{
uint32_t wiredNominalVoltage{};
};
template <bool used>
struct WiredMaximumCurrentModule
{
};
template <>
struct WiredMaximumCurrentModule<true>
{
uint32_t wiredMaximumCurrent{};
};
template <bool used>
struct WiredPresentModule
{
};
template <>
struct WiredPresentModule<true>
{
bool wiredPresent{};
};
template <bool used>
struct ActiveWiredFaultsModule
{
};
template <>
struct ActiveWiredFaultsModule<true>
{
protected:
BitSetType activeWiredFaultsBitSet{};
};
template <bool used>
struct BatVoltageModule
{
};
template <>
struct BatVoltageModule<true>
{
Nullable<uint32_t> batVoltage{};
};
template <bool used>
struct BatPercentRemainingModule
{
};
template <>
struct BatPercentRemainingModule<true>
{
Nullable<uint8_t> batPercentRemaining{};
};
template <bool used>
struct BatTimeRemainingModule
{
};
template <>
struct BatTimeRemainingModule<true>
{
Nullable<uint32_t> batTimeRemaining{};
};
template <bool used>
struct BatPresentModule
{
};
template <>
struct BatPresentModule<true>
{
bool batPresent{};
};
template <bool used>
struct ActiveBatFaultsModule
{
};
template <>
struct ActiveBatFaultsModule<true>
{
protected:
BitSetType activeBatFaultsBitSet{};
};
template <bool used>
struct BatCommonDesignationModule
{
};
template <>
struct BatCommonDesignationModule<true>
{
BatCommonDesignationEnum batCommonDesignation{};
};
template <bool used>
struct BatANSIDesignationModule
{
};
template <>
struct BatANSIDesignationModule<true>
{
CharSpan batANSIDesignation{};
};
template <bool used>
struct BatIECDesignationModule
{
};
template <>
struct BatIECDesignationModule<true>
{
CharSpan batIECDesignation{};
};
template <bool used>
struct BatApprovedChemistryModule
{
};
template <>
struct BatApprovedChemistryModule<true>
{
BatApprovedChemistryEnum batApprovedChemistry{};
};
template <bool used>
struct BatCapacityModule
{
};
template <>
struct BatCapacityModule<true>
{
uint32_t batCapacity{};
};
template <bool used>
struct BatTimeToFullChargeModule
{
};
template <>
struct BatTimeToFullChargeModule<true>
{
Nullable<uint32_t> batTimeToFullCharge{};
};
template <bool used>
struct BatChargingCurrentModule
{
};
template <>
struct BatChargingCurrentModule<true>
{
Nullable<uint32_t> batChargingCurrent{};
};
template <bool used>
struct ActiveBatChargeFaultsModule
{
};
template <>
struct ActiveBatChargeFaultsModule<true>
{
protected:
BitSetType activeBatChargeFaultsBitSet{};
};
template <bool used, uint32_t optionalAttributeBits>
struct WiredModule
{
};
template <uint32_t optionalAttributeBits>
struct WiredModule<true, optionalAttributeBits>
: public WiredMandatoryModule,
public WiredAssessedInputVoltageModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredAssessedInputVoltage::Id)>,
public WiredAssessedInputFrequencyModule<
AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredAssessedInputFrequency::Id)>,
public WiredAssessedCurrentModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredAssessedCurrent::Id)>,
public WiredNominalVoltageModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredNominalVoltage::Id)>,
public WiredMaximumCurrentModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredMaximumCurrent::Id)>,
public WiredPresentModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::WiredPresent::Id)>,
public ActiveWiredFaultsModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::ActiveWiredFaults::Id)>
{
};
template <bool used, uint32_t optionalAttributeBits>
struct OnlyBatteryModule
{
};
template <uint32_t optionalAttributeBits>
struct OnlyBatteryModule<true, optionalAttributeBits>
: public BatteryMandatoryModule,
public BatVoltageModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatVoltage::Id)>,
public BatPercentRemainingModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatPercentRemaining::Id)>,
public BatTimeRemainingModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatTimeRemaining::Id)>,
public BatPresentModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatPresent::Id)>,
public ActiveBatFaultsModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::ActiveBatFaults::Id)>
{
};
template <bool used, uint32_t optionalAttributeBits>
struct ReplaceableModule
{
};
template <uint32_t optionalAttributeBits>
struct ReplaceableModule<true, optionalAttributeBits>
: public ReplaceableMandatoryModule,
public BatCommonDesignationModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatCommonDesignation::Id)>,
public BatANSIDesignationModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatANSIDesignation::Id)>,
public BatIECDesignationModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatIECDesignation::Id)>,
public BatApprovedChemistryModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatApprovedChemistry::Id)>
{
};
template <bool used, uint32_t optionalAttributeBits>
struct RechargeableModule
{
};
template <uint32_t optionalAttributeBits>
struct RechargeableModule<true, optionalAttributeBits>
: public RechargeableMandatoryModule,
public BatTimeToFullChargeModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatTimeToFullCharge::Id)>,
public BatChargingCurrentModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::BatChargingCurrent::Id)>,
public ActiveBatChargeFaultsModule<AttributeSet(optionalAttributeBits).IsSet(Attributes::ActiveBatChargeFaults::Id)>
{
};
template <bool used, bool supportsReplaceable, bool supportsRechargeable, uint32_t optionalAttributeBits>
struct BatteryModule
{
};
template <bool supportsReplaceable, bool supportsRechargeable, uint32_t optionalAttributeBits>
struct BatteryModule<true, supportsReplaceable, supportsRechargeable, optionalAttributeBits>
: public OnlyBatteryModule<true, optionalAttributeBits>,
public ReplaceableModule<supportsReplaceable, optionalAttributeBits>,
public RechargeableModule<supportsRechargeable, optionalAttributeBits>,
public BatCapacityModule<(supportsReplaceable || supportsRechargeable) &&
AttributeSet(optionalAttributeBits).IsSet(Attributes::BatCapacity::Id)>
{
protected:
bool batReplaceable = false;
bool batRechargeable = false;
TimerDelegate * mTimerDelegate{ nullptr };
};
template <std::underlying_type_t<Feature> featureBits, uint32_t optionalAttributeBits>
struct AllModules : public MandatoryModule,
public WiredModule<BitFlags<Feature>(featureBits).Has(Feature::kWired), optionalAttributeBits>,
public BatteryModule<BitFlags<Feature>(featureBits).Has(Feature::kBattery),
BitFlags<Feature>(featureBits).Has(Feature::kReplaceable),
BitFlags<Feature>(featureBits).Has(Feature::kRechargeable), optionalAttributeBits>
{
};
class BatteryTimerContext : public TimerContext
{
public:
constexpr static inline uint16_t kTimerDurationS = 10;
struct NotifierDelegate
{
virtual ~NotifierDelegate() = default;
virtual void Notify(AttributeId id) = 0;
};
BatteryTimerContext(AttributeId id, TimerDelegate & timerDelegate, NotifierDelegate & notifier) :
mId(id), mTimerDelegate(timerDelegate), mNotifier(notifier)
{}
CriticalFailure NotifyOrSchedule(uint32_t value)
{
mToBeReported = value;
// If same value as last reported, just return.
VerifyOrReturnValue(mToBeReported != mReported, CHIP_NO_ERROR);
// If currently there is a timer running, last report was less than kTimerDurationS seconds ago, so just return.
VerifyOrReturnValue(mTimerDelegate.IsTimerActive(this) == false, CHIP_NO_ERROR);
// Else, report the change and start the timer
NotifyChange();
return mTimerDelegate.StartTimer(this, System::Clock::Seconds16(kTimerDurationS));
}
void CancelCurrentTimer() { mTimerDelegate.CancelTimer(this); }
void TimerFired() override
{
// If at the end of the timer a different value to report has not been set, just return.
VerifyOrReturn(mToBeReported != mReported);
// Else, report the change and restart the timer.
NotifyChange();
mTimerDelegate.CancelTimer(this);
LogErrorOnFailure(mTimerDelegate.StartTimer(this, System::Clock::Seconds16(kTimerDurationS)));
}
AttributeId GetAttributeId() const { return mId; }
private:
const AttributeId mId;
uint32_t mReported{};
uint32_t mToBeReported{};
TimerDelegate & mTimerDelegate;
NotifierDelegate & mNotifier;
void NotifyChange()
{
mReported = mToBeReported;
mNotifier.Notify(mId);
}
};
template <bool used>
struct BatteryTimerContextsModule
{
};
template <>
struct BatteryTimerContextsModule<true>
{
BatteryTimerContext batPercentRemainingNotifyTimerContext;
BatteryTimerContext batTimeRemainingNotifyTimerContext;
BatteryTimerContext batTimeToFullChargeNotifyTimerContext;
BatteryTimerContextsModule(TimerDelegate & timerDelegate, BatteryTimerContext::NotifierDelegate & notifier) :
batPercentRemainingNotifyTimerContext(PowerSource::Attributes::BatPercentRemaining::Id, timerDelegate, notifier),
batTimeRemainingNotifyTimerContext(PowerSource::Attributes::BatTimeRemaining::Id, timerDelegate, notifier),
batTimeToFullChargeNotifyTimerContext(PowerSource::Attributes::BatTimeToFullCharge::Id, timerDelegate, notifier)
{}
};
} // namespace chip::app::Clusters::PowerSource::detail