Line data Source code
1 : /*
2 : * Copyright (c) 2025 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 "SpanEndpoint.h"
18 :
19 : #include <app/ConcreteClusterPath.h>
20 : #include <app/server-cluster/ServerClusterContext.h>
21 : #include <clusters/Descriptor/ClusterId.h>
22 : #include <lib/core/CHIPError.h>
23 : #include <lib/support/Span.h>
24 : #include <lib/support/logging/CHIPLogging.h>
25 :
26 : namespace chip {
27 : namespace app {
28 :
29 : // Builder implementation
30 129 : SpanEndpoint::Builder::Builder(EndpointId id) : mEndpointId(id) {}
31 :
32 115 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetComposition(DataModel::EndpointCompositionPattern composition)
33 : {
34 115 : mComposition = composition;
35 115 : return *this;
36 : }
37 :
38 3 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetParentId(EndpointId parentId)
39 : {
40 3 : mParentId = parentId;
41 3 : return *this;
42 : }
43 :
44 127 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetServerClusters(Span<ServerClusterInterface *> serverClusters)
45 : {
46 127 : mServerClusters = serverClusters;
47 127 : return *this;
48 : }
49 :
50 3 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetClientClusters(Span<const ClusterId> clientClusters)
51 : {
52 3 : mClientClusters = clientClusters;
53 3 : return *this;
54 : }
55 :
56 3 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetSemanticTags(Span<const SemanticTag> semanticTags)
57 : {
58 3 : mSemanticTags = semanticTags;
59 3 : return *this;
60 : }
61 :
62 3 : SpanEndpoint::Builder & SpanEndpoint::Builder::SetDeviceTypes(Span<const DataModel::DeviceTypeEntry> deviceTypes)
63 : {
64 3 : mDeviceTypes = deviceTypes;
65 3 : return *this;
66 : }
67 :
68 129 : std::variant<SpanEndpoint, CHIP_ERROR> SpanEndpoint::Builder::Build()
69 : {
70 129 : if (mEndpointId == kInvalidEndpointId || mServerClusters.empty())
71 : {
72 3 : return CHIP_ERROR_INVALID_ARGUMENT;
73 : }
74 :
75 : // Check that cluster list is not invalid and that it contains the Descriptor cluster
76 126 : bool foundDescriptor = false;
77 260 : for (auto * cluster : mServerClusters)
78 : {
79 136 : if (cluster == nullptr || cluster->GetPaths().empty())
80 : {
81 2 : ChipLogError(DataManagement, "Builder: Attempted to build with an invalid server cluster entry.");
82 2 : return CHIP_ERROR_INVALID_ARGUMENT;
83 : }
84 :
85 : // A given ServerClusterInterface can serve multiple endpoints. We only care about the
86 : // path that matches the endpoint we are building.
87 134 : if (cluster->PathsContains({ mEndpointId, Clusters::Descriptor::Id }))
88 : {
89 125 : foundDescriptor = true;
90 : }
91 : }
92 :
93 124 : if (!foundDescriptor)
94 : {
95 1 : ChipLogError(DataManagement, "Builder: Descriptor cluster is mandatory and was not found.");
96 1 : return CHIP_ERROR_INVALID_ARGUMENT;
97 : }
98 :
99 123 : return SpanEndpoint(mEndpointId, mComposition, mParentId, mServerClusters, mClientClusters, mSemanticTags, mDeviceTypes);
100 : }
101 :
102 : CHIP_ERROR
103 3 : SpanEndpoint::SemanticTags(ReadOnlyBufferBuilder<Clusters::Descriptor::Structs::SemanticTagStruct::Type> & out) const
104 : {
105 3 : return out.ReferenceExisting(mSemanticTags);
106 : }
107 :
108 3 : CHIP_ERROR SpanEndpoint::DeviceTypes(ReadOnlyBufferBuilder<DataModel::DeviceTypeEntry> & out) const
109 : {
110 3 : return out.ReferenceExisting(mDeviceTypes);
111 : }
112 :
113 3 : CHIP_ERROR SpanEndpoint::ClientClusters(ReadOnlyBufferBuilder<ClusterId> & out) const
114 : {
115 3 : return out.ReferenceExisting(mClientClusters);
116 : }
117 :
118 8 : ServerClusterInterface * SpanEndpoint::GetServerCluster(ClusterId clusterId) const
119 : {
120 17 : for (auto * serverCluster : mServerClusters)
121 : {
122 : // Don't check for serverCluster != nullptr or empty paths, as these are validated in Builder::Build().
123 : // A given ServerClusterInterface can serve multiple endpoints. We need to find the one
124 : // that handles the given clusterId on this specific endpoint.
125 15 : if (serverCluster->PathsContains({ mEndpointEntry.id, clusterId }))
126 : {
127 6 : return serverCluster;
128 : }
129 : }
130 2 : return nullptr;
131 : }
132 :
133 3 : CHIP_ERROR SpanEndpoint::ServerClusters(ReadOnlyBufferBuilder<ServerClusterInterface *> & out) const
134 : {
135 3 : return out.ReferenceExisting(mServerClusters);
136 : }
137 :
138 : // Private constructor for Builder
139 123 : SpanEndpoint::SpanEndpoint(EndpointId id, DataModel::EndpointCompositionPattern composition, EndpointId parentId,
140 : Span<ServerClusterInterface *> serverClusters, Span<const ClusterId> clientClusters,
141 123 : Span<const SemanticTag> semanticTags, Span<const DataModel::DeviceTypeEntry> deviceTypes) :
142 123 : mEndpointEntry({ id, parentId, composition }),
143 123 : mDeviceTypes(deviceTypes), mSemanticTags(semanticTags), mClientClusters(clientClusters), mServerClusters(serverClusters)
144 123 : {}
145 :
146 : } // namespace app
147 : } // namespace chip
|