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 : };
68 :
69 : enum class ClusterQualityFlags : uint32_t
70 : {
71 : kDiagnosticsData = 0x0001, // `K` quality, may be filtered out in subscriptions
72 : };
73 :
74 : struct ServerClusterEntry
75 : {
76 : ClusterId clusterId;
77 : DataVersion dataVersion; // current cluster data version,
78 : BitFlags<ClusterQualityFlags> flags;
79 : };
80 :
81 : struct ClusterInfo
82 : {
83 : DataVersion dataVersion; // current cluster data version,
84 : BitFlags<ClusterQualityFlags> flags;
85 :
86 : /// Constructor that marks data version as mandatory
87 : /// for this structure.
88 : ClusterInfo(DataVersion version) : dataVersion(version) {}
89 : };
90 :
91 : // Constant used to narrow binary expressions
92 : constexpr uint8_t kPrivilegeBits = 5;
93 :
94 : // Mask used in the narrowing of binary expressions
95 : constexpr uint8_t kPrivilegeMask = ((1 << kPrivilegeBits) - 1);
96 :
97 : // Validating contents of 'kPrivilegeMask'.
98 : static_assert(Access::kAllPrivilegeBits == kPrivilegeMask,
99 : "\"kPrivilegeMask\" does not match all the values defined "
100 : "inside the enum class Access::Privilege.");
101 :
102 : enum class AttributeQualityFlags : uint32_t
103 : {
104 : kListAttribute = 0x0004, // This attribute is a list attribute
105 : kFabricScoped = 0x0008, // 'F' quality on attributes
106 : kFabricSensitive = 0x0010, // 'S' quality on attributes
107 : kChangesOmitted = 0x0020, // `C` quality on attributes
108 : kTimed = 0x0040, // `T` quality on attributes (writes require timed interactions)
109 :
110 : // If you add new items here, remember to change kAttrQualityBits
111 : };
112 :
113 : struct AttributeEntry
114 : {
115 : AttributeId attributeId;
116 :
117 : // Constructor
118 :
119 : _StartBitFieldInit; // Disabling '-Wconversion' & '-Wnarrowing'
120 114805 : constexpr AttributeEntry(AttributeId id, BitMask<AttributeQualityFlags> attrQualityFlags,
121 114805 : std::optional<Access::Privilege> readPriv, std::optional<Access::Privilege> writePriv) :
122 114805 : attributeId{ id },
123 382526 : mask{
124 114805 : .flags = attrQualityFlags.Raw() & kAttrQualityMask,
125 229610 : .readPrivilege = readPriv.has_value() ? (to_underlying(*readPriv) & kPrivilegeMask) : 0,
126 152916 : .writePrivilege = writePriv.has_value() ? (to_underlying(*writePriv) & kPrivilegeMask) : 0,
127 : }
128 114805 : {}
129 :
130 : _EndBitFieldInit; // Enabling '-Wconversion' & '-Wnarrowing'
131 :
132 : // Getter for the read privilege for this attribute. std::nullopt means the attribute is not readable.
133 7430 : [[nodiscard]] constexpr std::optional<Access::Privilege> GetReadPrivilege() const
134 : {
135 7430 : if (mask.readPrivilege != 0)
136 : {
137 7430 : return static_cast<Access::Privilege>(mask.readPrivilege);
138 : }
139 0 : return std::nullopt;
140 : }
141 :
142 : // Getter for the write privilege for this attribute. std::nullopt means the attribute is not writable.
143 5201 : [[nodiscard]] constexpr std::optional<Access::Privilege> GetWritePrivilege() const
144 : {
145 5201 : if (mask.writePrivilege != 0)
146 : {
147 5201 : return static_cast<Access::Privilege>(mask.writePrivilege);
148 : }
149 0 : return std::nullopt;
150 : }
151 :
152 6289 : [[nodiscard]] constexpr bool HasFlags(AttributeQualityFlags f) const { return (mask.flags & to_underlying(f)) != 0; }
153 :
154 : bool operator==(const AttributeEntry & other) const
155 : {
156 : return (attributeId == other.attributeId) && (mask.flags == other.mask.flags) &&
157 : (mask.readPrivilege == other.mask.readPrivilege) && (mask.writePrivilege == other.mask.writePrivilege);
158 : }
159 :
160 : bool operator!=(const AttributeEntry & other) const { return !(*this == other); }
161 :
162 : private:
163 : // Constant used to narrow binary expressions
164 : static constexpr uint8_t kAttrQualityBits = 7;
165 :
166 : // Mask used in the narrowing of binary expressions
167 : static constexpr uint8_t kAttrQualityMask = ((1 << kAttrQualityBits) - 1);
168 :
169 : struct attribute_entry_mask_t
170 : {
171 :
172 : // attribute quality flags
173 : //
174 : // flags is a uint32_t bitfield of size kAttrQualityBits (aka 7),
175 : // in order to accomodate all the different values of
176 : // "enum class AttributeQualityFlags".
177 : //
178 : // Consider that any modification on the declaration of
179 : // "enum class AttributeQualityFlags" will affect flags.
180 : std::underlying_type_t<AttributeQualityFlags> flags : kAttrQualityBits;
181 :
182 : // read/write access privilege variables
183 : //
184 : // readPrivilege is a uint8_t bitfield of size kPrivilegeBits (aka 5),
185 : // in order to accomodate all the different values of "enum class Privilege".
186 : // Same case for writePrivilege.
187 : //
188 : // Consider that any modification on the declaration of "enum class Privilege"
189 : // will affect both readPrivilege and writePrivilege.
190 : //
191 : // The use of bitfields means that each variable holds an individual
192 : // Access::Privilege value, as a bitwise value. This allows us to
193 : // handle Access::Privilege information without any bit fiddling.
194 : std::underlying_type_t<Access::Privilege> readPrivilege : kPrivilegeBits;
195 : std::underlying_type_t<Access::Privilege> writePrivilege : kPrivilegeBits;
196 : };
197 :
198 : // Make sure that our various flags storage is never larger than 32 bits,
199 : // because we expect these fields to pack together.
200 : static_assert(sizeof(attribute_entry_mask_t) <= 4, "Size of attribute_entry_mask_t is not as expected.");
201 :
202 : attribute_entry_mask_t mask;
203 : };
204 :
205 : // Static ASSERT to check size of AttributeEntry
206 : static_assert(sizeof(AttributeEntry) <= 8, "Size of AttributeEntry is not as expected.");
207 :
208 : // Bitmask values for different Command qualities.
209 : enum class CommandQualityFlags : uint32_t
210 : {
211 : kFabricScoped = 0x0001,
212 : kTimed = 0x0002, // `T` quality on commands
213 : kLargeMessage = 0x0004, // `L` quality on commands
214 :
215 : // If you add new items here, remember to change kCmdQualityBits
216 : };
217 :
218 : struct AcceptedCommandEntry
219 : {
220 : CommandId commandId;
221 :
222 : // Constructor
223 :
224 : _StartBitFieldInit; // Disabling '-Wconversion' & '-Wnarrowing'
225 :
226 79 : constexpr AcceptedCommandEntry(CommandId id = 0, BitMask<CommandQualityFlags> cmdQualityFlags = BitMask<CommandQualityFlags>(),
227 79 : Access::Privilege invokePriv = Access::Privilege::kOperate) :
228 79 : commandId(id),
229 158 : mask{
230 79 : .flags = cmdQualityFlags.Raw() & kCmdQualityMask,
231 79 : .invokePrivilege = to_underlying(invokePriv) & kPrivilegeMask,
232 : }
233 79 : {}
234 :
235 : _EndBitFieldInit; // Enabling '-Wconversion' & '-Wnarrowing'
236 :
237 : // Getter for the invoke privilege for this command.
238 23 : [[nodiscard]] constexpr Access::Privilege GetInvokePrivilege() const
239 : {
240 23 : return static_cast<Access::Privilege>(mask.invokePrivilege);
241 : }
242 :
243 69 : [[nodiscard]] constexpr bool HasFlags(CommandQualityFlags f) const { return (mask.flags & to_underlying(f)) != 0; }
244 :
245 : private:
246 : // Constant used to narrow binary expressions
247 : static constexpr uint8_t kCmdQualityBits = 3;
248 :
249 : // Mask used in the narrowing of binary expressions
250 : static constexpr uint8_t kCmdQualityMask = ((1 << kCmdQualityBits) - 1);
251 :
252 : struct accepted_command_entry_mask_t
253 : {
254 : // command quality flags
255 : //
256 : std::underlying_type_t<CommandQualityFlags> flags : 3;
257 :
258 : std::underlying_type_t<Access::Privilege> invokePrivilege : 5;
259 : };
260 :
261 : // Make sure that our various flags storage is never larger than 32 bits,
262 : // because we expect these fields to pack together.
263 : static_assert(sizeof(accepted_command_entry_mask_t) <= 4, "Size of accepted_command_entry_mask_t is not as expected.");
264 :
265 : accepted_command_entry_mask_t mask;
266 : };
267 :
268 : // Static ASSERT to check size of AcceptedCommandEntry
269 : static_assert(sizeof(AcceptedCommandEntry) <= 8, "Size of AcceptedCommandEntry is not as expected.");
270 :
271 : /// Represents a device type that resides on an endpoint
272 : struct DeviceTypeEntry
273 : {
274 : DeviceTypeId deviceTypeId;
275 : uint8_t deviceTypeRevision;
276 :
277 : bool operator==(const DeviceTypeEntry & other) const
278 : {
279 : return (deviceTypeId == other.deviceTypeId) && (deviceTypeRevision == other.deviceTypeRevision);
280 : }
281 : };
282 :
283 : } // namespace DataModel
284 : } // namespace app
285 : } // namespace chip
286 :
287 : #undef _StartBitFieldInit
288 : #undef _EndBitFieldInit
|