|
|
@@ -37,6 +37,7 @@
|
|
|
#endif // EMBER_AF_PLUGIN_SCENES
|
|
|
|
|
|
using namespace chip;
|
|
|
+using namespace chip::app::Clusters;
|
|
|
using namespace chip::app::Clusters::WindowCovering;
|
|
|
|
|
|
#define CHECK_BOUNDS_INVALID(MIN, VAL, MAX) ((VAL < MIN) || (VAL > MAX))
|
|
|
@@ -44,13 +45,27 @@ using namespace chip::app::Clusters::WindowCovering;
|
|
|
|
|
|
#define FAKE_MOTION_DELAY_MS 5000
|
|
|
|
|
|
+namespace {
|
|
|
+
|
|
|
+constexpr size_t kWindowCoveringDelegateTableSize =
|
|
|
+ EMBER_AF_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT;
|
|
|
+
|
|
|
+Delegate * gDelegateTable[kWindowCoveringDelegateTableSize] = { nullptr };
|
|
|
+
|
|
|
+Delegate * GetDelegate(EndpointId endpoint)
|
|
|
+{
|
|
|
+ uint16_t ep = emberAfFindClusterServerEndpointIndex(endpoint, WindowCovering::Id);
|
|
|
+ return ((ep == kInvalidEndpointId || ep >= EMBER_AF_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT) ? nullptr
|
|
|
+ : gDelegateTable[ep]);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* ConvertValue: Converts values from one range to another
|
|
|
* Range In -> from inputLowValue to inputHighValue
|
|
|
* Range Out -> from outputLowValue to outputtHighValue
|
|
|
*/
|
|
|
-static uint16_t ConvertValue(uint16_t inputLowValue, uint16_t inputHighValue, uint16_t outputLowValue, uint16_t outputHighValue,
|
|
|
- uint16_t value)
|
|
|
+uint16_t ConvertValue(uint16_t inputLowValue, uint16_t inputHighValue, uint16_t outputLowValue, uint16_t outputHighValue,
|
|
|
+ uint16_t value)
|
|
|
{
|
|
|
uint16_t inputMin = inputLowValue, inputMax = inputHighValue, inputRange = UINT16_MAX;
|
|
|
uint16_t outputMin = outputLowValue, outputMax = outputHighValue, outputRange = UINT16_MAX;
|
|
|
@@ -88,10 +103,11 @@ static uint16_t ConvertValue(uint16_t inputLowValue, uint16_t inputHighValue, ui
|
|
|
return outputMax;
|
|
|
}
|
|
|
|
|
|
-static Percent100ths ValueToPercent100ths(AbsoluteLimits limits, uint16_t absolute)
|
|
|
+Percent100ths ValueToPercent100ths(AbsoluteLimits limits, uint16_t absolute)
|
|
|
{
|
|
|
return ConvertValue(limits.open, limits.closed, WC_PERCENT100THS_MIN_OPEN, WC_PERCENT100THS_MAX_CLOSED, absolute);
|
|
|
}
|
|
|
+} // namespace
|
|
|
|
|
|
namespace chip {
|
|
|
namespace app {
|
|
|
@@ -199,6 +215,7 @@ void OperationalStatusSet(chip::EndpointId endpoint, chip::BitMask<OperationalSt
|
|
|
// Filter changes
|
|
|
if (newStatus != prevStatus)
|
|
|
{
|
|
|
+ OperationalStatusPrint(newStatus);
|
|
|
Attributes::OperationalStatus::Set(endpoint, newStatus);
|
|
|
}
|
|
|
}
|
|
|
@@ -490,72 +507,6 @@ Percent100ths ComputePercent100thsStep(OperationalState direction, Percent100ths
|
|
|
return percent100ths;
|
|
|
}
|
|
|
|
|
|
-void emberAfPluginWindowCoveringFinalizeFakeMotionEventHandler(EndpointId endpoint)
|
|
|
-{
|
|
|
- NPercent100ths position;
|
|
|
-
|
|
|
- OperationalState opLift = OperationalStateGet(endpoint, OperationalStatus::kLift);
|
|
|
- OperationalState opTilt = OperationalStateGet(endpoint, OperationalStatus::kTilt);
|
|
|
-
|
|
|
- emberAfWindowCoveringClusterPrint("WC DELAYED CALLBACK 100ms w/ OpLift=0x%02X OpTilt=0x%02X", (unsigned char) opLift,
|
|
|
- (unsigned char) opTilt);
|
|
|
-
|
|
|
- /* Update position to simulate movement to pass the CI */
|
|
|
- if (OperationalState::Stall != opLift)
|
|
|
- {
|
|
|
- Attributes::TargetPositionLiftPercent100ths::Get(endpoint, position);
|
|
|
- if (!position.IsNull())
|
|
|
- {
|
|
|
- LiftPositionSet(endpoint, position);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Update position to simulate movement to pass the CI */
|
|
|
- if (OperationalState::Stall != opTilt)
|
|
|
- {
|
|
|
- Attributes::TargetPositionTiltPercent100ths::Get(endpoint, position);
|
|
|
- if (!position.IsNull())
|
|
|
- {
|
|
|
- TiltPositionSet(endpoint, position);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief Get event control object for an endpoint
|
|
|
- *
|
|
|
- * @param[in] endpoint
|
|
|
- * @return EmberEventControl*
|
|
|
- */
|
|
|
-EmberEventControl * GetEventControl(EndpointId endpoint)
|
|
|
-{
|
|
|
- static EmberEventControl eventControls[EMBER_AF_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT];
|
|
|
- uint16_t index = emberAfFindClusterServerEndpointIndex(endpoint, WindowCovering::Id);
|
|
|
- EmberEventControl * event = nullptr;
|
|
|
-
|
|
|
- if (index < ArraySize(eventControls))
|
|
|
- {
|
|
|
- event = &eventControls[index];
|
|
|
- }
|
|
|
- return event;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief Configure Fake Motion event control object for an endpoint
|
|
|
- *
|
|
|
- * @param[in] endpoint
|
|
|
- * @return EmberEventControl*
|
|
|
- */
|
|
|
-EmberEventControl * ConfigureFakeMotionEventControl(EndpointId endpoint)
|
|
|
-{
|
|
|
- EmberEventControl * controller = GetEventControl(endpoint);
|
|
|
-
|
|
|
- controller->endpoint = endpoint;
|
|
|
- controller->callback = &emberAfPluginWindowCoveringFinalizeFakeMotionEventHandler;
|
|
|
-
|
|
|
- return controller;
|
|
|
-}
|
|
|
-
|
|
|
void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeId)
|
|
|
{
|
|
|
// all-cluster-app: simulation for the CI testing
|
|
|
@@ -571,27 +522,23 @@ void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeI
|
|
|
|
|
|
switch (attributeId)
|
|
|
{
|
|
|
- /* RO OperationalStatus */
|
|
|
- case Attributes::OperationalStatus::Id:
|
|
|
- if (OperationalState::Stall != OperationalStateGet(endpoint, OperationalStatus::kGlobal))
|
|
|
- {
|
|
|
- // Finish the fake motion attribute update:
|
|
|
- emberEventControlSetDelayMS(ConfigureFakeMotionEventControl(endpoint), FAKE_MOTION_DELAY_MS);
|
|
|
- }
|
|
|
- break;
|
|
|
/* ============= Positions for Position Aware ============= */
|
|
|
case Attributes::CurrentPositionLiftPercent100ths::Id:
|
|
|
- if (OperationalState::Stall != opLift)
|
|
|
+ Attributes::TargetPositionLiftPercent100ths::Get(endpoint, target);
|
|
|
+ Attributes::CurrentPositionLiftPercent100ths::Get(endpoint, current);
|
|
|
+ if ((OperationalState::Stall != opLift) && (current == target))
|
|
|
{
|
|
|
- opLift = OperationalState::Stall;
|
|
|
emberAfWindowCoveringClusterPrint("Lift stop");
|
|
|
+ OperationalStateSet(endpoint, OperationalStatus::kLift, OperationalState::Stall);
|
|
|
}
|
|
|
break;
|
|
|
case Attributes::CurrentPositionTiltPercent100ths::Id:
|
|
|
- if (OperationalState::Stall != opTilt)
|
|
|
+ Attributes::TargetPositionTiltPercent100ths::Get(endpoint, target);
|
|
|
+ Attributes::CurrentPositionTiltPercent100ths::Get(endpoint, current);
|
|
|
+ if ((OperationalState::Stall != opTilt) && (current == target))
|
|
|
{
|
|
|
- opTilt = OperationalState::Stall;
|
|
|
emberAfWindowCoveringClusterPrint("Tilt stop");
|
|
|
+ OperationalStateSet(endpoint, OperationalStatus::kTilt, OperationalState::Stall);
|
|
|
}
|
|
|
break;
|
|
|
/* For a device supporting Position Awareness : Changing the Target triggers motions on the real or simulated device */
|
|
|
@@ -599,12 +546,14 @@ void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeI
|
|
|
Attributes::TargetPositionLiftPercent100ths::Get(endpoint, target);
|
|
|
Attributes::CurrentPositionLiftPercent100ths::Get(endpoint, current);
|
|
|
opLift = ComputeOperationalState(target, current);
|
|
|
+ OperationalStateSet(endpoint, OperationalStatus::kLift, opLift);
|
|
|
break;
|
|
|
/* For a device supporting Position Awareness : Changing the Target triggers motions on the real or simulated device */
|
|
|
case Attributes::TargetPositionTiltPercent100ths::Id:
|
|
|
Attributes::TargetPositionTiltPercent100ths::Get(endpoint, target);
|
|
|
Attributes::CurrentPositionTiltPercent100ths::Get(endpoint, current);
|
|
|
opTilt = ComputeOperationalState(target, current);
|
|
|
+ OperationalStateSet(endpoint, OperationalStatus::kTilt, opTilt);
|
|
|
break;
|
|
|
/* Mode change is either internal from the application or external from a write request */
|
|
|
case Attributes::Mode::Id:
|
|
|
@@ -619,10 +568,6 @@ void PostAttributeChange(chip::EndpointId endpoint, chip::AttributeId attributeI
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- /* This decides and triggers fake motion for the selected endpoint */
|
|
|
- OperationalStateSet(endpoint, OperationalStatus::kLift, opLift);
|
|
|
- OperationalStateSet(endpoint, OperationalStatus::kTilt, opTilt);
|
|
|
}
|
|
|
|
|
|
EmberAfStatus GetMotionLockStatus(chip::EndpointId endpoint)
|
|
|
@@ -649,6 +594,21 @@ EmberAfStatus GetMotionLockStatus(chip::EndpointId endpoint)
|
|
|
return EMBER_ZCL_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+void SetDefaultDelegate(EndpointId endpoint, Delegate * delegate)
|
|
|
+{
|
|
|
+ uint16_t ep = emberAfFindClusterServerEndpointIndex(endpoint, Channel::Id);
|
|
|
+
|
|
|
+ // if endpoint is found and is not a dynamic endpoint
|
|
|
+ if (ep != 0xFFFF && ep < EMBER_AF_WINDOW_COVERING_CLUSTER_SERVER_ENDPOINT_COUNT)
|
|
|
+ {
|
|
|
+ gDelegateTable[ep] = delegate;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("Failed to set WindowCovering delegate for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
} // namespace WindowCovering
|
|
|
} // namespace Clusters
|
|
|
} // namespace app
|
|
|
@@ -658,19 +618,6 @@ EmberAfStatus GetMotionLockStatus(chip::EndpointId endpoint)
|
|
|
// Callbacks
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
-/** @brief Window Covering Cluster Init
|
|
|
- *
|
|
|
- * Cluster Init
|
|
|
- *
|
|
|
- * @param endpoint Endpoint that is being initialized
|
|
|
- */
|
|
|
-void emberAfWindowCoveringClusterInitCallback(chip::EndpointId endpoint)
|
|
|
-{
|
|
|
- emberAfWindowCoveringClusterPrint("Window Covering Cluster init");
|
|
|
-
|
|
|
- ConfigStatusUpdateFeatures(endpoint);
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* @brief Cluster UpOrOpen Command callback (from client)
|
|
|
*/
|
|
|
@@ -697,7 +644,26 @@ bool emberAfWindowCoveringClusterUpOrOpenCallback(app::CommandHandler * commandO
|
|
|
{
|
|
|
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, WC_PERCENT100THS_MIN_OPEN);
|
|
|
}
|
|
|
+
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ if (HasFeature(endpoint, Feature::kPositionAwareLift))
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Lift));
|
|
|
+ }
|
|
|
+ else if (HasFeature(endpoint, Feature::kPositionAwareTilt))
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Tilt));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
+
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -728,6 +694,24 @@ bool emberAfWindowCoveringClusterDownOrCloseCallback(app::CommandHandler * comma
|
|
|
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, WC_PERCENT100THS_MAX_CLOSED);
|
|
|
}
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
+
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ if (HasFeature(endpoint, Feature::kPositionAwareLift))
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Lift));
|
|
|
+ }
|
|
|
+ else if (HasFeature(endpoint, Feature::kPositionAwareTilt))
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Tilt));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -750,6 +734,16 @@ bool emberAfWindowCoveringClusterStopMotionCallback(app::CommandHandler * comman
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleStopMotion());
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
+
|
|
|
if (HasFeaturePaLift(endpoint))
|
|
|
{
|
|
|
(void) Attributes::CurrentPositionLiftPercent100ths::Get(endpoint, current);
|
|
|
@@ -789,6 +783,15 @@ bool emberAfWindowCoveringClusterGoToLiftValueCallback(app::CommandHandler * com
|
|
|
if (HasFeature(endpoint, Feature::kAbsolutePosition) && HasFeaturePaLift(endpoint))
|
|
|
{
|
|
|
Attributes::TargetPositionLiftPercent100ths::Set(endpoint, LiftToPercent100ths(endpoint, liftValue));
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Lift));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
}
|
|
|
else
|
|
|
@@ -824,6 +827,15 @@ bool emberAfWindowCoveringClusterGoToLiftPercentageCallback(app::CommandHandler
|
|
|
if (IsPercent100thsValid(percent100ths))
|
|
|
{
|
|
|
Attributes::TargetPositionLiftPercent100ths::Set(endpoint, percent100ths);
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Lift));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
}
|
|
|
else
|
|
|
@@ -863,6 +875,15 @@ bool emberAfWindowCoveringClusterGoToTiltValueCallback(app::CommandHandler * com
|
|
|
if (HasFeature(endpoint, Feature::kAbsolutePosition) && HasFeaturePaTilt(endpoint))
|
|
|
{
|
|
|
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, TiltToPercent100ths(endpoint, tiltValue));
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Tilt));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
}
|
|
|
else
|
|
|
@@ -898,6 +919,15 @@ bool emberAfWindowCoveringClusterGoToTiltPercentageCallback(app::CommandHandler
|
|
|
if (IsPercent100thsValid(percent100ths))
|
|
|
{
|
|
|
Attributes::TargetPositionTiltPercent100ths::Set(endpoint, percent100ths);
|
|
|
+ Delegate * delegate = GetDelegate(endpoint);
|
|
|
+ if (delegate)
|
|
|
+ {
|
|
|
+ LogErrorOnFailure(delegate->HandleMovement(WindowCoveringType::Tilt));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emberAfWindowCoveringClusterPrint("WindowCovering has no delegate set for endpoint:%u", endpoint);
|
|
|
+ }
|
|
|
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
|
|
|
}
|
|
|
else
|