Skip to content

Commit

Permalink
Update operational state server and related examples (#28577)
Browse files Browse the repository at this point in the history
* Reordered Mode Base functions.

* Moved generic OpState cluster objects into one header file.

* Reordered OperationalStateServer functions.

* Moved OpState delegate in the server header file.

* Updated the TestOperationalStateDelegate inctludes following the operational state delegate change in location.

* Renamed TestOperationalStateDelegate.cpp -> src/app/tests/TestOperationalStateClusterObjects.cpp

* Restyled by clang-format

* Minor corrections following revision.

* Refactored the OperationalState server code to match with other derived cluters. Updated the examples to work with this change.

* Explicitly initialised the edpoint ID in the operational state examples to improve readability.

* OpState: Made OpState getters return const.

* Restyled by clang-format

* Moved the responsibility of storing and managing the countdown time attribute to the delegate.

* Applied minor review changes.

* OpState: Made the improved the relationship between the Delegate and Instance classes.

* OpState: Removed the ability to set the OperationalState to the Error state and the ability to set the OperationalError. These can only be set via the ErrorDetected event.

* OpState: Fixed GetCurrentOperationalError

* Restyled by clang-format

* Added checks to the phase and operational state setters to ensure that the value given is valid.

* Added a safe method to check if two GenericOperationalError objects are equal.

* GetInstance returns a const pointer.

Co-authored-by: Boris Zbarsky <[email protected]>

* Restyled by clang-format

---------

Co-authored-by: Restyled.io <[email protected]>
Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
3 people authored and pull[bot] committed Feb 5, 2024
1 parent 2633df6 commit 2d7a8d7
Show file tree
Hide file tree
Showing 16 changed files with 665 additions and 835 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,79 +26,39 @@
namespace chip {
namespace app {
namespace Clusters {

namespace OperationalState {

// This is an application level delegate to handle operational state commands according to the specific business logic.
class OperationalStateDelegate : public Delegate
class GenericOperationalStateDelegateImpl : public Delegate
{

public:
/**
* Get the current operational state.
* @return The current operational state value
* Get the countdown time. This attribute is not used in this application.
* @return The current countdown time.
*/
uint8_t GetCurrentOperationalState() override;
app::DataModel::Nullable<uint32_t> GetCountdownTime() override { return {}; };

/**
* Get the list of supported operational states.
* Fills in the provided GenericOperationalState with the state at index `index` if there is one,
* or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of states.
* Note: This is used by the SDK to populate the operational state list attribute. If the contents of this list changes,
* the device SHALL call the Instance's ReportOperationalStateListChange method to report that this attribute has changed.
* @param index The index of the state, with 0 representing the first state.
* @param operationalState The GenericOperationalState is filled.
*/
CHIP_ERROR GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState) override;

/**
* Get the list of supported operational phases.
* Fills in the provided GenericOperationalPhase with the phase at index `index` if there is one,
* or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of phases.
* Note: This is used by the SDK to populate the phase list attribute. If the contents of this list changes, the
* device SHALL call the Instance's ReportPhaseListChange method to report that this attribute has changed.
* @param index The index of the phase, with 0 representing the first phase.
* @param operationalPhase The GenericOperationalPhase is filled.
*/
CHIP_ERROR GetOperationalPhaseAtIndex(size_t index, GenericOperationalPhase & operationalPhase) override;

/**
* Get current operational error.
* @param error The GenericOperationalError to fill with the current operational error value
*/
void GetCurrentOperationalError(GenericOperationalError & error) override;

/**
* Get current phase
* @param phase The app::DataModel::Nullable<uint8_t> to fill with the current phase value
*/
void GetCurrentPhase(app::DataModel::Nullable<uint8_t> & phase) override;

/**
* Get countdown time
* @param time The app::DataModel::Nullable<uint32_t> to fill with the coutdown time value
*/
void GetCountdownTime(app::DataModel::Nullable<uint32_t> & time) override;

/**
* Set operational error.
* @param opErrState The new operational error.
*/
CHIP_ERROR SetOperationalError(const GenericOperationalError & opErrState) override;

/**
* Set current operational state.
* @param opState The operational state that should now be the current one.
*/
CHIP_ERROR SetOperationalState(uint8_t opState) override;

/**
* Set operational phase.
* @param phase The operational phase that should now be the current one.
*/
CHIP_ERROR SetPhase(const app::DataModel::Nullable<uint8_t> & phase) override;

/**
* Set coutdown time.
* @param time The coutdown time that should now be the current one.
*/
CHIP_ERROR SetCountdownTime(const app::DataModel::Nullable<uint32_t> & time) override;

// command callback
/**
* Handle Command Callback in application: Pause
Expand All @@ -124,27 +84,74 @@ class OperationalStateDelegate : public Delegate
*/
void HandleStopStateCallback(GenericOperationalError & err) override;

OperationalStateDelegate(uint8_t aOperationalState, GenericOperationalError aOperationalError,
Span<const GenericOperationalState> aOperationalStateList,
Span<const GenericOperationalPhase> aOperationalPhaseList,
app::DataModel::Nullable<uint8_t> aPhase = DataModel::Nullable<uint8_t>(),
app::DataModel::Nullable<uint32_t> aCountdownTime = DataModel::Nullable<uint32_t>()) :
mOperationalState(aOperationalState),
mOperationalError(aOperationalError), mOperationalStateList(aOperationalStateList),
mOperationalPhaseList(aOperationalPhaseList), mOperationalPhase(aPhase), mCountdownTime(aCountdownTime)
{}
~OperationalStateDelegate() = default;
protected:
Span<const GenericOperationalState> mOperationalStateList;
Span<const GenericOperationalPhase> mOperationalPhaseList;
};

// This is an application level delegate to handle operational state commands according to the specific business logic.
class OperationalStateDelegate : public GenericOperationalStateDelegateImpl
{
private:
uint8_t mOperationalState;
GenericOperationalError mOperationalError;
app::DataModel::List<const GenericOperationalState> mOperationalStateList;
Span<const GenericOperationalPhase> mOperationalPhaseList;
app::DataModel::Nullable<uint8_t> mOperationalPhase;
app::DataModel::Nullable<uint32_t> mCountdownTime;
const GenericOperationalState opStateList[4] = {
GenericOperationalState(to_underlying(OperationalStateEnum::kStopped)),
GenericOperationalState(to_underlying(OperationalStateEnum::kRunning)),
GenericOperationalState(to_underlying(OperationalStateEnum::kPaused)),
GenericOperationalState(to_underlying(OperationalStateEnum::kError)),
};

const GenericOperationalPhase opPhaseList[1] = {
// Phase List is null
GenericOperationalPhase(DataModel::Nullable<CharSpan>()),
};

public:
OperationalStateDelegate()
{
GenericOperationalStateDelegateImpl::mOperationalStateList = Span<const GenericOperationalState>(opStateList);
GenericOperationalStateDelegateImpl::mOperationalPhaseList = Span<const GenericOperationalPhase>(opPhaseList);
}
};

void Shutdown();

} // namespace OperationalState

namespace RvcOperationalState {

// This is an application level delegate to handle operational state commands according to the specific business logic.
class RvcOperationalStateDelegate : public OperationalState::GenericOperationalStateDelegateImpl
{
private:
const OperationalState::GenericOperationalState rvcOpStateList[7] = {
OperationalState::GenericOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)),
OperationalState::GenericOperationalState(to_underlying(OperationalState::OperationalStateEnum::kRunning)),
OperationalState::GenericOperationalState(to_underlying(OperationalState::OperationalStateEnum::kPaused)),
OperationalState::GenericOperationalState(to_underlying(OperationalState::OperationalStateEnum::kError)),
OperationalState::GenericOperationalState(
to_underlying(Clusters::RvcOperationalState::OperationalStateEnum::kSeekingCharger)),
OperationalState::GenericOperationalState(to_underlying(Clusters::RvcOperationalState::OperationalStateEnum::kCharging)),
OperationalState::GenericOperationalState(to_underlying(Clusters::RvcOperationalState::OperationalStateEnum::kDocked)),
};

const OperationalState::GenericOperationalPhase rvcOpPhaseList[1] = {
// Phase List is null
OperationalState::GenericOperationalPhase(DataModel::Nullable<CharSpan>()),
};

public:
RvcOperationalStateDelegate()
{
GenericOperationalStateDelegateImpl::mOperationalStateList =
Span<const OperationalState::GenericOperationalState>(rvcOpStateList);
GenericOperationalStateDelegateImpl::mOperationalPhaseList =
Span<const OperationalState::GenericOperationalPhase>(rvcOpPhaseList);
}
};

void Shutdown();

} // namespace RvcOperationalState
} // namespace Clusters
} // namespace app
} // namespace chip
Original file line number Diff line number Diff line change
Expand Up @@ -17,106 +17,151 @@
*/
#include <operational-state-delegate-impl.h>

