Skip to content

Commit 7a54749

Browse files
shripad621gitsoares-sergiolpbeliveau-silabs
authored
Backport the fan-control circular callback changes to v1.4-branch (project-chip#40351)
* fan_control_server: Fix circular callback issue (project-chip#36489) * fan_control_server: Fix circular callback issue This PR fixes a circular callback bug in fan control server using flags when updating SpeedSetting and PercentSetting. Before this change, a PercentSetting write to 25% would end up circling back to 30% as shown: ``` [MatterTest] 11-12 19:16:40.792 INFO @@@ WRITE PercentSetting to 25 [MatterTest] 11-12 19:16:40.801 INFO @@@ ATTRIB: EP1/FanControl/SpeedSetting: 3 [MatterTest] 11-12 19:16:40.802 INFO @@@ ATTRIB: EP1/FanControl/SpeedCurrent: 3 [MatterTest] 11-12 19:16:40.802 INFO @@@ ATTRIB: EP1/FanControl/PercentSetting: 30 [MatterTest] 11-12 19:16:40.802 INFO @@@ ATTRIB: EP1/FanControl/PercentCurrent: 30 ``` Now it behaves as expected: ``` [MatterTest] 11-13 18:54:27.961 INFO @@@ WRITE PercentSetting to 25 [MatterTest] 11-13 18:54:27.970 INFO @@@ ATTRIB: EP1/FanControl/SpeedSetting: 3 [MatterTest] 11-13 18:54:27.970 INFO @@@ ATTRIB: EP1/FanControl/SpeedCurrent: 3 [MatterTest] 11-13 18:54:27.970 INFO @@@ ATTRIB: EP1/FanControl/PercentSetting: 25 [MatterTest] 11-13 18:54:27.971 INFO @@@ ATTRIB: EP1/FanControl/PercentCurrent: 25 ``` Co-authored-by: lpbeliveau-silabs <[email protected]> * Addressed review suggestions --------- Co-authored-by: lpbeliveau-silabs <[email protected]> * fan-control-server: Fix FanMode circular callback issue (project-chip#36515) Similar to what was done for Speed and Percent, this PR fixes a bug where a FanMode could result in a circular callback. For example, setting the FanMode to kAuto, could trigger this issue. --------- Co-authored-by: Sergio Soares <[email protected]> Co-authored-by: lpbeliveau-silabs <[email protected]>
1 parent 7031f81 commit 7a54749

File tree

1 file changed

+42
-35
lines changed

1 file changed

+42
-35
lines changed

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

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <app/util/attribute-storage.h>
3131
#include <app/util/config.h>
3232
#include <lib/support/CodeUtils.h>
33+
#include <lib/support/Scoped.h>
3334
#include <lib/support/logging/CHIPLogging.h>
3435
#include <protocols/interaction_model/StatusCode.h>
3536

@@ -85,6 +86,11 @@ namespace {
8586
// Indicates if the write operation is from the cluster server itself
8687
bool gWriteFromClusterLogic = false;
8788

89+
// Avoid circular callback calls when adjusting SpeedSetting and PercentSetting together.
90+
ScopedChangeOnly gSpeedWriteInProgress(false);
91+
ScopedChangeOnly gPercentWriteInProgress(false);
92+
ScopedChangeOnly gFanModeWriteInProgress(false);
93+
8894
Status SetFanModeToOff(EndpointId endpointId)
8995
{
9096
FanModeEnum currentFanMode;
@@ -155,12 +161,16 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute
155161
switch (attributePath.mAttributeId)
156162
{
157163
case FanMode::Id: {
164+
if (gFanModeWriteInProgress)
165+
{
166+
return Status::WriteIgnored;
167+
}
158168
if (*value == to_underlying(FanModeEnum::kOn))
159169
{
160170
FanMode::Set(attributePath.mEndpointId, FanModeEnum::kHigh);
161-
res = Status::WriteIgnored;
171+
return Status::WriteIgnored;
162172
}
163-
else if (*value == to_underlying(FanModeEnum::kSmart))
173+
if (*value == to_underlying(FanModeEnum::kSmart))
164174
{
165175
FanModeSequenceEnum fanModeSequence;
166176
Status status = FanModeSequence::Get(attributePath.mEndpointId, &fanModeSequence);
@@ -185,6 +195,10 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute
185195
break;
186196
}
187197
case SpeedSetting::Id: {
198+
if (gSpeedWriteInProgress)
199+
{
200+
return Status::WriteIgnored;
201+
}
188202
if (SupportsMultiSpeed(attributePath.mEndpointId))
189203
{
190204
// Check if the SpeedSetting is null.
@@ -224,6 +238,10 @@ MatterFanControlClusterServerPreAttributeChangedCallback(const ConcreteAttribute
224238
break;
225239
}
226240
case PercentSetting::Id: {
241+
if (gPercentWriteInProgress)
242+
{
243+
return Status::WriteIgnored;
244+
}
227245
// Check if the PercentSetting is null.
228246
if (NumericAttributeTraits<Percent>::IsNullValue(*value))
229247
{
@@ -315,6 +333,9 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
315333
Status status = FanMode::Get(attributePath.mEndpointId, &mode);
316334
VerifyOrReturn(Status::Success == status);
317335

336+
// Avoid circular callback calls
337+
ScopedChange FanModeWriteInProgress(gFanModeWriteInProgress, true);
338+
318339
// Setting the FanMode value to Off SHALL set the values of PercentSetting, PercentCurrent,
319340
// SpeedSetting, SpeedCurrent attributes to 0 (zero).
320341
if (mode == FanModeEnum::kOff)
@@ -362,39 +383,32 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
362383
DataModel::Nullable<Percent> percentSetting;
363384
Status status = PercentSetting::Get(attributePath.mEndpointId, percentSetting);
364385
VerifyOrReturn(Status::Success == status && !percentSetting.IsNull());
386+
uint8_t speedMax;
387+
status = SpeedMax::Get(attributePath.mEndpointId, &speedMax);
388+
VerifyOrReturn(Status::Success == status,
389+
ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", to_underlying(status)));
365390

391+
// Avoid circular callback calls
392+
ScopedChange PercentWriteInProgress(gPercentWriteInProgress, true);
366393
// If PercentSetting is set to 0, the server SHALL set the FanMode attribute value to Off.
367394
if (percentSetting.Value() == 0)
368395
{
369396
status = SetFanModeToOff(attributePath.mEndpointId);
370-
VerifyOrReturn(Status::Success == status,
397+
VerifyOrReturn(status == Status::Success,
371398
ChipLogError(Zcl, "Failed to set FanMode to off with error: 0x%02x", to_underlying(status)));
372399
}
373400

374401
if (SupportsMultiSpeed(attributePath.mEndpointId))
375402
{
376403
// Adjust SpeedSetting from a percent value change for PercentSetting
377404
// speed = ceil( SpeedMax * (percent * 0.01) )
378-
uint8_t speedMax;
379-
status = SpeedMax::Get(attributePath.mEndpointId, &speedMax);
380-
VerifyOrReturn(Status::Success == status,
381-
ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", to_underlying(status)));
382-
383-
DataModel::Nullable<uint8_t> currentSpeedSetting;
384-
status = SpeedSetting::Get(attributePath.mEndpointId, currentSpeedSetting);
385-
VerifyOrReturn(Status::Success == status,
386-
ChipLogError(Zcl, "Failed to get SpeedSetting with error: 0x%02x", to_underlying(status)));
387-
388405
uint16_t percent = percentSetting.Value();
389406
// Plus 99 then integer divide by 100 instead of multiplying 0.01 to avoid floating point precision error
390407
uint8_t speedSetting = static_cast<uint8_t>((speedMax * percent + 99) / 100);
391408

392-
if (currentSpeedSetting.IsNull() || speedSetting != currentSpeedSetting.Value())
393-
{
394-
status = SpeedSetting::Set(attributePath.mEndpointId, speedSetting);
395-
VerifyOrReturn(Status::Success == status,
396-
ChipLogError(Zcl, "Failed to set SpeedSetting with error: 0x%02x", to_underlying(status)));
397-
}
409+
status = SpeedSetting::Set(attributePath.mEndpointId, speedSetting);
410+
VerifyOrDo(Status::Success == status,
411+
ChipLogError(Zcl, "Failed to set SpeedSetting with error: 0x%02x", to_underlying(status)));
398412
}
399413
break;
400414
}
@@ -404,7 +418,13 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
404418
DataModel::Nullable<uint8_t> speedSetting;
405419
Status status = SpeedSetting::Get(attributePath.mEndpointId, speedSetting);
406420
VerifyOrReturn(Status::Success == status && !speedSetting.IsNull());
421+
uint8_t speedMax;
422+
status = SpeedMax::Get(attributePath.mEndpointId, &speedMax);
423+
VerifyOrReturn(Status::Success == status,
424+
ChipLogError(Zcl, "Failed to get SpeedMax with error: 0x%02x", to_underlying(status)));
407425

426+
// Avoid circular callback calls
427+
ScopedChange SpeedWriteInProgress(gSpeedWriteInProgress, true);
408428
// If SpeedSetting is set to 0, the server SHALL set the FanMode attribute value to Off.
409429
if (speedSetting.Value() == 0)
410430
{
@@ -415,25 +435,12 @@ void MatterFanControlClusterServerAttributeChangedCallback(const app::ConcreteAt
415435

416436
// Adjust PercentSetting from a speed value change for SpeedSetting
417437
// 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)));
422-
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)));
427-
428438
float speed = speedSetting.Value();
429439
Percent percentSetting = static_cast<Percent>(speed / speedMax * 100);
430440

431-
if (currentPercentSetting.IsNull() || percentSetting != currentPercentSetting.Value())
432-
{
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)));
436-
}
441+
status = PercentSetting::Set(attributePath.mEndpointId, percentSetting);
442+
VerifyOrDo(Status::Success == status,
443+
ChipLogError(Zcl, "Failed to set PercentSetting with error: 0x%02x", to_underlying(status)));
437444
}
438445
break;
439446
}

0 commit comments

Comments
 (0)