Skip to content

Commit

Permalink
[ESP32] Added support of mode select for esp32 to read/write Supporte…
Browse files Browse the repository at this point in the history
…dModes attribute from factory partition (#25766)

* [ESP32] Added support of mode select for esp32 to read/write SupportedModes attribute from factory partition

* Restyled by whitespace

* Restyled by clang-format

* Restyled by autopep8

* Restyled by isort

* Addressed review comments

* Free allocated memory

* Restyled by whitespace

* Restyled by clang-format

* Restyled by prettier-markdown

* Tested memory leaks

* Restyled by clang-format

* Restyled by prettier-markdown

* Addressed review comments

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Sep 21, 2023
1 parent 1fdde78 commit 7c60f6b
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 4 deletions.
3 changes: 3 additions & 0 deletions docs/guides/esp32/factory_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Following data can be added to the manufacturing partition using
- Fixed Labels
- Supported locales
- Supported calendar types
- Supported modes
- Note: As per spec at max size of label should be 64 and `\0` will be
added at the end.

### Configuration Options

Expand Down
6 changes: 5 additions & 1 deletion examples/all-clusters-app/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(SRC_DIRS_LIST
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/shell_extension"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/lock"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/mode-support"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/reporting"
Expand Down Expand Up @@ -91,6 +92,9 @@ set(SRC_DIRS_LIST
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/src"
)


set(EXCLUDE_SRCS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp")

if (CONFIG_ENABLE_PW_RPC)
# Append additional directories for RPC build
set(PRIV_INCLUDE_DIRS_LIST "${PRIV_INCLUDE_DIRS_LIST}"
Expand Down Expand Up @@ -119,7 +123,7 @@ endif()

idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST}
SRC_DIRS ${SRC_DIRS_LIST}
EXCLUDE_SRCS ${EXCLUDE_SRCS_LIST}
EXCLUDE_SRCS ${EXCLUDE_SRCS}
PRIV_REQUIRES ${PRIV_REQUIRES_LIST})

get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
*
* 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 "static-supported-modes-manager.h"
#include <app/util/debug-printing.h>
#include <app/util/ember-print.h>
#include <platform/ESP32/ESP32Config.h>

using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::DeviceLayer::Internal;
using namespace chip::app::Clusters::ModeSelect;
using chip::Protocols::InteractionModel::Status;

using ModeOptionStructType = Structs::ModeOptionStruct::Type;
using SemanticTag = Structs::SemanticTagStruct::Type;
template <typename T>
using List = app::DataModel::List<T>;

const StaticSupportedModesManager StaticSupportedModesManager::instance = StaticSupportedModesManager();

SupportedModesManager::ModeOptionsProvider StaticSupportedModesManager::epModeOptionsProviderList[FIXED_ENDPOINT_COUNT];

void StaticSupportedModesManager::InitEndpointArray()
{
for (int i = 0; i < FIXED_ENDPOINT_COUNT; i++)
{
epModeOptionsProviderList[i] = ModeOptionsProvider();
}
}

SupportedModesManager::ModeOptionsProvider StaticSupportedModesManager::getModeOptionsProvider(EndpointId endpointId) const
{
if (epModeOptionsProviderList[endpointId].begin() != nullptr && epModeOptionsProviderList[endpointId].end() != nullptr)
{
return ModeOptionsProvider(epModeOptionsProviderList[endpointId].begin(), epModeOptionsProviderList[endpointId].end());
}

ModeOptionStructType * modeOptionStructList = nullptr;
SemanticTag * semanticTags = nullptr;

char keyBuf[ESP32Config::kMaxConfigKeyNameLength];
uint32_t supportedModeCount = 0;

VerifyOrReturnValue(ESP32Config::KeyAllocator::SupportedModesCount(keyBuf, sizeof(keyBuf), endpointId) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr));
ESP32Config::Key countKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValue(countKey, supportedModeCount) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr));

modeOptionStructList = new ModeOptionStructType[supportedModeCount];
if (modeOptionStructList == nullptr)
{
return ModeOptionsProvider(nullptr, nullptr);
}

epModeOptionsProviderList[endpointId] = ModeOptionsProvider(modeOptionStructList, modeOptionStructList + supportedModeCount);

for (int index = 0; index < supportedModeCount; index++)
{
Structs::ModeOptionStruct::Type option;
uint32_t supportedModeMode = 0;
uint32_t semanticTagCount = 0;
size_t outLen = 0;

memset(keyBuf, 0, sizeof(char) * ESP32Config::kMaxConfigKeyNameLength);
VerifyOrReturnValue(ESP32Config::KeyAllocator::SupportedModesLabel(keyBuf, sizeof(keyBuf), endpointId, index) ==
CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));
ESP32Config::Key labelKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValueStr(labelKey, nullptr, 0, outLen) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

char * modeLabel = new char[outLen + 1];
if (modeLabel == nullptr)
{
CleanUp(endpointId);
return ModeOptionsProvider(nullptr, nullptr);
}

VerifyOrReturnValue(ESP32Config::ReadConfigValueStr(labelKey, modeLabel, outLen + 1, outLen) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

memset(keyBuf, 0, sizeof(char) * ESP32Config::kMaxConfigKeyNameLength);
VerifyOrReturnValue(ESP32Config::KeyAllocator::SupportedModesValue(keyBuf, sizeof(keyBuf), endpointId, index) ==
CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));
ESP32Config::Key modeKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValue(labelKey, supportedModeMode) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

