blob: 36747b218b32df27f2b1679303d310d5d6eb568d [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 "WindowCoveringDelegate.h"
#include <app-common/zap-generated/cluster-objects.h>
#include <app/data-model/Nullable.h>
#include <app/server-cluster/DefaultServerCluster.h>
#include <app/server-cluster/OptionalAttributeSet.h>
#include <clusters/WindowCovering/Attributes.h>
#include <clusters/WindowCovering/Enums.h>
#include <lib/support/BitFlags.h>
#include <lib/support/BitMask.h>
#include <protocols/interaction_model/StatusCode.h>
namespace chip {
namespace app {
namespace Clusters {
namespace WindowCovering {
static constexpr Percent100ths kWcPercent100thsMinOpen = 0;
static constexpr Percent100ths kWcPercent100thsMaxClosed = 10000;
static constexpr Percent100ths kWcPercent100thsMiddle = 5000;
static constexpr Percent100ths kWcPercent100thsCOEF = 100;
typedef DataModel::Nullable<Percent> NPercent;
typedef DataModel::Nullable<Percent100ths> NPercent100ths;
using OptionalAttributeSet =
app::OptionalAttributeSet<Attributes::NumberOfActuationsLift::Id, Attributes::NumberOfActuationsTilt::Id,
Attributes::CurrentPositionLiftPercentage::Id, Attributes::CurrentPositionTiltPercentage::Id,
Attributes::SafetyStatus::Id>;
// Match directly with OperationalStatus 2 bits Fields
enum class OperationalState : uint8_t
{
Stall = 0x00, // currently not moving
MovingUpOrOpen = 0x01, // is currently opening
MovingDownOrClose = 0x02, // is currently closing
Reserved = 0x03, // dont use
};
static_assert(sizeof(OperationalState) == sizeof(uint8_t), "OperationalState Size is not correct");
class WindowCoveringCluster : public DefaultServerCluster
{
public:
class Config
{
public:
Config(WindowCoveringDelegate & delegate) : mDelegate(delegate) {}
Config & WithFeatures(BitFlags<Feature> features)
{
mFeatures = features;
return *this;
}
Config & WithOptionalAttributes(OptionalAttributeSet optionalAttributes)
{
mOptionalAttributes = optionalAttributes;
return *this;
}
Config & WithType(Type type)
{
mType = type;
return *this;
}
Config & WithEndProductType(EndProductType endProductType)
{
mEndProductType = endProductType;
return *this;
}
WindowCoveringDelegate & mDelegate;
BitFlags<Feature> mFeatures;
OptionalAttributeSet mOptionalAttributes;
Type mType = Type::kRollerShade;
EndProductType mEndProductType = EndProductType::kRollerShade;
};
WindowCoveringCluster(EndpointId endpointId, const Config & config);
// Server cluster implementation
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & encoder) override;
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,
AttributeValueDecoder & decoder) override;
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path,
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) override;
CHIP_ERROR Startup(ServerClusterContext & context) override;
std::optional<DataModel::ActionReturnStatus> InvokeCommand(const DataModel::InvokeRequest & request,
chip::TLV::TLVReader & input_arguments,
CommandHandler * handler) override;
/**
* @brief Computes the motion lock status from the current Mode and ConfigStatus members.
*
* @return Status::Success if motion is allowed.
* Status::Busy if maintenance mode is active.
* Status::Failure if calibration mode is active (or otherwise not operational).
*/
std::optional<DataModel::ActionReturnStatus> GetMotionLockStatus() const;
// Setters and Getters
BitFlags<Feature> GetFeatureMap() const { return mFeatureMap; }
Type GetType() const { return mType; }
void SetNumberOfActuationsLift(uint16_t numOfLifts);
uint16_t GetNumberOfActuationsLift() const { return mNumberOfActuationsLift; }
void SetNumberOfActuationsTilt(uint16_t numOfLifts);
uint16_t GetNumberOfActuationsTilt() const { return mNumberOfActuationsTilt; }
void SetConfigStatus(chip::BitMask<ConfigStatus> status);
chip::BitMask<ConfigStatus> GetConfigStatus() const { return mConfigStatus; }
void SetOperationalStatus(chip::BitMask<OperationalStatus> newStatus);
chip::BitMask<OperationalStatus> GetOperationalStatus() const { return mOperationalStatus; }
void SetTargetPositionLiftPercent100ths(NPercent100ths newTargetLift);
NPercent100ths GetTargetPositionLiftPercent100ths() const { return mTargetPositionLiftPercent100ths; }
void SetTargetPositionTiltPercent100ths(NPercent100ths newTargetLift);
NPercent100ths GetTargetPositionTiltPercent100ths() const { return mTargetPositionTiltPercent100ths; }
EndProductType GetEndProductType() const { return mEndProductType; }
void SetCurrentPositionLiftPercent100ths(NPercent100ths curLiftPercent100ths);
NPercent100ths GetCurrentPositionLiftPercent100ths() const { return mCurrentPositionLiftPercent100ths; }
void SetCurrentPositionTiltPercent100ths(NPercent100ths curTiltPercent100ths);
NPercent100ths GetCurrentPositionTiltPercent100ths() const { return mCurrentPositionTiltPercent100ths; }
void SetMode(chip::BitMask<Mode> mode);
chip::BitMask<Mode> GetMode() const { return mMode; }
void SetSafetyStatus(chip::BitMask<SafetyStatus> status);
chip::BitMask<SafetyStatus> GetSafetyStatus() const { return mSafetyStatus; }
protected:
void SetType(Type type) { SetAttributeValue(mType, type, Attributes::Type::Id); }
void SetEndProductType(EndProductType type);
private:
// Percentage attributes are derived from Percent100ths, not stored separately.
static NPercent PercentFromPercent100ths(NPercent100ths percent100ths);
void UpdateOperationalStateForField(chip::BitMask<OperationalStatus> field, OperationalState state);
std::optional<DataModel::ActionReturnStatus> HandleUpOrOpen();
std::optional<DataModel::ActionReturnStatus> HandleDownOrClose();
std::optional<DataModel::ActionReturnStatus> HandleStopMotion(const Commands::StopMotion::DecodableType & fields);
std::optional<DataModel::ActionReturnStatus>
HandleGoToLiftPercentage(const Commands::GoToLiftPercentage::DecodableType & fields);
std::optional<DataModel::ActionReturnStatus>
HandleGoToTiltPercentage(const Commands::GoToTiltPercentage::DecodableType & fields);
WindowCoveringDelegate & mDelegate;
const BitFlags<WindowCovering::Feature> mFeatureMap;
const OptionalAttributeSet mOptionalAttributes;
// Attributes
Type mType;
uint16_t mNumberOfActuationsLift = 0;
uint16_t mNumberOfActuationsTilt = 0;
chip::BitMask<ConfigStatus> mConfigStatus;
NPercent100ths mTargetPositionLiftPercent100ths;
NPercent100ths mTargetPositionTiltPercent100ths;
chip::BitMask<OperationalStatus> mOperationalStatus;
EndProductType mEndProductType;
NPercent100ths mCurrentPositionLiftPercent100ths;
NPercent100ths mCurrentPositionTiltPercent100ths;
chip::BitMask<Mode> mMode;
chip::BitMask<SafetyStatus> mSafetyStatus;
};
} // namespace WindowCovering
} // namespace Clusters
} // namespace app
} // namespace chip