blob: 21c9253703b36ad67b764ac2c07dc3f96bf0f579 [file] [log] [blame]
/**
*
* 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 <app-common/zap-generated/attributes/Accessors.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <system/SystemClock.h>
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<uint16_t>(0));
mTargetLiftPosition.SetNonNull(static_cast<uint16_t>(0));
mCurrentTiltPosition.SetNonNull(static_cast<uint16_t>(0));
mTargetTiltPosition.SetNonNull(static_cast<uint16_t>(0));
SetEndpoint(endpoint);
}
void WindowCoveringManager::HandleLiftMovementTimer(System::Layer * layer, void * aAppState)
{
WindowCoveringManager * manager = reinterpret_cast<WindowCoveringManager *>(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<WindowCoveringManager *>(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;
}