namespace chip {
namespace app {
namespace Clusters {
namespace OperationalState {
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::OperationalState;
using namespace chip::app::Clusters::RvcOperationalState;

using chip::Protocols::InteractionModel::Status;

CHIP_ERROR OperationalStateDelegate::SetOperationalState(uint8_t opState)
CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState)
{
mOperationalState = opState;
if (index >= mOperationalStateList.size())
{
return CHIP_ERROR_NOT_FOUND;
}
operationalState = mOperationalStateList[index];
return CHIP_NO_ERROR;
}

CHIP_ERROR OperationalStateDelegate::SetPhase(const app::DataModel::Nullable<uint8_t> & phase)
CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalPhaseAtIndex(size_t index, GenericOperationalPhase & operationalPhase)
{
mOperationalPhase = phase;
if (index >= mOperationalPhaseList.size())
{
return CHIP_ERROR_NOT_FOUND;
}
operationalPhase = mOperationalPhaseList[index];
return CHIP_NO_ERROR;
}

CHIP_ERROR OperationalStateDelegate::SetCountdownTime(const app::DataModel::Nullable<uint32_t> & time)
void GenericOperationalStateDelegateImpl::HandlePauseStateCallback(GenericOperationalError & err)
{
mCountdownTime = time;
return CHIP_NO_ERROR;
// placeholder implementation
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kPaused));
if (error == CHIP_NO_ERROR)
{
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
else
{
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
}
}

uint8_t OperationalStateDelegate::GetCurrentOperationalState()
void GenericOperationalStateDelegateImpl::HandleResumeStateCallback(GenericOperationalError & err)
{
return mOperationalState;
// placeholder implementation
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning));
if (error == CHIP_NO_ERROR)
{
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
else
{
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
}
}

CHIP_ERROR OperationalStateDelegate::SetOperationalError(const GenericOperationalError & opErrState)
void GenericOperationalStateDelegateImpl::HandleStartStateCallback(GenericOperationalError & err)
{
mOperationalError = opErrState;
return CHIP_NO_ERROR;
// placeholder implementation
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning));
if (error == CHIP_NO_ERROR)
{
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
else
{
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
}
}

