Skip to content

Commit

Permalink
Add implementation for Mode Select Cluster.
Browse files Browse the repository at this point in the history
Include header file in heap-based-supported-modes-manager.cpp.

Add implementation for ModeSelectCluster.
  • Loading branch information
dinglamazon committed Oct 22, 2021
1 parent d1051fb commit 8620937
Show file tree
Hide file tree
Showing 55 changed files with 10,636 additions and 8,294 deletions.
1 change: 1 addition & 0 deletions examples/all-clusters-app/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ set(SRC_DIRS_LIST
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/content-launch-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/media-input-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/mode-select-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/low-power-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/keypad-input-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/media-playback-server"
Expand Down
5 changes: 5 additions & 0 deletions src/app/chip_data_model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ template("chip_data_model") {
"${_app_root}/clusters/${cluster}/${cluster}-ember.cpp",
"${_app_root}/clusters/${cluster}/${cluster}.cpp",
]
} else if (cluster == "mode-select-server") {
sources += [
"${_app_root}/clusters/${cluster}/heap-based-supported-modes-manager.cpp",
"${_app_root}/clusters/${cluster}/${cluster}.cpp"
]
} else {
sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// Created by Ding, Li-an on 10/21/21.
//
#include <app/clusters/mode-select-server/heap-based-supported-modes-manager.h>
#include <vector>
#include <map>

using namespace std;
using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::ModeSelectCluster;

using ModeOptionStructType = Structs::ModeOptionStruct::Type;

HeapBasedSupportedModesManager::Builder &
HeapBasedSupportedModesManager::Builder::addSupportedMode(EndpointId endpointId, ModeOptionStructType & modeOptionStruct)
{
if (mSupportedModesByEndpoints.end() == mSupportedModesByEndpoints.find(endpointId))
{
mSupportedModesByEndpoints.insert(
pair<uint8_t, vector<ModeOptionStructType> *>(endpointId, new vector<ModeOptionStructType>()));
}
mSupportedModesByEndpoints[endpointId]->push_back(modeOptionStruct);

return *this;
}

HeapBasedSupportedModesManager::Builder &
HeapBasedSupportedModesManager::Builder::addSupportedMode(EndpointId endpointId,
ModeOptionStructType && modeOptionStruct)
{
if (mSupportedModesByEndpoints.end() == mSupportedModesByEndpoints.find(endpointId))
{
mSupportedModesByEndpoints.insert(
pair<uint8_t, vector<ModeOptionStructType> *>(endpointId, new vector<ModeOptionStructType>()));
}
mSupportedModesByEndpoints[endpointId]->push_back(forward<ModeOptionStructType>(modeOptionStruct));

return *this;
}

HeapBasedSupportedModesManager ModeSelectCluster::HeapBasedSupportedModesManager::Builder::build()
{
map<EndpointId, const vector<ModeOptionStructType>> supportedOptions;
for (map<EndpointId, vector<ModeOptionStructType> *>::iterator it = mSupportedModesByEndpoints.begin();
it != mSupportedModesByEndpoints.end(); ++it)
{
EndpointId endpointId = it->first;

const vector<ModeOptionStructType> modeOptionsForEndpoint(*(it->second));
supportedOptions.insert(pair<EndpointId, const vector<ModeOptionStructType>>(endpointId, modeOptionsForEndpoint));
}

return HeapBasedSupportedModesManager(supportedOptions);
}

const vector<ModeOptionStructType>
HeapBasedSupportedModesManager::getSupportedModesForEndpoint(EndpointId endpoint) const
{
return _supportedModesForAllEndpoints.at(endpoint);
};

EmberAfStatus HeapBasedSupportedModesManager::getModeOptionByMode(
unsigned short endpointId, unsigned char mode, const ModeOptionStructType *& dataPtr) const
{
const vector<ModeOptionStructType> & supportedModeOptions = this->getSupportedModesForEndpoint(endpointId);
for (uint i = 0u; i < supportedModeOptions.size(); i++)
{
if (supportedModeOptions.at(i).mode == mode)
{
dataPtr = &(supportedModeOptions.at(i));
return EMBER_ZCL_STATUS_SUCCESS;
}
}
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "Cannot find the mode %c", mode);
return EMBER_ZCL_STATUS_INVALID_ARGUMENT;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
*
* Copyright (c) 2021 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-select-server/supported-modes-manager.h>
#include <vector>
#include <map>

namespace chip{
namespace app{
namespace Clusters{
namespace ModeSelectCluster{

/**
* This implementation uses the heap to store the supported options
*/
class HeapBasedSupportedModesManager: public chip::app::Clusters::ModeSelectCluster::SupportedModesManager
{
using ModeOptionStructType = Structs::ModeOptionStruct::Type;

public:
/**
* A builder for HeapBasedSupportedModesManager, for conveniently injecting the supported options and building the SupportedModesManager.
*/
class Builder
{
public:
/**
* Fluent method for adding a ModeOptionStruct::Type.
* @param endpointId The endpoint to which to add the supported mode
* @return this builder instance.
*/
Builder & addSupportedMode(EndpointId endpointId, ModeOptionStructType & modeOptionStruct);
/**
* Fluent method for adding a ModeOptionStruct::Type.
* @param endpointId The endpoint to which to add the supported mode
* @return this builder instance.
*/
Builder & addSupportedMode(EndpointId endpointId, ModeOptionStructType && modeOptionStruct);
HeapBasedSupportedModesManager build();

private:
std::map<EndpointId, std::vector<ModeOptionStructType> *> mSupportedModesByEndpoints;
};


const std::vector<ModeOptionStructType> getSupportedModesForEndpoint(EndpointId endpointId) const override;

EmberAfStatus getModeOptionByMode(EndpointId endpointId, uint8_t mode, const ModeOptionStructType *& dataPtr) const override;


private:
HeapBasedSupportedModesManager(std::map<EndpointId, const std::vector<ModeOptionStructType>> supportedModes) :
_supportedModesForAllEndpoints(supportedModes) {}
// TODO: Implement move constructor?

// endpoint index -> **ModeOptionStruct;
std::map<EndpointId, const std::vector<ModeOptionStructType>> _supportedModesForAllEndpoints;
};
}
}
}
}
140 changes: 140 additions & 0 deletions src/app/clusters/mode-select-server/mode-select-server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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.
*/

/****************************************************************************
* @file
* @brief Routines for the Mode Select plugin, the
*server implementation of the Mode Select Cluster.
*******************************************************************************
******************************************************************************/
#include <string>

#include <app-common/zap-generated/af-structs.h>
#include <app-common/zap-generated/att-storage.h>
#include <app-common/zap-generated/attribute-type.h>
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <app/clusters/mode-select-server/heap-based-supported-modes-manager.h>
#include <app/util/af.h>
#include <app/util/attribute-storage.h>
#include <lib/support/CodeUtils.h>

using namespace std;
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;

namespace {

class ModeSelectAttrAccess : public AttributeAccessInterface
{
public:
ModeSelectAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), ModeSelectCluster::Id) {}

CHIP_ERROR Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
};

