Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature map support to window covering cluster #12937

Merged
merged 10 commits into from Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 91 additions & 40 deletions src/app/clusters/window-covering-server/window-covering-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,18 @@ using namespace chip::app::Clusters::WindowCovering;

#define WC_PERCENT100THS_MAX 10000

static bool HasFeature(chip::EndpointId endpoint, Features feature)
static bool HasFeature(chip::EndpointId endpoint, WindowCoveringFeature feature)
{
return true;
uint32_t FeatureMap = 0;
if (EMBER_ZCL_STATUS_SUCCESS ==
emberAfReadServerAttribute(endpoint, chip::app::Clusters::WindowCovering::Id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eve-cxrp For future reference, please do not use emberAfReadServerAttribute. Use the Accessors functions, that make sure you're using the right type and whatnot, instead of easy-to-mess-up reinterpret_cast.

chip::app::Clusters::WindowCovering::Attributes::FeatureMap::Id,
reinterpret_cast<uint8_t *>(&FeatureMap), sizeof(FeatureMap)))
{
return (FeatureMap & chip::to_underlying(feature)) != 0;
}

return false;
}

static uint16_t ValueToPercent100ths(uint16_t openLimit, uint16_t closedLimit, uint16_t value)
Expand Down Expand Up @@ -158,26 +167,42 @@ bool IsOpen(chip::EndpointId endpoint)
uint16_t liftLimit = 0;
uint16_t tiltPosition = 0;
uint16_t tiltLimit = 0;
bool isOpen = false;

if (HasFeature(endpoint, WindowCoveringFeature::kLift) && HasFeature(endpoint, WindowCoveringFeature::kPositionAwareLift) &&
HasFeature(endpoint, WindowCoveringFeature::kAbsolutePosition) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::TargetPositionLiftPercent100ths::Get(endpoint, &liftPosition) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::InstalledOpenLimitLift::Get(endpoint, &liftLimit))
{
isOpen = liftPosition == liftLimit;
}
else if (HasFeature(endpoint, WindowCoveringFeature::kLift) &&
HasFeature(endpoint, WindowCoveringFeature::kPositionAwareLift) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::TargetPositionLiftPercent100ths::Get(endpoint, &liftPosition))
{
isOpen = 0 == liftPosition;
}

if (HasFeature(endpoint, WindowCoveringFeature::kTilt) && HasFeature(endpoint, WindowCoveringFeature::kPositionAwareTilt) &&
HasFeature(endpoint, WindowCoveringFeature::kAbsolutePosition) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::TargetPositionTiltPercent100ths::Get(endpoint, &tiltPosition) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::InstalledOpenLimitTilt::Get(endpoint, &tiltLimit))
{
isOpen = isOpen && tiltPosition == tiltLimit;
}
else if (HasFeature(endpoint, WindowCoveringFeature::kTilt) &&
HasFeature(endpoint, WindowCoveringFeature::kPositionAwareTilt) &&
EMBER_ZCL_STATUS_SUCCESS == Attributes::TargetPositionTiltPercent100ths::Get(endpoint, &tiltPosition))
{
isOpen = isOpen && 0 == tiltPosition;
}

Attributes::TargetPositionLiftPercent100ths::Get(endpoint, &liftPosition);
Attributes::InstalledOpenLimitLift::Get(endpoint, &liftLimit);
Attributes::TargetPositionTiltPercent100ths::Get(endpoint, &tiltPosition);
Attributes::InstalledOpenLimitTilt::Get(endpoint, &tiltLimit);
return liftPosition == liftLimit && tiltPosition == tiltLimit;
return isOpen;
}

bool IsClosed(chip::EndpointId endpoint)
{
uint16_t liftPosition = 0;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
uint16_t liftLimit = 0;
uint16_t tiltPosition = 0;
uint16_t tiltLimit = 0;

Attributes::TargetPositionLiftPercent100ths::Get(endpoint, &liftPosition);
Attributes::InstalledClosedLimitLift::Get(endpoint, &liftLimit);
Attributes::TargetPositionTiltPercent100ths::Get(endpoint, &tiltPosition);
Attributes::InstalledClosedLimitTilt::Get(endpoint, &tiltLimit);
return liftPosition == liftLimit && tiltPosition == tiltLimit;
return !IsOpen(endpoint);
}

void TypeSet(chip::EndpointId endpoint, EmberAfWcType type)
Expand All @@ -194,9 +219,15 @@ EmberAfWcType TypeGet(chip::EndpointId endpoint)