memset(keyBuf, 0, sizeof(char) * ESP32Config::kMaxConfigKeyNameLength);
VerifyOrReturnValue(ESP32Config::KeyAllocator::SemanticTagsCount(keyBuf, sizeof(keyBuf), endpointId, index) ==
CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));
ESP32Config::Key stCountKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValue(stCountKey, semanticTagCount) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

semanticTags = new SemanticTag[semanticTagCount];
if (semanticTags == nullptr)
{
CleanUp(endpointId);
return ModeOptionsProvider(nullptr, nullptr);
}
for (auto stIndex = 0; stIndex < semanticTagCount; stIndex++)
{

uint32_t semanticTagValue = 0;
uint32_t semanticTagMfgCode = 0;
SemanticTag tag;

memset(keyBuf, 0, sizeof(char) * ESP32Config::kMaxConfigKeyNameLength);
VerifyOrReturnValue(ESP32Config::KeyAllocator::SemanticTagValue(keyBuf, sizeof(keyBuf), endpointId, index, stIndex) ==
CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));
ESP32Config::Key stValueKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValue(stValueKey, semanticTagValue) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

memset(keyBuf, 0, sizeof(char) * ESP32Config::kMaxConfigKeyNameLength);
VerifyOrReturnValue(ESP32Config::KeyAllocator::SemanticTagMfgCode(keyBuf, sizeof(keyBuf), endpointId, index, stIndex) ==
CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));
ESP32Config::Key stMfgCodeKey(ESP32Config::kConfigNamespace_ChipFactory, keyBuf);
VerifyOrReturnValue(ESP32Config::ReadConfigValue(stMfgCodeKey, semanticTagMfgCode) == CHIP_NO_ERROR,
ModeOptionsProvider(nullptr, nullptr), CleanUp(endpointId));

tag.value = static_cast<uint16_t>(semanticTagValue);
tag.mfgCode = static_cast<chip::VendorId>(semanticTagMfgCode);
semanticTags[stIndex] = tag;
}

option.label = chip::CharSpan::fromCharString(modeLabel);
option.mode = static_cast<uint8_t>(supportedModeMode);
option.semanticTags = DataModel::List<const SemanticTag>(semanticTags, semanticTagCount);

modeOptionStructList[index] = option;
}

return ModeOptionsProvider(modeOptionStructList, modeOptionStructList + supportedModeCount);
}

Status StaticSupportedModesManager::getModeOptionByMode(unsigned short endpointId, unsigned char mode,
const ModeOptionStructType ** dataPtr) const
{
auto modeOptionsProvider = this->getModeOptionsProvider(endpointId);
if (modeOptionsProvider.begin() == nullptr)
{
return Status::UnsupportedCluster;
}
auto * begin = modeOptionsProvider.begin();
auto * end = modeOptionsProvider.end();

for (auto * it = begin; it != end; ++it)
{
auto & modeOption = *it;
if (modeOption.mode == mode)
{
*dataPtr = &modeOption;
return Status::Success;
}
}
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "Cannot find the mode %u", mode);
return Status::InvalidCommand;
}

const ModeSelect::SupportedModesManager * ModeSelect::getSupportedModesManager()
{
return &StaticSupportedModesManager::instance;
}

void StaticSupportedModesManager::FreeSupportedModes(EndpointId endpointId) const
{
if (epModeOptionsProviderList[endpointId].begin() != nullptr)
{
auto * begin = epModeOptionsProviderList[endpointId].begin();
auto * end = epModeOptionsProviderList[endpointId].end();
for (auto * it = begin; it != end; ++it)
{
auto & modeOption = *it;
delete[] modeOption.label.data();
delete[] modeOption.semanticTags.data();
}
delete[] begin;
}
epModeOptionsProviderList[endpointId] = ModeOptionsProvider();
}

void StaticSupportedModesManager::CleanUp(EndpointId endpointId) const
{
ChipLogError(Zcl, "Supported mode data is in incorrect format");
FreeSupportedModes(endpointId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
*
* 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-select-server/supported-modes-manager.h>
#include <src/app/util/af.h>

namespace chip {
namespace app {
namespace Clusters {
namespace ModeSelect {

class StaticSupportedModesManager : public chip::app::Clusters::ModeSelect::SupportedModesManager
{
private:
using ModeOptionStructType = Structs::ModeOptionStruct::Type;
using SemanticTag = Structs::SemanticTagStruct::Type;

static ModeOptionsProvider epModeOptionsProviderList[FIXED_ENDPOINT_COUNT];

void InitEndpointArray();

void FreeSupportedModes(EndpointId endpointId) const;

public:
static const StaticSupportedModesManager instance;

SupportedModesManager::ModeOptionsProvider getModeOptionsProvider(EndpointId endpointId) const override;

Protocols::InteractionModel::Status getModeOptionByMode(EndpointId endpointId, uint8_t mode,
const ModeOptionStructType ** dataPtr) const override;

void CleanUp(EndpointId endpointId) const;

StaticSupportedModesManager() { InitEndpointArray(); }

~StaticSupportedModesManager()
{
for (int i = 0; i < FIXED_ENDPOINT_COUNT; i++)
{
FreeSupportedModes(i);
}
}

static inline const StaticSupportedModesManager & getStaticSupportedModesManagerInstance() { return instance; }
};

const SupportedModesManager * getSupportedModesManager();

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

0 comments on commit 7c60f6b

Please sign in to comment.