ModeSelectCluster::Structs::ModeOptionStruct::Type buildModeOptionStruct(const char * label, size_t labelLength, uint8_t mode,
uint32_t semanticTag)
{
ModeSelectCluster::Structs::ModeOptionStruct::Type option;
option.label = CharSpan(label, std::strlen(label));
option.mode = mode;
option.semanticTag = semanticTag;
return option;
}

ModeSelectAttrAccess gModeSelectAttrAccess;

// TODO: Add as many ModeOptions as necessary.
ModeSelectCluster::Structs::ModeOptionStruct::Type option1 = buildModeOptionStruct("Black", 5, 0, 0);
ModeSelectCluster::Structs::ModeOptionStruct::Type option2 = buildModeOptionStruct("White", 5, 4, 0);
ModeSelectCluster::Structs::ModeOptionStruct::Type option3 = buildModeOptionStruct("Half-and-half", 13, 7, 0);

const ModeSelectCluster::HeapBasedSupportedModesManager & gSupportedModeManager = ModeSelectCluster::HeapBasedSupportedModesManager::Builder()
// TODO: Add as many ModeOptions as necessary.
.addSupportedMode((EndpointId) 0u, option1)
.addSupportedMode((EndpointId) 0u, option2)
.addSupportedMode((EndpointId) 0u, option3)
.build();

