Skip to content

Commit 1994498

Browse files
du48s03pull[bot]
authored andcommitted
Add Mode Select Cluster (#10752)
1 parent 781d294 commit 1994498

File tree

66 files changed

+4144
-206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4144
-206
lines changed

examples/all-clusters-app/all-clusters-common/all-clusters-app.zap

+136
Original file line numberDiff line numberDiff line change
@@ -9500,6 +9500,142 @@
95009500
}
95019501
]
95029502
},
9503+
{
9504+
"name": "Mode Select",
9505+
"code": 80,
9506+
"mfgCode": null,
9507+
"define": "MODE_SELECT_CLUSTER",
9508+
"side": "client",
9509+
"enabled": 0,
9510+
"commands": [
9511+
{
9512+
"name": "ChangeToMode",
9513+
"code": 0,
9514+
"mfgCode": null,
9515+
"source": "client",
9516+
"incoming": 1,
9517+
"outgoing": 1
9518+
}
9519+
],
9520+
"attributes": [
9521+
{
9522+
"name": "ClusterRevision",
9523+
"code": 65533,
9524+
"mfgCode": null,
9525+
"side": "client",
9526+
"included": 1,
9527+
"storageOption": "RAM",
9528+
"singleton": 0,
9529+
"bounded": 0,
9530+
"defaultValue": "1",
9531+
"reportable": 0,
9532+
"minInterval": 1,
9533+
"maxInterval": 65534,
9534+
"reportableChange": 0
9535+
}
9536+
]
9537+
},
9538+
{
9539+
"name": "Mode Select",
9540+
"code": 80,
9541+
"mfgCode": null,
9542+
"define": "MODE_SELECT_CLUSTER",
9543+
"side": "server",
9544+
"enabled": 1,
9545+
"commands": [],
9546+
"attributes": [
9547+
{
9548+
"name": "CurrentMode",
9549+
"code": 0,
9550+
"mfgCode": null,
9551+
"side": "server",
9552+
"included": 1,
9553+
"storageOption": "RAM",
9554+
"singleton": 0,
9555+
"bounded": 0,
9556+
"defaultValue": "0",
9557+
"reportable": 1,
9558+
"minInterval": 1,
9559+
"maxInterval": 65534,
9560+
"reportableChange": 0
9561+
},
9562+
{
9563+
"name": "SupportedModes",
9564+
"code": 1,
9565+
"mfgCode": null,
9566+
"side": "server",
9567+
"included": 1,
9568+
"storageOption": "External",
9569+
"singleton": 0,
9570+
"bounded": 0,
9571+
"defaultValue": "0",
9572+
"reportable": 0,
9573+
"minInterval": 1,
9574+
"maxInterval": 65534,
9575+
"reportableChange": 0
9576+
},
9577+
{
9578+
"name": "OnMode",
9579+
"code": 2,
9580+
"mfgCode": null,
9581+
"side": "server",
9582+
"included": 1,
9583+
"storageOption": "RAM",
9584+
"singleton": 0,
9585+
"bounded": 0,
9586+
"defaultValue": "0",
9587+
"reportable": 0,
9588+
"minInterval": 1,
9589+
"maxInterval": 65534,
9590+
"reportableChange": 0
9591+
},
9592+
{
9593+
"name": "StartUpMode",
9594+
"code": 3,
9595+
"mfgCode": null,
9596+
"side": "server",
9597+
"included": 1,
9598+
"storageOption": "RAM",
9599+
"singleton": 0,
9600+
"bounded": 0,
9601+
"defaultValue": "0",
9602+
"reportable": 0,
9603+
"minInterval": 1,
9604+
"maxInterval": 65534,
9605+
"reportableChange": 0
9606+
},
9607+
{
9608+
"name": "Description",
9609+
"code": 4,
9610+
"mfgCode": null,
9611+
"side": "server",
9612+
"included": 1,
9613+
"storageOption": "RAM",
9614+
"singleton": 0,
9615+
"bounded": 0,
9616+
"defaultValue": "Coffee",
9617+
"reportable": 0,
9618+
"minInterval": 1,
9619+
"maxInterval": 65534,
9620+
"reportableChange": 0
9621+
},
9622+
{
9623+
"name": "ClusterRevision",
9624+
"code": 65533,
9625+
"mfgCode": null,
9626+
"side": "server",
9627+
"included": 1,
9628+
"storageOption": "RAM",
9629+
"singleton": 0,
9630+
"bounded": 0,
9631+
"defaultValue": "1",
9632+
"reportable": 0,
9633+
"minInterval": 1,
9634+
"maxInterval": 65534,
9635+
"reportableChange": 0
9636+
}
9637+
]
9638+
},
95039639
{
95049640
"name": "Door Lock",
95059641
"code": 257,

examples/all-clusters-app/esp32/main/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(SRC_DIRS_LIST
5353
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/content-launch-server"
5454
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server"
5555
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/media-input-server"
56+
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/mode-select-server"
5657
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/low-power-server"
5758
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/keypad-input-server"
5859
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/media-playback-server"

examples/all-clusters-app/mbed/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ target_sources(${APP_TARGET} PRIVATE
108108
${APP_CLUSTERS}/low-power-server/low-power-server.cpp
109109
${APP_CLUSTERS}/media-input-server/media-input-server.cpp
110110
${APP_CLUSTERS}/media-playback-server/media-playback-server.cpp
111+
${APP_CLUSTERS}/mode-select-server/mode-select-server.cpp
112+
${APP_CLUSTERS}/mode-select-server/static-supported-modes-manager.cpp
111113
${APP_CLUSTERS}/network-commissioning/network-commissioning-ember.cpp
112114
${APP_CLUSTERS}/network-commissioning/network-commissioning.cpp
113115
${APP_CLUSTERS}/on-off-server/on-off-server.cpp

examples/chip-tool/templates/tests.js

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ function getTests()
150150
'TestBasicInformation',
151151
'TestIdentifyCluster',
152152
'TestOperationalCredentialsCluster',
153+
'TestModeSelectCluster',
153154
];
154155

155156
const Subscriptions = [

src/app/chip_data_model.gni

+5
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ template("chip_data_model") {
142142
"${_app_root}/clusters/${cluster}/${cluster}-ember.cpp",
143143
"${_app_root}/clusters/${cluster}/${cluster}.cpp",
144144
]
145+
} else if (cluster == "mode-select-server") {
146+
sources += [
147+
"${_app_root}/clusters/${cluster}/${cluster}.cpp",
148+
"${_app_root}/clusters/${cluster}/static-supported-modes-manager.cpp",
149+
]
145150
} else {
146151
sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ]
147152
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
*
3+
* Copyright (c) 2021 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <app-common/zap-generated/af-structs.h>
19+
#include <app-common/zap-generated/att-storage.h>
20+
#include <app-common/zap-generated/attribute-type.h>
21+
#include <app-common/zap-generated/attributes/Accessors.h>
22+
#include <app-common/zap-generated/cluster-objects.h>
23+
#include <app-common/zap-generated/ids/Attributes.h>
24+
#include <app-common/zap-generated/ids/Clusters.h>
25+
#include <app/AttributeAccessInterface.h>
26+
#include <app/CommandHandler.h>
27+
#include <app/ConcreteCommandPath.h>
28+
#include <app/clusters/mode-select-server/static-supported-modes-manager.h>
29+
#include <app/util/af.h>
30+
#include <app/util/attribute-storage.h>
31+
#include <lib/support/CodeUtils.h>
32+
33+
using namespace std;
34+
using namespace chip;
35+
using namespace chip::app;
36+
using namespace chip::app::Clusters;
37+
38+
namespace {
39+
40+
class ModeSelectAttrAccess : public AttributeAccessInterface
41+
{
42+
public:
43+
ModeSelectAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), ModeSelect::Id) {}
44+
45+
CHIP_ERROR Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
46+
};
47+
48+
ModeSelectAttrAccess gModeSelectAttrAccess;
49+
50+
CHIP_ERROR ModeSelectAttrAccess::Read(const ConcreteAttributePath & aPath, AttributeValueEncoder & aEncoder)
51+
{
52+
VerifyOrDie(aPath.mClusterId == ModeSelect::Id);
53+
54+
const ModeSelect::StaticSupportedModesManager & gSupportedModeManager =
55+
ModeSelect::StaticSupportedModesManager::getStaticSupportedModesManagerInstance();
56+
57+
if (ModeSelect::Attributes::SupportedModes::Id == aPath.mAttributeId)
58+
{
59+
const ModeSelect::StaticSupportedModesManager::IteratorFactory * iteratorFactory =
60+
gSupportedModeManager.getIteratorFactory(aPath.mEndpointId);
61+
if (iteratorFactory == nullptr)
62+
{
63+
aEncoder.Encode(DataModel::List<ModeSelect::Structs::ModeOptionStruct::Type>());
64+
return CHIP_NO_ERROR;
65+
}
66+
CHIP_ERROR err;
67+
err = aEncoder.EncodeList([iteratorFactory](const TagBoundEncoder & encoder) -> CHIP_ERROR {
68+
const auto & end = *(iteratorFactory->end());
69+
for (auto it = *(iteratorFactory->begin()); it != end; ++it)
70+
{
71+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelect: dereferencing it");
72+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelect: it= %p", (void *) it.operator->());
73+
auto & modeOption = *it;
74+
ReturnErrorOnFailure(encoder.Encode(modeOption));
75+
}
76+
return CHIP_NO_ERROR;
77+
});
78+
ReturnErrorOnFailure(err);
79+
}
80+
return CHIP_NO_ERROR;
81+
}
82+
83+
} // anonymous namespace
84+
85+
bool emberAfModeSelectClusterChangeToModeCallback(CommandHandler * commandHandler, const ConcreteCommandPath & commandPath,
86+
const ModeSelect::Commands::ChangeToMode::DecodableType & commandData)
87+
{
88+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelect: Entering emberAfModeSelectClusterChangeToModeCallback");
89+
EndpointId endpointId = commandPath.mEndpointId;
90+
uint8_t newMode = commandData.newMode;
91+
// Check that the newMode matches one of the supported options
92+
const ModeSelect::Structs::ModeOptionStruct::Type * modeOptionPtr;
93+
const ModeSelect::StaticSupportedModesManager & gSupportedModeManager =
94+
ModeSelect::StaticSupportedModesManager::getStaticSupportedModesManagerInstance();
95+
EmberAfStatus checkSupportedModeStatus = gSupportedModeManager.getModeOptionByMode(endpointId, newMode, &modeOptionPtr);
96+
if (EMBER_ZCL_STATUS_SUCCESS != checkSupportedModeStatus)
97+
{
98+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelect: Failed to find the option with mode %" PRIu8, newMode);
99+
emberAfSendImmediateDefaultResponse(checkSupportedModeStatus);
100+
return false;
101+
}
102+
ModeSelect::Attributes::CurrentMode::Set(endpointId, newMode);
103+
// TODO: Implement application logic
104+
105+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "ModeSelect: ChangeToMode successful");
106+
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
107+
return true;
108+
}
109+
110+
void MatterModeSelectPluginServerInitCallback(void)
111+
{
112+
registerAttributeAccessOverride(&gModeSelectAttrAccess);
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//
2+
// Created by Ding, Li-an on 10/21/21.
3+
//
4+
#include <app/clusters/mode-select-server/static-supported-modes-manager.h>
5+
#include <map>
6+
#include <vector>
7+
8+
using namespace std;
9+
using namespace chip;
10+
using namespace chip::app::Clusters;
11+
using namespace chip::app::Clusters::ModeSelect;
12+
13+
using ModeOptionStructType = Structs::ModeOptionStruct::Type;
14+
using storage_value_type = const ModeOptionStructType *;
15+
namespace {
16+
Structs::ModeOptionStruct::Type buildModeOptionStruct(const char * label, uint8_t mode, uint32_t semanticTag)
17+
{
18+
Structs::ModeOptionStruct::Type option;
19+
option.label = CharSpan(label, strlen(label));
20+
option.mode = mode;
21+
option.semanticTag = semanticTag;
22+
return option;
23+
}
24+
} // namespace
25+
26+
const Structs::ModeOptionStruct::Type StaticSupportedModesManager::blackOption = buildModeOptionStruct("Black", 0, 0);
27+
const Structs::ModeOptionStruct::Type StaticSupportedModesManager::cappuccinoOption = buildModeOptionStruct("Cappuccino", 4, 0);
28+
const Structs::ModeOptionStruct::Type StaticSupportedModesManager::espressoOption = buildModeOptionStruct("Espresso", 7, 0);
29+
storage_value_type StaticSupportedModesManager::coffeeOptions[] = { &blackOption, &cappuccinoOption, &espressoOption };
30+
const Span<storage_value_type> StaticSupportedModesManager::coffeeOptionsSpan =
31+
Span<storage_value_type>(StaticSupportedModesManager::coffeeOptions);
32+
const map<EndpointId, Span<storage_value_type>> StaticSupportedModesManager::optionsByEndpoints = {
33+
{ 1, StaticSupportedModesManager::coffeeOptionsSpan }
34+
};
35+
36+
const StaticSupportedModesManager StaticSupportedModesManager::instance = StaticSupportedModesManager();
37+
38+
const StaticSupportedModesManager::IteratorFactory * StaticSupportedModesManager::getIteratorFactory(EndpointId endpointId) const
39+
{
40+
const auto & it = _iteratorFactoriesByEndpoints.find(endpointId);
41+
return (it == _iteratorFactoriesByEndpoints.end()) ? nullptr : &(it->second);
42+
}
43+
44+
EmberAfStatus StaticSupportedModesManager::getModeOptionByMode(unsigned short endpointId, unsigned char mode,
45+
const ModeOptionStructType ** dataPtr) const
46+
{
47+
auto * iteratorFactory = this->getIteratorFactory(endpointId);
48+
if (iteratorFactory == nullptr)
49+
{
50+
return EMBER_ZCL_STATUS_UNSUPPORTED_CLUSTER;
51+
}
52+
const StaticSupportedModesManager::Iterator & begin = *(this->getIteratorFactory(endpointId)->begin());
53+
const StaticSupportedModesManager::Iterator & end = *(this->getIteratorFactory(endpointId)->end());
54+
for (auto it = begin; it != end; ++it)
55+
{
56+
auto & modeOption = *it;
57+
if (modeOption.mode == mode)
58+
{
59+
*dataPtr = &modeOption;
60+
return EMBER_ZCL_STATUS_SUCCESS;
61+
}
62+
}
63+
emberAfPrintln(EMBER_AF_PRINT_DEBUG, "Cannot find the mode %c", mode);
64+
return EMBER_ZCL_STATUS_INVALID_ARGUMENT;
65+
}

0 commit comments

Comments
 (0)