diff --git a/examples/chef/common/clusters/window-covering/chef-window-covering.cpp b/examples/chef/common/clusters/window-covering/chef-window-covering.cpp new file mode 100644 index 00000000000000..ffcd66e08601d6 --- /dev/null +++ b/examples/chef/common/clusters/window-covering/chef-window-covering.cpp @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2022 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 "chef-window-covering.h" +#include "app/clusters/window-covering-server/window-covering-server.h" +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app::Clusters; +using chip::Protocols::InteractionModel::Status; + +constexpr size_t kWindowCoveringDelegateTableSize = MATTER_DM_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT; +static_assert(kWindowCoveringDelegateTableSize <= kEmberInvalidEndpointIndex, "WindowCovering Delegate table size error"); + +std::unique_ptr gDelegateTable[kWindowCoveringDelegateTableSize]; + +WindowCovering::ChefDelegate * GetDelegate(EndpointId endpoint) +{ + uint16_t ep = + emberAfGetClusterServerEndpointIndex(endpoint, WindowCovering::Id, MATTER_DM_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT); + return (ep >= kWindowCoveringDelegateTableSize ? nullptr : gDelegateTable[ep].get()); +} + +void InitChefWindowCoveringCluster() +{ + const uint16_t endpointCount = emberAfEndpointCount(); + + for (uint16_t endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++) + { + EndpointId endpointId = emberAfEndpointFromIndex(endpointIndex); + if (endpointId == kInvalidEndpointId) + { + continue; + } + + // Check if endpoint has WindowCovering cluster enabled + uint16_t epIndex = emberAfGetClusterServerEndpointIndex(endpointId, WindowCovering::Id, + MATTER_DM_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT); + if (epIndex >= kWindowCoveringDelegateTableSize) + continue; + + // Skip if delegate was already initialized. + if (gDelegateTable[epIndex]) + continue; + + gDelegateTable[epIndex] = std::make_unique(); + gDelegateTable[epIndex]->SetEndpoint(endpointId); + WindowCovering::SetDefaultDelegate(endpointId, gDelegateTable[epIndex].get()); + } +} + +CHIP_ERROR WindowCovering::ChefDelegate::HandleMovement(WindowCoveringType type) +{ + Status status; + app::DataModel::Nullable current; + + if (type == WindowCoveringType::Lift) + { + status = WindowCovering::Attributes::TargetPositionLiftPercent100ths::Get(mEndpoint, current); + if (status != Status::Success) + { + ChipLogError(DeviceLayer, "HandleMovement: Failed to get TargetPositionLiftPercent100ths with error code %d", + to_underlying(status)); + return CHIP_ERROR_READ_FAILED; + } + + // Instant update. No transition for now. + status = WindowCovering::Attributes::CurrentPositionLiftPercent100ths::Set(mEndpoint, current); + if (status != Status::Success) + { + ChipLogError(DeviceLayer, "HandleMovement: Failed to set CurrentPositionLiftPercent100ths with error code %d", + to_underlying(status)); + return CHIP_ERROR_WRITE_FAILED; + } + + MatterReportingAttributeChangeCallback(mEndpoint, WindowCovering::Id, + WindowCovering::Attributes::CurrentPositionLiftPercent100ths::Id); + + return CHIP_NO_ERROR; + } + else if (type == WindowCoveringType::Tilt) + { + status = WindowCovering::Attributes::TargetPositionTiltPercent100ths::Get(mEndpoint, current); + if (status != Status::Success) + { + ChipLogError(DeviceLayer, "HandleMovement: Failed to get TargetPositionTiltPercent100ths - %d", to_underlying(status)); + return CHIP_ERROR_READ_FAILED; + } + + // Instant update. No transition for now. + status = WindowCovering::Attributes::CurrentPositionTiltPercent100ths::Set(mEndpoint, current); + if (status != Status::Success) + { + ChipLogError(DeviceLayer, "HandleMovement: Failed to set CurrentPositionTiltPercent100ths - %d", to_underlying(status)); + return CHIP_ERROR_WRITE_FAILED; + } + + MatterReportingAttributeChangeCallback(mEndpoint, WindowCovering::Id, + WindowCovering::Attributes::CurrentPositionTiltPercent100ths::Id); + + return CHIP_NO_ERROR; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR WindowCovering::ChefDelegate::HandleStopMotion() +{ + return CHIP_NO_ERROR; +} diff --git a/examples/chef/common/clusters/window-covering/chef-window-covering.h b/examples/chef/common/clusters/window-covering/chef-window-covering.h new file mode 100644 index 00000000000000..852354bba31bdc --- /dev/null +++ b/examples/chef/common/clusters/window-covering/chef-window-covering.h @@ -0,0 +1,68 @@ +/* + * + * 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 + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace WindowCovering { + +/** @brief + * Defines methods for implementing application-specific logic for the WindowCovering Cluster. + */ +class ChefDelegate : public Delegate +{ +public: + /** + * @brief + * This method adjusts window covering position so the physical lift/slide and tilt is at the target + * open/up position set before calling this method. This will happen as fast as possible. + * + * @param[in] type window covering type. + * + * @return CHIP_NO_ERROR On success. + * @return Other Value indicating it failed to adjust window covering position. + */ + CHIP_ERROR HandleMovement(WindowCoveringType type); + + /** + * @brief + * This method stops any adjusting to the physical tilt and lift/slide that is currently occurring. + * + * @return CHIP_NO_ERROR On success. + * @return Other Value indicating it failed to stop any adjusting to the physical tilt and lift/slide that is currently + * occurring.. + */ + CHIP_ERROR HandleStopMotion(); + + ~ChefDelegate() = default; + ChefDelegate() = default; +}; + +} // namespace WindowCovering +} // namespace Clusters +} // namespace app +} // namespace chip + +void InitChefWindowCoveringCluster(); diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index 16e9b1b8694c64..ace91bf7187ec8 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -81,6 +81,10 @@ const Clusters::Descriptor::Structs::SemanticTagStruct::Type freezerTagList[] #include "temperature-control/static-supported-temperature-levels.h" #endif // MATTER_DM_PLUGIN_TEMPERATURE_CONTROL_SERVER +#ifdef MATTER_DM_PLUGIN_WINDOW_COVERING_SERVER +#include "window-covering/chef-window-covering.h" +#endif // MATTER_DM_PLUGIN_WINDOW_COVERING_SERVER + Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) @@ -350,6 +354,11 @@ void ApplicationInit() SetTagList(kColdCabinetEndpointId, Span(refrigeratorTagList)); SetTagList(kFreezeCabinetEndpointId, Span(freezerTagList)); #endif // MATTER_DM_PLUGIN_REFRIGERATOR_ALARM_SERVER + +#ifdef MATTER_DM_PLUGIN_WINDOW_COVERING_SERVER + ChipLogProgress(NotSpecified, "Initializing WindowCovering cluster delegate."); + InitChefWindowCoveringCluster(); +#endif // MATTER_DM_PLUGIN_WINDOW_COVERING_SERVER } void ApplicationShutdown() diff --git a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter index 7302d71d92f595..aa5b4e84afb216 100644 --- a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter +++ b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter @@ -2014,7 +2014,7 @@ endpoint 1 { callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; - ram attribute featureMap default = 0x1f; + ram attribute featureMap default = 0x17; ram attribute clusterRevision default = 5; handle command UpOrOpen; diff --git a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.zap b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.zap index e608fff6c2c2ab..26cefd63e91a2d 100644 --- a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.zap +++ b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.zap @@ -17,13 +17,6 @@ } ], "package": [ - { - "pathRelativity": "relativeToZap", - "path": "../../../src/app/zap-templates/app-templates.json", - "type": "gen-templates-json", - "category": "matter", - "version": "chip-v1" - }, { "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/zcl/zcl.json", @@ -31,6 +24,13 @@ "category": "matter", "version": 1, "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" } ], "endpointTypes": [ @@ -3273,7 +3273,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0x1f", + "defaultValue": "0x17", "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index 360c5fb349d147..3dc0934deab611 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -67,6 +67,7 @@ executable("${sample_name}") { "${project_dir}/common/clusters/target-navigator/TargetNavigatorManager.cpp", "${project_dir}/common/clusters/temperature-control/static-supported-temperature-levels.cpp", "${project_dir}/common/clusters/wake-on-lan/WakeOnLanManager.cpp", + "${project_dir}/common/clusters/window-covering/chef-window-covering.cpp", "${project_dir}/common/stubs.cpp", "${project_dir}/linux/main.cpp", ] diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index 32def1dbf41445..20fcc2cdf4be84 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -104,6 +104,7 @@ target_sources(app PRIVATE ${CHEF}/common/clusters/temperature-control/static-supported-temperature-levels.cpp ${CHEF}/common/clusters/target-navigator/TargetNavigatorManager.cpp ${CHEF}/common/clusters/wake-on-lan/WakeOnLanManager.cpp + ${CHEF}/common/clusters/window-covering/chef-window-covering.cpp ${CHEF}/common/stubs.cpp ${CHEF}/nrfconnect/main.cpp )