Skip to content

Commit 078bc30

Browse files
[SL-UP] Circular callback fix (#85) (#36406)
1 parent 8aa5f60 commit 078bc30

File tree

4 files changed

+73
-23
lines changed

4 files changed

+73
-23
lines changed

examples/all-clusters-app/all-clusters-common/src/fan-stub.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <app-common/zap-generated/cluster-objects.h>
2020
#include <app-common/zap-generated/ids/Attributes.h>
2121
#include <app-common/zap-generated/ids/Clusters.h>
22-
#include <app/AttributeAccessInterface.h>
2322
#include <app/AttributeAccessInterfaceRegistry.h>
2423
#include <app/clusters/fan-control-server/fan-control-server.h>
2524
#include <app/util/attribute-storage.h>
@@ -34,13 +33,11 @@ using namespace chip::app::Clusters::FanControl::Attributes;
3433
using Protocols::InteractionModel::Status;
3534

3635
namespace {
37-
class FanControlManager : public AttributeAccessInterface, public Delegate
36+
class FanControlManager : public FanControlAttributeAccessInterface, public Delegate
3837
{
3938
public:
4039
// Register for the FanControl cluster on all endpoints.
41-
FanControlManager(EndpointId aEndpointId) :
42-
AttributeAccessInterface(Optional<EndpointId>(aEndpointId), FanControl::Id), Delegate(aEndpointId)
43-
{}
40+
FanControlManager(EndpointId aEndpointId) : FanControlAttributeAccessInterface(aEndpointId), Delegate(aEndpointId) {}
4441

4542
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
4643
Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override;

src/app/clusters/fan-control-server/fan-control-server.cpp

+60-17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <app-common/zap-generated/cluster-objects.h>
2525
#include <app-common/zap-generated/ids/Attributes.h>
2626
#include <app-common/zap-generated/ids/Clusters.h>
27+
#include <app/AttributeAccessInterfaceRegistry.h>
2728
#include <app/CommandHandler.h>
2829
#include <app/ConcreteCommandPath.h>
2930
#include <app/clusters/fan-control-server/fan-control-server.h>
@@ -389,7 +390,7 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
389390
// Plus 99 then integer divide by 100 instead of multiplying 0.01 to avoid floating point precision error
390391
uint8_t speedSetting = static_cast<uint8_t>((speedMax * percent + 99) / 100);
391392

392-
if (currentSpeedSetting.IsNull() || speedSetting != currentSpeedSetting.Value())
393+
if (currentSpeedSetting != speedSetting)
393394
{
394395
status = SpeedSetting::Set(attributePath.mEndpointId, speedSetting);
395396
VerifyOrReturn(Status::Success == status,
@@ -413,33 +414,75 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
413414
ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", to_underlying(status)));
414415
}
415416

416-
// Adjust PercentSetting from a speed value change for SpeedSetting
417-
// percent = floor( speed/SpeedMax * 100 )
418-
uint8_t speedMax;
419-
status = SpeedMax::Get(attributePath.mEndpointId, &speedMax);
420-
VerifyOrReturn(Status::Success == status,
421-
ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", to_underlying(status)));
417+
// Adjust PercentSetting from a speed value change for SpeedSetting only when the SpeedSetting change was received
418+
// on a write command, not when it was changed by the server or the app logic. This avoids circular logic such as
419+
//(with a SpeedMax of 10):
420+
// 1. Client sets the PercetSetting to 25%
421+
// 2. Server sets the SpeedSetting to 3 through the server callbackm, which sets the PercentSetting to 30%
422+
// 3. Server sets the PercentSetting to 30% through the server callback
423+
}
424+
break;
425+
}
426+
default:
427+
break;
428+
}
429+
}
422430

423-
DataModel::Nullable<Percent> currentPercentSetting;
424-
status = PercentSetting::Get(attributePath.mEndpointId, currentPercentSetting);
425-
VerifyOrReturn(Status::Success == status,
426-
ChipLogError(Zcl, "Failed to get PercentSetting with error: 0x%02x", to_underlying(status)));
431+
CHIP_ERROR FanControlAttributeAccessInterface::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder)
432+
{
433+
Status status = Status::Success;
434+
switch (aPath.mAttributeId)
435+
{
436+
case SpeedSetting::Id: {
437+
DataModel::Nullable<uint8_t> speedSetting;
438+
ReturnErrorOnFailure(aDecoder.Decode(speedSetting));
439+
440+
DataModel::Nullable<uint8_t> currentSpeedSetting;
441+
status = SpeedSetting::Get(aPath.mEndpointId, currentSpeedSetting);
442+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
427443

428-
float speed = speedSetting.Value();
429-
Percent percentSetting = static_cast<Percent>(speed / speedMax * 100);
444+
if (speedSetting != currentSpeedSetting)
445+
{
446+
status = SpeedSetting::Set(aPath.mEndpointId, speedSetting);
447+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
448+
// Skip the last step if we are writing NULL
449+
VerifyOrReturnValue(!speedSetting.IsNull(), CHIP_NO_ERROR);
430450

431-
if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value())
451+
if (SupportsMultiSpeed(aPath.mEndpointId))
432452
{
433-
status = PercentSetting::Set(attributePath.mEndpointId, percentSetting);
434-
VerifyOrReturn(Status::Success == status,
435-
ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", to_underlying(status)));
453+
// If SpeedSetting is set to 0, the server SHALL set the FanMode attribute value to Off.
454+
if (speedSetting.Value() == 0)
455+
{
456+
status = SetFanModeToOff(aPath.mEndpointId);
457+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
458+
}
459+
460+
// Adjust PercentSetting from a speed value change for SpeedSetting
461+
// percent = floor( speed/SpeedMax * 100 )
462+
uint8_t speedMax;
463+
status = SpeedMax::Get(aPath.mEndpointId, &speedMax);
464+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
465+
466+
DataModel::Nullable<Percent> currentPercentSetting;
467+
status = PercentSetting::Get(aPath.mEndpointId, currentPercentSetting);
468+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
469+
470+
float speed = speedSetting.Value();
471+
Percent percentSetting = static_cast<Percent>(speed / speedMax * 100);
472+
473+
if (currentPercentSetting != percentSetting)
474+
{
475+
status = PercentSetting::Set(aPath.mEndpointId, percentSetting);
476+
ReturnLogErrorOnFailure(StatusIB(status).ToChipError());
477+
}
436478
}
437479
}
438480
break;
439481
}
440482
default:
441483
break;
442484
}
485+
return CHIP_NO_ERROR;
443486
}
444487

