From 8aecb621b08c8029823a11700b86f6b109a4abf7 Mon Sep 17 00:00:00 2001 From: erwinpan1 Date: Fri, 29 Sep 2023 12:28:29 +0800 Subject: [PATCH 1/6] Add Chef RVC device type --- .../chef/common/chef-rvc-mode-delegate.cpp | 210 ++++++++++++++++++ examples/chef/common/chef-rvc-mode-delegate.h | 122 ++++++++++ .../chef-rvc-operational-state-delegate.cpp | 172 ++++++++++++++ .../chef-rvc-operational-state-delegate.h | 157 +++++++++++++ ...otnode_roboticvacuumcleaner_1807ff0c49.zap | 95 ++++---- examples/chef/linux/BUILD.gn | 2 + examples/chef/nrfconnect/CMakeLists.txt | 2 + 7 files changed, 721 insertions(+), 39 deletions(-) create mode 100644 examples/chef/common/chef-rvc-mode-delegate.cpp create mode 100644 examples/chef/common/chef-rvc-mode-delegate.h create mode 100644 examples/chef/common/chef-rvc-operational-state-delegate.cpp create mode 100644 examples/chef/common/chef-rvc-operational-state-delegate.h diff --git a/examples/chef/common/chef-rvc-mode-delegate.cpp b/examples/chef/common/chef-rvc-mode-delegate.cpp new file mode 100644 index 00000000000000..93d08ac25d4717 --- /dev/null +++ b/examples/chef/common/chef-rvc-mode-delegate.cpp @@ -0,0 +1,210 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +using namespace chip::app::Clusters; +using chip::Protocols::InteractionModel::Status; +template +using List = chip::app::DataModel::List; +using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type; + +#ifdef ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER +#include +using namespace chip::app::Clusters::RvcRunMode; +static RvcRunModeDelegate * gRvcRunModeDelegate = nullptr; +static ModeBase::Instance * gRvcRunModeInstance = nullptr; + +CHIP_ERROR RvcRunModeDelegate::Init() +{ + return CHIP_NO_ERROR; +} + +void RvcRunModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) +{ + uint8_t currentMode = mInstance->GetCurrentMode(); + + // Our business logic states that we can only switch into the mapping state from the idle state. + if (NewMode == RvcRunMode::ModeMapping && currentMode != RvcRunMode::ModeIdle) + { + response.status = to_underlying(ModeBase::StatusCode::kGenericFailure); + response.statusText.SetValue(chip::CharSpan::fromCharString("Change to the mapping mode is only allowed from idle")); + return; + } + + response.status = to_underlying(ModeBase::StatusCode::kSuccess); +} + +CHIP_ERROR RvcRunModeDelegate::GetModeLabelByIndex(uint8_t modeIndex, chip::MutableCharSpan & label) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + return chip::CopyCharSpanToMutableCharSpan(kModeOptions[modeIndex].label, label); +} + +CHIP_ERROR RvcRunModeDelegate::GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + value = kModeOptions[modeIndex].mode; + return CHIP_NO_ERROR; +} + +CHIP_ERROR RvcRunModeDelegate::GetModeTagsByIndex(uint8_t modeIndex, List & tags) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + + if (tags.size() < kModeOptions[modeIndex].modeTags.size()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + std::copy(kModeOptions[modeIndex].modeTags.begin(), kModeOptions[modeIndex].modeTags.end(), tags.begin()); + tags.reduce_size(kModeOptions[modeIndex].modeTags.size()); + + return CHIP_NO_ERROR; +} + +ModeBase::Instance * RvcRunMode::Instance() +{ + return gRvcRunModeInstance; +} + +void RvcRunMode::Shutdown() +{ + if (gRvcRunModeInstance != nullptr) + { + delete gRvcRunModeInstance; + gRvcRunModeInstance = nullptr; + } + if (gRvcRunModeDelegate != nullptr) + { + delete gRvcRunModeDelegate; + gRvcRunModeDelegate = nullptr; + } +} + +void emberAfRvcRunModeClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gRvcRunModeDelegate == nullptr && gRvcRunModeInstance == nullptr); + gRvcRunModeDelegate = new RvcRunMode::RvcRunModeDelegate; + gRvcRunModeInstance = + new ModeBase::Instance(gRvcRunModeDelegate, 0x1, RvcRunMode::Id, chip::to_underlying(RvcRunMode::Feature::kOnOff)); + gRvcRunModeInstance->Init(); +} +#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER + +#ifdef ZCL_USING_RVC_CLEAN_MODE_CLUSTER_SERVER +#include +using namespace chip::app::Clusters::RvcCleanMode; +static RvcCleanModeDelegate * gRvcCleanModeDelegate = nullptr; +static ModeBase::Instance * gRvcCleanModeInstance = nullptr; + +CHIP_ERROR RvcCleanModeDelegate::Init() +{ + return CHIP_NO_ERROR; +} + +void RvcCleanModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) +{ + uint8_t rvcRunCurrentMode = gRvcRunModeInstance->GetCurrentMode(); + + if (rvcRunCurrentMode == RvcRunMode::ModeCleaning) + { + response.status = to_underlying(RvcCleanMode::StatusCode::kCleaningInProgress); + response.statusText.SetValue(chip::CharSpan::fromCharString("Cannot change the cleaning mode during a clean")); + return; + } + + response.status = to_underlying(ModeBase::StatusCode::kSuccess); +} + +CHIP_ERROR RvcCleanModeDelegate::GetModeLabelByIndex(uint8_t modeIndex, chip::MutableCharSpan & label) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + return chip::CopyCharSpanToMutableCharSpan(kModeOptions[modeIndex].label, label); +} + +CHIP_ERROR RvcCleanModeDelegate::GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + value = kModeOptions[modeIndex].mode; + return CHIP_NO_ERROR; +} + +CHIP_ERROR RvcCleanModeDelegate::GetModeTagsByIndex(uint8_t modeIndex, List & tags) +{ + if (modeIndex >= ArraySize(kModeOptions)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + + if (tags.size() < kModeOptions[modeIndex].modeTags.size()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + std::copy(kModeOptions[modeIndex].modeTags.begin(), kModeOptions[modeIndex].modeTags.end(), tags.begin()); + tags.reduce_size(kModeOptions[modeIndex].modeTags.size()); + + return CHIP_NO_ERROR; +} + +ModeBase::Instance * RvcCleanMode::Instance() +{ + return gRvcCleanModeInstance; +} + +void RvcCleanMode::Shutdown() +{ + if (gRvcCleanModeInstance != nullptr) + { + delete gRvcCleanModeInstance; + gRvcCleanModeInstance = nullptr; + } + if (gRvcCleanModeDelegate != nullptr) + { + delete gRvcCleanModeDelegate; + gRvcCleanModeDelegate = nullptr; + } +} + +void emberAfRvcCleanModeClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gRvcCleanModeDelegate == nullptr && gRvcCleanModeInstance == nullptr); + gRvcCleanModeDelegate = new RvcCleanMode::RvcCleanModeDelegate; + gRvcCleanModeInstance = + new ModeBase::Instance(gRvcCleanModeDelegate, 0x1, RvcCleanMode::Id, chip::to_underlying(RvcCleanMode::Feature::kOnOff)); + gRvcCleanModeInstance->Init(); +} +#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER diff --git a/examples/chef/common/chef-rvc-mode-delegate.h b/examples/chef/common/chef-rvc-mode-delegate.h new file mode 100644 index 00000000000000..2453e017bd1c8d --- /dev/null +++ b/examples/chef/common/chef-rvc-mode-delegate.h @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { + +namespace RvcRunMode { + +const uint8_t ModeIdle = 0; +const uint8_t ModeCleaning = 1; +const uint8_t ModeMapping = 2; + +/// This is an application level delegate to handle RvcRun commands according to the specific business logic. +class RvcRunModeDelegate : public ModeBase::Delegate +{ +private: + using ModeTagStructType = detail::Structs::ModeTagStruct::Type; + ModeTagStructType ModeTagsIdle[1] = { { .value = to_underlying(ModeTag::kIdle) } }; + ModeTagStructType ModeTagsCleaning[1] = { { .value = to_underlying(ModeTag::kCleaning) } }; + + const detail::Structs::ModeOptionStruct::Type kModeOptions[3] = { + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Idle"), + .mode = ModeIdle, + .modeTags = DataModel::List(ModeTagsIdle) }, + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Cleaning"), + .mode = ModeCleaning, + .modeTags = DataModel::List(ModeTagsCleaning) }, + detail::Structs::ModeOptionStruct::Type{ + .label = CharSpan::fromCharString("Mapping"), + .mode = ModeMapping, + .modeTags = DataModel::List(ModeTagsIdle) }, // todo set to no mode tags + }; + + CHIP_ERROR Init() override; + void HandleChangeToMode(uint8_t mode, ModeBase::Commands::ChangeToModeResponse::Type & response) override; + + CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) override; + CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override; + CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List & tags) override; + +public: + ~RvcRunModeDelegate() override = default; +}; + +ModeBase::Instance * Instance(); + +void Shutdown(); + +} // namespace RvcRunMode + +namespace RvcCleanMode { + +const uint8_t ModeVacuum = 0; +const uint8_t ModeWash = 1; +const uint8_t ModeDeepClean = 2; + +/// This is an application level delegate to handle RvcClean commands according to the specific business logic. +class RvcCleanModeDelegate : public ModeBase::Delegate +{ +private: + using ModeTagStructType = detail::Structs::ModeTagStruct::Type; + ModeTagStructType modeTagsVac[1] = { { .value = to_underlying(ModeTag::kVacuum) } }; + ModeTagStructType modeTagsMop[1] = { { .value = to_underlying(ModeTag::kMop) } }; + ModeTagStructType modeTagsBoost[2] = { { .value = to_underlying(ModeBase::ModeTag::kMax) }, + { .value = to_underlying(ModeTag::kDeepClean) } }; + + const detail::Structs::ModeOptionStruct::Type kModeOptions[3] = { + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Vacuum"), + .mode = ModeVacuum, + .modeTags = DataModel::List(modeTagsVac) }, + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Wash"), + .mode = ModeWash, + .modeTags = DataModel::List(modeTagsMop) }, + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Deep clean"), + .mode = ModeDeepClean, + .modeTags = DataModel::List(modeTagsBoost) }, + }; + + CHIP_ERROR Init() override; + void HandleChangeToMode(uint8_t mode, ModeBase::Commands::ChangeToModeResponse::Type & response) override; + + CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) override; + CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override; + CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List & tags) override; + +public: + ~RvcCleanModeDelegate() override = default; +}; + +ModeBase::Instance * Instance(); + +void Shutdown(); + +} // namespace RvcCleanMode + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/chef/common/chef-rvc-operational-state-delegate.cpp b/examples/chef/common/chef-rvc-operational-state-delegate.cpp new file mode 100644 index 00000000000000..119c2cfdb019be --- /dev/null +++ b/examples/chef/common/chef-rvc-operational-state-delegate.cpp @@ -0,0 +1,172 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#ifdef ZCL_USING_OPERATIONAL_STATE_RVC_CLUSTER_SERVER +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::OperationalState; +using namespace chip::app::Clusters::RvcOperationalState; + +CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState) +{ + if (index >= mOperationalStateList.size()) + { + return CHIP_ERROR_NOT_FOUND; + } + operationalState = mOperationalStateList[index]; + return CHIP_NO_ERROR; +} + +CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalPhaseAtIndex(size_t index, GenericOperationalPhase & operationalPhase) +{ + if (index >= mOperationalPhaseList.size()) + { + return CHIP_ERROR_NOT_FOUND; + } + operationalPhase = mOperationalPhaseList[index]; + return CHIP_NO_ERROR; +} + +void GenericOperationalStateDelegateImpl::HandlePauseStateCallback(GenericOperationalError & err) +{ + // 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)); + } +} + +void GenericOperationalStateDelegateImpl::HandleResumeStateCallback(GenericOperationalError & err) +{ + // 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 GenericOperationalStateDelegateImpl::HandleStartStateCallback(GenericOperationalError & err) +{ + // 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 GenericOperationalStateDelegateImpl::HandleStopStateCallback(GenericOperationalError & err) +{ + // 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)); + } +} + +// Init Operational State cluster + +static OperationalState::Instance * gOperationalStateInstance = nullptr; +static OperationalStateDelegate * gOperationalStateDelegate = nullptr; + +void OperationalState::Shutdown() +{ + if (gOperationalStateInstance != nullptr) + { + delete gOperationalStateInstance; + gOperationalStateInstance = nullptr; + } + if (gOperationalStateDelegate != nullptr) + { + delete gOperationalStateDelegate; + gOperationalStateDelegate = nullptr; + } +} + +void emberAfOperationalStateClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gOperationalStateInstance == nullptr && gOperationalStateDelegate == nullptr); + + gOperationalStateDelegate = new OperationalStateDelegate; + EndpointId operationalStateEndpoint = 0x01; + gOperationalStateInstance = new Instance(gOperationalStateDelegate, operationalStateEndpoint, Clusters::OperationalState::Id); + + gOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + + gOperationalStateInstance->Init(); +} + +// Init RVC Operational State cluster + +static OperationalState::Instance * gRvcOperationalStateInstance = nullptr; +static RvcOperationalStateDelegate * gRvcOperationalStateDelegate = nullptr; + +void RvcOperationalState::Shutdown() +{ + if (gRvcOperationalStateInstance != nullptr) + { + delete gRvcOperationalStateInstance; + gRvcOperationalStateInstance = nullptr; + } + if (gRvcOperationalStateDelegate != nullptr) + { + delete gRvcOperationalStateDelegate; + gRvcOperationalStateDelegate = nullptr; + } +} + +void emberAfRvcOperationalStateClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gRvcOperationalStateInstance == nullptr && gRvcOperationalStateDelegate == nullptr); + + gRvcOperationalStateDelegate = new RvcOperationalStateDelegate; + EndpointId operationalStateEndpoint = 0x01; + gRvcOperationalStateInstance = + new Instance(gRvcOperationalStateDelegate, operationalStateEndpoint, Clusters::RvcOperationalState::Id); + + gRvcOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + + gRvcOperationalStateInstance->Init(); +} +#endif // EMBER_AF_PLUGIN_RVC_OPERATIONAL_STATE_SERVER diff --git a/examples/chef/common/chef-rvc-operational-state-delegate.h b/examples/chef/common/chef-rvc-operational-state-delegate.h new file mode 100644 index 00000000000000..fd6df4b90359f1 --- /dev/null +++ b/examples/chef/common/chef-rvc-operational-state-delegate.h @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +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 GenericOperationalStateDelegateImpl : public Delegate +{ +public: + /** + * Get the countdown time. This attribute is not used in this application. + * @return The current countdown time. + */ + app::DataModel::Nullable GetCountdownTime() override { return {}; }; + + /** + * 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; + + /** + * 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; + + // command callback + /** + * Handle Command Callback in application: Pause + * @param[out] get operational error after callback. + */ + void HandlePauseStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Resume + * @param[out] get operational error after callback. + */ + void HandleResumeStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Start + * @param[out] get operational error after callback. + */ + void HandleStartStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Stop + * @param[out] get operational error after callback. + */ + void HandleStopStateCallback(GenericOperationalError & err) override; + +protected: + Span mOperationalStateList; + Span mOperationalPhaseList; +}; + +// This is an application level delegate to handle operational state commands according to the specific business logic. +class OperationalStateDelegate : public GenericOperationalStateDelegateImpl +{ +private: + 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()), + }; + +public: + OperationalStateDelegate() + { + GenericOperationalStateDelegateImpl::mOperationalStateList = Span(opStateList); + GenericOperationalStateDelegateImpl::mOperationalPhaseList = Span(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()), + }; + +public: + RvcOperationalStateDelegate() + { + GenericOperationalStateDelegateImpl::mOperationalStateList = + Span(rvcOpStateList); + GenericOperationalStateDelegateImpl::mOperationalPhaseList = + Span(rvcOpPhaseList); + } +}; + +void Shutdown(); + +} // namespace RvcOperationalState +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.zap b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.zap index b9f4ebb8516683..f3eeac565bbfe4 100644 --- a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.zap +++ b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.zap @@ -16,6 +16,12 @@ } ], "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "version": "chip-v1" + }, { "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/zcl/zcl.json", @@ -23,12 +29,6 @@ "category": "matter", "version": 1, "description": "Matter SDK ZCL data" - }, - { - "pathRelativity": "relativeToZap", - "path": "../../../src/app/zap-templates/app-templates.json", - "type": "gen-templates-json", - "version": "chip-v1" } ], "endpointTypes": [ @@ -7432,10 +7432,10 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7448,10 +7448,10 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7463,11 +7463,11 @@ "mfgCode": null, "side": "server", "type": "int8u", - "included": 0, - "storageOption": "External", + "included": 1, + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7479,11 +7479,11 @@ "mfgCode": null, "side": "server", "type": "int8u", - "included": 0, - "storageOption": "External", + "included": 1, + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7664,10 +7664,10 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7680,10 +7680,10 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7695,11 +7695,11 @@ "mfgCode": null, "side": "server", "type": "int8u", - "included": 0, - "storageOption": "External", + "included": 1, + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7711,11 +7711,11 @@ "mfgCode": null, "side": "server", "type": "int8u", - "included": 0, - "storageOption": "External", + "included": 1, + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7835,6 +7835,22 @@ "incoming": 1, "outgoing": 0 }, + { + "name": "Stop", + "code": 1, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, + { + "name": "Start", + "code": 2, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + }, { "name": "Resume", "code": 3, @@ -7904,7 +7920,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -7920,10 +7936,10 @@ "side": "server", "type": "int8u", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7935,11 +7951,11 @@ "mfgCode": null, "side": "server", "type": "elapsed_s", - "included": 0, - "storageOption": "External", + "included": 1, + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7952,10 +7968,10 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7968,10 +7984,10 @@ "side": "server", "type": "enum8", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -7984,10 +8000,10 @@ "side": "server", "type": "ErrorStateStruct", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -10881,5 +10897,6 @@ "endpointId": 1, "networkId": 0 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index 37a04ece688c22..c3ea39ce52eaef 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -45,6 +45,8 @@ executable("${sample_name}") { "${project_dir}/common/chef-air-quality.cpp", "${project_dir}/common/chef-channel-manager.cpp", "${project_dir}/common/chef-concentration-measurement.cpp", + "${project_dir}/common/chef-rvc-mode-delegate.cpp", + "${project_dir}/common/chef-rvc-operational-state-delegate.cpp", "${project_dir}/common/stubs.cpp", "${project_dir}/linux/main.cpp", ] diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index 90869f9d4ed2c9..feefec055ee7f2 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -92,6 +92,8 @@ target_sources(app PRIVATE ${CHEF}/nrfconnect/main.cpp ${CHEF}/common/stubs.cpp ${CHEF}/common/chef-channel-manager.cpp + ${CHEF}/common/chef-rvc-mode-delegate.cpp + ${CHEF}/common/chef-rvc-operational-state-delegate.cpp ) message(STATUS ${CHEF}/devices/${SAMPLE_NAME}.zap) From a95d889184c52a6b5121c90480e358fc4b56189a Mon Sep 17 00:00:00 2001 From: erwinpan1 Date: Sun, 1 Oct 2023 16:58:54 +0800 Subject: [PATCH 2/6] Update rootnode_roboticvacuumcleaner_1807ff0c49.matter --- ...ode_roboticvacuumcleaner_1807ff0c49.matter | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter index 2945ee6e8c58dc..583711ba680fe4 100644 --- a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter +++ b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter @@ -1040,6 +1040,8 @@ server cluster RvcRunMode = 84 { readonly attribute ModeOptionStruct supportedModes[] = 0; readonly attribute int8u currentMode = 1; + attribute nullable int8u startUpMode = 2; + attribute nullable int8u onMode = 3; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1088,6 +1090,8 @@ server cluster RvcCleanMode = 85 { readonly attribute ModeOptionStruct supportedModes[] = 0; readonly attribute int8u currentMode = 1; + attribute nullable int8u startUpMode = 2; + attribute nullable int8u onMode = 3; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1149,6 +1153,7 @@ server cluster RvcOperationalState = 97 { readonly attribute nullable CHAR_STRING phaseList[] = 0; readonly attribute nullable int8u currentPhase = 1; + readonly attribute nullable elapsed_s countdownTime = 2; readonly attribute OperationalStateStruct operationalStateList[] = 3; readonly attribute enum8 operationalState = 4; readonly attribute ErrorStateStruct operationalError = 5; @@ -1164,6 +1169,8 @@ server cluster RvcOperationalState = 97 { } command Pause(): OperationalCommandResponse = 0; + command Stop(): OperationalCommandResponse = 1; + command Start(): OperationalCommandResponse = 2; command Resume(): OperationalCommandResponse = 3; } @@ -1346,8 +1353,10 @@ endpoint 1 { } server cluster RvcRunMode { - callback attribute supportedModes; - callback attribute currentMode; + callback attribute supportedModes default = 0; + callback attribute currentMode default = 0; + callback attribute startUpMode default = 0; + callback attribute onMode default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -1357,8 +1366,10 @@ endpoint 1 { } server cluster RvcCleanMode { - callback attribute supportedModes; - callback attribute currentMode; + callback attribute supportedModes default = 0; + callback attribute currentMode default = 0; + callback attribute startUpMode default = 0; + callback attribute onMode default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -1371,10 +1382,11 @@ endpoint 1 { emits event OperationalError; emits event OperationCompletion; callback attribute phaseList; - callback attribute currentPhase; - callback attribute operationalStateList; - callback attribute operationalState; - callback attribute operationalError; + callback attribute currentPhase default = 0; + callback attribute countdownTime default = 0; + callback attribute operationalStateList default = 0; + callback attribute operationalState default = 0; + callback attribute operationalError default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; From f1e485dc5c49e3eafd635cd9d3350f64e2766f38 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 1 Oct 2023 08:59:30 +0000 Subject: [PATCH 3/6] Restyled by clang-format --- examples/chef/common/chef-rvc-mode-delegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/chef/common/chef-rvc-mode-delegate.h b/examples/chef/common/chef-rvc-mode-delegate.h index 2453e017bd1c8d..af8313fa285385 100644 --- a/examples/chef/common/chef-rvc-mode-delegate.h +++ b/examples/chef/common/chef-rvc-mode-delegate.h @@ -18,9 +18,9 @@ #pragma once +#include #include #include -#include #include #include From 4d33670861f7fac282cf459d5667c41f39e4c9ee Mon Sep 17 00:00:00 2001 From: erwinpan1 Date: Mon, 2 Oct 2023 22:56:40 +0800 Subject: [PATCH 4/6] Fix nit in chef-rvc-mode-delegate.* --- examples/chef/common/chef-rvc-mode-delegate.cpp | 9 +++++---- examples/chef/common/chef-rvc-mode-delegate.h | 7 +++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/chef/common/chef-rvc-mode-delegate.cpp b/examples/chef/common/chef-rvc-mode-delegate.cpp index 93d08ac25d4717..65e3fa9ca9af70 100644 --- a/examples/chef/common/chef-rvc-mode-delegate.cpp +++ b/examples/chef/common/chef-rvc-mode-delegate.cpp @@ -130,12 +130,13 @@ CHIP_ERROR RvcCleanModeDelegate::Init() void RvcCleanModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) { - uint8_t rvcRunCurrentMode = gRvcRunModeInstance->GetCurrentMode(); + uint8_t rvcCleanCurrentMode = gRvcCleanModeInstance->GetCurrentMode(); - if (rvcRunCurrentMode == RvcRunMode::ModeCleaning) + // An example to show how do we block mode change in some circumstance + if (rvcCleanCurrentMode == RvcCleanMode::ModeDeepClean) { response.status = to_underlying(RvcCleanMode::StatusCode::kCleaningInProgress); - response.statusText.SetValue(chip::CharSpan::fromCharString("Cannot change the cleaning mode during a clean")); + response.statusText.SetValue(chip::CharSpan::fromCharString("Cannot change the cleaning mode during a deep clean")); return; } @@ -207,4 +208,4 @@ void emberAfRvcCleanModeClusterInitCallback(chip::EndpointId endpointId) new ModeBase::Instance(gRvcCleanModeDelegate, 0x1, RvcCleanMode::Id, chip::to_underlying(RvcCleanMode::Feature::kOnOff)); gRvcCleanModeInstance->Init(); } -#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER +#endif // ZCL_USING_RVC_CLEAN_MODE_CLUSTER_SERVER diff --git a/examples/chef/common/chef-rvc-mode-delegate.h b/examples/chef/common/chef-rvc-mode-delegate.h index af8313fa285385..3b08552776319a 100644 --- a/examples/chef/common/chef-rvc-mode-delegate.h +++ b/examples/chef/common/chef-rvc-mode-delegate.h @@ -49,10 +49,9 @@ class RvcRunModeDelegate : public ModeBase::Delegate detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Cleaning"), .mode = ModeCleaning, .modeTags = DataModel::List(ModeTagsCleaning) }, - detail::Structs::ModeOptionStruct::Type{ - .label = CharSpan::fromCharString("Mapping"), - .mode = ModeMapping, - .modeTags = DataModel::List(ModeTagsIdle) }, // todo set to no mode tags + detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Mapping"), + .mode = ModeMapping, + .modeTags = DataModel::List(ModeTagsIdle) }, }; CHIP_ERROR Init() override; From a65fb767e2ecb56aed3078fb1593a45c628e215b Mon Sep 17 00:00:00 2001 From: erwinpan1 Date: Mon, 2 Oct 2023 23:04:41 +0800 Subject: [PATCH 5/6] Rollback previous changes regarding to RvcCleanMode --- examples/chef/common/chef-rvc-mode-delegate.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/chef/common/chef-rvc-mode-delegate.cpp b/examples/chef/common/chef-rvc-mode-delegate.cpp index 65e3fa9ca9af70..7920f21cd4cb9c 100644 --- a/examples/chef/common/chef-rvc-mode-delegate.cpp +++ b/examples/chef/common/chef-rvc-mode-delegate.cpp @@ -130,13 +130,12 @@ CHIP_ERROR RvcCleanModeDelegate::Init() void RvcCleanModeDelegate::HandleChangeToMode(uint8_t NewMode, ModeBase::Commands::ChangeToModeResponse::Type & response) { - uint8_t rvcCleanCurrentMode = gRvcCleanModeInstance->GetCurrentMode(); + uint8_t rvcRunCurrentMode = gRvcRunModeInstance->GetCurrentMode(); - // An example to show how do we block mode change in some circumstance - if (rvcCleanCurrentMode == RvcCleanMode::ModeDeepClean) + if (rvcRunCurrentMode == RvcRunMode::ModeCleaning) { response.status = to_underlying(RvcCleanMode::StatusCode::kCleaningInProgress); - response.statusText.SetValue(chip::CharSpan::fromCharString("Cannot change the cleaning mode during a deep clean")); + response.statusText.SetValue(chip::CharSpan::fromCharString("Cannot change the cleaning mode during a clean")); return; } From 775a54f960ec70876fd91ae9d14555968ffef257 Mon Sep 17 00:00:00 2001 From: erwinpan1 Date: Mon, 2 Oct 2023 23:14:15 +0800 Subject: [PATCH 6/6] Move ifdef ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER to latest line since the RVC_CLEAN_MODE will use global variable in RVC_RUN_MODE --- examples/chef/common/chef-rvc-mode-delegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/chef/common/chef-rvc-mode-delegate.cpp b/examples/chef/common/chef-rvc-mode-delegate.cpp index 7920f21cd4cb9c..20f3afbbd5592d 100644 --- a/examples/chef/common/chef-rvc-mode-delegate.cpp +++ b/examples/chef/common/chef-rvc-mode-delegate.cpp @@ -115,7 +115,6 @@ void emberAfRvcRunModeClusterInitCallback(chip::EndpointId endpointId) new ModeBase::Instance(gRvcRunModeDelegate, 0x1, RvcRunMode::Id, chip::to_underlying(RvcRunMode::Feature::kOnOff)); gRvcRunModeInstance->Init(); } -#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER #ifdef ZCL_USING_RVC_CLEAN_MODE_CLUSTER_SERVER #include @@ -208,3 +207,4 @@ void emberAfRvcCleanModeClusterInitCallback(chip::EndpointId endpointId) gRvcCleanModeInstance->Init(); } #endif // ZCL_USING_RVC_CLEAN_MODE_CLUSTER_SERVER +#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER