Line data Source code
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 <data-model-providers/codegen/CodegenDataModelProvider.h>
18 :
19 : #include <access/AccessControl.h>
20 : #include <access/Privilege.h>
21 : #include <app-common/zap-generated/attribute-type.h>
22 : #include <app/CommandHandlerInterface.h>
23 : #include <app/CommandHandlerInterfaceRegistry.h>
24 : #include <app/ConcreteAttributePath.h>
25 : #include <app/ConcreteClusterPath.h>
26 : #include <app/ConcreteCommandPath.h>
27 : #include <app/EventPathParams.h>
28 : #include <app/GlobalAttributes.h>
29 : #include <app/RequiredPrivilege.h>
30 : #include <app/data-model-provider/MetadataList.h>
31 : #include <app/data-model-provider/MetadataTypes.h>
32 : #include <app/data-model-provider/Provider.h>
33 : #include <app/util/DataModelHandler.h>
34 : #include <app/util/IMClusterCommandHandler.h>
35 : #include <app/util/af-types.h>
36 : #include <app/util/attribute-metadata.h>
37 : #include <app/util/attribute-storage.h>
38 : #include <app/util/endpoint-config-api.h>
39 : #include <app/util/persistence/AttributePersistenceProvider.h>
40 : #include <app/util/persistence/DefaultAttributePersistenceProvider.h>
41 : #include <data-model-providers/codegen/EmberMetadata.h>
42 : #include <lib/core/CHIPError.h>
43 : #include <lib/core/DataModelTypes.h>
44 : #include <lib/support/CodeUtils.h>
45 : #include <lib/support/SpanSearchValue.h>
46 :
47 : #include <cstdint>
48 : #include <optional>
49 :
50 : namespace chip {
51 : namespace app {
52 : namespace {
53 :
54 79 : DataModel::AcceptedCommandEntry AcceptedCommandEntryFor(const ConcreteCommandPath & path)
55 : {
56 79 : const CommandId commandId = path.mCommandId;
57 :
58 79 : DataModel::AcceptedCommandEntry entry;
59 :
60 79 : entry.commandId = path.mCommandId;
61 79 : entry.invokePrivilege = RequiredPrivilege::ForInvokeCommand(path);
62 79 : entry.flags.Set(DataModel::CommandQualityFlags::kTimed, CommandNeedsTimedInvoke(path.mClusterId, commandId));
63 79 : entry.flags.Set(DataModel::CommandQualityFlags::kFabricScoped, CommandIsFabricScoped(path.mClusterId, commandId));
64 79 : entry.flags.Set(DataModel::CommandQualityFlags::kLargeMessage, CommandHasLargePayload(path.mClusterId, commandId));
65 :
66 79 : return entry;
67 : }
68 :
69 11438 : DataModel::ServerClusterEntry ServerClusterEntryFrom(EndpointId endpointId, const EmberAfCluster & cluster)
70 : {
71 11438 : DataModel::ServerClusterEntry entry;
72 :
73 11438 : entry.clusterId = cluster.clusterId;
74 :
75 11438 : DataVersion * versionPtr = emberAfDataVersionStorage(ConcreteClusterPath(endpointId, cluster.clusterId));
76 11438 : if (versionPtr == nullptr)
77 : {
78 : #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
79 0 : ChipLogError(AppServer, "Failed to get data version for %d/" ChipLogFormatMEI, endpointId,
80 : ChipLogValueMEI(cluster.clusterId));
81 : #endif
82 0 : entry.dataVersion = 0;
83 : }
84 : else
85 : {
86 11438 : entry.dataVersion = *versionPtr;
87 : }
88 :
89 : // TODO: set entry flags:
90 : // entry.flags.Set(ClusterQualityFlags::kDiagnosticsData)
91 :
92 11438 : return entry;
93 : }
94 :
95 56265 : DataModel::AttributeEntry AttributeEntryFrom(const ConcreteClusterPath & clusterPath, const EmberAfAttributeMetadata & attribute)
96 : {
97 56265 : DataModel::AttributeEntry entry;
98 :
99 56265 : const ConcreteAttributePath attributePath(clusterPath.mEndpointId, clusterPath.mClusterId, attribute.attributeId);
100 :
101 56265 : entry.attributeId = attribute.attributeId;
102 56265 : entry.readPrivilege = RequiredPrivilege::ForReadAttribute(attributePath);
103 56265 : if (!attribute.IsReadOnly())
104 : {
105 31147 : entry.writePrivilege = RequiredPrivilege::ForWriteAttribute(attributePath);
106 : }
107 :
108 56265 : entry.flags.Set(DataModel::AttributeQualityFlags::kListAttribute, (attribute.attributeType == ZCL_ARRAY_ATTRIBUTE_TYPE));
109 56265 : entry.flags.Set(DataModel::AttributeQualityFlags::kTimed, attribute.MustUseTimedWrite());
110 :
111 : // NOTE: we do NOT provide additional info for:
112 : // - IsExternal/IsSingleton/IsAutomaticallyPersisted is not used by IM handling
113 : // - IsSingleton spec defines it for CLUSTERS where as we have it for ATTRIBUTES
114 : // - Several specification flags are not available (reportable, quieter reporting,
115 : // fixed, source attribution)
116 :
117 : // TODO: Set additional flags:
118 : // entry.flags.Set(DataModel::AttributeQualityFlags::kFabricScoped)
119 : // entry.flags.Set(DataModel::AttributeQualityFlags::kFabricSensitive)
120 : // entry.flags.Set(DataModel::AttributeQualityFlags::kChangesOmitted)
121 56265 : return entry;
122 : }
123 :
124 : const ConcreteCommandPath kInvalidCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId);
125 :
126 : DefaultAttributePersistenceProvider gDefaultAttributePersistence;
127 :
128 : } // namespace
129 :
130 387 : CHIP_ERROR CodegenDataModelProvider::Startup(DataModel::InteractionModelContext context)
131 : {
132 387 : ReturnErrorOnFailure(DataModel::Provider::Startup(context));
133 :
134 : // Ember NVM requires have a data model provider. attempt to create one if one is not available
135 : //
136 : // It is not a critical failure to not have one, however if one is not set up, ember NVM operations
137 : // will error out with a `persistence not available`.
138 387 : if (GetAttributePersistenceProvider() == nullptr)
139 : {
140 : #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
141 387 : ChipLogProgress(DataManagement, "Ember attribute persistence requires setting up");
142 : #endif
143 387 : if (mPersistentStorageDelegate != nullptr)
144 : {
145 1 : ReturnErrorOnFailure(gDefaultAttributePersistence.Init(mPersistentStorageDelegate));
146 1 : SetAttributePersistenceProvider(&gDefaultAttributePersistence);
147 : #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
148 : }
149 : else
150 : {
151 386 : ChipLogError(DataManagement, "No storage delegate available, will not set up attribute persistence.");
152 : #endif
153 : }
154 : }
155 :
156 387 : InitDataModelForTesting();
157 :
158 387 : return CHIP_NO_ERROR;
159 : }
160 :
161 5 : std::optional<DataModel::ActionReturnStatus> CodegenDataModelProvider::Invoke(const DataModel::InvokeRequest & request,
162 : TLV::TLVReader & input_arguments,
163 : CommandHandler * handler)
164 : {
165 : CommandHandlerInterface * handler_interface =
166 5 : CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(request.path.mEndpointId, request.path.mClusterId);
167 :
168 5 : if (handler_interface)
169 : {
170 3 : CommandHandlerInterface::HandlerContext context(*handler, request.path, input_arguments);
171 3 : handler_interface->InvokeCommand(context);
172 :
173 : // If the command was handled, don't proceed any further and return successfully.
174 3 : if (context.mCommandHandled)
175 : {
176 3 : return std::nullopt;
177 : }
178 : }
179 :
180 : // Ember always sets the return in the handler
181 2 : DispatchSingleClusterCommand(request.path, input_arguments, handler);
182 2 : return std::nullopt;
183 : }
184 :
185 2924 : CHIP_ERROR CodegenDataModelProvider::Endpoints(DataModel::ListBuilder<DataModel::EndpointEntry> & builder)
186 : {
187 2924 : const uint16_t endpointCount = emberAfEndpointCount();
188 :
189 2924 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(endpointCount));
190 :
191 17113 : for (uint16_t endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++)
192 : {
193 14189 : if (!emberAfEndpointIndexIsEnabled(endpointIndex))
194 : {
195 4333 : continue;
196 : }
197 :
198 : DataModel::EndpointEntry entry;
199 9856 : entry.id = emberAfEndpointFromIndex(endpointIndex);
200 9856 : entry.parentId = emberAfParentEndpointFromIndex(endpointIndex);
201 :
202 9856 : switch (GetCompositionForEndpointIndex(endpointIndex))
203 : {
204 8376 : case EndpointComposition::kFullFamily:
205 8376 : entry.compositionPattern = DataModel::EndpointCompositionPattern::kFullFamily;
206 8376 : break;
207 1480 : case EndpointComposition::kTree:
208 : case EndpointComposition::kInvalid: // should NOT happen, but force compiler to check we validate all versions
209 1480 : entry.compositionPattern = DataModel::EndpointCompositionPattern::kTree;
210 1480 : break;
211 : }
212 9856 : ReturnErrorOnFailure(builder.Append(entry));
213 : }
214 :
215 2924 : return CHIP_NO_ERROR;
216 : }
217 :
218 3 : std::optional<unsigned> CodegenDataModelProvider::TryFindEndpointIndex(EndpointId id) const
219 : {
220 3 : const uint16_t lastEndpointIndex = emberAfEndpointCount();
221 :
222 6 : if ((mEndpointIterationHint < lastEndpointIndex) && emberAfEndpointIndexIsEnabled(mEndpointIterationHint) &&
223 3 : (id == emberAfEndpointFromIndex(mEndpointIterationHint)))
224 : {
225 1 : return std::make_optional(mEndpointIterationHint);
226 : }
227 :
228 : // Linear search, this may be slow
229 2 : uint16_t idx = emberAfIndexFromEndpoint(id);
230 2 : if (idx == kEmberInvalidEndpointIndex)
231 : {
232 0 : return std::nullopt;
233 : }
234 :
235 2 : return std::make_optional<unsigned>(idx);
236 : }
237 :
238 8442 : CHIP_ERROR CodegenDataModelProvider::ServerClusters(EndpointId endpointId,
239 : DataModel::ListBuilder<DataModel::ServerClusterEntry> & builder)
240 : {
241 8442 : const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId);
242 :
243 8442 : VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND);
244 8431 : VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR);
245 8431 : VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR);
246 :
247 8431 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ true)));
248 :
249 8431 : const EmberAfCluster * begin = endpoint->cluster;
250 8431 : const EmberAfCluster * end = endpoint->cluster + endpoint->clusterCount;
251 21264 : for (const EmberAfCluster * cluster = begin; cluster != end; cluster++)
252 : {
253 12833 : if (!cluster->IsServer())
254 : {
255 1395 : continue;
256 : }
257 11438 : ReturnErrorOnFailure(builder.Append(ServerClusterEntryFrom(endpointId, *cluster)));
258 : }
259 :
260 8431 : return CHIP_NO_ERROR;
261 : }
262 :
263 13356 : CHIP_ERROR CodegenDataModelProvider::Attributes(const ConcreteClusterPath & path,
264 : DataModel::ListBuilder<DataModel::AttributeEntry> & builder)
265 : {
266 13356 : const EmberAfCluster * cluster = FindServerCluster(path);
267 :
268 13356 : VerifyOrReturnValue(cluster != nullptr, CHIP_ERROR_NOT_FOUND);
269 12655 : VerifyOrReturnValue(cluster->attributeCount > 0, CHIP_NO_ERROR);
270 12655 : VerifyOrReturnValue(cluster->attributes != nullptr, CHIP_NO_ERROR);
271 :
272 : // TODO: if ember would encode data in AttributeEntry form, we could reference things directly (shorter code,
273 : // although still allocation overhead due to global attributes not in metadata)
274 : //
275 : // We have Attributes from ember + global attributes that are NOT in ember metadata.
276 : // We have to report them all
277 12655 : constexpr size_t kGlobalAttributeNotInMetadataCount = MATTER_ARRAY_SIZE(GlobalAttributesNotInMetadata);
278 :
279 12655 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(cluster->attributeCount + kGlobalAttributeNotInMetadataCount));
280 :
281 12655 : Span<const EmberAfAttributeMetadata> attributeSpan(cluster->attributes, cluster->attributeCount);
282 :
283 68920 : for (auto & attribute : attributeSpan)
284 : {
285 56265 : ReturnErrorOnFailure(builder.Append(AttributeEntryFrom(path, attribute)));
286 : }
287 :
288 : // This "GlobalListEntry" is specific for metadata that ember does not include
289 : // in its attribute list metadata.
290 : //
291 : // By spec these Attribute/AcceptedCommands/GeneratedCommants lists are:
292 : // - lists of elements
293 : // - read-only, with read privilege view
294 : // - fixed value (no such flag exists, so this is not a quality flag we set/track)
295 12655 : DataModel::AttributeEntry globalListEntry;
296 :
297 12655 : globalListEntry.readPrivilege = Access::Privilege::kView;
298 12655 : globalListEntry.flags.Set(DataModel::AttributeQualityFlags::kListAttribute);
299 :
300 50620 : for (auto & attribute : GlobalAttributesNotInMetadata)
301 : {
302 37965 : globalListEntry.attributeId = attribute;
303 37965 : ReturnErrorOnFailure(builder.Append(globalListEntry));
304 : }
305 :
306 12655 : return CHIP_NO_ERROR;
307 : }
308 :
309 4 : CHIP_ERROR CodegenDataModelProvider::ClientClusters(EndpointId endpointId, DataModel::ListBuilder<ClusterId> & builder)
310 : {
311 4 : const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId);
312 :
313 4 : VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND);
314 2 : VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR);
315 2 : VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR);
316 :
317 2 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ false)));
318 :
319 2 : const EmberAfCluster * begin = endpoint->cluster;
320 2 : const EmberAfCluster * end = endpoint->cluster + endpoint->clusterCount;
321 10 : for (const EmberAfCluster * cluster = begin; cluster != end; cluster++)
322 : {
323 8 : if (!cluster->IsClient())
324 : {
325 4 : continue;
326 : }
327 4 : ReturnErrorOnFailure(builder.Append(cluster->clusterId));
328 : }
329 :
330 2 : return CHIP_NO_ERROR;
331 : }
332 :
333 14161 : const EmberAfCluster * CodegenDataModelProvider::FindServerCluster(const ConcreteClusterPath & path)
334 : {
335 27278 : if (mPreviouslyFoundCluster.has_value() && (mPreviouslyFoundCluster->path == path) &&
336 13117 : (mEmberMetadataStructureGeneration == emberAfMetadataStructureGeneration()))
337 :
338 : {
339 13008 : return mPreviouslyFoundCluster->cluster;
340 : }
341 :
342 1153 : const EmberAfCluster * cluster = emberAfFindServerCluster(path.mEndpointId, path.mClusterId);
343 1153 : if (cluster != nullptr)
344 : {
345 439 : mPreviouslyFoundCluster = std::make_optional<ClusterReference>(path, cluster);
346 439 : mEmberMetadataStructureGeneration = emberAfMetadataStructureGeneration();
347 : }
348 1153 : return cluster;
349 : }
350 :
351 428 : CHIP_ERROR CodegenDataModelProvider::AcceptedCommands(const ConcreteClusterPath & path,
352 : DataModel::ListBuilder<DataModel::AcceptedCommandEntry> & builder)
353 : {
354 : // Some CommandHandlerInterface instances are registered of ALL endpoints, so make sure first that
355 : // the cluster actually exists on this endpoint before asking the CommandHandlerInterface what commands
356 : // it claims to support.
357 428 : const EmberAfCluster * serverCluster = FindServerCluster(path);
358 428 : VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND);
359 :
360 : CommandHandlerInterface * interface =
361 421 : CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
362 421 : if (interface != nullptr)
363 : {
364 16 : size_t commandCount = 0;
365 :
366 16 : CHIP_ERROR err = interface->EnumerateAcceptedCommands(
367 : path,
368 6 : [](CommandId id, void * context) -> Loop {
369 6 : *reinterpret_cast<size_t *>(context) += 1;
370 6 : return Loop::Continue;
371 : },
372 : reinterpret_cast<void *>(&commandCount));
373 :
374 16 : if (err == CHIP_NO_ERROR)
375 : {
376 : using EnumerationData = struct
377 : {
378 : ConcreteCommandPath commandPath;
379 : DataModel::ListBuilder<DataModel::AcceptedCommandEntry> * acceptedCommandList;
380 : CHIP_ERROR processingError;
381 : };
382 :
383 8 : EnumerationData enumerationData;
384 8 : enumerationData.commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId);
385 8 : enumerationData.processingError = CHIP_NO_ERROR;
386 8 : enumerationData.acceptedCommandList = &builder;
387 :
388 8 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount));
389 :
390 14 : ReturnErrorOnFailure(interface->EnumerateAcceptedCommands(
391 : path,
392 : [](CommandId commandId, void * context) -> Loop {
393 : auto input = reinterpret_cast<EnumerationData *>(context);
394 : input->commandPath.mCommandId = commandId;
395 : CHIP_ERROR appendError = input->acceptedCommandList->Append(AcceptedCommandEntryFor(input->commandPath));
396 : if (appendError != CHIP_NO_ERROR)
397 : {
398 : input->processingError = appendError;
399 : return Loop::Break;
400 : }
401 : return Loop::Continue;
402 : },
403 : reinterpret_cast<void *>(&enumerationData)));
404 8 : ReturnErrorOnFailure(enumerationData.processingError);
405 :
406 : // the two invocations MUST return the same sizes.
407 8 : VerifyOrReturnError(builder.Size() == commandCount, CHIP_ERROR_INTERNAL);
408 8 : return CHIP_NO_ERROR;
409 : }
410 8 : VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err);
411 : }
412 :
413 413 : VerifyOrReturnError(serverCluster->acceptedCommandList != nullptr, CHIP_NO_ERROR);
414 :
415 28 : const chip::CommandId * endOfList = serverCluster->acceptedCommandList;
416 101 : while (*endOfList != kInvalidCommandId)
417 : {
418 73 : endOfList++;
419 : }
420 28 : const auto commandCount = static_cast<size_t>(endOfList - serverCluster->acceptedCommandList);
421 :
422 : // TODO: if ember would store command entries, we could simplify this code to use static data
423 28 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount));
424 :
425 28 : ConcreteCommandPath commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId);
426 101 : for (const chip::CommandId * p = serverCluster->acceptedCommandList; p != endOfList; p++)
427 : {
428 73 : commandPath.mCommandId = *p;
429 73 : ReturnErrorOnFailure(builder.Append(AcceptedCommandEntryFor(commandPath)));
430 : }
431 :
432 28 : return CHIP_NO_ERROR;
433 : }
434 :
435 377 : CHIP_ERROR CodegenDataModelProvider::GeneratedCommands(const ConcreteClusterPath & path,
436 : DataModel::ListBuilder<CommandId> & builder)
437 : {
438 : // Some CommandHandlerInterface instances are registered of ALL endpoints, so make sure first that
439 : // the cluster actually exists on this endpoint before asking the CommandHandlerInterface what commands
440 : // it claims to support.
441 377 : const EmberAfCluster * serverCluster = FindServerCluster(path);
442 377 : VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND);
443 :
444 : CommandHandlerInterface * interface =
445 371 : CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
446 371 : if (interface != nullptr)
447 : {
448 4 : size_t commandCount = 0;
449 :
450 4 : CHIP_ERROR err = interface->EnumerateGeneratedCommands(
451 : path,
452 1 : [](CommandId id, void * context) -> Loop {
453 1 : *reinterpret_cast<size_t *>(context) += 1;
454 1 : return Loop::Continue;
455 : },
456 : reinterpret_cast<void *>(&commandCount));
457 :
458 4 : if (err == CHIP_NO_ERROR)
459 : {
460 2 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount));
461 :
462 : using EnumerationData = struct
463 : {
464 : DataModel::ListBuilder<CommandId> * generatedCommandList;
465 : CHIP_ERROR processingError;
466 : };
467 : EnumerationData enumerationData;
468 2 : enumerationData.processingError = CHIP_NO_ERROR;
469 2 : enumerationData.generatedCommandList = &builder;
470 :
471 3 : ReturnErrorOnFailure(interface->EnumerateGeneratedCommands(
472 : path,
473 : [](CommandId id, void * context) -> Loop {
474 : auto input = reinterpret_cast<EnumerationData *>(context);
475 :
476 : CHIP_ERROR appendError = input->generatedCommandList->Append(id);
477 : if (appendError != CHIP_NO_ERROR)
478 : {
479 : input->processingError = appendError;
480 : return Loop::Break;
481 : }
482 : return Loop::Continue;
483 : },
484 : reinterpret_cast<void *>(&enumerationData)));
485 2 : ReturnErrorOnFailure(enumerationData.processingError);
486 :
487 : // the two invocations MUST return the same sizes.
488 2 : VerifyOrReturnError(builder.Size() == commandCount, CHIP_ERROR_INTERNAL);
489 2 : return CHIP_NO_ERROR;
490 : }
491 2 : VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err);
492 : }
493 :
494 369 : VerifyOrReturnError(serverCluster->generatedCommandList != nullptr, CHIP_NO_ERROR);
495 :
496 2 : const chip::CommandId * endOfList = serverCluster->generatedCommandList;
497 6 : while (*endOfList != kInvalidCommandId)
498 : {
499 4 : endOfList++;
500 : }
501 2 : const auto commandCount = static_cast<size_t>(endOfList - serverCluster->generatedCommandList);
502 2 : return builder.ReferenceExisting({ serverCluster->generatedCommandList, commandCount });
503 : }
504 :
505 380 : void CodegenDataModelProvider::InitDataModelForTesting()
506 : {
507 : // Call the Ember-specific InitDataModelHandler
508 380 : InitDataModelHandler();
509 380 : }
510 :
511 3 : CHIP_ERROR CodegenDataModelProvider::DeviceTypes(EndpointId endpointId,
512 : DataModel::ListBuilder<DataModel::DeviceTypeEntry> & builder)
513 : {
514 3 : std::optional<unsigned> endpoint_index = TryFindEndpointIndex(endpointId);
515 3 : if (!endpoint_index.has_value())
516 : {
517 0 : return {};
518 : }
519 :
520 3 : CHIP_ERROR err = CHIP_NO_ERROR;
521 :
522 3 : builder.ReferenceExisting(emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err));
523 3 : return CHIP_NO_ERROR;
524 : }
525 :
526 2 : CHIP_ERROR CodegenDataModelProvider::SemanticTags(EndpointId endpointId, DataModel::ListBuilder<SemanticTag> & builder)
527 : {
528 2 : DataModel::Provider::SemanticTag semanticTag;
529 2 : size_t count = 0;
530 :
531 5 : while (GetSemanticTagForEndpointAtIndex(endpointId, count, semanticTag) == CHIP_NO_ERROR)
532 : {
533 3 : count++;
534 : }
535 :
536 2 : ReturnErrorOnFailure(builder.EnsureAppendCapacity(count));
537 :
538 5 : for (size_t idx = 0; idx < count; idx++)
539 : {
540 3 : ReturnErrorOnFailure(GetSemanticTagForEndpointAtIndex(endpointId, idx, semanticTag));
541 3 : ReturnErrorOnFailure(builder.Append(semanticTag));
542 : }
543 :
544 2 : return CHIP_NO_ERROR;
545 : }
546 :
547 : } // namespace app
548 : } // namespace chip
|