Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #pragma once
20 :
21 : #include <app/AttributeReportBuilder.h>
22 : #include <app/AttributeValueDecoder.h>
23 : #include <app/AttributeValueEncoder.h>
24 : #include <app/data-model-provider/OperationTypes.h>
25 : #include <lib/core/CHIPError.h>
26 :
27 : /**
28 : * Callback class that clusters can implement in order to interpose custom
29 : * attribute-handling logic. An AttributeAccessInterface instance is associated
30 : * with some specific cluster. A single instance may be used for a specific
31 : * endpoint or for all endpoints.
32 : *
33 : * Instances of AttributeAccessInterface that are registered via
34 : * AttributeAccessInterfaceRegistry::Instance().Register will be consulted before taking the
35 : * normal attribute access codepath and can use that codepath as a fallback if desired.
36 : */
37 : namespace chip {
38 : namespace app {
39 :
40 : class AttributeAccessInterface
41 : {
42 : public:
43 : /**
44 : * aEndpointId can be Missing to indicate that this object is meant to be
45 : * used with all endpoints.
46 : */
47 139 : AttributeAccessInterface(Optional<EndpointId> aEndpointId, ClusterId aClusterId) :
48 139 : mEndpointId(aEndpointId), mClusterId(aClusterId)
49 139 : {}
50 139 : virtual ~AttributeAccessInterface() {}
51 :
52 : /**
53 : * Callback for reading attributes.
54 : *
55 : * @param [in] aRequest indicates which exact data is being read along with attributes of how data is being read.
56 : * @param [in] aEncoder the AttributeValueEncoder to use for encoding the
57 : * data.
58 : *
59 : * The implementation can do one of three things:
60 : *
61 : * 1) Return a failure. This is treated as a failed read and the error is
62 : * returned to the client, by converting it to a StatusIB.
63 : * 2) Return success and attempt to encode data using aEncoder. The data is
64 : * returned to the client.
65 : * 3) Return success and not attempt to encode any data using aEncoder. In
66 : * this case, Ember attribute access will happen for the read. This may
67 : * involve reading from the attribute store or external attribute
68 : * callbacks.
69 : */
70 1762 : virtual CHIP_ERROR Read(const DataModel::ReadAttributeRequest & aRequest, AttributeValueEncoder & aEncoder)
71 : {
72 1762 : return Read(aRequest.path, aEncoder);
73 : }
74 :
75 : /**
76 : * A simpler version of Read(const ReadAttributeRequest & request, AttributeValueEncoder & aEncoder)
77 : * which takes simply the path being read, for backwards compatibility.
78 : *
79 : * @param [in] aPath indicates which exact data is being read.
80 : */
81 : virtual CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) = 0;
82 :
83 : /**
84 : * Callback for writing attributes.
85 : *
86 : * @param [in] aPath indicates which exact data is being written.
87 : * @param [in] aDecoder the AttributeValueDecoder to use for decoding the
88 : * data.
89 : *
90 : * The implementation can do one of three things:
91 : *
92 : * 1) Return a failure. This is treated as a failed write and the error is
93 : * sent to the client, by converting it to a StatusIB.
94 : * 2) Return success and attempt to decode from aDecoder. This is
95 : * treated as a successful write.
96 : * 3) Return success and not attempt to decode from aDecoder. In
97 : * this case, Ember attribute access will happen for the write. This may
98 : * involve writing to the attribute store or external attribute
99 : * callbacks.
100 : */
101 0 : virtual CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) { return CHIP_NO_ERROR; }
102 :
103 : /**
104 : * Indicates the start of a series of list operations. This function will be called before the first Write operation of a series
105 : * of consequence attribute data of the same attribute.
106 : *
107 : * 1) This function will be called if the client tries to set a nullable list attribute to null.
108 : * 2) This function will only be called once for a series of consequent attribute data (regardless the kind of list operation)
109 : * of the same attribute.
110 : *
111 : * @param [in] aPath indicates the path of the modified list.
112 : */
113 0 : virtual void OnListWriteBegin(const ConcreteAttributePath & aPath) {}
114 :
115 : /**
116 : * Indicates the end of a series of list operations. This function will be called after the last Write operation of a series
117 : * of consequence attribute data of the same attribute.
118 : *
119 : * 1) This function will be called if the client tries to set a nullable list attribute to null.
120 : * 2) This function will only be called once for a series of consequent attribute data (regardless the kind of list operation)
121 : * of the same attribute.
122 : * 3) When aWriteWasSuccessful is true, the data written must be consistent or the list is untouched.
123 : *
124 : * @param [in] aPath indicates the path of the modified list
125 : * @param [in] aWriteWasSuccessful indicates whether the delivered list is complete.
126 : *
127 : */
128 0 : virtual void OnListWriteEnd(const ConcreteAttributePath & aPath, bool aWriteWasSuccessful) {}
129 :
130 : /**
131 : * Mechanism for keeping track of a chain of AttributeAccessInterfaces.
132 : */
133 22 : void SetNext(AttributeAccessInterface * aNext) { mNext = aNext; }
134 47 : AttributeAccessInterface * GetNext() const { return mNext; }
135 :
136 : /**
137 : * Check whether a this AttributeAccessInterface is relevant for a
138 : * particular endpoint+cluster. An AttributeAccessInterface will be used
139 : * for a read from a particular cluster only when this function returns
140 : * true.
141 : */
142 34 : bool Matches(EndpointId aEndpointId, ClusterId aClusterId) const
143 : {
144 34 : return (!mEndpointId.HasValue() || mEndpointId.Value() == aEndpointId) && mClusterId == aClusterId;
145 : }
146 :
147 : /**
148 : * Check whether an AttributeAccessInterface is relevant for a particular
149 : * specific endpoint. This is used to clean up overrides registered for an
150 : * endpoint that becomes disabled.
151 : */
152 29 : bool MatchesEndpoint(EndpointId aEndpointId) const { return mEndpointId.HasValue() && mEndpointId.Value() == aEndpointId; }
153 :
154 : /**
155 : * Check whether another AttributeAccessInterface wants to handle the same set of
156 : * attributes as we do.
157 : */
158 13 : bool Matches(const AttributeAccessInterface & aOther) const
159 : {
160 21 : return mClusterId == aOther.mClusterId &&
161 21 : (!mEndpointId.HasValue() || !aOther.mEndpointId.HasValue() || mEndpointId.Value() == aOther.mEndpointId.Value());
162 : }
163 :
164 : protected:
165 : Optional<EndpointId> GetEndpointId() { return mEndpointId; }
166 :
167 : private:
168 : Optional<EndpointId> mEndpointId;
169 : ClusterId mClusterId;
170 : AttributeAccessInterface * mNext = nullptr;
171 : };
172 :
173 : } // namespace app
174 : } // namespace chip
|