void OperationalStateDelegate::GetCurrentOperationalError(GenericOperationalError & error)
void GenericOperationalStateDelegateImpl::HandleStopStateCallback(GenericOperationalError & err)
{
error = mOperationalError;
// placeholder implementation
auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kStopped));
if (error == CHIP_NO_ERROR)
{
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
else
{
err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation));
}
}

void OperationalStateDelegate::GetCurrentPhase(app::DataModel::Nullable<uint8_t> & phase)
{
phase = mOperationalPhase;
}
// Init Operational State cluster

void OperationalStateDelegate::GetCountdownTime(app::DataModel::Nullable<uint32_t> & time)
{
time = mCountdownTime;
}
static OperationalState::Instance * gOperationalStateInstance = nullptr;
static OperationalStateDelegate * gOperationalStateDelegate = nullptr;

CHIP_ERROR OperationalStateDelegate::GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState)
void OperationalState::Shutdown()
{
if (index > mOperationalStateList.size() - 1)
if (gOperationalStateInstance != nullptr)
{
return CHIP_ERROR_NOT_FOUND;
delete gOperationalStateInstance;
gOperationalStateInstance = nullptr;
}
operationalState = mOperationalStateList[index];
return CHIP_NO_ERROR;
}

CHIP_ERROR OperationalStateDelegate::GetOperationalPhaseAtIndex(size_t index, GenericOperationalPhase & operationalPhase)
{
if (index > mOperationalPhaseList.size() - 1)
if (gOperationalStateDelegate != nullptr)
{
return CHIP_ERROR_NOT_FOUND;
delete gOperationalStateDelegate;
gOperationalStateDelegate = nullptr;
}
operationalPhase = mOperationalPhaseList[index];
return CHIP_NO_ERROR;
}

