Skip to content

Commit 30812a9

Browse files
committed
Initial copy with a clean history
1 parent 947dc7c commit 30812a9

File tree

11 files changed

+721
-2
lines changed

11 files changed

+721
-2
lines changed

src/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ if (chip_build_tests) {
5555
chip_test_group("tests") {
5656
deps = []
5757
tests = [
58+
"${chip_root}/src/app/codegen-interaction-model/tests",
5859
"${chip_root}/src/app/interaction-model/tests",
5960
"${chip_root}/src/access/tests",
6061
"${chip_root}/src/crypto/tests",

src/app/ConcreteClusterPath.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct ConcreteClusterPath
5252
// to alignment requirements it's "free" in the sense of not needing more
5353
// memory to put it here. But we don't initialize it, because that
5454
// increases codesize for the non-consumers.
55-
bool mExpanded; // NOTE: in between larger members
55+
bool mExpanded = false; // NOTE: in between larger members
5656
ClusterId mClusterId = 0;
5757
};
5858

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import("//build_overrides/chip.gni")
15+
# This source set is TIGHLY coupled with code-generated data models
16+
# as generally implemented by `src/app/util`
17+
#
18+
# Corresponding functions defined in attribute-storace.cpp/attribute-table.cpp must
19+
# be available at link time for this model to use
20+
# Use `model.gni` to get access to:
21+
# model.cpp
22+
# model.h
+267
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
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+
#include <app/codegen-interaction-model/Model.h>
18+
19+
#include <app-common/zap-generated/attribute-type.h>
20+
#include <app/util/attribute-storage.h>
21+
#include <app/util/endpoint-config-api.h>
22+
23+
namespace chip {
24+
namespace app {
25+
namespace CodegenDataModel {
26+
27+
namespace {
28+
29+
/// Checks if the specified ember cluster mask corresponds to a valid
30+
/// server cluster.
31+
bool IsServerMask(EmberAfClusterMask mask)
32+
{
33+
return (mask == 0) || ((mask & CLUSTER_MASK_SERVER) != 0);
34+
}
35+
36+
/// Load the cluster information into the specified destination
37+
void LoadClusterInfo(const ConcreteClusterPath & path, const EmberAfCluster & cluster, InteractionModel::ClusterInfo * info)
38+
{
39+
chip::DataVersion * versionPtr = emberAfDataVersionStorage(path);
40+
if (versionPtr != nullptr)
41+
{
42+
info->dataVersion = *versionPtr;
43+
}
44+
else
45+
{
46+
ChipLogError(AppServer, "Failed to get data version for %d/" ChipLogFormatMEI, static_cast<int>(path.mEndpointId),
47+
ChipLogValueMEI(cluster.clusterId));
48+
info->dataVersion = 0;
49+
}
50+
51+
// TODO: set entry flags:
52+
// info->flags.Set(ClusterQualityFlags::kDiagnosticsData)
53+
}
54+
55+
/// Converts a EmberAfCluster into a ClusterEntry
56+
InteractionModel::ClusterEntry ClusterEntryFrom(EndpointId endpointId, const EmberAfCluster & cluster)
57+
{
58+
InteractionModel::ClusterEntry entry;
59+
60+
entry.path = ConcreteClusterPath(endpointId, cluster.clusterId);
61+
LoadClusterInfo(entry.path, cluster, &entry.info);
62+
63+
return entry;
64+
}
65+
66+
/// Finds the first server cluster entry for the given endpoint data starting at [start_index]
67+
///
68+
/// Returns an invalid entry if no more server clusters are found
69+
InteractionModel::ClusterEntry FirstServerClusterEntry(EndpointId endpointId, const EmberAfEndpointType * endpoint,
70+
uint16_t start_index)
71+
{
72+
for (unsigned i = start_index; i < endpoint->clusterCount; i++)
73+
{
74+
const EmberAfCluster & cluster = endpoint->cluster[i];
75+
if (!IsServerMask(cluster.mask & CLUSTER_MASK_SERVER))
76+
{
77+
continue;
78+
}
79+
80+
return ClusterEntryFrom(endpointId, cluster);
81+
}
82+
83+
return InteractionModel::ClusterEntry::Invalid();
84+
}
85+
86+
/// Load the cluster information into the specified destination
87+
void LoadAttributeInfo(const ConcreteAttributePath & path, const EmberAfAttributeMetadata & attribute,
88+
InteractionModel::AttributeInfo * info)
89+
{
90+
if (attribute.attributeType == ZCL_ARRAY_ATTRIBUTE_TYPE)
91+
{
92+
info->flags.Set(InteractionModel::AttributeQualityFlags::kListAttribute);
93+
}
94+
95+
// TODO: Set additional flags:
96+
// info->flags.Set(InteractionModel::AttributeQualityFlags::kChangesOmitted)
97+
}
98+
99+
InteractionModel::AttributeEntry AttributeEntryFrom(const ConcreteClusterPath & clusterPath,
100+
const EmberAfAttributeMetadata & attribute)
101+
{
102+
InteractionModel::AttributeEntry entry;
103+
104+
entry.path = ConcreteAttributePath(clusterPath.mEndpointId, clusterPath.mClusterId, attribute.attributeId);
105+
LoadAttributeInfo(entry.path, attribute, &entry.info);
106+
107+
return entry;
108+
}
109+
110+
} // namespace
111+
112+
CHIP_ERROR Model::ReadAttribute(const InteractionModel::ReadAttributeRequest & request, InteractionModel::ReadState & state,
113+
AttributeValueEncoder & encoder)
114+
{
115+
// TODO: this needs an implementation
116+
return CHIP_ERROR_NOT_IMPLEMENTED;
117+
}
118+
119+
CHIP_ERROR Model::WriteAttribute(const InteractionModel::WriteAttributeRequest & request, AttributeValueDecoder & decoder)
120+
{
121+
// TODO: this needs an implementation
122+
return CHIP_ERROR_NOT_IMPLEMENTED;
123+
}
124+
125+
CHIP_ERROR Model::Invoke(const InteractionModel::InvokeRequest & request, chip::TLV::TLVReader & input_arguments,
126+
InteractionModel::InvokeReply & reply)
127+
{
128+
// TODO: this needs an implementation
129+
return CHIP_ERROR_NOT_IMPLEMENTED;
130+
}
131+
132+
EndpointId Model::FirstEndpoint()
133+
{
134+
// find the first enabled index
135+
const uint16_t lastEndpointIndex = emberAfEndpointCount();
136+
for (uint16_t endpointIndex = 0; endpointIndex < lastEndpointIndex; endpointIndex++)
137+
{
138+
if (emberAfEndpointIndexIsEnabled(endpointIndex))
139+
{
140+
return emberAfEndpointFromIndex(endpointIndex);
141+
}
142+
}
143+
144+
// No enabled endpoint found. Give up
145+
return kInvalidEndpointId;
146+
}
147+
148+
EndpointId Model::NextEndpoint(EndpointId before)
149+
{
150+
// find the first enabled index
151+
bool beforeFound = false;
152+
153+
const uint16_t lastEndpointIndex = emberAfEndpointCount();
154+
for (uint16_t endpointIndex = 0; endpointIndex < lastEndpointIndex; endpointIndex++)
155+
{
156+
if (!beforeFound)
157+
{
158+
beforeFound = (before == emberAfEndpointFromIndex(endpointIndex));
159+
continue;
160+
}
161+
162+
if (emberAfEndpointIndexIsEnabled(endpointIndex))
163+
{
164+
return emberAfEndpointFromIndex(endpointIndex);
165+
}
166+
}
167+
168+
// No enabled enpoint after "before" was found, give up
169+
return kInvalidEndpointId;
170+
}
171+
172+
InteractionModel::ClusterEntry Model::FirstCluster(EndpointId endpointId)
173+
{
174+
const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId);
175+
VerifyOrReturnValue(endpoint != nullptr, InteractionModel::ClusterEntry::Invalid());
176+
VerifyOrReturnValue(endpoint->clusterCount > 0, InteractionModel::ClusterEntry::Invalid());
177+
VerifyOrReturnValue(endpoint->cluster != nullptr, InteractionModel::ClusterEntry::Invalid());
178+
179+
return FirstServerClusterEntry(endpointId, endpoint, 0);
180+
}
181+
182+
InteractionModel::ClusterEntry Model::NextCluster(const ConcreteClusterPath & before)
183+
{
184+
const EmberAfEndpointType * endpoint = emberAfFindEndpointType(before.mEndpointId);
185+
VerifyOrReturnValue(endpoint != nullptr, InteractionModel::ClusterEntry::Invalid());
186+
VerifyOrReturnValue(endpoint->clusterCount > 0, InteractionModel::ClusterEntry::Invalid());
187+
VerifyOrReturnValue(endpoint->cluster != nullptr, InteractionModel::ClusterEntry::Invalid());
188+
189+
for (uint16_t i = 0; i < endpoint->clusterCount; i++)
190+
{
191+
const EmberAfCluster & cluster = endpoint->cluster[i];
192+
if (IsServerMask(cluster.mask) && (cluster.clusterId == before.mClusterId))
193+
{
194+
return FirstServerClusterEntry(before.mEndpointId, endpoint, i + 1);
195+
}
196+
}
197+
198+
return InteractionModel::ClusterEntry::Invalid();
199+
}
200+
201+
std::optional<InteractionModel::ClusterInfo> Model::GetClusterInfo(const ConcreteClusterPath & path)
202+
{
203+
const EmberAfCluster * cluster = emberAfFindServerCluster(path.mEndpointId, path.mClusterId);
204+
VerifyOrReturnValue(cluster != nullptr, std::nullopt);
205+
206+
InteractionModel::ClusterInfo info;
207+
LoadClusterInfo(path, *cluster, &info);
208+
209+
return std::make_optional(info);
210+
}
211+
212+
InteractionModel::AttributeEntry Model::FirstAttribute(const ConcreteClusterPath & path)
213+
{
214+
const EmberAfCluster * cluster = emberAfFindServerCluster(path.mEndpointId, path.mClusterId);
215+
VerifyOrReturnValue(cluster != nullptr, InteractionModel::AttributeEntry::Invalid());
216+
VerifyOrReturnValue(cluster->attributeCount > 0, InteractionModel::AttributeEntry::Invalid());
217+
VerifyOrReturnValue(cluster->attributes != nullptr, InteractionModel::AttributeEntry::Invalid());
218+
219+
return AttributeEntryFrom(path, cluster->attributes[0]);
220+
}
221+
222+
InteractionModel::AttributeEntry Model::NextAttribute(const ConcreteAttributePath & before)
223+
{
224+
const EmberAfCluster * cluster = emberAfFindServerCluster(before.mEndpointId, before.mClusterId);
225+
VerifyOrReturnValue(cluster != nullptr, InteractionModel::AttributeEntry::Invalid());
226+
VerifyOrReturnValue(cluster->attributeCount > 0, InteractionModel::AttributeEntry::Invalid());
227+
VerifyOrReturnValue(cluster->attributes != nullptr, InteractionModel::AttributeEntry::Invalid());
228+
229+
// find the given attribute in the list and then return the next one
230+
bool foundPosition = false;
231+
const unsigned attributeCount = cluster->attributeCount;
232+
for (unsigned i = 0; i < attributeCount; i++)
233+
{
234+
if (foundPosition)
235+
{
236+
return AttributeEntryFrom(before, cluster->attributes[i]);
237+
}
238+
239+
foundPosition = (cluster->attributes[i].attributeId == before.mAttributeId);
240+
}
241+
242+
return InteractionModel::AttributeEntry::Invalid();
243+
}
244+
245+
std::optional<InteractionModel::AttributeInfo> Model::GetAttributeInfo(const ConcreteAttributePath & path)
246+
{
247+
const EmberAfCluster * cluster = emberAfFindServerCluster(path.mEndpointId, path.mClusterId);
248+
VerifyOrReturnValue(cluster != nullptr, std::nullopt);
249+
VerifyOrReturnValue(cluster->attributeCount > 0, std::nullopt);
250+
VerifyOrReturnValue(cluster->attributes != nullptr, std::nullopt);
251+
const unsigned attributeCount = cluster->attributeCount;
252+
for (unsigned i = 0; i < attributeCount; i++)
253+
{
254+
if (cluster->attributes[i].attributeId == path.mAttributeId)
255+
{
256+
InteractionModel::AttributeInfo info;
257+
LoadAttributeInfo(path, cluster->attributes[i], &info);
258+
return std::make_optional(info);
259+
}
260+
}
261+
262+
return std::nullopt;
263+
}
264+
265+
} // namespace CodegenDataModel
266+
} // namespace app
267+
} // namespace chip
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
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+
#pragma once
18+
19+
#include <app/interaction-model/Model.h>
20+
21+
namespace chip {
22+
namespace app {
23+
namespace CodegenDataModel {
24+
25+
class Model : public chip::app::InteractionModel::Model
26+
{
27+
public:
28+
/// Generic model implementations
29+
CHIP_ERROR Shutdown() override { return CHIP_NO_ERROR; }
30+
31+
CHIP_ERROR ReadAttribute(const InteractionModel::ReadAttributeRequest & request, InteractionModel::ReadState & state,
32+
AttributeValueEncoder & encoder) override;
33+
CHIP_ERROR WriteAttribute(const InteractionModel::WriteAttributeRequest & request, AttributeValueDecoder & decoder) override;
34+
CHIP_ERROR Invoke(const InteractionModel::InvokeRequest & request, chip::TLV::TLVReader & input_arguments,
35+
InteractionModel::InvokeReply & reply) override;
36+
37+
/// attribute tree iteration
38+
EndpointId FirstEndpoint() override;
39+
EndpointId NextEndpoint(EndpointId before) override;
40+
41+
InteractionModel::ClusterEntry FirstCluster(EndpointId endpoint) override;
42+
InteractionModel::ClusterEntry NextCluster(const ConcreteClusterPath & before) override;
43+
std::optional<InteractionModel::ClusterInfo> GetClusterInfo(const ConcreteClusterPath & path) override;
44+
45+
InteractionModel::AttributeEntry FirstAttribute(const ConcreteClusterPath & cluster) override;
46+
InteractionModel::AttributeEntry NextAttribute(const ConcreteAttributePath & before) override;
47+
std::optional<InteractionModel::AttributeInfo> GetAttributeInfo(const ConcreteAttributePath & path) override;
48+
};
49+
50+
} // namespace CodegenDataModel
51+
} // namespace app
52+
} // namespace chip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import("//build_overrides/chip.gni")
15+
16+
# The sources in this directory are TIGHLY coupled with code-generated data models
17+
# as generally implemented by `src/app/util`
18+
#
19+
# Corresponding functions defined in attribute-storace.cpp/attribute-table.cpp must
20+
# be available at link time for this model to use and constants heavily depend
21+
# on `zap-generated/endpoint_config.h` (generally compile-time constants that
22+
# are code generated)
23+
#
24+
# As a result, the files here are NOT a source_set or similar because they cannot
25+
# be cleanly built as a stand-alone and instead have to be imported as part of
26+
# a different data model or compilation unit.
27+
codegen_interaction_model_SOURCES = [
28+
"${chip_root}/src/app/codegen-interaction-model/Model.h",
29+
"${chip_root}/src/app/codegen-interaction-model/Model.cpp",
30+
]
31+
32+
codegen_interaction_model_PUBLIC_DEPS = [
33+
"${chip_root}/src/app/common:attribute-type",
34+
"${chip_root}/src/app/interaction-model",
35+
]

0 commit comments

Comments
 (0)