Line data Source code
1 : /*
2 : * Copyright (c) 2024 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 : #pragma once
18 :
19 : #include <cstdint>
20 : #include <optional>
21 :
22 : #include <access/Privilege.h>
23 : #include <lib/core/DataModelTypes.h>
24 : #include <lib/support/BitFlags.h>
25 : #include <lib/support/BitMask.h>
26 : #include <lib/support/TypeTraits.h>
27 :
28 : // Pragma macro to disable the "conversion" and "narrowing" warnings.
29 : // This is done in some sections of the code in order to allow
30 : // the use of narrowing masks when assigning values to bitfields variables.
31 : // Without the use of these macros, the compiler would not allow
32 : // the narrowing and conversion of input values during the settings
33 : // of the variables inside of both 'AttributeEntry.mask' and 'AcceptedCommandEntry.mask'.
34 : #define _StartBitFieldInit \
35 : _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wconversion\"") \
36 : _Pragma("GCC diagnostic ignored \"-Wnarrowing\"")
37 : #define _EndBitFieldInit _Pragma("GCC diagnostic pop")
38 :
39 : namespace chip {
40 : namespace app {
41 : namespace DataModel {
42 :
43 : /// Represents various endpoint composition patterns as defined in the spec
44 : /// as `9.2.1. Endpoint Composition patterns`
45 : enum class EndpointCompositionPattern : uint8_t
46 : {
47 : // Tree pattern supports a general tree of endpoints. Commonly used for
48 : // device types that support physical device composition (e.g. Refrigerator)
49 : kTree = 0x1,
50 :
51 : // A full-family pattern is a list of all descendant endpoints, with no
52 : // imposed hierarchy.
53 : //
54 : // For example the Root Node and Aggregator device types use the full-familiy
55 : // pattern, as defined in their device type specification
56 : kFullFamily = 0x2,
57 : };
58 :
59 : struct EndpointEntry
60 : {
61 : EndpointId id;
62 :
63 : // kInvalidEndpointId if there is no explicit parent endpoint (which means the parent is endpoint 0,
64 : // for endpoints other than endpoint 0).
65 : EndpointId parentId;
66 : EndpointCompositionPattern compositionPattern;
67 : bool operator==(const EndpointEntry & rhs) const
68 : {
69 : return id == rhs.id && parentId == rhs.parentId && compositionPattern == rhs.compositionPattern;
70 : }
71 : };
72 :
73 : enum class ClusterQualityFlags : uint32_t
74 : {
75 : kDiagnosticsData = 0x0001, // `K` quality, may be filtered out in subscriptions
76 : };
77 :
78 : struct ServerClusterEntry
79 : {
80 : ClusterId clusterId;
81 : DataVersion dataVersion; // current cluster data version,
82 : BitFlags<ClusterQualityFlags> flags;
83 : };
84 :
85 : struct ClusterInfo
86 : {
87 : DataVersion dataVersion; // current cluster data version,
88 : BitFlags<ClusterQualityFlags> flags;
89 :
90 : /// Constructor that marks data version as mandatory
91 : /// for this structure.
92 : ClusterInfo(DataVersion version) : dataVersion(version) {}
93 : };
94 :
95 : // Constant used to narrow binary expressions
96 : constexpr uint8_t kPrivilegeBits = 5;
97 :
98 : // Mask used in the narrowing of binary expressions
99 : constexpr uint8_t kPrivilegeMask = ((1 << kPrivilegeBits) - 1);
100 :
101 : // Validating contents of 'kPrivilegeMask'.
102 : static_assert(Access::kAllPrivilegeBits == kPrivilegeMask,
103 : "\"kPrivilegeMask\" does not match all the values defined "
104 : "inside the enum class Access::Privilege.");
105 :
106 : enum class AttributeQualityFlags : uint32_t
107 : {
108 : kListAttribute = 0x0004, // This attribute is a list attribute
109 : kFabricScoped = 0x0008, // 'F' quality on attributes
110 : kFabricSensitive = 0x0010, // 'S' quality on attributes
111 : kChangesOmitted = 0x0020, // `C` quality on attributes
112 : kTimed = 0x0040, // `T` quality on attributes (writes require timed interactions)
113 :
114 : // If you add new items here, remember to change kAttrQualityBits
115 : };
116 :
117 : struct EventEntry
118 : {
119 : Access::Privilege readPrivilege; // Required access level to read this event
120 : };
121 :
122 : struct AttributeEntry
123 : {
124 : const AttributeId attributeId;
125 :
126 : // Constructor
127 :
128 : _StartBitFieldInit; // Disabling '-Wconversion' & '-Wnarrowing'
129 124186 : constexpr AttributeEntry(AttributeId id, BitMask<AttributeQualityFlags> attrQualityFlags,
130 124186 : std::optional<Access::Privilege> readPriv, std::optional<Access::Privilege> writePriv) :
131 124186 : attributeId{ id },
132 414775 : mask{
133 124186 : .flags = attrQualityFlags.Raw() & kAttrQualityMask,
134 248372 : .readPrivilege = readPriv.has_value() ? (to_underlying(*readPriv) & kPrivilegeMask) : 0,
135 166403 : .writePrivilege = writePriv.has_value() ? (to_underlying(*writePriv) & kPrivilegeMask) : 0,
136 : }
137 124186 : {}
138 :
139 : _EndBitFieldInit; // Enabling '-Wconversion' & '-Wnarrowing'
140 :
141 : // Getter for the read privilege for this attribute. std::nullopt means the attribute is not readable.
142 8162 : [[nodiscard]] constexpr std::optional<Access::Privilege> GetReadPrivilege() const
143 : {
144 8162 : if (mask.readPrivilege != 0)
145 : {
146 8162 : return static_cast<Access::Privilege>(mask.readPrivilege);
147 : }
148 0 : return std::nullopt;
149 : }
150 :
151 : // Getter for the write privilege for this attribute. std::nullopt means the attribute is not writable.
152 9086 : [[nodiscard]] constexpr std::optional<Access::Privilege> GetWritePrivilege() const
153 : {
154 9086 : if (mask.writePrivilege != 0)
155 : {
156 9086 : return static_cast<Access::Privilege>(mask.writePrivilege);
157 : }
158 0 : return std::nullopt;
159 : }
160 :
161 6289 : [[nodiscard]] constexpr bool HasFlags(AttributeQualityFlags f) const { return (mask.flags & to_underlying(f)) != 0; }
162 :
163 : bool operator==(const AttributeEntry & other) const
164 : {
165 : return (attributeId == other.attributeId) && (mask.flags == other.mask.flags) &&
166 : (mask.readPrivilege == other.mask.readPrivilege) && (mask.writePrivilege == other.mask.writePrivilege);
167 : }
168 :
169 : bool operator!=(const AttributeEntry & other) const { return !(*this == other); }
170 :
171 : private:
172 : // Constant used to narrow binary expressions
173 : static constexpr uint8_t kAttrQualityBits = 7;
174 :
175 : // Mask used in the narrowing of binary expressions
176 : static constexpr uint8_t kAttrQualityMask = ((1 << kAttrQualityBits) - 1);
177 :
178 : struct attribute_entry_mask_t
179 : {
180 :
181 : // attribute quality flags
182 : //
183 : // flags is a uint32_t bitfield of size kAttrQualityBits (aka 7),
184 : // in order to accomodate all the different values of
185 : // "enum class AttributeQualityFlags".
186 : //
187 : // Consider that any modification on the declaration of
188 : // "enum class AttributeQualityFlags" will affect flags.
189 : std::underlying_type_t<AttributeQualityFlags> flags : kAttrQualityBits;
190 :
191 : // read/write access privilege variables
192 : //
193 : // readPrivilege is a uint8_t bitfield of size kPrivilegeBits (aka 5),
194 : // in order to accomodate all the different values of "enum class Privilege".
195 : // Same case for writePrivilege.
196 : //
197 : // Consider that any modification on the declaration of "enum class Privilege"
198 : // will affect both readPrivilege and writePrivilege.
199 : //
200 : // The use of bitfields means that each variable holds an individual
201 : // Access::Privilege value, as a bitwise value. This allows us to
202 : // handle Access::Privilege information without any bit fiddling.
203 : std::underlying_type_t<Access::Privilege> readPrivilege : kPrivilegeBits;
204 : std::underlying_type_t<Access::Privilege> writePrivilege : kPrivilegeBits;
205 : };
206 :
207 : // Make sure that our various flags storage is never larger than 32 bits,
208 : // because we expect these fields to pack together.
209 : static_assert(sizeof(attribute_entry_mask_t) <= 4, "Size of attribute_entry_mask_t is not as expected.");
210 :
211 : attribute_entry_mask_t mask;
212 : };
213 :
214 : // Static ASSERT to check size of AttributeEntry
215 : static_assert(sizeof(AttributeEntry) <= 8, "Size of AttributeEntry is not as expected.");
216 :
217 : // Bitmask values for different Command qualities.
218 : enum class CommandQualityFlags : uint32_t
219 : {
220 : kFabricScoped = 0x0001,
221 : kTimed = 0x0002, // `T` quality on commands
222 : kLargeMessage = 0x0004, // `L` quality on commands
223 :
224 : // If you add new items here, remember to change kCmdQualityBits
225 : };
226 :
227 : struct AcceptedCommandEntry
228 : {
229 : CommandId commandId;
230 :
231 : // Constructor
232 :
233 : _StartBitFieldInit; // Disabling '-Wconversion' & '-Wnarrowing'
234 :
235 104 : constexpr AcceptedCommandEntry(CommandId id = 0, BitMask<CommandQualityFlags> cmdQualityFlags = BitMask<CommandQualityFlags>(),
236 104 : Access::Privilege invokePriv = Access::Privilege::kOperate) :
237 104 : commandId(id),
238 208 : mask{
239 104 : .flags = cmdQualityFlags.Raw() & kCmdQualityMask,
240 104 : .invokePrivilege = to_underlying(invokePriv) & kPrivilegeMask,
241 : }
242 104 : {}
243 :
244 : _EndBitFieldInit; // Enabling '-Wconversion' & '-Wnarrowing'
245 :
246 : // Getter for the invoke privilege for this command.
247 25 : [[nodiscard]] constexpr Access::Privilege GetInvokePrivilege() const
248 : {
249 25 : return static_cast<Access::Privilege>(mask.invokePrivilege);
250 : }
251 :
252 75 : [[nodiscard]] constexpr bool HasFlags(CommandQualityFlags f) const { return (mask.flags & to_underlying(f)) != 0; }
253 :
254 : bool operator==(const AcceptedCommandEntry & other) const
255 : {
256 : return (commandId == other.commandId) && (mask.flags == other.mask.flags) &&
257 : (mask.invokePrivilege == other.mask.invokePrivilege);
258 : }
259 :
260 : bool operator!=(const AcceptedCommandEntry & other) const { return !(*this == other); }
261 :
262 : private:
263 : // Constant used to narrow binary expressions
264 : static constexpr uint8_t kCmdQualityBits = 3;
265 :
266 : // Mask used in the narrowing of binary expressions
267 : static constexpr uint8_t kCmdQualityMask = ((1 << kCmdQualityBits) - 1);
268 :
269 : struct accepted_command_entry_mask_t
270 : {
271 : // command quality flags
272 : //
273 : std::underlying_type_t<CommandQualityFlags> flags : 3;
274 :
275 : std::underlying_type_t<Access::Privilege> invokePrivilege : 5;
276 : };
277 :
278 : // Make sure that our various flags storage is never larger than 32 bits,
279 : // because we expect these fields to pack together.
280 : static_assert(sizeof(accepted_command_entry_mask_t) <= 4, "Size of accepted_command_entry_mask_t is not as expected.");
281 :
282 : accepted_command_entry_mask_t mask;
283 : };
284 :
285 : // Static ASSERT to check size of AcceptedCommandEntry
286 : static_assert(sizeof(AcceptedCommandEntry) <= 8, "Size of AcceptedCommandEntry is not as expected.");
287 :
288 : /// Represents a device type that resides on an endpoint
289 : struct DeviceTypeEntry
290 : {
291 : DeviceTypeId deviceTypeId;
292 : uint8_t deviceTypeRevision;
293 :
294 : bool operator==(const DeviceTypeEntry & other) const
295 : {
296 : return (deviceTypeId == other.deviceTypeId) && (deviceTypeRevision == other.deviceTypeRevision);
297 : }
298 : };
299 :
300 : } // namespace DataModel
301 : } // namespace app
302 : } // namespace chip
303 :
304 : #undef _StartBitFieldInit
305 : #undef _EndBitFieldInit
|