/** * * Copyright (c) 2022 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. */ #include "WindowCoveringManager.h" #include #include #include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters::WindowCovering; using namespace chip::System::Clock::Literals; namespace { constexpr const System::Clock::Milliseconds32 kIncrementMovementTimeout = 700_ms32; constexpr const uint16_t kDefaultMovementStep = 2000; } // namespace void WindowCoveringManager::Init(EndpointId endpoint) { mState = OperationalState::Stall; mCurrentLiftPosition.SetNonNull(static_cast(0)); mTargetLiftPosition.SetNonNull(static_cast(0)); mCurrentTiltPosition.SetNonNull(static_cast(0)); mTargetTiltPosition.SetNonNull(static_cast(0)); SetEndpoint(endpoint); } void WindowCoveringManager::HandleLiftMovementTimer(System::Layer * layer, void * aAppState) { WindowCoveringManager * manager = reinterpret_cast(aAppState); VerifyOrReturn(manager->mState != OperationalState::Stall); Percent100ths currentPosition = manager->mCurrentLiftPosition.Value(); Percent100ths targetPosition = manager->mTargetLiftPosition.Value(); ChipLogProgress(NotSpecified, "HandleLiftMovementTimer:currentPosition:%u, targetPosition:%u", currentPosition, targetPosition); if (OperationalState::MovingUpOrOpen == manager->mState) { if (ComputeOperationalState(targetPosition, currentPosition) != OperationalState::MovingUpOrOpen) { ChipLogProgress(NotSpecified, "Reached the target position"); return; } Percent100ths tempPosition = ComputePercent100thsStep(OperationalState::MovingUpOrOpen, currentPosition, kDefaultMovementStep); currentPosition = tempPosition > targetPosition ? tempPosition : targetPosition; manager->mCurrentLiftPosition.SetNonNull(currentPosition); } else { if (ComputeOperationalState(targetPosition, currentPosition) != OperationalState::MovingDownOrClose) { ChipLogProgress(NotSpecified, "Reached the target position"); return; } Percent100ths tempPosition = ComputePercent100thsStep(OperationalState::MovingDownOrClose, currentPosition, kDefaultMovementStep); currentPosition = tempPosition < targetPosition ? tempPosition : targetPosition; manager->mCurrentLiftPosition.SetNonNull(currentPosition); } LiftPositionSet(manager->mEndpoint, manager->mCurrentLiftPosition); if (manager->mCurrentLiftPosition != manager->mTargetLiftPosition) { LogErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kIncrementMovementTimeout, HandleLiftMovementTimer, aAppState)); } } void WindowCoveringManager::HandleTiltMovementTimer(System::Layer * layer, void * aAppState) { WindowCoveringManager * manager = reinterpret_cast(aAppState); VerifyOrReturn(manager->mState != OperationalState::Stall); Percent100ths currentPosition = manager->mCurrentTiltPosition.Value(); Percent100ths targetPosition = manager->mTargetTiltPosition.Value(); ChipLogProgress(NotSpecified, "HandleTiltMovementTimer:currentPosition:%u, targetPosition:%u", currentPosition, targetPosition); if (OperationalState::MovingUpOrOpen == manager->mState) { if (ComputeOperationalState(targetPosition, currentPosition) != OperationalState::MovingUpOrOpen) { ChipLogProgress(NotSpecified, "Reached the target position"); return; } Percent100ths tempPosition = ComputePercent100thsStep(OperationalState::MovingUpOrOpen, currentPosition, kDefaultMovementStep); currentPosition = tempPosition > targetPosition ? tempPosition : targetPosition; manager->mCurrentTiltPosition.SetNonNull(currentPosition); } else { if (ComputeOperationalState(targetPosition, currentPosition) != OperationalState::MovingDownOrClose) { ChipLogProgress(NotSpecified, "Reached the target position"); return; } Percent100ths tempPosition = ComputePercent100thsStep(OperationalState::MovingDownOrClose, currentPosition, kDefaultMovementStep); currentPosition = tempPosition < targetPosition ? tempPosition : targetPosition; manager->mCurrentTiltPosition.SetNonNull(currentPosition); } TiltPositionSet(manager->mEndpoint, manager->mCurrentTiltPosition); if (manager->mCurrentTiltPosition != manager->mTargetTiltPosition) { LogErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kIncrementMovementTimeout, HandleTiltMovementTimer, aAppState)); } } CHIP_ERROR WindowCoveringManager::HandleMovement(WindowCoveringType type) { if (type == WindowCoveringType::Lift) { mState = OperationalStateGet(mEndpoint, OperationalStatus::kLift); } else { mState = OperationalStateGet(mEndpoint, OperationalStatus::kTilt); } if (OperationalState::Stall == mState) { ChipLogProgress(NotSpecified, "Covering is currently not moving"); return CHIP_NO_ERROR; } CHIP_ERROR err = CHIP_NO_ERROR; // At least one of the Lift and Tilt features SHALL be supported. if (type == WindowCoveringType::Lift) { // Cancel ongoing window covering movement timer if any. DeviceLayer::SystemLayer().CancelTimer(HandleLiftMovementTimer, this); Attributes::CurrentPositionLiftPercent100ths::Get(mEndpoint, mCurrentLiftPosition); Attributes::TargetPositionLiftPercent100ths::Get(mEndpoint, mTargetLiftPosition); VerifyOrReturnError(!mCurrentLiftPosition.IsNull(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(!mTargetLiftPosition.IsNull(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mCurrentLiftPosition != mTargetLiftPosition, CHIP_ERROR_INCORRECT_STATE); err = DeviceLayer::SystemLayer().StartTimer(kIncrementMovementTimeout, HandleLiftMovementTimer, this); } else { // Cancel ongoing window covering movement timer if any. DeviceLayer::SystemLayer().CancelTimer(HandleTiltMovementTimer, this); Attributes::CurrentPositionTiltPercent100ths::Get(mEndpoint, mCurrentTiltPosition); Attributes::TargetPositionTiltPercent100ths::Get(mEndpoint, mTargetTiltPosition); VerifyOrReturnError(!mCurrentTiltPosition.IsNull(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(!mTargetTiltPosition.IsNull(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(mCurrentTiltPosition != mTargetTiltPosition, CHIP_ERROR_INCORRECT_STATE); err = DeviceLayer::SystemLayer().StartTimer(kIncrementMovementTimeout, HandleTiltMovementTimer, this); } return err; } CHIP_ERROR WindowCoveringManager::HandleStopMotion() { DeviceLayer::SystemLayer().CancelTimer(HandleLiftMovementTimer, this); DeviceLayer::SystemLayer().CancelTimer(HandleTiltMovementTimer, this); return CHIP_NO_ERROR; }