| /** |
| * |
| * 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 |