void OperationalStateDelegate::HandlePauseStateCallback(GenericOperationalError & err)
void emberAfOperationalStateClusterInitCallback(chip::EndpointId endpointId)
{
// placeholder implementation
mOperationalState = to_underlying(OperationalStateEnum::kPaused);
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1.
VerifyOrDie(gOperationalStateInstance == nullptr && gOperationalStateDelegate == nullptr);

void OperationalStateDelegate::HandleResumeStateCallback(GenericOperationalError & err)
{
// placeholder implementation
mOperationalState = to_underlying(OperationalStateEnum::kRunning);
err.Set(to_underlying(ErrorStateEnum::kNoError));
gOperationalStateDelegate = new OperationalStateDelegate;
EndpointId operationalStateEndpoint = 0x01;
gOperationalStateInstance = new Instance(gOperationalStateDelegate, operationalStateEndpoint, Clusters::OperationalState::Id);

gOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped));

gOperationalStateInstance->Init();
}

void OperationalStateDelegate::HandleStartStateCallback(GenericOperationalError & err)
// Init RVC Operational State cluster

static OperationalState::Instance * gRvcOperationalStateInstance = nullptr;
static RvcOperationalStateDelegate * gRvcOperationalStateDelegate = nullptr;

void RvcOperationalState::Shutdown()
{
// placeholder implementation
mOperationalState = to_underlying(OperationalStateEnum::kRunning);
err.Set(to_underlying(ErrorStateEnum::kNoError));
if (gRvcOperationalStateInstance != nullptr)
{
delete gRvcOperationalStateInstance;
gRvcOperationalStateInstance = nullptr;
}
if (gRvcOperationalStateDelegate != nullptr)
{
delete gRvcOperationalStateDelegate;
gRvcOperationalStateDelegate = nullptr;
}
}

void OperationalStateDelegate::HandleStopStateCallback(GenericOperationalError & err)
void emberAfRvcOperationalStateClusterInitCallback(chip::EndpointId endpointId)
{
// placeholder implementation
mOperationalState = to_underlying(OperationalStateEnum::kStopped);
err.Set(to_underlying(ErrorStateEnum::kNoError));
}
VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1.
VerifyOrDie(gRvcOperationalStateInstance == nullptr && gRvcOperationalStateDelegate == nullptr);

} // namespace OperationalState
} // namespace Clusters
} // namespace app
} // namespace chip
gRvcOperationalStateDelegate = new RvcOperationalStateDelegate;
EndpointId operationalStateEndpoint = 0x01;
gRvcOperationalStateInstance =
new Instance(gRvcOperationalStateDelegate, operationalStateEndpoint, Clusters::RvcOperationalState::Id);

gRvcOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped));

gRvcOperationalStateInstance->Init();
}
Loading

0 comments on commit 2d7a8d7

Please sign in to comment.