blob: 6e774319fff4353b49f31b62695d50f70311ea93 [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.
*/
/**
* @file Cross-platform API to handle cluster-specific logic for the valve configuration and control cluster on a single endpoint.
*/
#pragma once
#include "closure-dimension-cluster-objects.h"
#include "closure-dimension-delegate.h"
#include "closure-dimension-matter-context.h"
#include <app/cluster-building-blocks/QuieterReporting.h>
namespace chip {
namespace app {
namespace Clusters {
namespace ClosureDimension {
/**
* @brief Structure is used to configure and validate the Cluster configuration.
* Validates if the feature map, attributes and commands configuration is valid.
*/
struct ClusterConformance
{
BitFlags<Feature> & FeatureMap() { return mFeatureMap; }
const BitFlags<Feature> & FeatureMap() const { return mFeatureMap; }
inline bool HasFeature(Feature aFeature) const { return mFeatureMap.Has(aFeature); }
/**
* @brief Function determines if Cluster conformance is valid
*
* The function executes these checks in order to validate the conformance
* 1. Check if either Positioning or MotionLatching is supported. If neither are enabled, returns false.
* 2. If Unit, Limitation or speed is enabled, Positioning must be enabled. Return false otherwise.
* 3. If Translation, Rotation or Modulation is enabled, Positioning must be enabled. Return false otherwise.
* 4. Only one of Translation, Rotation or Modulation must be enabled. Return false otherwise.
* 5. If the Overflow attribute is supported, at least one of Rotation or MotionLatching feature must be supported.
* Return false otherwise.
* 6. If Rotation feature is enabled, then the Overflow attribute must be supported. Return false otherwise.
*
* @return true, the cluster confirmance is valid
* false, otherwise
*/
bool Valid() const
{
// Positioning or Matching must be enabled
VerifyOrReturnValue(HasFeature(Feature::kPositioning) || HasFeature(Feature::kMotionLatching), false,
ChipLogError(AppServer, "Validation failed: Neither Positioning nor MotionLatching is enabled."));
// If Unit, Limitation or speed is enabled, Positioning must be enabled
if (HasFeature(Feature::kUnit) || HasFeature(Feature::kLimitation) || HasFeature(Feature::kSpeed))
{
VerifyOrReturnValue(
HasFeature(Feature::kPositioning), false,
ChipLogError(AppServer, "Validation failed: Unit , Limitation, and speed requires the Positioning feature."));
}
// If Translation, Rotation or Modulation is enabled, Positioning must be enabled.
if (HasFeature(Feature::kTranslation) || HasFeature(Feature::kRotation) || HasFeature(Feature::kModulation))
{
VerifyOrReturnValue(
HasFeature(Feature::kPositioning), false,
ChipLogError(NotSpecified, "Validation failed: Translation, Rotation or Modulation requires Positioning enabled."));
}
// Only one of Translation, Rotation or Modulation features must be enabled. Return false otherwise.
if ((HasFeature(Feature::kTranslation) && HasFeature(Feature::kRotation)) ||
(HasFeature(Feature::kRotation) && HasFeature(Feature::kModulation)) ||
(HasFeature(Feature::kModulation) && HasFeature(Feature::kTranslation)))
{
ChipLogError(AppServer, "Validation failed: Only one of Translation, Rotation or Modulation feature can be enabled.");
return false;
}
return true;
}
private:
BitFlags<Feature> mFeatureMap;
};
/**
* @brief Struct to store the cluster Initilization parameters
*/
struct ClusterInitParameters
{
TranslationDirectionEnum translationDirection = TranslationDirectionEnum::kUnknownEnumValue;
RotationAxisEnum rotationAxis = RotationAxisEnum::kUnknownEnumValue;
ModulationTypeEnum modulationType = ModulationTypeEnum::kUnknownEnumValue;
};
/**
* @brief Struct to store the current cluster state
*/
struct ClusterState
{
DataModel::Nullable<GenericDimensionStateStruct> currentState{ DataModel::NullNullable };
DataModel::Nullable<GenericDimensionStateStruct> targetState{ DataModel::NullNullable };
Percent100ths resolution = 1;
Percent100ths stepValue = 1;
ClosureUnitEnum unit = ClosureUnitEnum::kUnknownEnumValue;
DataModel::Nullable<Structs::UnitRangeStruct::Type> unitRange = DataModel::Nullable<Structs::UnitRangeStruct::Type>();
Structs::RangePercent100thsStruct::Type limitRange{};
TranslationDirectionEnum translationDirection = TranslationDirectionEnum::kUnknownEnumValue;
RotationAxisEnum rotationAxis = RotationAxisEnum::kUnknownEnumValue;
OverflowEnum overflow = OverflowEnum::kUnknownEnumValue;
ModulationTypeEnum modulationType = ModulationTypeEnum::kUnknownEnumValue;
BitFlags<LatchControlModesBitmap> latchControlModes;
};
class ClusterLogic
{
public:
/**
* @brief Instantiates a ClusterLogic class. The caller maintains ownership of the driver and the context,
* but provides them for use by the ClusterLogic class.
*/
ClusterLogic(DelegateBase & delegate, MatterContext & matterContext) : mDelegate(delegate), mMatterContext(matterContext) {}
const ClusterState & GetState() { return mState; }
const ClusterConformance & GetConformance() { return mConformance; }
/**
* @brief Validates the conformance and performs initialisation and sets up the ClusterInitParameters into Attributes.
*
* @param [in] conformance cluster conformance
* @param [in] clusterInitParameters cluster Init Parameters
*
* @return CHIP_ERROR_INCORRECT_STATE if the cluster has already been initialized,
* CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR if the conformance is incorrect.
* Set function errors if setting the attributes with the provided ClusterInitParameters fails.
* CHIP_NO_ERROR on succesful initialisation.
*/
CHIP_ERROR Init(const ClusterConformance & conformance, const ClusterInitParameters & clusterInitParameters);
/**
* @brief Set Current State.
*
* @param[in] currentState Current State Position, Latch and Speed.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized.
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
*/
CHIP_ERROR SetCurrentState(const DataModel::Nullable<GenericDimensionStateStruct> & currentState);
/**
* @brief Set TargetState.
*
* @param[in] targetState TargetState Position, Latch and Speed.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized.
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
*/
CHIP_ERROR SetTargetState(const DataModel::Nullable<GenericDimensionStateStruct> & targetState);
/**
* @brief Set Resolution.
*
* @param[in] resolution Minimal acceptable change of Position fields of attributes.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetResolution(const Percent100ths resolution);
/**
* @brief Set StepValue.
*
* @param[in] stepValue One step value for Step command
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetStepValue(const Percent100ths stepValue);
/**
* @brief Set Unit.
*
* @param[in] unit Unit related to the Positioning.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetUnit(const ClosureUnitEnum unit);
/**
* @brief Set UnitRange.
*
* @param[in] unitRange Minimum and Maximum values expressed by positioning following the unit.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetUnitRange(const DataModel::Nullable<Structs::UnitRangeStruct::Type> & unitRange);
/**
* @brief Set LimitRange.
*
* @param[in] limitRange Range of possible values for the position field in Current attribute.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetLimitRange(const Structs::RangePercent100thsStruct::Type & limitRange);
/**
* @brief Set Overflow.
*
* @param[in] overflow Overflow related to Rotation.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*/
CHIP_ERROR SetOverflow(const OverflowEnum overflow);
/**
* @brief Sets the latch control modes for the closure dimension cluster.
*
* This method updates the latch control modes using the provided bit flags.
*
* @param latchControlModes BitFlags representing the desired latch control modes.
* @return CHIP_ERROR Returns CHIP_NO_ERROR on success, or an appropriate error code on failure.
*/
CHIP_ERROR SetLatchControlModes(const BitFlags<LatchControlModesBitmap> & latchControlModes);
// All Get functions:
// Return CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized.
// Return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if the attribute is not supported.
// Otherwise return CHIP_NO_ERROR and set the input parameter value to the current cluster state value
CHIP_ERROR GetCurrentState(DataModel::Nullable<GenericDimensionStateStruct> & currentState);
CHIP_ERROR GetTargetState(DataModel::Nullable<GenericDimensionStateStruct> & targetState);
CHIP_ERROR GetResolution(Percent100ths & resolution);
CHIP_ERROR GetStepValue(Percent100ths & stepValue);
CHIP_ERROR GetUnit(ClosureUnitEnum & unit);
CHIP_ERROR GetUnitRange(DataModel::Nullable<Structs::UnitRangeStruct::Type> & unitRange);
CHIP_ERROR GetLimitRange(Structs::RangePercent100thsStruct::Type & limitRange);
CHIP_ERROR GetTranslationDirection(TranslationDirectionEnum & translationDirection);
CHIP_ERROR GetRotationAxis(RotationAxisEnum & rotationAxis);
CHIP_ERROR GetOverflow(OverflowEnum & overflow);
CHIP_ERROR GetModulationType(ModulationTypeEnum & modulationType);
CHIP_ERROR GetLatchControlModes(BitFlags<LatchControlModesBitmap> & latchControlModes);
CHIP_ERROR GetFeatureMap(BitFlags<Feature> & featureMap);
CHIP_ERROR GetClusterRevision(Attributes::ClusterRevision::TypeInfo::Type & clusterRevision);
/**
* @brief Calls delegate HandleSetTarget function after validating the parameters and conformance.
*
* @param [in] position TargetState position
* @param [in] latch TargetState latch
* @param [in] speed TargetState speed
*
* @return Exits if the cluster is not initialized.
* InvalidCommand if none of the input parameters are present.
* ConstraintError if the input values are out is out of range.
* InvalidInState if the current position of closure is not known.
* Success on succesful handling.
*/
Protocols::InteractionModel::Status HandleSetTargetCommand(Optional<Percent100ths> position, Optional<bool> latch,
Optional<Globals::ThreeLevelAutoEnum> speed);
/**
* @brief Calls delegate HandleStep function after validating the parameters and conformance.
*
* @param [in] direction step direction
* @param [in] numberOfSteps Number of steps
* @param [in] speed step speed
*
* @return Exits if the cluster is not initialized.
* UnsupportedCommand if Positioning feature is not supported.
* ConstraintError if the input values are out is out of range.
* InvalidInState if the current position of closure is not known.
* Success on successful handling.
*/
Protocols::InteractionModel::Status HandleStepCommand(StepDirectionEnum direction, uint16_t numberOfSteps,
Optional<Globals::ThreeLevelAutoEnum> speed);
private:
/**
* @brief Set TranslationDirection.
* This attribute is not supposed to change once the installation is finalized.
* SetTranslationDirection should only be called from Init()
*
* @param[in] translationDirection Direction of the translation.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported
*
*/
CHIP_ERROR SetTranslationDirection(const TranslationDirectionEnum translationDirection);
/**
* @brief Set RotationAxis.
* This attribute is not supposed to change once the installation is finalized.
* so SetRotationAxis should only be called from Init().
*
* @param[in] rotationAxis Axis of the rotation.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported
*
*/
CHIP_ERROR SetRotationAxis(const RotationAxisEnum rotationAxis);
/**
* @brief Set ModulationType.
* This attribute is not supposed to change once the installation is finalized.
* so SetModulationType should only be called from Init().
*
* @param[in] modulationType Modulation type.
*
* @return CHIP_NO_ERROR if set was successful.
* CHIP_ERROR_INVALID_ARGUMENT if argument are not valid
* CHIP_ERROR_INCORRECT_STATE if the cluster has not been initialized
* CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if feature is not supported.
*
*/
CHIP_ERROR SetModulationType(const ModulationTypeEnum modulationType);
bool mInitialized = false;
ClusterState mState;
ClusterConformance mConformance;
DelegateBase & mDelegate;
MatterContext & mMatterContext;
// At Present, QuieterReportingAttribute doesnt support Structs.
// So, this variable will be used for Quietreporting of current state position.
// TODO: Refactor CurrentState Atrribute to use QuieterReportingAttribute once Issue#39801 is resolved
QuieterReportingAttribute<Percent100ths> quietReportableCurrentStatePosition{ DataModel::NullNullable };
};
} // namespace ClosureDimension
} // namespace Clusters
} // namespace app
} // namespace chip