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 Q quality to OperationalState CountdownTime #34422

Merged
merged 16 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Instance::Instance(Delegate * aDelegate, EndpointId aEndpointId, ClusterId aClus
mDelegate(aDelegate), mEndpointId(aEndpointId), mClusterId(aClusterId)
{
mDelegate->SetInstance(this);
mCountdownTime.policy()
.Set(QuieterReportingPolicyEnum::kMarkDirtyOnIncrement)
.Set(QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero);
}

Instance::Instance(Delegate * aDelegate, EndpointId aEndpointId) : Instance(aDelegate, aEndpointId, OperationalState::Id) {}
Expand Down Expand Up @@ -82,6 +85,7 @@ CHIP_ERROR Instance::SetCurrentPhase(const DataModel::Nullable<uint8_t> & aPhase
if (mCurrentPhase != oldPhase)
{
MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::CurrentPhase::Id);
UpdateCountdownTimeFromClusterLogic();
}
return CHIP_NO_ERROR;
}
Expand All @@ -94,9 +98,11 @@ CHIP_ERROR Instance::SetOperationalState(uint8_t aOpState)
return CHIP_ERROR_INVALID_ARGUMENT;
}

bool runUpdateCountdownTime = false;
tcarmelveilleux marked this conversation as resolved.
Show resolved Hide resolved
if (mOperationalError.errorStateID != to_underlying(ErrorStateEnum::kNoError))
{
mOperationalError.Set(to_underlying(ErrorStateEnum::kNoError));
runUpdateCountdownTime = true;
MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::OperationalError::Id);
}

Expand All @@ -105,6 +111,12 @@ CHIP_ERROR Instance::SetOperationalState(uint8_t aOpState)
if (mOperationalState != oldState)
{
MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::OperationalState::Id);
runUpdateCountdownTime = true;
}

if (runUpdateCountdownTime)
{
UpdateCountdownTimeFromClusterLogic();
}
return CHIP_NO_ERROR;
}
Expand Down Expand Up @@ -141,6 +153,8 @@ void Instance::OnOperationalErrorDetected(const Structs::ErrorStateStruct::Type
MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::OperationalError::Id);
}

UpdateCountdownTimeFromClusterLogic();

// Generate an ErrorDetected event
GenericErrorEvent event(mClusterId, aError);
EventNumber eventNumber;
Expand All @@ -154,7 +168,7 @@ void Instance::OnOperationalErrorDetected(const Structs::ErrorStateStruct::Type

void Instance::OnOperationCompletionDetected(uint8_t aCompletionErrorCode,
const Optional<DataModel::Nullable<uint32_t>> & aTotalOperationalTime,
const Optional<DataModel::Nullable<uint32_t>> & aPausedTime) const
const Optional<DataModel::Nullable<uint32_t>> & aPausedTime)
{
ChipLogDetail(Zcl, "OperationalStateServer: OnOperationCompletionDetected");

Expand All @@ -167,6 +181,8 @@ void Instance::OnOperationCompletionDetected(uint8_t aCompletionErrorCode,
ChipLogError(Zcl, "OperationalStateServer: Failed to record OperationCompletion event: %" CHIP_ERROR_FORMAT,
error.Format());
}

UpdateCountdownTimeFromClusterLogic();
}

void Instance::ReportOperationalStateListChange()
Expand All @@ -177,6 +193,43 @@ void Instance::ReportOperationalStateListChange()
void Instance::ReportPhaseListChange()
{
MatterReportingAttributeChangeCallback(ConcreteAttributePath(mEndpointId, mClusterId, Attributes::PhaseList::Id));
UpdateCountdownTimeFromClusterLogic();
}

void Instance::UpdateCountdownTime(bool fromDelegate)
{
app::DataModel::Nullable<uint32_t> newCountdownTime = mDelegate->GetCountdownTime();
auto now = System::SystemClock().GetMonotonicTimestamp();

bool markDirty = false;

if (fromDelegate)
{
// Updates from delegate are reduce-reported to every 10s max (choice of this implementation), in addition
// to default change-from-null, change-from-zero and increment policy.
auto predicate = [](const decltype(mCountdownTime)::SufficientChangePredicateCandidate & candidate) -> bool {
if (candidate.lastDirtyValue.IsNull() || candidate.newValue.IsNull())
{
return false;
}

uint32_t lastDirtyValue = candidate.lastDirtyValue.Value();
uint32_t newValue = candidate.newValue.Value();
uint32_t kNumSecondsDeltaToReport = 10;
return (newValue < lastDirtyValue) && ((lastDirtyValue - newValue) > kNumSecondsDeltaToReport);
woody-apple marked this conversation as resolved.
Show resolved Hide resolved
};
markDirty = (mCountdownTime.SetValue(newCountdownTime, now, predicate) == AttributeDirtyState::kMustReport);
}
else
{
auto predicate = [](const decltype(mCountdownTime)::SufficientChangePredicateCandidate &) -> bool { return true; };
tcarmelveilleux marked this conversation as resolved.
Show resolved Hide resolved
markDirty = (mCountdownTime.SetValue(newCountdownTime, now, predicate) == AttributeDirtyState::kMustReport);
}

if (markDirty)
{
MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::CountdownTime::Id);
}
}

