Line data Source code
1 : /*
2 : * Copyright (c) 2021-2024 Project CHIP Authors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 : #include <app/util/ember-global-attribute-access-interface.h>
17 :
18 : #include <app/CommandHandlerInterfaceRegistry.h>
19 : #include <app/GlobalAttributes.h>
20 : #include <app/InteractionModelEngine.h>
21 :
22 : namespace chip {
23 : namespace app {
24 : namespace Compatibility {
25 :
26 716 : CHIP_ERROR GlobalAttributeReader::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
27 : {
28 : using namespace Clusters::Globals::Attributes;
29 716 : switch (aPath.mAttributeId)
30 : {
31 280 : case AttributeList::Id:
32 280 : return aEncoder.EncodeList([this](const auto & encoder) {
33 250 : const size_t count = mCluster->attributeCount;
34 250 : bool addedExtraGlobals = false;
35 1635 : for (size_t i = 0; i < count; ++i)
36 : {
37 1429 : AttributeId id = mCluster->attributes[i].attributeId;
38 1429 : constexpr auto lastGlobalId = GlobalAttributesNotInMetadata[ArraySize(GlobalAttributesNotInMetadata) - 1];
39 : // If EventList is not supported. The GlobalAttributesNotInMetadata is missing one id here.
40 : static_assert(lastGlobalId - GlobalAttributesNotInMetadata[0] == ArraySize(GlobalAttributesNotInMetadata),
41 : "Ids in GlobalAttributesNotInMetadata not consecutive (except EventList)");
42 1429 : if (!addedExtraGlobals && id > lastGlobalId)
43 : {
44 884 : for (const auto & globalId : GlobalAttributesNotInMetadata)
45 : {
46 672 : ReturnErrorOnFailure(encoder.Encode(globalId));
47 : }
48 212 : addedExtraGlobals = true;
49 : }
50 1411 : ReturnErrorOnFailure(encoder.Encode(id));
51 : }
52 206 : if (!addedExtraGlobals)
53 : {
54 0 : for (const auto & globalId : GlobalAttributesNotInMetadata)
55 : {
56 0 : ReturnErrorOnFailure(encoder.Encode(globalId));
57 : }
58 : }
59 206 : return CHIP_NO_ERROR;
60 280 : });
61 231 : case AcceptedCommandList::Id:
62 231 : return EncodeCommandList(aPath, aEncoder, &CommandHandlerInterface::EnumerateAcceptedCommands,
63 231 : mCluster->acceptedCommandList);
64 205 : case GeneratedCommandList::Id:
65 205 : return EncodeCommandList(aPath, aEncoder, &CommandHandlerInterface::EnumerateGeneratedCommands,
66 205 : mCluster->generatedCommandList);
67 0 : default:
68 : // This function is only called if attributeCluster is non-null in
69 : // ReadSingleClusterData, which only happens for attributes listed in
70 : // GlobalAttributesNotInMetadata. If we reach this code, someone added
71 : // a global attribute to that list but not the above switch.
72 0 : VerifyOrDieWithMsg(false, DataManagement, "Unexpected global attribute: " ChipLogFormatMEI,
73 : ChipLogValueMEI(aPath.mAttributeId));
74 : return CHIP_NO_ERROR;
75 : }
76 : }
77 :
78 436 : CHIP_ERROR GlobalAttributeReader::EncodeCommandList(const ConcreteClusterPath & aClusterPath, AttributeValueEncoder & aEncoder,
79 : GlobalAttributeReader::CommandListEnumerator aEnumerator,
80 : const CommandId * aClusterCommandList)
81 : {
82 436 : return aEncoder.EncodeList([&](const auto & encoder) {
83 : auto * commandHandler =
84 416 : CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(aClusterPath.mEndpointId, aClusterPath.mClusterId);
85 416 : if (commandHandler)
86 : {
87 : struct Context
88 : {
89 : decltype(encoder) & commandIdEncoder;
90 : CHIP_ERROR err;
91 6 : } context{ encoder, CHIP_NO_ERROR };
92 6 : CHIP_ERROR err = (commandHandler->*aEnumerator)(
93 : aClusterPath,
94 2 : [](CommandId command, void * closure) -> Loop {
95 2 : auto * ctx = static_cast<Context *>(closure);
96 2 : ctx->err = ctx->commandIdEncoder.Encode(command);
97 2 : if (ctx->err != CHIP_NO_ERROR)
98 : {
99 0 : return Loop::Break;
100 : }
101 2 : return Loop::Continue;
102 : },
103 : &context);
104 6 : if (err != CHIP_ERROR_NOT_IMPLEMENTED)
105 : {
106 3 : return context.err;
107 : }
108 : // Else fall through to the list in aClusterCommandList.
109 : }
110 :
111 414 : for (const CommandId * cmd = aClusterCommandList; cmd != nullptr && *cmd != kInvalidCommandId; cmd++)
112 : {
113 1 : ReturnErrorOnFailure(encoder.Encode(*cmd));
114 : }
115 413 : return CHIP_NO_ERROR;
116 436 : });
117 : }
118 :
119 : } // namespace Compatibility
120 : } // namespace app
121 : } // namespace chip
|