Skip to content

Commit b81998f

Browse files
Return invalid command on move when rate is 0 or rate is null and defaultRate is 0
1 parent 2fddae4 commit b81998f

File tree

2 files changed

+45
-40
lines changed

2 files changed

+45
-40
lines changed

src/app/clusters/level-control/level-control.cpp

+42-39
Original file line numberDiff line numberDiff line change
@@ -970,18 +970,56 @@ static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCom
970970
goto send_default_response;
971971
}
972972

973+
// Always validate the rate parameter received. A rate of 0 is invalid.
973974
if (!rate.IsNull() && (rate.Value() == 0))
974975
{
975-
// Move at a rate of zero is no move at all. Immediately succeed without touching anything.
976-
ChipLogProgress(Zcl, "Immediate success due to move rate of 0 (would move at no rate).");
977-
status = Status::Success;
976+
// Providing rate of 0 is not allowed.
977+
status = Status::InvalidCommand;
978978
goto send_default_response;
979979
}
980980

981+
uint8_t eventDuration; // use this local var so state->eventDurationMs is only set once the command is validated.
982+
#ifndef IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
983+
// If the Rate field is null, the device should move at the default move rate, if available,
984+
// Otherwise, move as fast as possible
985+
if (rate.IsNull())
986+
{
987+
app::DataModel::Nullable<uint8_t> defaultMoveRate;
988+
status = Attributes::DefaultMoveRate::Get(endpoint, defaultMoveRate);
989+
if (status != Status::Success || defaultMoveRate.IsNull())
990+
{
991+
ChipLogProgress(Zcl, "ERR: reading default move rate %x", to_underlying(status));
992+
eventDuration = FASTEST_TRANSITION_TIME_MS;
993+
}
994+
else
995+
{
996+
// The defaultMoveRate cannot be 0
997+
if (defaultMoveRate.Value() == 0)
998+
{
999+
status = Status::InvalidCommand;
1000+
goto send_default_response;
1001+
}
1002+
// Already checked that defaultMoveRate.Value() != 0.
1003+
eventDuration = static_cast<uint8_t>(MILLISECOND_TICKS_PER_SECOND / defaultMoveRate.Value());
1004+
}
1005+
}
1006+
else
1007+
{
1008+
// Already confirmed rate.Value() != 0.
1009+
eventDuration = static_cast<uint8_t>(MILLISECOND_TICKS_PER_SECOND / rate.Value());
1010+
}
1011+
#else
1012+
// Transition/rate is not supported so always use fastest transition time and ignore
1013+
// both the provided transition time as well as OnOffTransitionTime.
1014+
ChipLogProgress(Zcl, "Device does not support transition, ignoring rate");
1015+
eventDuration = FASTEST_TRANSITION_TIME_MS;
1016+
#endif // IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
1017+
9811018
// Cancel any currently active command before fiddling with the state.
9821019
cancelEndpointTimerCallback(endpoint);
9831020

984-
status = Attributes::CurrentLevel::Get(endpoint, currentLevel);
1021+
state->eventDurationMs = eventDuration;
1022+
status = Attributes::CurrentLevel::Get(endpoint, currentLevel);
9851023
if (status != Status::Success)
9861024
{
9871025
ChipLogProgress(Zcl, "ERR: reading current level %x", to_underlying(status));
@@ -1034,41 +1072,6 @@ static void moveHandler(app::CommandHandler * commandObj, const app::ConcreteCom
10341072
}
10351073
}
10361074

1037-
#ifndef IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
1038-
// If the Rate field is null, the device should move at the default move rate, if available,
1039-
// Otherwise, move as fast as possible
1040-
if (rate.IsNull())
1041-
{
1042-
app::DataModel::Nullable<uint8_t> defaultMoveRate;
1043-
status = Attributes::DefaultMoveRate::Get(endpoint, defaultMoveRate);
1044-
if (status != Status::Success || defaultMoveRate.IsNull())
1045-
{
1046-
ChipLogProgress(Zcl, "ERR: reading default move rate %x", to_underlying(status));
1047-
state->eventDurationMs = FASTEST_TRANSITION_TIME_MS;
1048-
}
1049-
else
1050-
{
1051-
// nonsensical case, means "don't move", so we're done
1052-
if (defaultMoveRate.Value() == 0)
1053-
{
1054-
status = Status::Success;
1055-
goto send_default_response;
1056-
}
1057-
// Already checked that defaultMoveRate.Value() != 0.
1058-
state->eventDurationMs = MILLISECOND_TICKS_PER_SECOND / defaultMoveRate.Value();
1059-
}
1060-
}
1061-
else
1062-
{
1063-
state->eventDurationMs = MILLISECOND_TICKS_PER_SECOND / std::max(static_cast<uint8_t>(1u), rate.Value());
1064-
}
1065-
#else
1066-
// Transition/rate is not supported so always use fastest transition time and ignore
1067-
// both the provided transition time as well as OnOffTransitionTime.
1068-
ChipLogProgress(Zcl, "Device does not support transition, ignoring rate");
1069-
state->eventDurationMs = FASTEST_TRANSITION_TIME_MS;
1070-
#endif // IGNORE_LEVEL_CONTROL_CLUSTER_TRANSITION
1071-
10721075
state->transitionTimeMs = difference * state->eventDurationMs;
10731076
state->elapsedTimeMs = 0;
10741077

src/app/tests/suites/certification/Test_TC_LVL_4_1.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ tests:
269269

270270
- label:
271271
"Step 4h: TH sends a Move command to the DUT with MoveMode =0x00 (up)
272-
and Rate =0 (units/s), expect success"
272+
and Rate =0 (units/s), expect failure"
273273
PICS: LVL.S.C01.Rsp
274274
command: "Move"
275275
arguments:
@@ -282,6 +282,8 @@ tests:
282282
value: 1
283283
- name: "OptionsOverride"
284284
value: 1
285+
response:
286+
error: INVALID_COMMAND
285287

286288
- label: "Wait 5s"
287289
cluster: "DelayCommands"

0 commit comments

Comments
 (0)