void ConfigStatusSet(chip::EndpointId endpoint, const ConfigStatus & status)
{
uint8_t value = (status.operational ? 0x01 : 0) | (status.online ? 0x02 : 0) | (status.liftIsReversed ? 0x04 : 0) |
(status.liftIsPA ? 0x08 : 0) | (status.tiltIsPA ? 0x10 : 0) | (status.liftIsEncoderControlled ? 0x20 : 0) |
(status.tiltIsEncoderControlled ? 0x40 : 0);
/* clang-format off */
uint8_t value = (status.operational ? 0x01 : 0)
| (status.online ? 0x02 : 0)
| (status.liftIsReversed ? 0x04 : 0)
| (status.liftIsPA ? 0x08 : 0)
| (status.tiltIsPA ? 0x10 : 0)
| (status.liftIsEncoderControlled ? 0x20 : 0)
| (status.tiltIsEncoderControlled ? 0x40 : 0);
/* clang-format on */
Attributes::ConfigStatus::Set(endpoint, value);
}

Expand Down Expand Up @@ -271,12 +302,19 @@ const Mode ModeGet(chip::EndpointId endpoint)

void SafetyStatusSet(chip::EndpointId endpoint, SafetyStatus & status)
{
uint16_t value = (status.remoteLockout ? 0x0001 : 0) | (status.tamperDetection ? 0x0002 : 0) |
(status.failedCommunication ? 0x0004 : 0) | (status.positionFailure ? 0x0008 : 0) |
(status.thermalProtection ? 0x0010 : 0) | (status.obstacleDetected ? 0x0020 : 0) | (status.powerIssue ? 0x0040 : 0) |
(status.stopInput ? 0x0080 : 0);
value |= (uint16_t)(status.motorJammed ? 0x0100 : 0) | (uint16_t)(status.hardwareFailure ? 0x0200 : 0) |
(uint16_t)(status.manualOperation ? 0x0400 : 0);
/* clang-format off */
uint16_t value = (status.remoteLockout ? 0x0001 : 0)
| (status.tamperDetection ? 0x0002 : 0)
| (status.failedCommunication ? 0x0004 : 0)
| (status.positionFailure ? 0x0008 : 0)
| (status.thermalProtection ? 0x0010 : 0)
| (status.obstacleDetected ? 0x0020 : 0)
| (status.powerIssue ? 0x0040 : 0)
| (status.stopInput ? 0x0080 : 0);
value |= (uint16_t) (status.motorJammed ? 0x0100 : 0)
| (uint16_t) (status.hardwareFailure ? 0x0200 : 0)
| (uint16_t) (status.manualOperation ? 0x0400 : 0);
/* clang-format on */
Attributes::SafetyStatus::Set(endpoint, value);
}

Expand Down Expand Up @@ -387,11 +425,11 @@ bool emberAfWindowCoveringClusterUpOrOpenCallback(app::CommandHandler * commandO
EndpointId endpoint = commandPath.mEndpointId;

emberAfWindowCoveringClusterPrint("UpOrOpen command received");
if (HasFeature(endpoint, Features::Lift))
if (HasFeature(endpoint, WindowCoveringFeature::kLift))
{
Attributes::TargetPositionLiftPercent100ths::Set(endpoint, 0);
}
if (HasFeature(endpoint, Features::Tilt))
if (HasFeature(endpoint, WindowCoveringFeature::kTilt))
{
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, 0);
}
Expand All @@ -408,11 +446,11 @@ bool emberAfWindowCoveringClusterDownOrCloseCallback(app::CommandHandler * comma
EndpointId endpoint = commandPath.mEndpointId;

emberAfWindowCoveringClusterPrint("DownOrClose command received");
if (HasFeature(endpoint, Features::Lift))
if (HasFeature(endpoint, WindowCoveringFeature::kLift))
{
Attributes::TargetPositionLiftPercent100ths::Set(endpoint, WC_PERCENT100THS_MAX);
}
if (HasFeature(endpoint, Features::Tilt))
if (HasFeature(endpoint, WindowCoveringFeature::kTilt))
{
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, WC_PERCENT100THS_MAX);
}
Expand All @@ -428,9 +466,22 @@ emberAfWindowCoveringClusterStopMotionCallback(app::CommandHandler * commandObj,
const Commands::StopMotion::DecodableType & fields)
{
emberAfWindowCoveringClusterPrint("StopMotion command received");
uint16_t current = 0;
chip::EndpointId endpoint = commandPath.mEndpointId;

emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
if (HasFeature(endpoint, WindowCoveringFeature::kLift) && HasFeature(endpoint, WindowCoveringFeature::kPositionAwareLift))
{
(void) Attributes::CurrentPositionLiftPercent100ths::Get(endpoint, &current);
(void) Attributes::TargetPositionLiftPercent100ths::Set(endpoint, current);
}

if (HasFeature(endpoint, WindowCoveringFeature::kTilt) && HasFeature(endpoint, WindowCoveringFeature::kPositionAwareTilt))
{
(void) Attributes::CurrentPositionTiltPercent100ths::Get(endpoint, &current);
(void) Attributes::TargetPositionTiltPercent100ths::Set(endpoint, current);
}

return EMBER_SUCCESS == emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
}

