Skip to content

Commit

Permalink
[Chef] Add Robotic Vacuum Cleaner (RVC) device type delegates (#29519)
Browse files Browse the repository at this point in the history
* Add Chef RVC device type

* Update rootnode_roboticvacuumcleaner_1807ff0c49.matter

* Restyled by clang-format

* Fix nit in chef-rvc-mode-delegate.*

* Rollback previous changes regarding to RvcCleanMode

* 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

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Dec 12, 2023
1 parent fc1ce18 commit 1064879
Show file tree
Hide file tree
Showing 8 changed files with 740 additions and 47 deletions.
210 changes: 210 additions & 0 deletions examples/chef/common/chef-rvc-mode-delegate.cpp
Original file line number Diff line number Diff line change
@@ -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 <app-common/zap-generated/attributes/Accessors.h>
#include <app/util/config.h>

using namespace chip::app::Clusters;
using chip::Protocols::InteractionModel::Status;
template <typename T>
using List = chip::app::DataModel::List<T>;
using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type;

#ifdef ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER
#include <chef-rvc-mode-delegate.h>
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<ModeTagStructType> & 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();
}

#ifdef ZCL_USING_RVC_CLEAN_MODE_CLUSTER_SERVER
#include <chef-rvc-mode-delegate.h>
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<ModeTagStructType> & 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_CLEAN_MODE_CLUSTER_SERVER
#endif // ZCL_USING_RVC_RUN_MODE_CLUSTER_SERVER
121 changes: 121 additions & 0 deletions examples/chef/common/chef-rvc-mode-delegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
*
* 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 <app/clusters/mode-base-server/mode-base-server.h>
#include <app/util/af.h>
#include <app/util/config.h>
#include <cstring>
#include <utility>

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<const ModeTagStructType>(ModeTagsIdle) },
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Cleaning"),
.mode = ModeCleaning,
.modeTags = DataModel::List<const ModeTagStructType>(ModeTagsCleaning) },
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Mapping"),
.mode = ModeMapping,
.modeTags = DataModel::List<const ModeTagStructType>(ModeTagsIdle) },
};

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<ModeTagStructType> & 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<const ModeTagStructType>(modeTagsVac) },
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Wash"),
.mode = ModeWash,
.modeTags = DataModel::List<const ModeTagStructType>(modeTagsMop) },
detail::Structs::ModeOptionStruct::Type{ .label = CharSpan::fromCharString("Deep clean"),
.mode = ModeDeepClean,
.modeTags = DataModel::List<const ModeTagStructType>(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<ModeTagStructType> & tags) override;

public:
~RvcCleanModeDelegate() override = default;
};

ModeBase::Instance * Instance();

void Shutdown();

} // namespace RvcCleanMode

} // namespace Clusters
} // namespace app
} // namespace chip
Loading

0 comments on commit 1064879

Please sign in to comment.