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 <lib/core/CHIPError.h>
25 :
26 : /**
27 : * Callback class that clusters can implement in order to interpose custom
28 : * attribute-handling logic. An AttributeAccessInterface instance is associated
29 : * with some specific cluster. A single instance may be used for a specific
30 : * endpoint or for all endpoints.
31 : *
32 : * Instances of AttributeAccessInterface that are registered via
33 : * AttributeAccessInterfaceRegistry::Instance().Register will be consulted before taking the
34 : * normal attribute access codepath and can use that codepath as a fallback if desired.
35 : */
36 : namespace chip {
37 : namespace app {
38 :
39 : class AttributeAccessInterface
40 : {
41 : public:
42 : /**
43 : * aEndpointId can be Missing to indicate that this object is meant to be
44 : * used with all endpoints.
45 : */
46 727 : AttributeAccessInterface(Optional<EndpointId> aEndpointId, ClusterId aClusterId) :
47 727 : mEndpointId(aEndpointId), mClusterId(aClusterId)
48 727 : {}
49 727 : virtual ~AttributeAccessInterface() {}
50 :
51 : /**
52 : * Callback for reading attributes.
53 : *
54 : * @param [in] aPath indicates which exact data is being read.
55 : * @param [in] aEncoder the AttributeValueEncoder to use for encoding the
56 : * data.
57 : *
58 : * The implementation can do one of three things:
59 : *
60 : * 1) Return a failure. This is treated as a failed read and the error is
61 : * returned to the client, by converting it to a StatusIB.
62 : * 2) Return success and attempt to encode data using aEncoder. The data is
63 : * returned to the client.
64 : * 3) Return success and not attempt to encode any data using aEncoder. In
65 : * this case, Ember attribute access will happen for the read. This may
66 : * involve reading from the attribute store or external attribute
67 : * callbacks.
68 : */
69 : virtual CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) = 0;
70 :
71 : /**
72 : * Callback for writing attributes.
73 : *
74 : * @param [in] aPath indicates which exact data is being written.
75 : * @param [in] aDecoder the AttributeValueDecoder to use for decoding the
76 : * data.
77 : *
78 : * The implementation can do one of three things:
79 : *
80 : * 1) Return a failure. This is treated as a failed write and the error is
81 : * sent to the client, by converting it to a StatusIB.
82 : * 2) Return success and attempt to decode from aDecoder. This is
83 : * treated as a successful write.
84 : * 3) Return success and not attempt to decode from aDecoder. In
85 : * this case, Ember attribute access will happen for the write. This may
86 : * involve writing to the attribute store or external attribute
87 : * callbacks.
88 : */
89 0 : virtual CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) { return CHIP_NO_ERROR; }
90 :
91 : /**
92 : * Indicates the start of a series of list operations. This function will be called before the first Write operation of a series
93 : * of consequence attribute data of the same attribute.
94 : *
95 : * 1) This function will be called if the client tries to set a nullable list attribute to null.
96 : * 2) This function will only be called once for a series of consequent attribute data (regardless the kind of list operation)
97 : * of the same attribute.
98 : *
99 : * @param [in] aPath indicates the path of the modified list.
100 : */
101 0 : virtual void OnListWriteBegin(const ConcreteAttributePath & aPath) {}
102 :
103 : /**
104 : * Indicates the end of a series of list operations. This function will be called after the last 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 : * 3) When aWriteWasSuccessful is true, the data written must be consistent or the list is untouched.
111 : *
112 : * @param [in] aPath indicates the path of the modified list
113 : * @param [in] aWriteWasSuccessful indicates whether the delivered list is complete.
114 : *
115 : */
116 0 : virtual void OnListWriteEnd(const ConcreteAttributePath & aPath, bool aWriteWasSuccessful) {}
117 :
118 : /**
119 : * Mechanism for keeping track of a chain of AttributeAccessInterfaces.
120 : */
121 19 : void SetNext(AttributeAccessInterface * aNext) { mNext = aNext; }
122 23 : AttributeAccessInterface * GetNext() const { return mNext; }
123 :
124 : /**
125 : * Check whether a this AttributeAccessInterface is relevant for a
126 : * particular endpoint+cluster. An AttributeAccessInterface will be used
127 : * for a read from a particular cluster only when this function returns
128 : * true.
129 : */
130 25 : bool Matches(EndpointId aEndpointId, ClusterId aClusterId) const
131 : {
132 25 : return (!mEndpointId.HasValue() || mEndpointId.Value() == aEndpointId) && mClusterId == aClusterId;
133 : }
134 :
135 : /**
136 : * Check whether an AttributeAccessInterface is relevant for a particular
137 : * specific endpoint. This is used to clean up overrides registered for an
138 : * endpoint that becomes disabled.
139 : */
140 15 : bool MatchesEndpoint(EndpointId aEndpointId) const { return mEndpointId.HasValue() && mEndpointId.Value() == aEndpointId; }
141 :
142 : /**
143 : * Check whether another AttributeAccessInterface wants to handle the same set of
144 : * attributes as we do.
145 : */
146 4 : bool Matches(const AttributeAccessInterface & aOther) const
147 : {
148 8 : return mClusterId == aOther.mClusterId &&
149 8 : (!mEndpointId.HasValue() || !aOther.mEndpointId.HasValue() || mEndpointId.Value() == aOther.mEndpointId.Value());
150 : }
151 :
152 : protected:
153 : Optional<EndpointId> GetEndpointId() { return mEndpointId; }
154 :
155 : private:
156 : Optional<EndpointId> mEndpointId;
157 : ClusterId mClusterId;
158 : AttributeAccessInterface * mNext = nullptr;
159 : };
160 :
161 : } // namespace app
162 : } // namespace chip
|