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