CHIP_ERROR ModeSelectAttrAccess::Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder)
{
if (aPath.mClusterId != ModeSelectCluster::Id)
{
// We shouldn't have been called at all.
return CHIP_ERROR_INVALID_ARGUMENT;
}

if (ModeSelectCluster::Attributes::SupportedModes::Id == aPath.mAttributeId)
{
const vector<ModeSelectCluster::Structs::ModeOptionStruct::Type> & supportedOptions =
gSupportedModeManager.getSupportedModesForEndpoint(aPath.mEndpointId);
CHIP_ERROR err;
err = aEncoder.EncodeList([supportedOptions](const TagBoundEncoder & encoder) -> CHIP_ERROR {
for (auto modeOption: supportedOptions)
{
ReturnErrorOnFailure(encoder.Encode(modeOption));
}
return CHIP_NO_ERROR;
});
ReturnErrorOnFailure(err);
}
return CHIP_NO_ERROR;
}

} // anonymous namespace

bool emberAfModeSelectClusterClusterChangeToModeCallback(
CommandHandler * commandHandler, const ConcreteCommandPath & commandPath,
const ModeSelectCluster::Commands::ChangeToMode::DecodableType & commandData)
{
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelectCluster: Entering emberAfModeSelectClusterClusterChangeToModeCallback");
EndpointId endpointId = commandPath.mEndpointId;
uint8_t newMode = commandData.newMode;
// Check that the newMode matches one of the supported options
const ModeSelectCluster::Structs::ModeOptionStruct::Type * modeOptionPtr;
EmberAfStatus checkSupportedModeStatus = gSupportedModeManager.getModeOptionByMode(endpointId, newMode, modeOptionPtr);
if (EMBER_ZCL_STATUS_SUCCESS != checkSupportedModeStatus)
{
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelectCluster: Failed to find the option with mode %hhu", newMode);
emberAfSendImmediateDefaultResponse(checkSupportedModeStatus);
return false;
}
ModeSelectCluster::Attributes::CurrentMode::Set(endpointId, newMode);
// TODO: Implement application logic


emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelectCluster: ChangeToMode successful");
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
}

void emberAfModeSelectClusterClusterInitCallback(EndpointId endpoint)
{
static bool attrAccessRegistered = false;
if (!attrAccessRegistered)
{
registerAttributeAccessOverride(&gModeSelectAttrAccess);
attrAccessRegistered = true;
}
}
70 changes: 70 additions & 0 deletions src/app/clusters/mode-select-server/supported-modes-manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
*
* Copyright (c) 2021 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 <map>
#include <vector>

#include <app-common/zap-generated/cluster-objects.h>
#include <app/util/af-enums.h>
#include <app/util/af.h>
#include <app/util/attribute-storage.h>
#include <app/util/basic-types.h>


namespace chip {
namespace app {
namespace Clusters {
namespace ModeSelectCluster {

/**
* Interface to help manage the supported modes of the Mode Select Cluster.
*/
class SupportedModesManager
{

using ModeOptionStructType = Structs::ModeOptionStruct::Type;

public:

/**
* Given the endpointId, returns all its supported modes options.
* @param endpointId
* @return
*/
virtual const std::vector<ModeOptionStructType> getSupportedModesForEndpoint(EndpointId endpointId) const = 0;

/**
* Given the endpointId and a mode value, find the ModeOptionStruct that matches the mode.
* @param endpointId
* @param mode
* @param dataPtr
* @return
*/
virtual EmberAfStatus getModeOptionByMode(EndpointId endpointId, uint8_t mode, const ModeOptionStructType *& dataPtr) const = 0;

virtual ~SupportedModesManager() {};

};


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

0 comments on commit 8620937

Please sign in to comment.