bool Instance::IsSupportedPhase(uint8_t aPhase)
Expand Down Expand Up @@ -268,6 +321,9 @@ void Instance::InvokeCommand(HandlerContext & handlerContext)
ChipLogDetail(Zcl, "OperationalState: Entering handling derived cluster commands");

InvokeDerivedClusterCommand(handlerContext);
// Call here to avoid the subclasses forgetting about it.
UpdateCountdownTimeFromClusterLogic();
break;
}
}

Expand Down Expand Up @@ -339,7 +395,7 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu
break;

case OperationalState::Attributes::CountdownTime::Id: {
ReturnErrorOnFailure(aEncoder.Encode(mDelegate->GetCountdownTime()));
ReturnErrorOnFailure(aEncoder.Encode(mCountdownTime.value()));
}
break;
}
Expand Down Expand Up @@ -379,6 +435,8 @@ void Instance::HandlePauseState(HandlerContext & ctx, const Commands::Pause::Dec
response.commandResponseState = err;

ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);

UpdateCountdownTimeFromClusterLogic();
}

void Instance::HandleStopState(HandlerContext & ctx, const Commands::Stop::DecodableType & req)
Expand All @@ -397,6 +455,8 @@ void Instance::HandleStopState(HandlerContext & ctx, const Commands::Stop::Decod
response.commandResponseState = err;

ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);

UpdateCountdownTimeFromClusterLogic();
woody-apple marked this conversation as resolved.
Show resolved Hide resolved
tcarmelveilleux marked this conversation as resolved.
Show resolved Hide resolved
}

void Instance::HandleStartState(HandlerContext & ctx, const Commands::Start::DecodableType & req)
Expand All @@ -415,6 +475,8 @@ void Instance::HandleStartState(HandlerContext & ctx, const Commands::Start::Dec
response.commandResponseState = err;

ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);

UpdateCountdownTimeFromClusterLogic();
}

void Instance::HandleResumeState(HandlerContext & ctx, const Commands::Resume::DecodableType & req)
Expand Down Expand Up @@ -450,6 +512,8 @@ void Instance::HandleResumeState(HandlerContext & ctx, const Commands::Resume::D
response.commandResponseState = err;

ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response);

UpdateCountdownTimeFromClusterLogic();
}

// RvcOperationalState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <app-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandlerInterface.h>
#include <app/cluster-building-blocks/QuieterReporting.h>
#include <app/data-model/Nullable.h>

namespace chip {
namespace app {
Expand Down Expand Up @@ -113,6 +115,12 @@ class Instance : public CommandHandlerInterface, public AttributeAccessInterface
*/
void GetCurrentOperationalError(GenericOperationalError & error) const;

/**
* @brief Whenever application delegate wants to possibly report a new updated time,
* call this method. The `GetCountdownTime()` method will be called on the delegate.
*/
void UpdateCountdownTimeFromDelegate() { UpdateCountdownTime(/* fromDelegate = */ true); }

// Event triggers
/**
* @brief Called when the Node detects a OperationalError has been raised.
Expand All @@ -129,7 +137,7 @@ class Instance : public CommandHandlerInterface, public AttributeAccessInterface
*/
void OnOperationCompletionDetected(uint8_t aCompletionErrorCode,
const Optional<DataModel::Nullable<uint32_t>> & aTotalOperationalTime = NullOptional,
const Optional<DataModel::Nullable<uint32_t>> & aPausedTime = NullOptional) const;
const Optional<DataModel::Nullable<uint32_t>> & aPausedTime = NullOptional);

// List change reporting
/**
Expand Down Expand Up @@ -192,6 +200,19 @@ class Instance : public CommandHandlerInterface, public AttributeAccessInterface
*/
virtual void InvokeDerivedClusterCommand(HandlerContext & handlerContext) { return; };

/**
* Causes reporting/udpating of CountdownTime attribute from driver if sufficient changes have
* occurred (based on Q quality definition for operational state). Calls the Delegate::GetCountdownTime() method.
*
* @param fromDelegate true if the change notice was triggered by the delegate, false if internal to cluster logic.
*/
void UpdateCountdownTime(bool fromDelegate);

/**
* @brief Whenever the cluster logic thinks time should be updated, call this.
*/
void UpdateCountdownTimeFromClusterLogic() { UpdateCountdownTime(/* fromDelegate=*/false); }

private:
Delegate * mDelegate;

Expand All @@ -202,6 +223,7 @@ class Instance : public CommandHandlerInterface, public AttributeAccessInterface
app::DataModel::Nullable<uint8_t> mCurrentPhase;
uint8_t mOperationalState = 0; // assume 0 for now.
GenericOperationalError mOperationalError = to_underlying(ErrorStateEnum::kNoError);
app::QuieterReportingAttribute<uint32_t> mCountdownTime{ DataModel::NullNullable };

/**
* This method is inherited from CommandHandlerInterface.
Expand Down Expand Up @@ -262,9 +284,10 @@ class Delegate
virtual ~Delegate() = default;

/**
* Get the countdown time.
* NOTE: Changes to this attribute should not be reported.
* From the spec: Changes to this value SHALL NOT be reported in a subscription.
* Get the countdown time. This will get called on many edges such as
* commands to change operational state, or when the delegate deals with
* changes. Make sure it becomes null whenever it is appropriate.
*
* @return The current countdown time.
*/
virtual app::DataModel::Nullable<uint32_t> GetCountdownTime() = 0;
Expand Down
Loading