445488
bool emberAfFanControlClusterStepCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath,

src/app/clusters/fan-control-server/fan-control-server.h

+10
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,23 @@
1919

2020
#include "fan-control-delegate.h"
2121
#include <app-common/zap-generated/cluster-objects.h>
22+
#include <app/AttributeAccessInterface.h>
2223
#include <app/util/af-types.h>
2324

2425
namespace chip {
2526
namespace app {
2627
namespace Clusters {
2728
namespace FanControl {
2829

30+
class FanControlAttributeAccessInterface : public AttributeAccessInterface
31+
{
32+
public:
33+
FanControlAttributeAccessInterface(EndpointId aEndpoint) : AttributeAccessInterface(Optional<EndpointId>(aEndpoint), Id) {}
34+
35+
CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override;
36+
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override { return CHIP_NO_ERROR; }
37+
};
38+
2939
void SetDefaultDelegate(EndpointId aEndpoint, Delegate * aDelegate);
3040
Delegate * GetDelegate(EndpointId aEndpoint);
3141

src/app/util/util.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ void MatterUnitLocalizationPluginServerInitCallback() {}
107107
void MatterProxyValidPluginServerInitCallback() {}
108108
void MatterProxyDiscoveryPluginServerInitCallback() {}
109109
void MatterProxyConfigurationPluginServerInitCallback() {}
110-
void MatterFanControlPluginServerInitCallback() {}
111110
void MatterActivatedCarbonFilterMonitoringPluginServerInitCallback() {}
112111
void MatterHepaFilterMonitoringPluginServerInitCallback() {}
113112
void MatterAirQualityPluginServerInitCallback() {}
113+
void MatterFanControlPluginServerInitCallback() {}
114114
void MatterCarbonMonoxideConcentrationMeasurementPluginServerInitCallback() {}
115115
void MatterCarbonDioxideConcentrationMeasurementPluginServerInitCallback() {}
116116
void MatterFormaldehydeConcentrationMeasurementPluginServerInitCallback() {}

0 commit comments

Comments
 (0)