Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / util / attribute-storage.cpp
1 /**
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
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
18 /**
19  *
20  *    Copyright (c) 2020 Silicon Labs
21  *
22  *    Licensed under the Apache License, Version 2.0 (the "License");
23  *    you may not use this file except in compliance with the License.
24  *    You may obtain a copy of the License at
25  *
26  *        http://www.apache.org/licenses/LICENSE-2.0
27  *
28  *    Unless required by applicable law or agreed to in writing, software
29  *    distributed under the License is distributed on an "AS IS" BASIS,
30  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  *    See the License for the specific language governing permissions and
32  *    limitations under the License.
33  */
34 /***************************************************************************/
35 /**
36  * @file
37  * @brief Contains the per-endpoint configuration of
38  *attribute tables.
39  *******************************************************************************
40  ******************************************************************************/
41
42 #include "attribute-storage.h"
43 #include "af.h"
44 #include "app/util/common.h"
45
46 #include "gen/attribute-type.h"
47 #include "gen/callback.h"
48
49 using namespace chip;
50
51 //------------------------------------------------------------------------------
52 // Globals
53 // This is not declared CONST in order to handle dynamic endpoint information
54 // retrieved from tokens.
55 EmberAfDefinedEndpoint emAfEndpoints[MAX_ENDPOINT_COUNT];
56
57 #if (ATTRIBUTE_MAX_SIZE == 0)
58 #define ACTUAL_ATTRIBUTE_SIZE 1
59 #else
60 #define ACTUAL_ATTRIBUTE_SIZE ATTRIBUTE_MAX_SIZE
61 #endif
62
63 uint8_t attributeData[ACTUAL_ATTRIBUTE_SIZE];
64
65 #if (!defined(ATTRIBUTE_SINGLETONS_SIZE)) || (ATTRIBUTE_SINGLETONS_SIZE == 0)
66 #define ACTUAL_SINGLETONS_SIZE 1
67 #else
68 #define ACTUAL_SINGLETONS_SIZE ATTRIBUTE_SINGLETONS_SIZE
69 #endif
70 uint8_t singletonAttributeData[ACTUAL_SINGLETONS_SIZE];
71
72 uint8_t emberEndpointCount = 0;
73
74 // If we have attributes that are more than 2 bytes, then
75 // we need this data block for the defaults
76 #if (defined(GENERATED_DEFAULTS) && GENERATED_DEFAULTS_COUNT)
77 const uint8_t generatedDefaults[] = GENERATED_DEFAULTS;
78 #endif // GENERATED_DEFAULTS
79
80 #if (defined(GENERATED_MIN_MAX_DEFAULTS) && GENERATED_MIN_MAX_DEFAULT_COUNT)
81 const EmberAfAttributeMinMaxValue minMaxDefaults[] = GENERATED_MIN_MAX_DEFAULTS;
82 #endif // GENERATED_MIN_MAX_DEFAULTS
83
84 #ifdef GENERATED_FUNCTION_ARRAYS
85 GENERATED_FUNCTION_ARRAYS
86 #endif
87
88 #ifdef EMBER_AF_SUPPORT_COMMAND_DISCOVERY
89 const EmberAfCommandMetadata generatedCommands[]              = GENERATED_COMMANDS;
90 const EmberAfManufacturerCodeEntry commandManufacturerCodes[] = GENERATED_COMMAND_MANUFACTURER_CODES;
91 const uint16_t commandManufacturerCodeCount                   = GENERATED_COMMAND_MANUFACTURER_CODE_COUNT;
92 #endif
93
94 const EmberAfAttributeMetadata generatedAttributes[]      = GENERATED_ATTRIBUTES;
95 const EmberAfCluster generatedClusters[]                  = GENERATED_CLUSTERS;
96 const EmberAfEndpointType generatedEmberAfEndpointTypes[] = GENERATED_ENDPOINT_TYPES;
97
98 const EmberAfManufacturerCodeEntry clusterManufacturerCodes[]   = GENERATED_CLUSTER_MANUFACTURER_CODES;
99 const uint16_t clusterManufacturerCodeCount                     = GENERATED_CLUSTER_MANUFACTURER_CODE_COUNT;
100 const EmberAfManufacturerCodeEntry attributeManufacturerCodes[] = GENERATED_ATTRIBUTE_MANUFACTURER_CODES;
101 const uint16_t attributeManufacturerCodeCount                   = GENERATED_ATTRIBUTE_MANUFACTURER_CODE_COUNT;
102
103 #if !defined(EMBER_SCRIPTED_TEST)
104 #define endpointNumber(x) fixedEndpoints[x]
105 #define endpointDeviceId(x) fixedDeviceIds[x]
106 #define endpointDeviceVersion(x) fixedDeviceVersions[x]
107 // Added 'Macro' to silence MISRA warning about conflict with synonymous vars.
108 #define endpointTypeMacro(x) (EmberAfEndpointType *) &(generatedEmberAfEndpointTypes[fixedEmberAfEndpointTypes[x]])
109 #define endpointNetworkIndex(x) fixedNetworks[x]
110 #endif
111
112 //------------------------------------------------------------------------------
113 // Forward declarations
114
115 // Returns endpoint index within a given cluster
116 static uint8_t findClusterEndpointIndex(EndpointId endpoint, ClusterId clusterId, uint8_t mask, uint16_t manufacturerCode);
117
118 //------------------------------------------------------------------------------
119
120 // Initial configuration
121 void emberAfEndpointConfigure(void)
122 {
123     uint8_t ep;
124
125 #if !defined(EMBER_SCRIPTED_TEST)
126     uint8_t fixedEndpoints[]            = FIXED_ENDPOINT_ARRAY;
127     uint16_t fixedDeviceIds[]           = FIXED_DEVICE_IDS;
128     uint8_t fixedDeviceVersions[]       = FIXED_DEVICE_VERSIONS;
129     uint8_t fixedEmberAfEndpointTypes[] = FIXED_ENDPOINT_TYPES;
130     uint8_t fixedNetworks[]             = FIXED_NETWORKS;
131 #endif
132
133     emberEndpointCount = FIXED_ENDPOINT_COUNT;
134     for (ep = 0; ep < FIXED_ENDPOINT_COUNT; ep++)
135     {
136         emAfEndpoints[ep].endpoint      = endpointNumber(ep);
137         emAfEndpoints[ep].deviceId      = endpointDeviceId(ep);
138         emAfEndpoints[ep].deviceVersion = endpointDeviceVersion(ep);
139         emAfEndpoints[ep].endpointType  = endpointTypeMacro(ep);
140         emAfEndpoints[ep].networkIndex  = endpointNetworkIndex(ep);
141         emAfEndpoints[ep].bitmask       = EMBER_AF_ENDPOINT_ENABLED;
142     }
143 }
144
145 void emberAfSetEndpointCount(uint8_t dynamicEndpointCount)
146 {
147     emberEndpointCount = static_cast<uint8_t>(FIXED_ENDPOINT_COUNT + dynamicEndpointCount);
148 }
149
150 uint8_t emberAfFixedEndpointCount(void)
151 {
152     return FIXED_ENDPOINT_COUNT;
153 }
154
155 uint8_t emberAfEndpointCount(void)
156 {
157     return emberEndpointCount;
158 }
159
160 bool emberAfEndpointIndexIsEnabled(uint8_t index)
161 {
162     return (emAfEndpoints[index].bitmask & EMBER_AF_ENDPOINT_ENABLED);
163 }
164
165 // some data types (like strings) are sent OTA in human readable order
166 // (how they are read) instead of little endian as the data types are.
167 bool emberAfIsThisDataTypeAStringType(EmberAfAttributeType dataType)
168 {
169     return (dataType == ZCL_OCTET_STRING_ATTRIBUTE_TYPE || dataType == ZCL_CHAR_STRING_ATTRIBUTE_TYPE ||
170             dataType == ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE || dataType == ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE);
171 }
172
173 bool emberAfIsStringAttributeType(EmberAfAttributeType attributeType)
174 {
175     return (attributeType == ZCL_OCTET_STRING_ATTRIBUTE_TYPE || attributeType == ZCL_CHAR_STRING_ATTRIBUTE_TYPE);
176 }
177
178 bool emberAfIsLongStringAttributeType(EmberAfAttributeType attributeType)
179 {
180     return (attributeType == ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE || attributeType == ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE);
181 }
182
183 // This function is used to call the per-cluster default response callback
184 void emberAfClusterDefaultResponseWithMfgCodeCallback(EndpointId endpoint, ClusterId clusterId, uint8_t commandId,
185                                                       EmberAfStatus status, uint8_t clientServerMask, uint16_t manufacturerCode)
186 {
187     EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode);
188     if (cluster != NULL)
189     {
190         EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, CLUSTER_MASK_DEFAULT_RESPONSE_FUNCTION);
191         if (f != NULL)
192         {
193             // emberAfPushEndpointNetworkIndex(endpoint);
194             ((EmberAfDefaultResponseFunction) f)(endpoint, commandId, status);
195             // emberAfPopNetworkIndex();
196         }
197     }
198 }
199
200 // This function is used to call the per-cluster default response callback, and
201 // wraps the emberAfClusterDefaultResponseWithMfgCodeCallback with a
202 // EMBER_AF_NULL_MANUFACTURER_CODE.
203 void emberAfClusterDefaultResponseCallback(EndpointId endpoint, ClusterId clusterId, CommandId commandId, EmberAfStatus status,
204                                            uint8_t clientServerMask)
205 {
206     emberAfClusterDefaultResponseWithMfgCodeCallback(endpoint, clusterId, commandId, status, clientServerMask,
207                                                      EMBER_AF_NULL_MANUFACTURER_CODE);
208 }
209
210 // This function is used to call the per-cluster message sent callback
211 void emberAfClusterMessageSentWithMfgCodeCallback(EmberOutgoingMessageType type, uint64_t indexOrDestination,
212                                                   EmberApsFrame * apsFrame, uint16_t msgLen, uint8_t * message, EmberStatus status,
213                                                   uint16_t mfgCode)
214 {
215     if (apsFrame != NULL && message != NULL && msgLen != 0)
216     {
217         EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(
218             apsFrame->sourceEndpoint, apsFrame->clusterId,
219             (((message[0] & ZCL_FRAME_CONTROL_DIRECTION_MASK) == ZCL_FRAME_CONTROL_SERVER_TO_CLIENT) ? CLUSTER_MASK_SERVER
220                                                                                                      : CLUSTER_MASK_CLIENT),
221             mfgCode);
222         if (cluster != NULL)
223         {
224             EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, CLUSTER_MASK_MESSAGE_SENT_FUNCTION);
225             if (f != NULL)
226             {
227                 // emberAfPushEndpointNetworkIndex(apsFrame->sourceEndpoint);
228                 ((EmberAfMessageSentFunction) f)(type, indexOrDestination, apsFrame, msgLen, message, status);
229                 // emberAfPopNetworkIndex();
230             }
231         }
232     }
233 }
234
235 // This function is used to call the per-cluster message sent callback, and
236 // wraps the emberAfClusterMessageSentWithMfgCodeCallback with a
237 // EMBER_AF_NULL_MANUFACTURER_CODE.
238 void emberAfClusterMessageSentCallback(EmberOutgoingMessageType type, uint16_t indexOrDestination, EmberApsFrame * apsFrame,
239                                        uint16_t msgLen, uint8_t * message, EmberStatus status)
240 {
241     emberAfClusterMessageSentWithMfgCodeCallback(type, indexOrDestination, apsFrame, msgLen, message, status,
242                                                  EMBER_AF_NULL_MANUFACTURER_CODE);
243 }
244
245 // This function is used to call the per-cluster attribute changed callback
246 void emAfClusterAttributeChangedCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
247                                          uint8_t clientServerMask, uint16_t manufacturerCode)
248 {
249     EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode);
250     if (cluster != NULL)
251     {
252         if (manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)
253         {
254             EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, CLUSTER_MASK_ATTRIBUTE_CHANGED_FUNCTION);
255             if (f != NULL)
256             {
257                 // emberAfPushEndpointNetworkIndex(endpoint);
258                 ((EmberAfClusterAttributeChangedCallback) f)(endpoint, attributeId);
259                 // emberAfPopNetworkIndex();
260             }
261         }
262         else
263         {
264             EmberAfGenericClusterFunction f =
265                 emberAfFindClusterFunction(cluster, CLUSTER_MASK_MANUFACTURER_SPECIFIC_ATTRIBUTE_CHANGED_FUNCTION);
266             if (f != NULL)
267             {
268                 // emberAfPushEndpointNetworkIndex(endpoint);
269                 ((EmberAfManufacturerSpecificClusterAttributeChangedCallback) f)(endpoint, attributeId, manufacturerCode);
270                 // emberAfPopNetworkIndex();
271             }
272         }
273     }
274 }
275
276 // This function is used to call the per-cluster pre-attribute changed callback
277 EmberAfStatus emAfClusterPreAttributeChangedCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
278                                                      uint8_t clientServerMask, uint16_t manufacturerCode,
279                                                      EmberAfAttributeType attributeType, uint8_t size, uint8_t * value)
280 {
281     EmberAfCluster * cluster = emberAfFindClusterWithMfgCode(endpoint, clusterId, clientServerMask, manufacturerCode);
282     if (cluster == NULL)
283     {
284         return EMBER_ZCL_STATUS_UNSUPPORTED_ATTRIBUTE;
285     }
286     else
287     {
288         EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
289         if (manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE)
290         {
291             EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, CLUSTER_MASK_PRE_ATTRIBUTE_CHANGED_FUNCTION);
292             if (f != NULL)
293             {
294                 // emberAfPushEndpointNetworkIndex(endpoint);
295                 status = ((EmberAfClusterPreAttributeChangedCallback) f)(endpoint, attributeId, attributeType, size, value);
296                 // emberAfPopNetworkIndex();
297             }
298         }
299         return status;
300     }
301 }
302
303 static void initializeEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
304 {
305     uint8_t clusterIndex;
306     EmberAfEndpointType * epType = definedEndpoint->endpointType;
307     // emberAfPushEndpointNetworkIndex(definedEndpoint->endpoint);
308     for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
309     {
310         EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
311         EmberAfGenericClusterFunction f;
312         emberAfClusterInitCallback(definedEndpoint->endpoint, cluster->clusterId);
313         f = emberAfFindClusterFunction(cluster, CLUSTER_MASK_INIT_FUNCTION);
314         if (f != NULL)
315         {
316             ((EmberAfInitFunction) f)(definedEndpoint->endpoint);
317         }
318     }
319     // emberAfPopNetworkIndex();
320 }
321
322 // Calls the init functions.
323 void emAfCallInits(void)
324 {
325     uint8_t index;
326     for (index = 0; index < emberAfEndpointCount(); index++)
327     {
328         if (emberAfEndpointIndexIsEnabled(index))
329         {
330             initializeEndpoint(&(emAfEndpoints[index]));
331         }
332     }
333 }
334
335 // Returns the pointer to metadata, or null if it is not found
336 EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
337                                                           uint8_t mask, uint16_t manufacturerCode)
338 {
339     EmberAfAttributeMetadata * metadata = NULL;
340     EmberAfAttributeSearchRecord record;
341     record.endpoint         = endpoint;
342     record.clusterId        = clusterId;
343     record.clusterMask      = mask;
344     record.attributeId      = attributeId;
345     record.manufacturerCode = manufacturerCode;
346     emAfReadOrWriteAttribute(&record, &metadata,
347                              NULL,   // buffer
348                              0,      // buffer size
349                              false); // write?
350     return metadata;
351 }
352
353 static uint8_t * singletonAttributeLocation(EmberAfAttributeMetadata * am)
354 {
355     EmberAfAttributeMetadata * m = (EmberAfAttributeMetadata *) &(generatedAttributes[0]);
356     uint16_t index               = 0;
357     while (m < am)
358     {
359         if ((m->mask & ATTRIBUTE_MASK_SINGLETON) != 0U)
360         {
361             index = static_cast<uint16_t>(index + m->size);
362         }
363         m++;
364     }
365     return (uint8_t *) (singletonAttributeData + index);
366 }
367
368 // This function does mem copy, but smartly, which means that if the type is a
369 // string, it will copy as much as it can.
370 // If src == NULL, then this method will set memory to zeroes
371 // See documentation for emAfReadOrWriteAttribute for the semantics of
372 // readLength when reading and writing.
373 static EmberAfStatus typeSensitiveMemCopy(uint8_t * dest, uint8_t * src, EmberAfAttributeMetadata * am, bool write,
374                                           uint16_t readLength)
375 {
376     EmberAfAttributeType attributeType = am->attributeType;
377     // readLength == 0 for a read indicates that we should just trust that the
378     // caller has enough space for an attribute...
379     bool ignoreReadLength = write || (readLength == 0);
380     uint16_t bufferSize   = ignoreReadLength ? am->size : readLength;
381
382     if (emberAfIsStringAttributeType(attributeType))
383     {
384         if (bufferSize < 1)
385         {
386             return EMBER_ZCL_STATUS_INSUFFICIENT_SPACE;
387         }
388         emberAfCopyString(dest, src, static_cast<uint8_t>(bufferSize - 1));
389     }
390     else if (emberAfIsLongStringAttributeType(attributeType))
391     {
392         if (bufferSize < 2)
393         {
394             return EMBER_ZCL_STATUS_INSUFFICIENT_SPACE;
395         }
396         emberAfCopyLongString(dest, src, static_cast<uint16_t>(bufferSize - 2));
397     }
398     else
399     {
400         if (!ignoreReadLength && readLength < am->size)
401         {
402             return EMBER_ZCL_STATUS_INSUFFICIENT_SPACE;
403         }
404         if (src == NULL)
405         {
406             memset(dest, 0, am->size);
407         }
408         else
409         {
410             memmove(dest, src, am->size);
411         }
412     }
413     return EMBER_ZCL_STATUS_SUCCESS;
414 }
415
416 // Returns the manufacturer code or ::EMBER_AF_NULL_MANUFACTURER_CODE if none
417 // could be found.
418 static uint16_t getManufacturerCode(EmberAfManufacturerCodeEntry * codes, uint16_t codeTableSize, uint16_t tableIndex)
419 {
420     uint16_t i;
421     for (i = 0; i < codeTableSize; i++)
422     {
423         if (codes->index == tableIndex)
424         {
425             return codes->manufacturerCode;
426         }
427         codes++;
428     }
429     return EMBER_AF_NULL_MANUFACTURER_CODE;
430 }
431
432 // This function basically wraps getManufacturerCode with the parameters
433 // associating an attributes metadata with its code.
434 uint16_t emberAfGetMfgCode(EmberAfAttributeMetadata * metadata)
435 {
436     return getManufacturerCode((EmberAfManufacturerCodeEntry *) attributeManufacturerCodes, attributeManufacturerCodeCount,
437                                static_cast<uint16_t>((metadata - generatedAttributes)));
438 }
439
440 uint16_t emAfGetManufacturerCodeForAttribute(EmberAfCluster * cluster, EmberAfAttributeMetadata * attMetaData)
441 {
442     return (emberAfClusterIsManufacturerSpecific(cluster) ? emAfGetManufacturerCodeForCluster(cluster)
443                                                           : emberAfGetMfgCode(attMetaData));
444 }
445
446 uint16_t emAfGetManufacturerCodeForCluster(EmberAfCluster * cluster)
447 {
448     return getManufacturerCode((EmberAfManufacturerCodeEntry *) clusterManufacturerCodes, clusterManufacturerCodeCount,
449                                static_cast<uint16_t>(cluster - generatedClusters));
450 }
451
452 /**
453  * @brief Matches a cluster based on cluster id, direction and manufacturer code.
454  *   This function assumes that the passed cluster's endpoint already
455  *   matches the endpoint of the EmberAfAttributeSearchRecord.
456  *
457  * Cluster's match if:
458  *   1. Cluster ids match AND
459  *   2. Cluster directions match as defined by cluster->mask
460  *        and attRecord->clusterMask AND
461  *   3. If the clusters are mf specific, their mfg codes match.
462  */
463 bool emAfMatchCluster(EmberAfCluster * cluster, EmberAfAttributeSearchRecord * attRecord)
464 {
465     return (cluster->clusterId == attRecord->clusterId && cluster->mask & attRecord->clusterMask &&
466             (!emberAfClusterIsManufacturerSpecific(cluster) ||
467              (emAfGetManufacturerCodeForCluster(cluster) == attRecord->manufacturerCode)));
468 }
469
470 /**
471  * @brief Matches an attribute based on attribute id and manufacturer code.
472  *   This function assumes that the passed cluster already matches the
473  *   clusterId, direction and mf specificity of the passed
474  *   EmberAfAttributeSearchRecord.
475  *
476  * Note: If both the attribute and cluster are manufacturer specific,
477  *   the cluster's mf code gets precedence.
478  *
479  * Attributes match if:
480  *   1. Att ids match AND
481  *      a. cluster IS mf specific OR
482  *      b. both stored and saught attributes are NOT mf specific OR
483  *      c. stored att IS mf specific AND mfg codes match.
484  */
485 bool emAfMatchAttribute(EmberAfCluster * cluster, EmberAfAttributeMetadata * am, EmberAfAttributeSearchRecord * attRecord)
486 {
487     return (am->attributeId == attRecord->attributeId &&
488             (emberAfClusterIsManufacturerSpecific(cluster) ||
489              (emAfGetManufacturerCodeForAttribute(cluster, am) == attRecord->manufacturerCode)));
490 }
491
492 // When reading non-string attributes, this function returns an error when destination
493 // buffer isn't large enough to accommodate the attribute type.  For strings, the
494 // function will copy at most readLength bytes.  This means the resulting string
495 // may be truncated.  The length byte(s) in the resulting string will reflect
496 // any truncation.  If readLength is zero, we are working with backwards-
497 // compatibility wrapper functions and we just cross our fingers and hope for
498 // the best.
499 //
500 // When writing attributes, readLength is ignored.  For non-string attributes,
501 // this function assumes the source buffer is the same size as the attribute
502 // type.  For strings, the function will copy as many bytes as will fit in the
503 // attribute.  This means the resulting string may be truncated.  The length
504 // byte(s) in the resulting string will reflect any truncated.
505 EmberAfStatus emAfReadOrWriteAttribute(EmberAfAttributeSearchRecord * attRecord, EmberAfAttributeMetadata ** metadata,
506                                        uint8_t * buffer, uint16_t readLength, bool write)
507 {
508     uint8_t i;
509     uint16_t attributeOffsetIndex = 0;
510
511     for (i = 0; i < emberAfEndpointCount(); i++)
512     {
513         if (emAfEndpoints[i].endpoint == attRecord->endpoint)
514         {
515             EmberAfEndpointType * endpointType = emAfEndpoints[i].endpointType;
516             uint8_t clusterIndex;
517             if (!emberAfEndpointIndexIsEnabled(i))
518             {
519                 continue;
520             }
521             for (clusterIndex = 0; clusterIndex < endpointType->clusterCount; clusterIndex++)
522             {
523                 EmberAfCluster * cluster = &(endpointType->cluster[clusterIndex]);
524                 if (emAfMatchCluster(cluster, attRecord))
525                 { // Got the cluster
526                     uint16_t attrIndex;
527                     for (attrIndex = 0; attrIndex < cluster->attributeCount; attrIndex++)
528                     {
529                         EmberAfAttributeMetadata * am = &(cluster->attributes[attrIndex]);
530                         if (emAfMatchAttribute(cluster, am, attRecord))
531                         { // Got the attribute
532                             // If passed metadata location is not null, populate
533                             if (metadata != NULL)
534                             {
535                                 *metadata = am;
536                             }
537
538                             {
539                                 uint8_t * attributeLocation =
540                                     (am->mask & ATTRIBUTE_MASK_SINGLETON ? singletonAttributeLocation(am)
541                                                                          : attributeData + attributeOffsetIndex);
542                                 uint8_t *src, *dst;
543                                 if (write)
544                                 {
545                                     src = buffer;
546                                     dst = attributeLocation;
547                                     if (!emberAfAttributeWriteAccessCallback(attRecord->endpoint, attRecord->clusterId,
548                                                                              emAfGetManufacturerCodeForAttribute(cluster, am),
549                                                                              am->attributeId))
550                                     {
551                                         return EMBER_ZCL_STATUS_NOT_AUTHORIZED;
552                                     }
553                                 }
554                                 else
555                                 {
556                                     if (buffer == NULL)
557                                     {
558                                         return EMBER_ZCL_STATUS_SUCCESS;
559                                     }
560
561                                     src = attributeLocation;
562                                     dst = buffer;
563                                     if (!emberAfAttributeReadAccessCallback(attRecord->endpoint, attRecord->clusterId,
564                                                                             emAfGetManufacturerCodeForAttribute(cluster, am),
565                                                                             am->attributeId))
566                                     {
567                                         return EMBER_ZCL_STATUS_NOT_AUTHORIZED;
568                                     }
569                                 }
570
571                                 return (am->mask & ATTRIBUTE_MASK_EXTERNAL_STORAGE
572                                             ? (write) ? emberAfExternalAttributeWriteCallback(
573                                                             attRecord->endpoint, attRecord->clusterId, am,
574                                                             emAfGetManufacturerCodeForAttribute(cluster, am), buffer)
575                                                       : emberAfExternalAttributeReadCallback(
576                                                             attRecord->endpoint, attRecord->clusterId, am,
577                                                             emAfGetManufacturerCodeForAttribute(cluster, am), buffer,
578                                                             emberAfAttributeSize(am))
579                                             : typeSensitiveMemCopy(dst, src, am, write, readLength));
580                             }
581                         }
582                         else
583                         { // Not the attribute we are looking for
584                             // Increase the index if attribute is not externally stored
585                             if (!(am->mask & ATTRIBUTE_MASK_EXTERNAL_STORAGE) && !(am->mask & ATTRIBUTE_MASK_SINGLETON))
586                             {
587                                 attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emberAfAttributeSize(am));
588                             }
589                         }
590                     }
591                 }
592                 else
593                 { // Not the cluster we are looking for
594                     attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + cluster->clusterSize);
595                 }
596             }
597         }
598         else
599         { // Not the endpoint we are looking for
600             attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emAfEndpoints[i].endpointType->endpointSize);
601         }
602     }
603     return EMBER_ZCL_STATUS_UNSUPPORTED_ATTRIBUTE; // Sorry, attribute was not found.
604 }
605
606 // Check if a cluster is implemented or not. If yes, the cluster is returned.
607 // If the cluster is not manufacturerSpecific [ClusterId < FC00] then
608 // manufacturerCode argument is ignored otherwise checked.
609 //
610 // mask = 0 -> find either client or server
611 // mask = CLUSTER_MASK_CLIENT -> find client
612 // mask = CLUSTER_MASK_SERVER -> find server
613 EmberAfCluster * emberAfFindClusterInTypeWithMfgCode(EmberAfEndpointType * endpointType, ClusterId clusterId,
614                                                      EmberAfClusterMask mask, uint16_t manufacturerCode)
615 {
616     uint8_t i;
617     for (i = 0; i < endpointType->clusterCount; i++)
618     {
619         EmberAfCluster * cluster = &(endpointType->cluster[i]);
620         if (cluster->clusterId == clusterId &&
621             (mask == 0 || (mask == CLUSTER_MASK_CLIENT && emberAfClusterIsClient(cluster)) ||
622              (mask == CLUSTER_MASK_SERVER && emberAfClusterIsServer(cluster))) &&
623             (!emberAfClusterIsManufacturerSpecific(cluster) ||
624              (emAfGetManufacturerCodeForCluster(cluster) == manufacturerCode)
625              // For compatibility with older stack api, we ignore manufacturer code here
626              // if the manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE
627              || manufacturerCode == EMBER_AF_NULL_MANUFACTURER_CODE))
628         {
629             return cluster;
630         }
631     }
632     return NULL;
633 }
634
635 // This functions wraps emberAfFindClusterInTypeWithMfgCode with
636 // a manufacturerCode of EMBER_AF_NULL_MANUFACTURER_CODE.
637 EmberAfCluster * emberAfFindClusterInType(EmberAfEndpointType * endpointType, ClusterId clusterId, EmberAfClusterMask mask)
638 {
639     return emberAfFindClusterInTypeWithMfgCode(endpointType, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE);
640 }
641
642 // This code is used during unit tests for clusters that do not involve manufacturer code.
643 // Should this code be used in other locations, manufacturerCode should be added.
644 uint8_t emberAfClusterIndex(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask)
645 {
646     uint8_t ep;
647     uint8_t index = 0xFF;
648     for (ep = 0; ep < emberAfEndpointCount(); ep++)
649     {
650         EmberAfEndpointType * endpointType = emAfEndpoints[ep].endpointType;
651         if (emberAfFindClusterInTypeWithMfgCode(endpointType, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL)
652         {
653             index++;
654             if (emAfEndpoints[ep].endpoint == endpoint)
655             {
656                 return index;
657             }
658         }
659     }
660     return 0xFF;
661 }
662
663 // Returns true uf endpoint contains passed cluster
664 bool emberAfContainsClusterWithMfgCode(EndpointId endpoint, ClusterId clusterId, uint16_t manufacturerCode)
665 {
666     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, 0, manufacturerCode) != NULL);
667 }
668
669 // Returns true if endpoint contains passed cluster as a server
670 bool emberAfContainsServerWithMfgCode(EndpointId endpoint, ClusterId clusterId, uint16_t manufacturerCode)
671 {
672     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_SERVER, manufacturerCode) != NULL);
673 }
674
675 // Returns true if endpoint contains passed cluster as a client
676 bool emberAfContainsClientWithMfgCode(EndpointId endpoint, ClusterId clusterId, uint16_t manufacturerCode)
677 {
678     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_CLIENT, manufacturerCode) != NULL);
679 }
680
681 // Wraps emberAfContainsClusterWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE
682 // This will find the first cluster that has the clusterId given, regardless of mfgCode.
683 bool emberAfContainsCluster(EndpointId endpoint, ClusterId clusterId)
684 {
685     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, 0, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL);
686 }
687
688 // Wraps emberAfContainsServerWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE
689 // This will find the first server that has the clusterId given, regardless of mfgCode.
690 bool emberAfContainsServer(EndpointId endpoint, ClusterId clusterId)
691 {
692     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_SERVER, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL);
693 }
694
695 // Wraps emberAfContainsClientWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE
696 // This will find the first client that has the clusterId given, regardless of mfgCode.
697 bool emberAfContainsClient(EndpointId endpoint, ClusterId clusterId)
698 {
699     return (emberAfFindClusterWithMfgCode(endpoint, clusterId, CLUSTER_MASK_CLIENT, EMBER_AF_NULL_MANUFACTURER_CODE) != NULL);
700 }
701
702 // Finds the cluster that matches endpoint, clusterId, direction, and manufacturerCode.
703 EmberAfCluster * emberAfFindClusterWithMfgCode(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask,
704                                                uint16_t manufacturerCode)
705 {
706     uint8_t ep = emberAfIndexFromEndpoint(endpoint);
707     if (ep == 0xFF)
708     {
709         return NULL;
710     }
711     else
712     {
713         return emberAfFindClusterInTypeWithMfgCode(emAfEndpoints[ep].endpointType, clusterId, mask, manufacturerCode);
714     }
715 }
716
717 // This function wraps emberAfFindClusterWithMfgCode with EMBER_AF_NULL_MANUFACTURER_CODE
718 // and will ignore the manufacturerCode when trying to find clusters.
719 // This will return the first cluster in the cluster table that matches the parameters given.
720 EmberAfCluster * emberAfFindCluster(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask)
721 {
722     return emberAfFindClusterWithMfgCode(endpoint, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE);
723 }
724
725 // Returns cluster within the endpoint; Does not ignore disabled endpoints
726 EmberAfCluster * emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(EndpointId endpoint, ClusterId clusterId,
727                                                                          EmberAfClusterMask mask, uint16_t manufacturerCode)
728 {
729     uint8_t ep = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpoint);
730     if (ep < MAX_ENDPOINT_COUNT)
731     {
732         return emberAfFindClusterInTypeWithMfgCode(emAfEndpoints[ep].endpointType, clusterId, mask, manufacturerCode);
733     }
734     return NULL;
735 }
736
737 // Returns cluster within the endpoint; Does not ignore disabled endpoints
738 // This will ignore manufacturerCode.
739 EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask)
740 {
741     return emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(endpoint, clusterId, mask, EMBER_AF_NULL_MANUFACTURER_CODE);
742 }
743
744 // Server wrapper for findClusterEndpointIndex.
745 static uint8_t emberAfFindClusterServerEndpointIndexWithMfgCode(EndpointId endpoint, ClusterId clusterId, uint16_t manufacturerCode)
746 {
747     return findClusterEndpointIndex(endpoint, clusterId, CLUSTER_MASK_SERVER, manufacturerCode);
748 }
749
750 // Client wrapper for findClusterEndpointIndex.
751 uint8_t emberAfFindClusterClientEndpointIndexWithMfgCode(EndpointId endpoint, ClusterId clusterId, uint16_t manufacturerCode)
752 {
753     return findClusterEndpointIndex(endpoint, clusterId, CLUSTER_MASK_CLIENT, manufacturerCode);
754 }
755
756 // Server wrapper for findClusterEndpointIndex
757 // This will ignore manufacturerCode, and return the index for the first server that matches on clusterId
758 uint8_t emberAfFindClusterServerEndpointIndex(EndpointId endpoint, ClusterId clusterId)
759 {
760     return emberAfFindClusterServerEndpointIndexWithMfgCode(endpoint, clusterId, EMBER_AF_NULL_MANUFACTURER_CODE);
761 }
762
763 // Client wrapper for findClusterEndpointIndex
764 // This will ignore manufacturerCode, and return the index for the first client that matches on clusterId
765 uint8_t emberAfFindClusterClientEndpointIndex(EndpointId endpoint, ClusterId clusterId)
766 {
767     return emberAfFindClusterClientEndpointIndexWithMfgCode(endpoint, clusterId, EMBER_AF_NULL_MANUFACTURER_CODE);
768 }
769
770 // Returns the endpoint index within a given cluster
771 static uint8_t findClusterEndpointIndex(EndpointId endpoint, ClusterId clusterId, uint8_t mask, uint16_t manufacturerCode)
772 {
773     uint8_t i, epi = 0;
774
775     if (emberAfFindClusterWithMfgCode(endpoint, clusterId, mask, manufacturerCode) == NULL)
776     {
777         return 0xFF;
778     }
779
780     for (i = 0; i < emberAfEndpointCount(); i++)
781     {
782         if (emAfEndpoints[i].endpoint == endpoint)
783         {
784             break;
785         }
786         epi = static_cast<uint8_t>(epi +
787                                    ((emberAfFindClusterIncludingDisabledEndpointsWithMfgCode(emAfEndpoints[i].endpoint, clusterId,
788                                                                                              mask, manufacturerCode) != NULL)
789                                         ? 1
790                                         : 0));
791     }
792
793     return epi;
794 }
795
796 static uint8_t findIndexFromEndpoint(EndpointId endpoint, bool ignoreDisabledEndpoints)
797 {
798     uint8_t epi;
799     for (epi = 0; epi < emberAfEndpointCount(); epi++)
800     {
801         if (emAfEndpoints[epi].endpoint == endpoint &&
802             (!ignoreDisabledEndpoints || emAfEndpoints[epi].bitmask & EMBER_AF_ENDPOINT_ENABLED))
803         {
804             return epi;
805         }
806     }
807     return 0xFF;
808 }
809
810 bool emberAfEndpointIsEnabled(EndpointId endpoint)
811 {
812     uint8_t index = findIndexFromEndpoint(endpoint,
813                                           false); // ignore disabled endpoints?
814
815     EMBER_TEST_ASSERT(0xFF != index);
816
817     if (0xFF == index)
818     {
819         return false;
820     }
821
822     return emberAfEndpointIndexIsEnabled(index);
823 }
824
825 // bool emberAfEndpointEnableDisable(EndpointId endpoint, bool enable)
826 // {
827 //     uint8_t index = findIndexFromEndpoint(endpoint,
828 //                                           false); // ignore disabled endpoints?
829 //     bool currentlyEnabled;
830
831 //     if (0xFF == index)
832 //     {
833 //         return false;
834 //     }
835
836 //     currentlyEnabled = emAfEndpoints[index].bitmask & EMBER_AF_ENDPOINT_ENABLED;
837
838 //     if (enable)
839 //     {
840 //         emAfEndpoints[index].bitmask |= EMBER_AF_ENDPOINT_ENABLED;
841 //     }
842 //     else
843 //     {
844 //         emAfEndpoints[index].bitmask &= EMBER_AF_ENDPOINT_DISABLED;
845 //     }
846
847 // #if defined(EZSP_HOST)
848 //     ezspSetEndpointFlags(endpoint, (enable ? EZSP_ENDPOINT_ENABLED : EZSP_ENDPOINT_DISABLED));
849 // #endif
850
851 //     if (currentlyEnabled != enable)
852 //     {
853 //         if (enable)
854 //         {
855 //             initializeEndpoint(&(emAfEndpoints[index]));
856 //         }
857 //         else
858 //         {
859 //             uint8_t i;
860 //             for (i = 0; i < emAfEndpoints[index].endpointType->clusterCount; i++)
861 //             {
862 //                 EmberAfCluster * cluster = &((emAfEndpoints[index].endpointType->cluster)[i]);
863 //                 //        emberAfCorePrintln("Disabling cluster tick for ep:%d, cluster:0x%2X, %p",
864 //                 //                           endpoint,
865 //                 //                           cluster->clusterId,
866 //                 //                           ((cluster->mask & CLUSTER_MASK_CLIENT)
867 //                 //                            ? "client"
868 //                 //                            : "server"));
869 //                 //        emberAfCoreFlush();
870 //                 emberAfDeactivateClusterTick(
871 //                     endpoint, cluster->clusterId,
872 //                     (cluster->mask & CLUSTER_MASK_CLIENT ? EMBER_AF_CLIENT_CLUSTER_TICK : EMBER_AF_SERVER_CLUSTER_TICK));
873 //             }
874 //         }
875 //     }
876
877 //     return true;
878 // }
879
880 // Returns the index of a given endpoint.  Does not consider disabled endpoints.
881 uint8_t emberAfIndexFromEndpoint(EndpointId endpoint)
882 {
883     return findIndexFromEndpoint(endpoint,
884                                  true); // ignore disabled endpoints?
885 }
886
887 // Returns the index of a given endpoint.  Considers disabled endpoints.
888 uint8_t emberAfIndexFromEndpointIncludingDisabledEndpoints(EndpointId endpoint)
889 {
890     return findIndexFromEndpoint(endpoint,
891                                  false); // ignore disabled endpoints?
892 }
893
894 EndpointId emberAfEndpointFromIndex(uint8_t index)
895 {
896     return emAfEndpoints[index].endpoint;
897 }
898
899 // If server == true, returns the number of server clusters,
900 // otherwise number of client clusters on this endpoint
901 uint8_t emberAfClusterCount(EndpointId endpoint, bool server)
902 {
903     uint8_t index = emberAfIndexFromEndpoint(endpoint);
904     uint8_t i, c = 0;
905     EmberAfDefinedEndpoint * de;
906     EmberAfCluster * cluster;
907
908     if (index == 0xFF)
909     {
910         return 0;
911     }
912     de = &(emAfEndpoints[index]);
913     if (de->endpointType == NULL)
914     {
915         return 0;
916     }
917     for (i = 0; i < de->endpointType->clusterCount; i++)
918     {
919         cluster = &(de->endpointType->cluster[i]);
920         if (server && emberAfClusterIsServer(cluster))
921         {
922             c++;
923         }
924         if ((!server) && emberAfClusterIsClient(cluster))
925         {
926             c++;
927         }
928     }
929     return c;
930 }
931
932 uint8_t emberAfGetClusterCountForEndpoint(EndpointId endpoint)
933 {
934     uint8_t index = emberAfIndexFromEndpoint(endpoint);
935     if (index == 0xFF)
936     {
937         return 0;
938     }
939     return emAfEndpoints[index].endpointType->clusterCount;
940 }
941
942 // Note the difference in implementation from emberAfGetNthCluster().
943 // emberAfGetClusterByIndex() retrieves the cluster by index regardless of server/client
944 // and those indexes may be DIFFERENT than the indexes returned from
945 // emberAfGetNthCluster().  In other words:
946 //
947 //  - Use emberAfGetClustersFromEndpoint()  with emberAfGetNthCluster()
948 //  - Use emberAfGetClusterCountForEndpoint() with emberAfGetClusterByIndex()
949 //
950 // Don't mix them.
951 EmberAfCluster * emberAfGetClusterByIndex(EndpointId endpoint, uint8_t clusterIndex)
952 {
953     uint8_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
954     EmberAfDefinedEndpoint * definedEndpoint;
955
956     if (endpointIndex == 0xFF)
957     {
958         return NULL;
959     }
960     definedEndpoint = &(emAfEndpoints[endpointIndex]);
961
962     if (clusterIndex >= definedEndpoint->endpointType->clusterCount)
963     {
964         return NULL;
965     }
966     return &(definedEndpoint->endpointType->cluster[clusterIndex]);
967 }
968
969 uint16_t emberAfGetDeviceIdForEndpoint(EndpointId endpoint)
970 {
971     uint8_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
972     if (endpointIndex == 0xFF)
973     {
974         return 0xFFFF;
975     }
976     return emAfEndpoints[endpointIndex].deviceId;
977 }
978
979 // Returns the cluster of Nth server or client cluster,
980 // depending on server toggle.
981 EmberAfCluster * emberAfGetNthCluster(EndpointId endpoint, uint8_t n, bool server)
982 {
983     uint8_t index = emberAfIndexFromEndpoint(endpoint);
984     EmberAfDefinedEndpoint * de;
985     uint8_t i, c = 0;
986     EmberAfCluster * cluster;
987
988     if (index == 0xFF)
989     {
990         return NULL;
991     }
992     de = &(emAfEndpoints[index]);
993
994     for (i = 0; i < de->endpointType->clusterCount; i++)
995     {
996         cluster = &(de->endpointType->cluster[i]);
997
998         if ((server && emberAfClusterIsServer(cluster)) || ((!server) && emberAfClusterIsClient(cluster)))
999         {
1000             if (c == n)
1001             {
1002                 return cluster;
1003             }
1004             c++;
1005         }
1006     }
1007     return NULL;
1008 }
1009
1010 // Returns number of clusters put into the passed cluster list
1011 // for the given endpoint and client/server polarity
1012 uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server)
1013 {
1014     uint8_t clusterCount = emberAfClusterCount(endpoint, server);
1015     uint8_t i;
1016     EmberAfCluster * cluster;
1017     if (clusterCount > listLen)
1018     {
1019         clusterCount = listLen;
1020     }
1021     for (i = 0; i < clusterCount; i++)
1022     {
1023         cluster        = emberAfGetNthCluster(endpoint, i, server);
1024         clusterList[i] = (cluster == NULL ? 0xFFFF : cluster->clusterId);
1025     }
1026     return clusterCount;
1027 }
1028
1029 void emberAfInitializeAttributes(EndpointId endpoint)
1030 {
1031     emAfLoadAttributeDefaults(endpoint, false);
1032 }
1033
1034 void emberAfResetAttributes(EndpointId endpoint)
1035 {
1036     emAfLoadAttributeDefaults(endpoint, true);
1037 }
1038
1039 void emAfLoadAttributeDefaults(EndpointId endpoint, bool writeTokens)
1040 {
1041     uint8_t ep, clusterI, curNetwork = 0 /* emberGetCurrentNetwork() */;
1042     uint16_t attr;
1043     uint8_t * ptr;
1044     uint8_t epCount = emberAfEndpointCount();
1045
1046     for (ep = 0; ep < epCount; ep++)
1047     {
1048         EmberAfDefinedEndpoint * de;
1049         if (endpoint != EMBER_BROADCAST_ENDPOINT)
1050         {
1051             ep = emberAfIndexFromEndpoint(endpoint);
1052             if (ep == 0xFF)
1053             {
1054                 return;
1055             }
1056         }
1057         de = &(emAfEndpoints[ep]);
1058
1059         // Ensure that the endpoint is on the current network
1060         if (endpoint == EMBER_BROADCAST_ENDPOINT && de->networkIndex != curNetwork)
1061         {
1062             continue;
1063         }
1064         for (clusterI = 0; clusterI < de->endpointType->clusterCount; clusterI++)
1065         {
1066             EmberAfCluster * cluster = &(de->endpointType->cluster[clusterI]);
1067
1068             // when the attributeCount is high, the loop takes too long to run and a
1069             // watchdog kicks in causing a reset. As a workaround, we'll
1070             // conditionally manually reset the watchdog. 300 sounds like a good
1071             // magic number for now.
1072             if (cluster->attributeCount > 300)
1073             {
1074                 // halResetWatchdog();
1075             }
1076             for (attr = 0; attr < cluster->attributeCount; attr++)
1077             {
1078                 EmberAfAttributeMetadata * am = &(cluster->attributes[attr]);
1079                 if (!(am->mask & ATTRIBUTE_MASK_EXTERNAL_STORAGE))
1080                 {
1081                     EmberAfAttributeSearchRecord record;
1082                     record.endpoint         = de->endpoint;
1083                     record.clusterId        = cluster->clusterId;
1084                     record.clusterMask      = (emberAfAttributeIsClient(am) ? CLUSTER_MASK_CLIENT : CLUSTER_MASK_SERVER);
1085                     record.attributeId      = am->attributeId;
1086                     record.manufacturerCode = emAfGetManufacturerCodeForAttribute(cluster, am);
1087                     if ((am->mask & ATTRIBUTE_MASK_MIN_MAX) != 0U)
1088                     {
1089                         if (emberAfAttributeSize(am) <= 2)
1090                         {
1091                             ptr = (uint8_t *) &(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue);
1092                         }
1093                         else
1094                         {
1095                             ptr = (uint8_t *) am->defaultValue.ptrToMinMaxValue->defaultValue.ptrToDefaultValue;
1096                         }
1097                     }
1098                     else
1099                     {
1100                         if (emberAfAttributeSize(am) <= 2)
1101                         {
1102                             ptr = (uint8_t *) &(am->defaultValue.defaultValue);
1103                         }
1104                         else
1105                         {
1106                             ptr = (uint8_t *) am->defaultValue.ptrToDefaultValue;
1107                         }
1108                     }
1109                     // At this point, ptr either points to a default value, or is NULL, in which case
1110                     // it should be treated as if it is pointing to an array of all zeroes.
1111
1112 #if (BIGENDIAN_CPU)
1113                     // The default value for one- and two-byte attributes is stored in an
1114                     // uint16_t.  On big-endian platforms, a pointer to the default value of
1115                     // a one-byte attribute will point to the wrong byte.  So, for those
1116                     // cases, nudge the pointer forward so it points to the correct byte.
1117                     if (emberAfAttributeSize(am) == 1 && ptr != NULL)
1118                     {
1119                         *ptr++;
1120                     }
1121 #endif // BIGENDIAN
1122                     emAfReadOrWriteAttribute(&record,
1123                                              NULL, // metadata - unused
1124                                              ptr,
1125                                              0,     // buffer size - unused
1126                                              true); // write?
1127                     if (writeTokens)
1128                     {
1129                         emAfSaveAttributeToToken(ptr, de->endpoint, record.clusterId, am);
1130                     }
1131                 }
1132             }
1133         }
1134         if (endpoint != EMBER_BROADCAST_ENDPOINT)
1135         {
1136             break;
1137         }
1138     }
1139
1140     if (!writeTokens)
1141     {
1142         emAfLoadAttributesFromTokens(endpoint);
1143     }
1144 }
1145
1146 void emAfLoadAttributesFromTokens(EndpointId endpoint)
1147 {
1148     // On EZSP host we currently do not support this. We need to come up with some
1149     // callbacks.
1150 #ifndef EZSP_HOST
1151     GENERATED_TOKEN_LOADER(endpoint);
1152 #endif // EZSP_HOST
1153 }
1154
1155 // 'data' argument may be null, since we changed the ptrToDefaultValue
1156 // to be null instead of pointing to all zeroes.
1157 // This function has to be able to deal with that.
1158 void emAfSaveAttributeToToken(uint8_t * data, EndpointId endpoint, ClusterId clusterId, EmberAfAttributeMetadata * metadata)
1159 {
1160     // Get out of here if this attribute doesn't have a token.
1161     if (!emberAfAttributeIsTokenized(metadata))
1162     {
1163         return;
1164     }
1165
1166 // On EZSP host we currently do not support this. We need to come up with some
1167 // callbacks.
1168 #ifndef EZSP_HOST
1169     GENERATED_TOKEN_SAVER;
1170 #endif // EZSP_HOST
1171 }
1172
1173 // This function returns the actual function point from the array,
1174 // iterating over the function bits.
1175 EmberAfGenericClusterFunction emberAfFindClusterFunction(EmberAfCluster * cluster, EmberAfClusterMask functionMask)
1176 {
1177     EmberAfClusterMask mask = 0x01;
1178     uint8_t functionIndex   = 0;
1179
1180     if ((cluster->mask & functionMask) == 0)
1181     {
1182         return NULL;
1183     }
1184
1185     while (mask < functionMask)
1186     {
1187         if ((cluster->mask & mask) != 0)
1188         {
1189             functionIndex++;
1190         }
1191         mask = static_cast<EmberAfClusterMask>(mask << 1);
1192     }
1193     return cluster->functions[functionIndex];
1194 }
1195
1196 #ifdef EMBER_AF_SUPPORT_COMMAND_DISCOVERY
1197
1198 uint16_t emAfGetManufacturerCodeForCommand(EmberAfCommandMetadata * command)
1199 {
1200     return getManufacturerCode((EmberAfManufacturerCodeEntry *) commandManufacturerCodes, commandManufacturerCodeCount,
1201                                static_cast<uint16_t>(command - generatedCommands));
1202 }
1203
1204 /**
1205  * This function populates command IDs into a given buffer.
1206  *
1207  * It returns true if commands are complete, meaning there are NO MORE
1208  * commands that would be returned after the last command.
1209  * It returns false, if there were more commands, but were not populated
1210  * because of maxIdCount limitation.
1211  */
1212 bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, ClusterId clusterId, uint8_t * buffer,
1213                               uint16_t bufferLength, uint16_t * bufferIndex, uint8_t startId, uint8_t maxIdCount)
1214 {
1215     uint16_t i, count = 0;
1216     bool returnValue   = true;
1217     uint8_t cmdDirMask = 0;
1218
1219     // determine the appropriate mask to match the request
1220     // discover commands generated, client is asking server what commands do you generate?
1221     if (outgoing && (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER))
1222     {
1223         cmdDirMask = COMMAND_MASK_OUTGOING_SERVER;
1224         // discover commands generated server is asking client what commands do you generate?
1225     }
1226     else if (outgoing && (cmd->direction == ZCL_DIRECTION_SERVER_TO_CLIENT))
1227     {
1228         cmdDirMask = COMMAND_MASK_OUTGOING_CLIENT;
1229         // discover commands received client is asking server what commands do you receive?
1230     }
1231     else if (!outgoing && (cmd->direction == ZCL_DIRECTION_CLIENT_TO_SERVER))
1232     {
1233         cmdDirMask = COMMAND_MASK_INCOMING_SERVER;
1234         // discover commands received server is asking client what commands do you receive?
1235     }
1236     else
1237     {
1238         cmdDirMask = COMMAND_MASK_INCOMING_CLIENT;
1239     }
1240
1241     for (i = 0; i < EMBER_AF_GENERATED_COMMAND_COUNT; i++)
1242     {
1243         if (generatedCommands[i].clusterId != clusterId)
1244         {
1245             continue;
1246         }
1247
1248         if ((generatedCommands[i].mask & cmdDirMask) == 0)
1249         {
1250             continue;
1251         }
1252
1253         // Only start from the passed command id
1254         if (generatedCommands[i].commandId < startId)
1255         {
1256             continue;
1257         }
1258
1259         // According to spec: if cmd->mfgSpecific is set, then we ONLY return the
1260         // mfg specific commands. If it's not, then we ONLY return non-mfg specific.
1261         if (generatedCommands[i].mask & COMMAND_MASK_MANUFACTURER_SPECIFIC)
1262         {
1263             // Command is Mfg specific
1264             if (!cmd->mfgSpecific)
1265             {
1266                 continue; // ignore if asking for not mfg specific
1267             }
1268             if (cmd->mfgCode != emAfGetManufacturerCodeForCommand((EmberAfCommandMetadata *) &(generatedCommands[i])))
1269             {
1270                 continue; // Ignore if mfg code doesn't match the commands
1271             }
1272         }
1273         else
1274         {
1275             // Command is not mfg specific.
1276             if (cmd->mfgSpecific)
1277             {
1278                 continue; // Ignore if asking for mfg specific
1279             }
1280         }
1281
1282         // The one we are about to put in, is beyond the maxIdCount,
1283         // so instead of populating it in, we set the return flag to
1284         // false and get out of here.
1285         if (maxIdCount == count || count >= bufferLength)
1286         {
1287             returnValue = false;
1288             break;
1289         }
1290         buffer[count] = generatedCommands[i].commandId;
1291         (*bufferIndex)++;
1292         count++;
1293     }
1294     return returnValue;
1295 }
1296 #else
1297 // We just need an empty stub if we don't support it
1298 bool emberAfExtractCommandIds(bool outgoing, EmberAfClusterCommand * cmd, ClusterId clusterId, uint8_t * buffer,
1299                               uint16_t bufferLength, uint16_t * bufferIndex, uint8_t startId, uint8_t maxIdCount)
1300 {
1301     return true;
1302 }
1303 #endif