/**
Expand All @@ -444,8 +495,8 @@ bool emberAfWindowCoveringClusterGoToLiftValueCallback(app::CommandHandler * com

EndpointId endpoint = commandPath.mEndpointId;

bool hasLift = HasFeature(endpoint, Features::Lift);
bool isPositionAware = HasFeature(endpoint, Features::PositionAware);
bool hasLift = HasFeature(endpoint, WindowCoveringFeature::kLift);
bool isPositionAware = HasFeature(endpoint, WindowCoveringFeature::kPositionAwareLift);

emberAfWindowCoveringClusterPrint("GoToLiftValue Value command received");
if (hasLift && isPositionAware)
Expand Down Expand Up @@ -473,8 +524,8 @@ bool emberAfWindowCoveringClusterGoToLiftPercentageCallback(app::CommandHandler

EndpointId endpoint = commandPath.mEndpointId;

bool hasLift = HasFeature(endpoint, Features::Lift);
bool isPositionAware = HasFeature(endpoint, Features::PositionAware);
bool hasLift = HasFeature(endpoint, WindowCoveringFeature::kLift);
bool isPositionAware = HasFeature(endpoint, WindowCoveringFeature::kPositionAwareLift);

emberAfWindowCoveringClusterPrint("GoToLiftPercentage Percentage command received");
if (hasLift && isPositionAware)
Expand Down Expand Up @@ -502,8 +553,8 @@ bool emberAfWindowCoveringClusterGoToTiltValueCallback(app::CommandHandler * com

EndpointId endpoint = commandPath.mEndpointId;

bool hasTilt = HasFeature(endpoint, Features::Tilt);
bool isPositionAware = HasFeature(endpoint, Features::PositionAware);
bool hasTilt = HasFeature(endpoint, WindowCoveringFeature::kTilt);
bool isPositionAware = HasFeature(endpoint, WindowCoveringFeature::kPositionAwareTilt);

emberAfWindowCoveringClusterPrint("GoToTiltValue command received");
if (hasTilt && isPositionAware)
Expand Down Expand Up @@ -531,8 +582,8 @@ bool emberAfWindowCoveringClusterGoToTiltPercentageCallback(app::CommandHandler

EndpointId endpoint = commandPath.mEndpointId;

bool hasTilt = HasFeature(endpoint, Features::Tilt);
bool isPositionAware = HasFeature(endpoint, Features::PositionAware);
bool hasTilt = HasFeature(endpoint, WindowCoveringFeature::kTilt);
bool isPositionAware = HasFeature(endpoint, WindowCoveringFeature::kPositionAwareTilt);

emberAfWindowCoveringClusterPrint("GoToTiltPercentage command received");
if (hasTilt && isPositionAware)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ namespace app {
namespace Clusters {
namespace WindowCovering {

enum class Features
{
Lift = 0x01,
Tilt = 0x02,
PositionAware = 0x04
};

struct Mode
{
uint8_t motorDirReversed : 1; // bit 0
Expand Down
19 changes: 12 additions & 7 deletions src/app/zap-templates/zcl/data-model/chip/window-covering.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,9 @@ limitations under the License.
<server tick="false" init="false">true</server>
<tag name="LF" description="Lift Control"/>
<tag name="TL" description="Tilt Control"/>
<tag name="PA" description="Position Aware"/>
<tag name="PA_LF" description="Position Aware lift control"/>
<tag name="ABS" description="Absolute Positioning"/>
<globalAttribute side="server" code="0xFFFC" value="0x0001">
<featureBit tag="LF" bit="0">true</featureBit>
<featureBit tag="TL" bit="1">false</featureBit>
<featureBit tag="PA" bit="2">false</featureBit>
<featureBit tag="ABS" bit="3">false</featureBit>
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
</globalAttribute>
<tag name="PA_TL" description="Position Aware tilt control"/>
<globalAttribute side="either" code="0xFFFD" value="5"/>
<!-- Window Covering Information Attribute Set -->
<attribute side="server" writable="false" code="0x0000" define="WC_TYPE" type="ENUM8" min="0x00" max="0x09" default="0x00" optional="false">Type</attribute>
Expand Down Expand Up @@ -178,4 +173,14 @@ limitations under the License.
<field mask="0x0400" name="ManualOperation"/>
<field mask="0x0800" name="Protection"/>
</bitmap>

<bitmap name="WindowCoveringFeature" type="BITMAP32">
<cluster code="0x0102"/>
<field name="Lift" mask="0x1"/>
<field name="Tilt" mask="0x2"/>
<field name="PositionAwareLift" mask="0x4"/>
<field name="AbsolutePosition" mask="0x8"/>
<field name="PositionAwareTilt" mask="0x10"/>
</bitmap>

</configurator>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions zzz_generated/app-common/app-common/zap-generated/enums.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.