Welcome to mirror list, hosted at ThFree Co, Russian Federation.

zcl.h « zcl « include « stack « zigbee « STM32_WPAN « ST « Middlewares - github.com/Flipper-Zero/STM32CubeWB.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 67f1515c423a15d4b13e9e06216bfb04ff071b17 (plain)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
/* Copyright [2009 - 2019] Exegin Technologies Limited. All rights reserved. */

#ifndef ZCL_H
# define ZCL_H

#ifdef __cplusplus
extern "C" {
#endif

/* Needs to come before zigbee.h. Should remove zigbee.h include from this file. */
struct ZbZclClusterT;

#include "zigbee.h"
#include "pletoh.h"

/*---------------------------------------------------------------
 * ZCL Debug Logging
 *---------------------------------------------------------------
 */
/*lint -save -e762 [ Redundantly declared symbol ] */
/*lint -save -e9004 [ previously declared - MISRA 2012 Rule 8.5, required ] */
extern void ZbLogPrintf(struct ZigBeeT *zb, uint32_t mask, const char *hdr, const char *fmt, ...);
/*lint -restore */
/*lint -restore */

#ifndef CONFIG_ZB_LOG_ALLOWED_MASK
/* If not defined, then disable debugging (minimal Flash size) */
# define CONFIG_ZB_LOG_ALLOWED_MASK         ZB_LOG_MASK_LEVEL_0
#endif

/*lint -emacro(506,ZCL_LOG_PRINTF) */
/* Info 774: Boolean within 'if' always evaluates to False */
/*lint -emacro(774,ZCL_LOG_PRINTF) */
/*lint -emacro(831,ZCL_LOG_PRINTF) */

#if ((ZB_LOG_MASK_ZCL & CONFIG_ZB_LOG_ALLOWED_MASK) != 0U)
#define ZCL_LOG_PRINTF(zb, hdr, ...) \
    do { \
        if ((zb) == NULL) { \
            break; \
        } \
        ZbLogPrintf(zb, ZB_LOG_MASK_ZCL, hdr, __VA_ARGS__); \
    } while (false)
#else
#define ZCL_LOG_PRINTF(zb, hdr, ...)    (void)zb
#endif

/*---------------------------------------------------------------
 * ZCL Header
 *---------------------------------------------------------------
 */
/* ZCL Frame Control Field Bits and macros.. */
#define ZCL_FRAMECTRL_TYPE                       0x03U
#define ZCL_FRAMECTRL_MANUFACTURER               0x04U
#define ZCL_FRAMECTRL_DIRECTION                  0x08U /* set for client, clear for server */
#define ZCL_FRAMECTRL_DISABLE_DEFAULT_RESP       0x10U
#define ZCL_FRAMECTRL_RESERVED                   0xe0U

/* ZCL Frame Type Values */
#define ZCL_FRAMETYPE_PROFILE                    0x00U /* Global */
#define ZCL_FRAMETYPE_CLUSTER                    0x01U /* Cluster Specific */

/* ZCL Direction Values */
enum ZbZclDirectionT {
    ZCL_DIRECTION_TO_SERVER = 0,
    ZCL_DIRECTION_TO_CLIENT = 1,
    ZCL_DIRECTION_ANY = 2 /* Only used internally with ZbZclClusterBind */
};

enum ZbZclNoDefaultResponseT {
    ZCL_NO_DEFAULT_RESPONSE_FALSE = 0,
    ZCL_NO_DEFAULT_RESPONSE_TRUE = 1
};

/* Lengths of the ZCL header. */
#define ZCL_HEADER_MIN_SIZE                      3U
#define ZCL_HEADER_MAX_SIZE                      5U /* with 2-byte manufacturer code */

/* Max safe ZCL payload size (with APS security and no fragmentation)
 * This value will be less with application security.
 * Assumes not manufacturer specific command. */
#define ZCL_PAYLOAD_UNFRAG_SAFE_SIZE             (ZB_APS_CONST_SAFE_APSSEC_PAYLOAD_SIZE - ZCL_HEADER_MIN_SIZE) /* 54 */

/* Maximum ZSE Message size (after fragmentation). */
#define ZCL_ASDU_LENGTH_SMART_ENERGY             128U

/* ZCL Indicator Values */
#define ZCL_INDICATOR_DEPTH                      0x0fU
#define ZCL_INDICATOR_OPERATION                  0xf0U
#define ZCL_INDICATOR_REPLACE                    0x00U
#define ZCL_INDICATOR_INSERT                     0x10U
#define ZCL_INDICATOR_REMOVE                     0x20U
#define ZCL_INDICATOR_DEPTH_DECR(x)              (x = (x & ZCL_INDICATOR_OPERATION_MASK) | ((x - 1) & ZCL_INDICATOR_DEPTH))

/* ZCL Semi-Precision Floating Point Fields. */
#define ZCL_FLOAT_SEMI_MANTISSA                  0x03ffU
#define ZCL_FLOAT_SEMI_EXPONENT                  0x7c00U
#define ZCL_FLOAT_SEMI_SIGN                      0x8000U
#define ZCL_FLOAT_SEMI_HIDDEN_BIT                10U
/* ZCL Single-Precision Floating Point Fields. */
#define ZCL_FLOAT_SINGLE_MANTISSA                0x007fffffU
#define ZCL_FLOAT_SINGLE_EXPONENT                0x7f800000U
#define ZCL_FLOAT_SINGLE_SIGN                    0x80000000U
#define ZCL_FLOAT_SINGLE_HIDDEN_BIT              23U
/* ZCL Double-Precision Floating point Fields. */
#define ZCL_FLOAT_DOUBLE_MANTISSA                0x000fffffffffffffULL
#define ZCL_FLOAT_DOUBLE_EXPONENT                0x7ff0000000000000ULL
#define ZCL_FLOAT_DOUBLE_SIGN                    0x8000000000000000ULL
#define ZCL_FLOAT_DOUBLE_HIDDEN_BIT              52U

/* Floating Point Helper Macros */
#ifdef _MSC_VER
#include <float.h>
#define ZCL_FLOAT_INFINITY                       (DBL_MAX + DBL_MAX)
#define ZCL_FLOAT_NAN                            (ZCL_FLOAT_INFINITY - ZCL_FLOAT_INFINITY)
#else
#define ZCL_FLOAT_INFINITY                       (1.0 / 0.0)
#define ZCL_FLOAT_NAN                            (0.0 / 0.0)
#endif
#define ZCL_FLOAT_ISNAN(x)                       ((x) != (x))
#define ZCL_FLOAT_ISINF(x)                       (((x) == ZCL_FLOAT_INFINITY) || ((x) == -ZCL_FLOAT_INFINITY))

/* Smart Energy Preferred channels: 11, 14, 15, 19, 20, 24, 25 */
#define ZCL_CHANNELMASK_SMART_ENERGY             0x318c800UL

/* Profile IDs and Ranges */
enum {
    ZCL_PROFILE_ZB_STANDARD_MIN = 0x0000,
    /* Note: Legacy profile range does not include HA (0x0104) */
    ZCL_PROFILE_LEGACY_MIN = 0x0101,
    ZCL_PROFILE_HOME_AUTOMATION = 0x0104,
    ZCL_PROFILE_LEGACY_MAX = 0x0108,
    ZCL_PROFILE_SMART_ENERGY = 0x0109,
    ZCL_PROFILE_RETAIL_SERVICES = 0x010A,
    ZCL_PROFILE_TP2 = 0x7f01, /* ZigBee Test Profile #2 Profile Id */
    ZCL_PROFILE_ZB_STANDARD_MAX = 0x7fff,

    ZCL_PROFILE_MFR_SPECIFIC_MIN = 0xc000,
    ZCL_PROFILE_ZLL = 0xc05e,
    ZCL_PROFILE_C4 = 0xc25d,
    ZCL_PROFILE_WILDCARD = 0xffff /* Wildcard Profile ID */
};

/* Device ID Ranges */
enum {
    ZCL_DEVICE_ZB_STANDARD_MIN = 0x0000,
    ZCL_DEVICE_ZB_STANDARD_MAX = 0xbfff
};

/* Attribute ID Ranges */
enum {
    ZCL_ATTRIBUTE_ZB_STANDARD_MIN = 0x0000,
    ZCL_ATTRIBUTE_ZB_STANDARD_MAX = 0x3fff
};

/* Command ID Ranges */
enum {
    ZCL_COMMAND_ZB_STANDARD_MIN = 0x00,
    ZCL_COMMAND_ZB_STANDARD_MAX = 0x7f
};

/* Global Attributes */
enum {
    /* CLUSTER_REV attribute is automatically allocated and initialized by
     * a cluster's alloc function when it calls ZbZclClusterAlloc.
     * It does not need to be included in the cluster's attribute list
     * during initialization. The value may be modified by the cluster or
     * application after initialization (ZbZclAttrIntegerWrite). */
    ZCL_GLOBAL_ATTR_CLUSTER_REV = 0xfffd, /* Mandatory */
    ZCL_GLOBAL_ATTR_REPORTING_STATUS = 0xfffe /* Optional */
};

/* ZCL_GLOBAL_ATTR_CLUSTER_REV */
enum {
    ZCL_CLUSTER_REVISION_LEGACY = 0,
    ZCL_CLUSTER_REVISION_ZCL6 = 1,
    ZCL_CLUSTER_REVISION_ZCL7 = 2
};

/* ZCL Attribute Flags
 * These define characteristics for a particular attribute
 * (e.g. write permissions, is persisted, etc).  */
typedef uint16_t ZclAttrFlagT;
/* i.e. read-only, non-reportable, etc */
#define ZCL_ATTR_FLAG_NONE                  (ZclAttrFlagT)0x0000U
/* read-write */
#define ZCL_ATTR_FLAG_WRITABLE              (ZclAttrFlagT)0x0001U
/* attribute may be reported */
#define ZCL_ATTR_FLAG_REPORTABLE            (ZclAttrFlagT)0x0002U
/* attribute is persisted */
#define ZCL_ATTR_FLAG_PERSISTABLE           (ZclAttrFlagT)0x0004U
/* Which callbacks does the application support */
#define ZCL_ATTR_FLAG_CB_MASK               0x00f0U
#define ZCL_ATTR_FLAG_CB_READ               (ZclAttrFlagT)0x0010U /* ZCL_ATTR_CB_TYPE_READ */
#define ZCL_ATTR_FLAG_CB_WRITE              (ZclAttrFlagT)0x0020U /* ZCL_ATTR_CB_TYPE_WRITE */
#define ZCL_ATTR_FLAG_CB_NOTIFY             (ZclAttrFlagT)0x0040U /* ZCL_ATTR_CB_TYPE_NOTIFY */
/* This flag means the attribute is for internal use only. Not discoverable. */
#define ZCL_ATTR_FLAG_INTERNAL              (ZclAttrFlagT)0x8000U

/* ZCL Attribute Write-Mode Flags */
typedef uint16_t ZclWriteModeT;
/* Perform all sanity checks, and write if allowed. */
#define ZCL_ATTR_WRITE_FLAG_NORMAL          (ZclWriteModeT)0x0000U
/* Sanity-check only, don't modify attribute data. */
#define ZCL_ATTR_WRITE_FLAG_TEST            (ZclWriteModeT)0x0001U
/* If the attribute is read only, write anyways. */
#define ZCL_ATTR_WRITE_FLAG_FORCE           (ZclWriteModeT)0x0002U
/* Data is from persistence (sometimes the application needs to
 * know where the data is coming from). */
#define ZCL_ATTR_WRITE_FLAG_PERSIST         (ZclWriteModeT)0x0004U

/* ZCL Data Types */
enum ZclDataTypeT {
    ZCL_DATATYPE_NULL = 0x00,
    ZCL_DATATYPE_GENERAL_8BIT = 0x08,
    ZCL_DATATYPE_GENERAL_16BIT = 0x09,
    ZCL_DATATYPE_GENERAL_24BIT = 0x0a,
    ZCL_DATATYPE_GENERAL_32BIT = 0x0b,
    ZCL_DATATYPE_GENERAL_40BIT = 0x0c,
    ZCL_DATATYPE_GENERAL_48BIT = 0x0d,
    ZCL_DATATYPE_GENERAL_56BIT = 0x0e,
    ZCL_DATATYPE_GENERAL_64BIT = 0x0f,
    ZCL_DATATYPE_BOOLEAN = 0x10,
    ZCL_DATATYPE_BITMAP_8BIT = 0x18,
    ZCL_DATATYPE_BITMAP_16BIT = 0x19,
    ZCL_DATATYPE_BITMAP_24BIT = 0x1a,
    ZCL_DATATYPE_BITMAP_32BIT = 0x1b,
    ZCL_DATATYPE_BITMAP_40BIT = 0x1c,
    ZCL_DATATYPE_BITMAP_48BIT = 0x1d,
    ZCL_DATATYPE_BITMAP_56BIT = 0x1e,
    ZCL_DATATYPE_BITMAP_64BIT = 0x1f,
    ZCL_DATATYPE_UNSIGNED_8BIT = 0x20,
    ZCL_DATATYPE_UNSIGNED_16BIT = 0x21,
    ZCL_DATATYPE_UNSIGNED_24BIT = 0x22,
    ZCL_DATATYPE_UNSIGNED_32BIT = 0x23,
    ZCL_DATATYPE_UNSIGNED_40BIT = 0x24,
    ZCL_DATATYPE_UNSIGNED_48BIT = 0x25,
    ZCL_DATATYPE_UNSIGNED_56BIT = 0x26,
    ZCL_DATATYPE_UNSIGNED_64BIT = 0x27,
    ZCL_DATATYPE_SIGNED_8BIT = 0x28,
    ZCL_DATATYPE_SIGNED_16BIT = 0x29,
    ZCL_DATATYPE_SIGNED_24BIT = 0x2a,
    ZCL_DATATYPE_SIGNED_32BIT = 0x2b,
    ZCL_DATATYPE_SIGNED_40BIT = 0x2c,
    ZCL_DATATYPE_SIGNED_48BIT = 0x2d,
    ZCL_DATATYPE_SIGNED_56BIT = 0x2e,
    ZCL_DATATYPE_SIGNED_64BIT = 0x2f,
    ZCL_DATATYPE_ENUMERATION_8BIT = 0x30,
    ZCL_DATATYPE_ENUMERATION_16BIT = 0x31,
    ZCL_DATATYPE_FLOATING_SEMI = 0x38,
    ZCL_DATATYPE_FLOATING_SINGLE = 0x39,
    ZCL_DATATYPE_FLOATING_DOUBLE = 0x3a,
    ZCL_DATATYPE_STRING_OCTET = 0x41,
    ZCL_DATATYPE_STRING_CHARACTER = 0x42,
    ZCL_DATATYPE_STRING_LONG_OCTET = 0x43,
    ZCL_DATATYPE_STRING_LONG_CHARACTER = 0x44,
    ZCL_DATATYPE_ARRAY = 0x48,
    ZCL_DATATYPE_STRUCT = 0x4c,
    ZCL_DATATYPE_SET = 0x50,
    ZCL_DATATYPE_BAG = 0x51,
    ZCL_DATATYPE_TIME_OF_DAY = 0xe0,
    ZCL_DATATYPE_DATE = 0xe1,
    ZCL_DATATYPE_TIME_UTC = 0xe2,
    ZCL_DATATYPE_CLUSTER_ID = 0xe8,
    ZCL_DATATYPE_ATTRIBUTE_ID = 0xe9,
    ZCL_DATATYPE_BACNET_OID = 0xea,
    ZCL_DATATYPE_EUI64 = 0xf0,
    ZCL_DATATYPE_SECURITY_KEY128 = 0xf1,
    ZCL_DATATYPE_UNKNOWN = 0xff
};

/* ZCL Invalid Data Values */
#define ZCL_INVALID_BOOLEAN                      0xffU
#define ZCL_INVALID_UNSIGNED_8BIT                0xffU
#define ZCL_INVALID_UNSIGNED_16BIT               0xffffU
#define ZCL_INVALID_UNSIGNED_24BIT               0xffffffU
#define ZCL_INVALID_UNSIGNED_32BIT               0xffffffffU
#define ZCL_INVALID_UNSIGNED_40BIT               0xffffffffffULL
#define ZCL_INVALID_UNSIGNED_48BIT               0xffffffffffffULL
#define ZCL_INVALID_UNSIGNED_56BIT               0xffffffffffffffULL
#define ZCL_INVALID_UNSIGNED_64BIT               0xffffffffffffffffULL

#define ZCL_INVALID_SIGNED_8BIT                  0x80
#define ZCL_INVALID_SIGNED_16BIT                 0x8000
#define ZCL_INVALID_SIGNED_24BIT                 0x800000
#define ZCL_INVALID_SIGNED_32BIT                 0x80000000U
#define ZCL_INVALID_SIGNED_40BIT                 0x8000000000LL
#define ZCL_INVALID_SIGNED_48BIT                 0x800000000000LL
#define ZCL_INVALID_SIGNED_56BIT                 0x80000000000000LL
#define ZCL_INVALID_SIGNED_64BIT                 0x8000000000000000UL

#define ZCL_INVALID_ENUMERATION_8BIT             0xffU
#define ZCL_INVALID_ENUMERATION_16BIT            0xffffU

#define ZCL_INVALID_FLOATING                     (0.0 / 0.0)
/* Note, can't bit-or signed values (MISRA rule 10.1) */
#define ZCL_INVALID_FLOATING_SEMI                (ZCL_FLOAT_SEMI_MANTISSA + ZCL_FLOAT_SEMI_EXPONENT)
#define ZCL_INVALID_FLOATING_SINGLE              (ZCL_FLOAT_SINGLE_MANTISSA + ZCL_FLOAT_SINGLE_MANTISSA)
#define ZCL_INVALID_FLOATING_DOUBLE              (ZCL_FLOAT_DOUBLE_MANTISSA + ZCL_FLOAT_DOUBLE_MANTISSA)

#define ZCL_INVALID_STRING_OCTET                 0xffU
#define ZCL_INVALID_STRING_CHARACTER             0xffU
#define ZCL_INVALID_STRING_LONG_OCTET            0xffffU
#define ZCL_INVALID_STRING_LONG_CHARACTER        0xffffU

#define ZCL_INVALID_ARRAY                        0xffffU
#define ZCL_INVALID_STRUCT                       0xffffU
#define ZCL_INVALID_SET                          0xffffU
#define ZCL_INVALID_BAG                          0xffffU
#define ZCL_INVALID_TIME_OF_DAY                  0xffffffffU
#define ZCL_INVALID_DATE                         0xffffffffU
#define ZCL_INVALID_TIME_UTC                     0xffffffffU
#define ZCL_INVALID_CLUSTER_ID                   0xffffU
#define ZCL_INVALID_ATTRIBUTE_ID                 0xffffU
#define ZCL_INVALID_BACNET_OID                   0xffffffffU
#define ZCL_INVALID_EUI64                        0xffffffffffffffffULL

/* ZCL Valid Ranges */
#define ZCL_MIN_SIGNED_8BIT                      (-(ZCL_INVALID_SIGNED_8BIT - 1))
#define ZCL_MIN_SIGNED_16BIT                     (-(ZCL_INVALID_SIGNED_16BIT - 1))
#define ZCL_MIN_SIGNED_24BIT                     (-(ZCL_INVALID_SIGNED_24BIT - 1))
#define ZCL_MIN_SIGNED_32BIT                     (-(ZCL_INVALID_SIGNED_32BIT - 1))
#define ZCL_MIN_SIGNED_40BIT                     (-(ZCL_INVALID_SIGNED_40BIT - 1))
#define ZCL_MIN_SIGNED_48BIT                     (-(ZCL_INVALID_SIGNED_48BIT - 1))
#define ZCL_MIN_SIGNED_56BIT                     (-(ZCL_INVALID_SIGNED_56BIT - 1))
#define ZCL_MIN_SIGNED_64BIT                     (-(ZCL_INVALID_SIGNED_64BIT - 1))

#define ZCL_MAX_SIGNED_8BIT                      0x7f
#define ZCL_MAX_SIGNED_16BIT                     0x7fff
#define ZCL_MAX_SIGNED_24BIT                     0x7fffff
#define ZCL_MAX_SIGNED_32BIT                     0x7fffffff
#define ZCL_MAX_SIGNED_40BIT                     0x7fffffffffULL
#define ZCL_MAX_SIGNED_48BIT                     0x7fffffffffffULL
#define ZCL_MAX_SIGNED_56BIT                     0x7fffffffffffffULL
#define ZCL_MAX_SIGNED_64BIT                     0x7fffffffffffffffULL

#define ZCL_MAX_UNSIGNED_8BIT                    (ZCL_INVALID_UNSIGNED_8BIT - 1U)
#define ZCL_MAX_UNSIGNED_16BIT                   (ZCL_INVALID_UNSIGNED_16BIT - 1U)
#define ZCL_MAX_UNSIGNED_24BIT                   (ZCL_INVALID_UNSIGNED_24BIT - 1U)
#define ZCL_MAX_UNSIGNED_32BIT                   (ZCL_INVALID_UNSIGNED_32BIT - 1U)
#define ZCL_MAX_UNSIGNED_40BIT                   (ZCL_INVALID_UNSIGNED_40BIT - 1U)
#define ZCL_MAX_UNSIGNED_48BIT                   (ZCL_INVALID_UNSIGNED_48BIT - 1U)
#define ZCL_MAX_UNSIGNED_56BIT                   (ZCL_INVALID_UNSIGNED_56BIT - 1U)
#define ZCL_MAX_UNSIGNED_64BIT                   (ZCL_INVALID_UNSIGNED_64BIT - 1U)

/* Type sizes */
#define ZCL_SIZEOF_8BIT                          1U
#define ZCL_SIZEOF_16BIT                         2U
#define ZCL_SIZEOF_24BIT                         3U
#define ZCL_SIZEOF_32BIT                         4U
#define ZCL_SIZEOF_40BIT                         5U
#define ZCL_SIZEOF_48BIT                         6U
#define ZCL_SIZEOF_56BIT                         7U
#define ZCL_SIZEOF_64BIT                         8U
#define ZCL_SIZEOF_128BIT                        16U

/* ZCL Status Codes */
enum ZclStatusCodeT {
    ZCL_STATUS_SUCCESS = 0x00,
    ZCL_STATUS_FAILURE = 0x01,
    ZCL_STATUS_ALLOC_FAIL = 0x70,
    ZCL_STATUS_NOT_AUTHORIZED = 0x7e,
    ZCL_STATUS_MALFORMED_COMMAND = 0x80,
    ZCL_STATUS_UNSUPP_CLUSTER_COMMAND = 0x81,
    ZCL_STATUS_UNSUPP_GENERAL_COMMAND = 0x82,
    ZCL_STATUS_UNSUPP_MFR_CLUSTER_COMMAND = 0x83,
    ZCL_STATUS_UNSUPP_MFR_GENERAL_COMMAND = 0x84,
    ZCL_STATUS_INVALID_FIELD = 0x85,
    ZCL_STATUS_UNSUPP_ATTRIBUTE = 0x86,
    ZCL_STATUS_INVALID_VALUE = 0x87,
    ZCL_STATUS_READ_ONLY = 0x88,
    ZCL_STATUS_INSUFFICIENT_SPACE = 0x89,
    ZCL_STATUS_DUPLICATE_EXISTS = 0x8a,
    ZCL_STATUS_NOT_FOUND = 0x8b,
    ZCL_STATUS_UNREPORTABLE_ATTRIBUTE = 0x8c,
    ZCL_STATUS_INVALID_DATA_TYPE = 0x8d,
    ZCL_STATUS_INVALID_SELECTOR = 0x8e,
    ZCL_STATUS_WRITE_ONLY = 0x8f,
    ZCL_STATUS_INCONSISTENT_STARTUP_STATE = 0x90,
    ZCL_STATUS_DEFINED_OUT_OF_BAND = 0x91,
    ZCL_STATUS_INCONSISTENT = 0x92,
    ZCL_STATUS_ACTION_DENIED = 0x93,
    ZCL_STATUS_TIMEOUT = 0x94,
    ZCL_STATUS_ABORT = 0x95,
    ZCL_STATUS_INVALID_IMAGE = 0x96,
    ZCL_STATUS_WAIT_FOR_DATA = 0x97,
    ZCL_STATUS_NO_IMAGE_AVAILABLE = 0x98,
    ZCL_STATUS_REQUIRE_MORE_IMAGE = 0x99,
    ZCL_STATUS_NOTIFICATION_PENDING = 0x9A,
    ZCL_STATUS_HARDWARE_FAILURE = 0xc0,
    ZCL_STATUS_SOFTWARE_FAILURE = 0xc1,
    ZCL_STATUS_CALIBRATION_ERROR = 0xc2,
    ZCL_STATUS_UNSUPP_CLUSTER = 0xc3,
    ZCL_STATUS_LIMIT_REACHED = 0xc4,

    /* Exegin add-on: Used with cluster command callback to indicate
     * command was handled successfully, but don't send a Default Response
     * for success. I.e. a response has already been sent. */
    ZCL_STATUS_SUCCESS_NO_DEFAULT_RESPONSE = 0xff
        /* zcl_attr_integer.c relies on these enum constants to be =< 0xff since they're cast as uint8_t */
};

/* For SE 1.2a Attribute Reporting Status for Sleepy Devices */
#define ZCL_ATTR_REPORTING_STATUS               0xfffeU
#define ZCL_ATTR_REPORTING_STATUS_PENDING       0x00U
#define ZCL_ATTR_REPORTING_STATUS_COMPLETE      0x01U

/* Device IDs */
enum ZbZclDeviceIdT {
    ZCL_DEVICE_ONOFF_SWITCH = 0x0000,
    ZCL_DEVICE_LEVEL_SWITCH = 0x0001,
    ZCL_DEVICE_ONOFF_OUTPUT = 0x0002,
    ZCL_DEVICE_LEVEL_OUTPUT = 0x0003,
    ZCL_DEVICE_SCENE_SELECTOR = 0x0004,
    ZCL_DEVICE_CONFIG_TOOL = 0x0005,
    ZCL_DEVICE_REMOTE_CONTROL = 0x0006,
    ZCL_DEVICE_COMBINED_INTERFACE = 0x0007,
    ZCL_DEVICE_RANGE_EXTENDER = 0x0008,
    ZCL_DEVICE_MAINS_POWER_OUTLET = 0x0009,
    ZCL_DEVICE_DOOR_LOCK = 0x000a,
    ZCL_DEVICE_DOOR_LOCK_CONTROLLER = 0x000b,
    ZCL_DEVICE_SIMPLE_SENSOR = 0x000c,
    ZCL_DEVICE_DATA_COLLECTION_UNIT = 0x0010,
    ZCL_DEVICE_ZIGBEE_SIM_CARD = 0x0020,
    ZCL_DEVICE_ZIGBEE_MOBILE_TERMINAL = 0x0021,
    ZCL_DEVICE_ZIGBEE_GLOBAL_PLATFORM_CARD = 0x0026, /* same as  */
    ZCL_DEVICE_CUSTOMER_HANDHELD_DEVICE = 0x0030,
    ZCL_DEVICE_RETAIL_ASSOCIATE_HANDHELD_DEVICE = 0x0031,
    ZCL_DEVICE_INTELLIGENT_SHOPPING_CART = 0x0032,
    ZCL_DEVICE_ELECTRONIC_SHELF_LABEL = 0x0033,
    ZCL_DEVICE_CUSTOMER_INFORMATION_POINT = 0x0034,
    ZCL_DEVICE_CUSTOMER_CARD = 0x0035,
    ZCL_DEVICE_CONSTRUCTED_BACNET_DEVICE = 0x004a,
    ZCL_DEVICE_BACNET_TUNNELED_DEVICE = 0x004b,
    ZCL_DEVICE_HOME_GATEWAY = 0x0050,
    ZCL_DEVICE_SMART_PLUG = 0x0051,
    ZCL_DEVICE_WHITE_GOODS = 0x0052,
    ZCL_DEVICE_METER_INTERFACE = 0x0053,
    ZCL_DEVICE_ZGP_PROXY = 0x0060,
    ZCL_DEVICE_ZGP_PROXY_BASIC = 0x0061,
    ZCL_DEVICE_ZGP_TARGET_PLUS = 0x0062,
    ZCL_DEVICE_ZGP_TARGET = 0x0063,
    ZCL_DEVICE_ZGP_COMMISSIONING_TOOL = 0x0064,
    ZCL_DEVICE_ZGP_COMBO = 0x0065,
    ZCL_DEVICE_ZGP_COMBO_BASIC = 0x0066,
    ZCL_DEVICE_ENVIRONMENTAL_SENSOR = 0x0067,

    /* Lighting and Occupancy (0x0100) */
    ZCL_DEVICE_ONOFF_LIGHT = 0x0100,
    ZCL_DEVICE_DIMMABLE_LIGHT = 0x0101,
    ZCL_DEVICE_COLOR_DIMMABLE_LIGHT = 0x0102,
    ZCL_DEVICE_ONOFF_LIGHT_SWITCH = 0x0103,
    ZCL_DEVICE_ONOFF_DIMMER_SWITCH = 0x0104,
    ZCL_DEVICE_ONOFF_COLOR_DIMMER_SWITCH = 0x0105,
    ZCL_DEVICE_ONOFF_LIGHT_SENSOR = 0x0106,
    ZCL_DEVICE_ONOFF_OCCUPANCY_SENSOR = 0x0107,
    /* TODO - add more from Lighting and Occupancy Device Spec */

    /* IAS (0x0400) */
    ZCL_DEVICE_IAS_CONTROL_AND_INDICATING_EQUIPMENT = 0x0400,
    ZCL_DEVICE_IAS_ANCILLARY_CONTROL_EQUIPMENT = 0x0401,
    ZCL_DEVICE_IAS_ZONE = 0x0402,
    ZCL_DEVICE_IAS_WARNING_DEVICE = 0x0403,

    /* Smart Energy device identifiers. (0x0500) */
    ZCL_DEVICE_ESP = 0x0500,
    ZCL_DEVICE_METER = 0x0501,
    ZCL_DEVICE_IN_HOME_DISPLAY = 0x0502,
    ZCL_DEVICE_PCT = 0x0503,
    ZCL_DEVICE_LOAD_CONTROL = 0x0504,
    ZCL_DEVICE_SMART_APPLIANCE = 0x0505,
    ZCL_DEVICE_PREPAYMENT_TERMINAL = 0x0506,
    ZCL_DEVICE_PHYSICAL_DEVICE = 0x0507,
    ZCL_DEVICE_REMOTE_COMMUNICATIONS_DEVICE = 0x0508,
    ZCL_DEVICE_ERL_INTERFACE = 0x0509,

    /* Lighting and Occupancy Continued (0x0800) */
    ZCL_DEVICE_COLOR_CONTROLLER = 0x0800,
    ZCL_DEVICE_COLOR_SCENE_CONTROLLER = 0x0810,
    ZCL_DEVICE_NON_COLOR_CONTROLLER = 0x0820,
    ZCL_DEVICE_NON_COLOR_SCENE_CONTROLLER = 0x0830,
    ZCL_DEVICE_CONTROL_BRIDGE = 0x0840,
    ZCL_DEVICE_ONOFF_SENSOR = 0x0850 /* aka Door Sensor? */
};

/* Cluster ID Ranges */
enum {
    ZCL_CLUSTER_ZB_STANDARD_MIN = 0x0000U,
    ZCL_CLUSTER_ZB_STANDARD_MAX = 0x7fffU,
    ZCL_CLUSTER_MFR_SPECIFIC_MIN = 0xfc00U,
    ZCL_CLUSTER_MFR_SPECIFIC_MAX = 0xffffU
};

/* Known Cluster IDs */
enum ZbZclClusterIdT {
    /* General cluster identifiers. */
    ZCL_CLUSTER_BASIC = 0x0000,
    ZCL_CLUSTER_POWER_CONFIG = 0x0001,
    ZCL_CLUSTER_DEVICE_TEMPERATURE = 0x0002,
    ZCL_CLUSTER_IDENTIFY = 0x0003,
    ZCL_CLUSTER_GROUPS = 0x0004,
    ZCL_CLUSTER_SCENES = 0x0005,
    ZCL_CLUSTER_ONOFF = 0x0006,
    ZCL_CLUSTER_ONOFF_CONFIG = 0x0007,
    ZCL_CLUSTER_LEVEL_CONTROL = 0x0008,
    ZCL_CLUSTER_ALARMS = 0x0009,
    ZCL_CLUSTER_TIME = 0x000a,
    ZCL_CLUSTER_RSSI_LOCATION = 0x000b,
    ZCL_CLUSTER_ANALOG_INPUT_BASIC = 0x000c,
    ZCL_CLUSTER_ANALOG_OUTPUT_BASIC = 0x000d,
    ZCL_CLUSTER_ANALOG_VALUE_BASIC = 0x000e,
    ZCL_CLUSTER_BINARY_INPUT_BASIC = 0x000f,
    ZCL_CLUSTER_BINARY_OUTPUT_BASIC = 0x0010,
    ZCL_CLUSTER_BINARY_VALUE_BASIC = 0x0011,
    ZCL_CLUSTER_MULTISTATE_INPUT_BASIC = 0x0012,
    ZCL_CLUSTER_MULTISTATE_OUTPUT_BASIC = 0x0013,
    ZCL_CLUSTER_MULTISTATE_VALUE_BASIC = 0x0014,
    ZCL_CLUSTER_COMMISSIONING = 0x0015,
    ZCL_CLUSTER_OTA_UPGRADE = 0x0019,
    ZCL_CLUSTER_POWER_PROFILE = 0x001a,
    ZCL_CLUSTER_POLL_CONTROL = 0x0020,
    ZCL_CLUSTER_GREEN_POWER = 0x0021,
    ZCL_CLUSTER_NEAREST_GATEWAY = 0x0024,
    ZCL_CLUSTER_KEEP_ALIVE = 0x0025,
    ZCL_CLUSTER_METER_ID = 0x0b01,
    ZCL_CLUSTER_DIAGNOSTICS = 0x0b05,

    /* Closures Cluster IDs */
    ZCL_CLUSTER_CLOSURE_SHADE_CONFIG = 0x0100,
    ZCL_CLUSTER_DOOR_LOCK = 0x0101,
    ZCL_CLUSTER_WINDOW_COVERING = 0x0102,

    /* HVAC Cluster IDs */
    ZCL_CLUSTER_HVAC_PUMP = 0x0200,
    ZCL_CLUSTER_HVAC_THERMOSTAT = 0x0201,
    ZCL_CLUSTER_HVAC_FAN = 0x0202,
    ZCL_CLUSTER_HVAC_DEHUMIDIFIER = 0x0203,
    ZCL_CLUSTER_HVAC_THERMOSTAT_UI = 0x0204,

    /* Lighting Cluster IDs */
    ZCL_CLUSTER_COLOR_CONTROL = 0x0300,
    ZCL_CLUSTER_BALLAST_CONTROL = 0x0301,

    /* Measurement Cluster IDs */
    ZCL_CLUSTER_MEAS_ILLUMINANCE = 0x0400,
    ZCL_CLUSTER_MEAS_ILLUMINANCE_LEVEL = 0x0401,
    ZCL_CLUSTER_MEAS_TEMPERATURE = 0x0402,
    ZCL_CLUSTER_MEAS_PRESSURE = 0x0403,
    ZCL_CLUSTER_MEAS_FLOW = 0x0404,
    ZCL_CLUSTER_MEAS_HUMIDITY = 0x0405,
    ZCL_CLUSTER_MEAS_OCCUPANCY = 0x0406,
    ZCL_CLUSTER_MEAS_LEAF_WETNESS = 0x0407,
    ZCL_CLUSTER_MEAS_SOIL_MOISTURE = 0x0408,
    ZCL_CLUSTER_MEAS_ELECTRICAL = 0x0b04,

    /* Security Cluster IDs */
    ZCL_CLUSTER_SECURITY_IAS_ZONE = 0x0500,
    ZCL_CLUSTER_SECURITY_IAS_ANCILLARY = 0x0501,
    ZCL_CLUSTER_SECURITY_IAS_WARNING = 0x0502,

    /* Protocol Cluster IDs */
    ZCL_CLUSTER_PROTOCOL_TUNNEL = 0x0600,
    ZCL_CLUSTER_BACNET_TUNNEL = 0x0601,
    ZCL_CLUSTER_BACNET_ANALOG_IN_REG = 0x0602,
    ZCL_CLUSTER_BACNET_ANALOG_IN_EXT = 0x0603,
    ZCL_CLUSTER_BACNET_ANALOG_OUT_REG = 0x0604,
    ZCL_CLUSTER_BACNET_ANALOG_OUT_EXT = 0x0605,
    ZCL_CLUSTER_BACNET_ANALOG_VAL_REG = 0x0606,
    ZCL_CLUSTER_BACNET_ANALOG_VAL_EXT = 0x0607,
    ZCL_CLUSTER_BACNET_BINARY_IN_REG = 0x0608,
    ZCL_CLUSTER_BACNET_BINARY_IN_EXT = 0x0609,
    ZCL_CLUSTER_BACNET_BINARY_OUT_REG = 0x060a,
    ZCL_CLUSTER_BACNET_BINARY_OUT_EXT = 0x060b,
    ZCL_CLUSTER_BACNET_BINARY_VAL_REG = 0x060c,
    ZCL_CLUSTER_BACNET_BINARY_VAL_EXT = 0x060d,
    ZCL_CLUSTER_BACNET_MULTI_IN_REG = 0x060e,
    ZCL_CLUSTER_BACNET_MULTI_IN_EXT = 0x060f,
    ZCL_CLUSTER_BACNET_MULTI_OUT_REG = 0x0610,
    ZCL_CLUSTER_BACNET_MULTI_OUT_EXT = 0x0611,
    ZCL_CLUSTER_BACNET_MULTI_VAL_REG = 0x0612,
    ZCL_CLUSTER_BACNET_MULTI_VAL_EXT = 0x0613,

    /* Smart Energy */
    ZCL_CLUSTER_PRICE = 0x0700,
    ZCL_CLUSTER_DRLC = 0x0701,
    ZCL_CLUSTER_SIMPLE_METERING = 0x0702,
    ZCL_CLUSTER_MESSAGING = 0x0703,
    ZCL_CLUSTER_TUNNELING = 0x0704,
    ZCL_CLUSTER_PREPAYMENT = 0x0705,
    ZCL_CLUSTER_ENERGY_MANAGEMENT = 0x0706, /* SE 1.2 */
    ZCL_CLUSTER_CALENDAR = 0x0707,
    ZCL_CLUSTER_DEVICE_MANAGEMENT = 0x0708, /* SE 1.2 */
    ZCL_CLUSTER_EVENTS = 0x0709, /* SE 1.2 */
    ZCL_CLUSTER_MDU_PAIRING = 0x070A, /* SE 1.2 */

    /* CBKE */
    ZCL_CLUSTER_KEY_ESTABLISHMENT = 0x0800,

    /* Telecommunication */
    ZCL_CLUSTER_VOICE_OVER_ZIGBEE = 0x0904,

    /* TOUCHLINK */
    ZCL_CLUSTER_TOUCHLINK = 0x1000,

    /* Custom, internal use only, for handling cluster persistence.
     * Used with ZCL_MANUF_CODE_INTERNAL. */
    ZCL_CLUSTER_PERSIST = 0xfffe,

    /* Custom, internal use only, for local loop-back commands we want to
     * send to all clusters. Used with ZCL_MANUF_CODE_INTERNAL. */
    ZCL_CLUSTER_WILDCARD = 0xffff
};

/* General ZCL Commands (ZCL_FRAMETYPE_PROFILE) */
enum {
    ZCL_COMMAND_READ = 0x00,
    ZCL_COMMAND_READ_RESPONSE = 0x01,
    ZCL_COMMAND_WRITE = 0x02,
    ZCL_COMMAND_WRITE_UNDIVIDED = 0x03,
    ZCL_COMMAND_WRITE_RESPONSE = 0x04,
    ZCL_COMMAND_WRITE_NO_RESPONSE = 0x05,
    ZCL_COMMAND_CONFIG_REPORTING = 0x06,
    ZCL_COMMAND_CONFIG_REPORTING_RESPONSE = 0x07,
    ZCL_COMMAND_READ_REPORTING = 0x08,
    ZCL_COMMAND_READ_REPORTING_RESPONSE = 0x09,
    ZCL_COMMAND_REPORT = 0x0a,
    ZCL_COMMAND_DEFAULT_RESPONSE = 0x0b,
    ZCL_COMMAND_DISCOVER_ATTR = 0x0c,
    ZCL_COMMAND_DISCOVER_ATTR_RSP = 0x0d,
    ZCL_COMMAND_READ_STRUCTURED = 0x0e,
    ZCL_COMMAND_WRITE_STRUCTURED = 0x0f,
    ZCL_COMMAND_WRITE_STRUCTURED_RESPONSE = 0x10
};

struct ZbZclAddrInfoT {
    struct ZbApsAddrT addr;
    uint8_t seqnum;
    uint16_t tx_options;
};

/* ZCL Frame Control field. */
struct ZbZclFrameControlT {
    uint8_t frameType; /* ZCL_FRAMECTRL_TYPE */
    uint8_t manufacturer; /* TRUE or FALSE */
    enum ZbZclDirectionT direction;
    enum ZbZclNoDefaultResponseT noDefaultResp;
};

/* General ZCL Frame Structure */
struct ZbZclHeaderT {
    struct ZbZclFrameControlT frameCtrl;
    uint16_t manufacturerCode;
    uint8_t seqNum;
    uint8_t cmdId;
};

/*---------------------------------------------------------------
 * Cluster Commands
 *---------------------------------------------------------------
 */
typedef struct {
    /* From APSDE-DATA.request */
    struct ZbApsAddrT dst;
    uint16_t profileId;
    enum ZbZclClusterIdT clusterId;
    uint16_t srcEndpt;
    uint16_t txOptions; /* e.g. ZB_APSDE_DATAREQ_TXOPTIONS_ACK */
    bool discoverRoute;
    uint8_t radius;
    /* ZCL command */
    struct ZbZclHeaderT hdr;
    /* if (txOptions & ZB_APSDE_DATAREQ_TXOPTIONS_VECTOR), then payload is
     * a pointer to list of ZbApsBufT, and length is the number of ZbApsBufT
     * items in the list. */
    const void *payload;
    unsigned int length;
} ZbZclCommandReqT;

/* ZCL Command Response
 *
 * Special case if src.mode == ZB_APSDE_ADDRMODE_NOTPRESENT (0), then
 *      - response generated internally.
 *      - src.endpoint = local endpoint that generated request
 *      - hdr.seqNum = request sequence number
 *      - hdr.cmdId = request command id
 */
struct ZbZclCommandRspT {
    enum ZclStatusCodeT status;
    struct ZbApsAddrT src;
    uint16_t profileId;
    enum ZbZclClusterIdT clusterId;
    uint8_t linkQuality;
    struct ZbZclHeaderT hdr;
    const uint8_t *payload;
    uint16_t length;
};

/* Send a ZCL command. The callback function is called when the
 * associated ZCL response is received, or there's an error. */
enum ZclStatusCodeT ZbZclCommandReq(struct ZigBeeT *zb, ZbZclCommandReqT *zclReq,
    void (*callback)(struct ZbZclCommandRspT *rsp, void *arg), void *arg);

/* Blocking version of ZbZclCommandReq */
/* Response Info (rsp) may be NULL. If not NULL, make sure to provide a valid buffer pointer
 * to rsp->payload and specify the maximum length to rsp->length. */
void ZbZclCommandWait(struct ZigBeeT *zb, ZbZclCommandReqT *req, struct ZbZclCommandRspT *rsp);

/* A version of ZbZclCommandReq that doesn't wait for a response. */
enum ZclStatusCodeT ZbZclCommandNoResp(struct ZigBeeT *zb, ZbZclCommandReqT *req,
    void (*callback)(ZbApsdeDataConfT *confPtr, void *arg), void *arg);

/*---------------------------------------------------------------
 * Cluster Attributes
 *---------------------------------------------------------------
 */

#define ZCL_ATTRIBUTE_BUFFER_SIZE_MAX       256U

struct ZbZclAttrCbInfoT;

/* The structure used to initialize a ZCL attribute when calling ZbZclAttrAppendList.
 *
 * PARAMETERS:
 *   attributeId    ; The attribute's ID
 *
 *   dataType       ; The attribute's data type, or ZCL_DATATYPE_UNKNOWN
 *                    if this is the last entry in a list.
 *
 *   flags          ; Flags that determine whether this attribute is writable,
 *                    reportable, persisted, etc
 *
 *   customValSz    ; A custom size is required if both customRead and
 *                    customWrite callbacks are provided (for maximum
 *                    persistence size), or for the following attribute data
 *                    types:
 *
 *                      ZCL_DATATYPE_STRING_OCTET,
 *                      ZCL_DATATYPE_STRING_CHARACTER,
 *                      ZCL_DATATYPE_STRING_LONG_OCTET,
 *                      ZCL_DATATYPE_STRING_LONG_CHARACTER,
 *                      ZCL_DATATYPE_ARRAY,
 *                      ZCL_DATATYPE_STRUCT,
 *                      ZCL_DATATYPE_SET,
 *                      ZCL_DATATYPE_BAG
 *
 *                    Maximum size is the length returned by ZbZclClusterGetMaxAsduLength() or
 *                    the cluster's maxAsduLength parameter. It should not exceed
 *                    ZB_APS_CONST_MAX_FRAG_SIZE.
 *
 *   customRead     ; Callback to let application handle an attribute read
 *                    request. If NULL, the default stack attribute read
 *                    handler is used.
 *
 *   customWrite    ; Callback to let application handle an attribute write
 *                    request. If NULL, the default stack attribute write
 *                    handler is used.
 *
 *                    NOTE: If customRead and customWrite are both provided,
 *                    ZbZclAttrAppendList will not allocate memory for the
 *                    attribute's data. The application must maintain this
 *                    information separately from the attribute.
 *
 *   customDefault  ; Called to reset attribute to default value. If NULL,
 *                    the attribute will be reset to the default value for the
 *                    given data type.
 *
 *   writeNotify    ; If customWrite is NULL and the stack is handling attribute
 *                    writes for this attribute, then this callback notifies
 *                    the application whenever a successful write takes place.
 *                    This callback is also called when the attributes is reset
 *                    to defaults and customDefault is NULL.
 *
 *   report_interval_secs_min ; Default minimum attribute reporting interval
 *                              in seconds.
 *
 *   report_interval_secs_max ; Default maximum attribute reporting interval
 *                              in seconds.
 */
struct ZbZclAttrT {
    uint16_t attributeId;
    enum ZclDataTypeT dataType;
    ZclAttrFlagT flags;
    unsigned int customValSz;
    enum ZclStatusCodeT (*callback)(struct ZbZclClusterT *clusterPtr, struct ZbZclAttrCbInfoT *info);
    struct {
        /* If min and max both equal zero, range checking is disabled. */
        long long min;
        long long max;
    } integer_range;
    struct {
        uint16_t interval_min; /* seconds */
        uint16_t interval_max; /* seconds */
    } reporting;
};

#define ZCL_ATTR_LIST_LEN(_list_)        (sizeof(_list_) / sizeof(struct ZbZclAttrT))

/* Appends attributes to the cluster.
 * Important note: attrList memory is attached to the cluster, so
 * it cannot be freed until the cluster is freed. */
enum ZclStatusCodeT ZbZclAttrAppendList(struct ZbZclClusterT *clusterPtr, const struct ZbZclAttrT *attrList, unsigned int num_attrs);

/* Attribute Callback Types */
enum ZbZclAttrCbTypeT {
    ZCL_ATTR_CB_TYPE_READ, /* Read Attribute */
    ZCL_ATTR_CB_TYPE_WRITE, /* Write Attribute */
    ZCL_ATTR_CB_TYPE_NOTIFY /* Write Notification */
};

/* Attribute Callback Information */
struct ZbZclAttrCbInfoT {
    const struct ZbZclAttrT *info; /* The original info used to create the attribute */
    enum ZbZclAttrCbTypeT type;
    /* Source of attribute data if ZCL_ATTR_CB_TYPE_WRITE.
     * Destination of attribute data if ZCL_ATTR_CB_TYPE_READ. */
    uint8_t *zcl_data;
    unsigned int zcl_len; /* Maximum length of 'zcl_data' */

    /* The following are only used if type == ZCL_ATTR_CB_TYPE_WRITE */
    ZclWriteModeT write_mode;
    void *attr_data; /* Location to write the new attribute value. */
    struct ZbApsAddrT *src; /* Source of the command, if not locally generated. May be NULL. */

    /* Application's defined callback argument */
    void *app_cb_arg;
};

/* The internal allocated attribute struct */
struct ZbZclAttrListEntryT {
    struct LinkListT link;
    const struct ZbZclAttrT *info; /* Attribute info */
    uint8_t *valBuf; /* ZCL format (i.e. same as what is sent over-the-air) */
    unsigned int valSz; /* Allocation size of valBuf. */
    struct {
        uint16_t interval_secs_min; /* seconds */
        uint16_t interval_secs_max; /* seconds */
    } reporting;
};

/* Returns the length of an attribute, solely based on type. Or 0, if length is unknown. */
unsigned int ZbZclAttrTypeLength(enum ZclDataTypeT type);
struct ZbZclAttrListEntryT * ZbZclAttrFind(struct ZbZclClusterT *clusterPtr, uint16_t attrId);
/* Returns the attribute length, or -1 on error. */
int ZbZclAttrDefaultValue(enum ZclDataTypeT type, uint8_t *buf, unsigned int max_len);
enum ZclStatusCodeT ZbZclAttrCallbackExec(struct ZbZclClusterT *clusterPtr,
    struct ZbZclAttrListEntryT *attrPtr, struct ZbZclAttrCbInfoT *cb);

/*---------------------------------------------------------------
 * Alarm Reset Handler
 *---------------------------------------------------------------
 */
typedef void (*ZbZclAlarmResetFuncT)(struct ZbZclClusterT *clusterPtr, uint8_t alarm_code,
    uint16_t cluster_id, ZbApsdeDataIndT *data_ind, struct ZbZclHeaderT *hdr);

enum ZclStatusCodeT ZbZclClusterRegisterAlarmResetHandler(struct ZbZclClusterT *clusterPtr, ZbZclAlarmResetFuncT callback);
void ZbZclClusterRemoveAlarmResetHandler(struct ZbZclClusterT *clusterPtr);

/*---------------------------------------------------------------
 * Cluster Base Type
 *---------------------------------------------------------------
 */
/* This structure describes a ZCL cluster */
struct ZbZclClusterT {
    struct LinkListT link; /* Optional linking for application use. */
    struct ZigBeeT *zb; /* ZigBee stack reference. */

    /*-------------------------------------------
     * Cluster Basics
     *-------------------------------------------
     */
    enum ZbZclClusterIdT clusterId;
    uint8_t endpoint;
    uint16_t mfrCode;
    /* minSecurity is one of: ZB_APS_STATUS_UNSECURED, ZB_APS_STATUS_SECURED_NWK_KEY or ZB_APS_STATUS_SECURED_LINK_KEY */
    enum ZbStatusCodeT minSecurity;
    uint16_t profileId;
    uint16_t txOptions; /* e.g. ZB_APSDE_DATAREQ_TXOPTIONS_ACK */
    bool discoverRoute;
    uint8_t radius;
    uint16_t maxAsduLength; /* with fragmentation, if enabled in txOptions. */
    /* Direction of incoming commands. I.e. the type of cluster this is
     * (client or server). */
    enum ZbZclDirectionT direction;

    /*-------------------------------------------
     * Filters, Lists, Timers
     *-------------------------------------------
     */
    struct ZbApsFilterT filter;
    struct ZbApsFilterT alarm_reset_filter;
    ZbZclAlarmResetFuncT alarm_reset_callback;
    struct LinkListT attributeList;
    struct LinkListT reports;
    struct ZbTimerT *persist_timer;

    /*-------------------------------------------
     * Callbacks
     *-------------------------------------------
     */
    /* The application argument passed through the various callbacks
     * to the application (e.g. custom attribute read/write). */
    void *app_cb_arg;

    /* Return value is a ZCL_STATUS_ code. If not ZCL_STATUS_SUCCESS, a default
     * response with the status code is sent to the originator of the command. */
    enum ZclStatusCodeT (*command)(struct ZbZclClusterT *clusterPtr, struct ZbZclHeaderT *zclHdrPtr,
        ZbApsdeDataIndT *dataIndPtr);

    /* Configure reporting */
    void (*config)(struct ZbZclClusterT *clusterPtr, ZbApsdeDataIndT *dataIndPtr, uint16_t attributeId,
        enum ZclStatusCodeT status, uint8_t direction);

    void (*report)(struct ZbZclClusterT *clusterPtr, ZbApsdeDataIndT *dataIndPtr, uint16_t attributeId,
        enum ZclDataTypeT dataType, const uint8_t *in_payload, uint16_t in_len);

    /* ZCL Internal Callback for the Scenes Cluster to Get a cluster's attribute
     * extension set.
     * extBuf has the format: [cluster (2 octets) | length (1 octet) | attribute data (N octets)]
     *
     * Returns length written to extBuf.  */
    uint8_t (*get_scene_data)(struct ZbZclClusterT *clusterPtr, uint8_t *extBuf, uint8_t extMaxLen);

    /* ZCL Internal Callback for the Scenes Cluster to Set a cluster's attribute
     * extension set.#define ZCL_BUILD_ADD_UINT8(_payload_, _max_len_, _index_, _arg_)  \
        do {                                                             \
            if (((_index_) + sizeof(uint8_t)) > (_max_len_)) {           \
                return -1;                                               \
            }                                                            \
            if (_payload_) {                                             \
                (_payload_)[_index_] = _arg_;                            \
            }                                                            \
            _index_ += sizeof(uint8_t);                                  \
     * extData has the format: [attribute data (N octets)]
     * extLen is the length of extData
     * transition_tenths ; transition time in tenths of a second.
     *
     * Returns ZCL status code (enum ZclStatusCodeT) */
    enum ZclStatusCodeT (*set_scene_data)(struct ZbZclClusterT *clusterPtr, uint8_t *extData, uint8_t extLen, uint16_t transition_tenths);

    /* cleanup() is called to free any cluster-specific data.
     * ZbZclClusterFree will already free any attributes and APS filter. */
    void (*cleanup)(struct ZbZclClusterT *clusterPtr);
};

/*---------------------------------------------------------------
 * Cluster Initialization
 *---------------------------------------------------------------
 */
/* Helper to create a ZCL endpoint. Calls ZbApsmeAddEndpoint to create the endpoint. Sets up a
 * filter to catch any ZCL commands for a cluster that doesn't exist on the endpoint, and
 * returns ZCL_STATUS_UNSUPPORTED_CLUSTER. Sets up filter bindings for the Basic Server
 * cluster (global stack clusters) and register's their cluster IDs with the endpoint
 * (e.g. for ZDO Match_Desc_req)  */
void ZbZclAddEndpoint(struct ZigBeeT *zb, ZbApsmeAddEndpointReqT *addReqPtr, ZbApsmeAddEndpointConfT *addConfPtr);
/* ZbZclAddEndpointNoBasic is the same as ZbZclAddEndpoint, except it does not allocate
 * a Basic Server cluster for the endpoint. */
void ZbZclAddEndpointNoBasic(struct ZigBeeT *zb, ZbApsmeAddEndpointReqT *addReqPtr, ZbApsmeAddEndpointConfT *addConfPtr);

/* Helper to remove a ZCL endpoint created by ZbZclAddEndpoint.
 * Calls ZbApsmeRemoveEndpoint and removes the ZCL filters created by ZbZclAddEndpoint. */
void ZbZclRemoveEndpoint(struct ZigBeeT *zb, ZbApsmeRemoveEndpointReqT *req, ZbApsmeRemoveEndpointConfT *conf);

/* Allocate and initialize a new cluster */
void * ZbZclClusterAlloc(struct ZigBeeT *zb, unsigned int alloc_sz, enum ZbZclClusterIdT cluster_id,
    uint8_t endpoint, enum ZbZclDirectionT direction);
/* Attach the cluster to the stack (after callbacks have been configured) */
enum ZclStatusCodeT ZbZclClusterAttach(struct ZbZclClusterT *clusterPtr);
/* Free and detach the cluster */
void ZbZclClusterFree(struct ZbZclClusterT *clusterPtr);

/* Register this cluster's ID on the endpoint if not already listed. */
bool ZbZclClusterEndpointRegister(struct ZbZclClusterT *clusterPtr);
bool ZbZclClusterEndpointRemove(struct ZbZclClusterT *clusterPtr);

/*---------------------------------------------------------------
 * Building and Parsing Frames
 *---------------------------------------------------------------
 */
/* Parses a ZCL Header from a received frame.
 * Returns Length of the ZCL header, or negative value (-1) on error. */
int ZbZclParseHeader(struct ZbZclHeaderT *zclHdrPtr, const uint8_t *buf, unsigned int len);

/* Builds and appends a ZCL Header to the start of a buffer.
 * Returns length of data written, or negative value (-1) on error. */
int ZbZclPrependHeader(struct ZbZclHeaderT *zclHdrPtr, uint8_t *data, unsigned int len);

/* Builds and appends a ZCL Header to the end of a buffer.
 * Returns Length of data written, or negative value (-1) on error. */
int ZbZclAppendHeader(struct ZbZclHeaderT *zclHdrPtr, uint8_t *data, unsigned int max_len);

/*---------------------------------------------------------------
 * Generic Attribute Functions
 *---------------------------------------------------------------
 */
int ZbZclAttrParseLength(enum ZclDataTypeT type, const uint8_t *ptr, unsigned int max_len, uint8_t recurs_depth);

bool ZbZclAttrIsFloat(enum ZclDataTypeT dataType);
bool ZbZclAttrIsAnalog(enum ZclDataTypeT dataType);
bool ZbZclAttrIsInteger(enum ZclDataTypeT dataType);

int ZbZclAppendInteger(unsigned long long value, enum ZclDataTypeT dataType, uint8_t *data, unsigned int len);
long long ZbZclParseInteger(enum ZclDataTypeT dataType, const uint8_t *data, enum ZclStatusCodeT *statusPtr);

int ZbZclAppendFloat(double value, enum ZclDataTypeT dataType, uint8_t *data, unsigned int len);
double ZbZclParseFloat(enum ZclDataTypeT dataType, const uint8_t *data);

/*---------------------------------------------------------------
 * Local Reading and Writing of Attributes
 *---------------------------------------------------------------
 */

/*FUNCTION
 *  ZbZclAttrRead
 *PARAMETERS
 *  clusterPtr      ; IN: Cluster Structure Pointer
 *  attrId          ; IN: Cluster's Attribute ID
 *  attrType        ; OUT (optional): Attribute Data Type
 *  outputBuf       ; OUT: Attribute data in ZCL format (i.e. same as what is sent over-the-air)
 *  max_len         ; IN: Maximum length that can be written to outputBuf.
 *  isReporting     ; IN: This read is from ZCL reporting. If the attribute does not support reporting, the read request will fail.
 */
enum ZclStatusCodeT ZbZclAttrRead(struct ZbZclClusterT *clusterPtr, uint16_t attrId, enum ZclDataTypeT *attrType,
    void *outputBuf, unsigned int max_len, bool isReporting);

/*FUNCTION
 *  ZbZclAttrWrite
 *PARAMETERS
 *  clusterPtr      ; IN: Cluster Structure Pointer
 *  src             ; IN: Source address of this command. May be NULL if generated locally.
 *  attr_id         ; IN: Cluster's Attribute ID
 *  attr_data       ; IN: Attribute data in ZCL format (i.e. same as what is sent over-the-air)
 *  max_len         ; IN: Length of attribute data
 *  mode            ; IN: Write mode
 */
enum ZclStatusCodeT ZbZclAttrWrite(struct ZbZclClusterT *clusterPtr, struct ZbApsAddrT *src, uint16_t attr_id,
    const uint8_t *attr_data, unsigned int max_len, ZclWriteModeT mode);

/* Integer Attribute Helpers */
long long ZbZclAttrIntegerRead(struct ZbZclClusterT *clusterPtr, uint16_t attributeId,
    enum ZclDataTypeT *typePtr, enum ZclStatusCodeT *statusPtr);
enum ZclStatusCodeT ZbZclAttrIntegerWrite(struct ZbZclClusterT *clusterPtr, uint16_t attributeId, long long value);
enum ZclStatusCodeT ZbZclAttrIntegerIncrement(struct ZbZclClusterT *clusterPtr, uint16_t attributeId, long long value);

uint64_t ZbZclAttrEuiRead(struct ZbZclClusterT *clusterPtr, uint16_t attributeId, enum ZclStatusCodeT *statusPtr);
enum ZclStatusCodeT ZbZclAttrEuiWrite(struct ZbZclClusterT *clusterPtr, uint16_t attributeId, uint64_t eui);

/* String Attribute Helpers */
/* zcl_str is in the ZCL string format (length field [1 or 2 bytes] + ascii string) */
/* ZCL_DATATYPE_STRING_OCTET or ZCL_DATATYPE_STRING_CHARACTER */
enum ZclStatusCodeT ZbZclAttrStringWriteShort(struct ZbZclClusterT *clusterPtr, uint16_t attributeId,
    const uint8_t *zcl_str);
/* ZCL_DATATYPE_STRING_LONG_OCTET or ZCL_DATATYPE_STRING_LONG_CHARACTER */
enum ZclStatusCodeT ZbZclAttrStringWriteLong(struct ZbZclClusterT *clusterPtr, uint16_t attributeId,
    const uint8_t *zcl_str);

/* Zero-length ZCL strings */
extern const uint8_t zcl_attr_str_short_zero[1]; /* i.e. {0x00} */
extern const uint8_t zcl_attr_str_long_zero[2]; /* i.e. {0x00, 0x00} */

/*---------------------------------------------------------------
 * Configure Reporting
 *---------------------------------------------------------------
 */
struct ZbZclAttrReportConfigT {
    struct ZbApsAddrT dst;
    uint16_t min;
    uint16_t max;
    uint16_t attr_id;
    uint8_t attr_type;
    uint64_t change;
};

enum ZclStatusCodeT ZbZclAttrReportConfigReq(struct ZbZclClusterT *clusterPtr, struct ZbZclAttrReportConfigT *report,
    void (*callback)(struct ZbZclCommandRspT *cmd_rsp, void *arg), void *arg);

struct ZbZclAttrReportReadT {
    struct ZbApsAddrT dst;
    uint16_t attr_id;
};

enum ZclStatusCodeT ZbZclAttrReportReadReq(struct ZbZclClusterT *clusterPtr, struct ZbZclAttrReportReadT *report,
    void (*callback)(struct ZbZclCommandRspT *cmd_rsp, void *arg), void *arg);

/*---------------------------------------------------------------
 * Remote Reading and Writing of Attributes
 *---------------------------------------------------------------
 */
/* The maximum number of attributes we support reading/writing through the API at once.
 * This is not the maximum that we support from requests arriving from the network.
 * Those depend on maximum ASDU limits and other resources. */
#define ZCL_ATTRIBUTE_LIST_MAX_SZ        8U

typedef struct {
    struct ZbApsAddrT dst;
    unsigned int count;
    uint16_t attr[ZCL_ATTRIBUTE_LIST_MAX_SZ];
} ZbZclReadReqT;

typedef struct {
    enum ZclStatusCodeT status;
    uint16_t attrId;
    enum ZclDataTypeT type;
    const uint8_t *value; /* Value as-is over-the-air (strings include the length octet(s)) */
    unsigned int length;
} ZbZclReadRspDataT;

typedef struct {
    enum ZclStatusCodeT status;
    struct ZbApsAddrT src;
    uint16_t profileId;
    uint8_t linkQuality;
    unsigned int count;
    ZbZclReadRspDataT attr[ZCL_ATTRIBUTE_LIST_MAX_SZ];
} ZbZclReadRspT;

/* ZbZclReadWait
 *      zb ;
 *      req ; request struct
 *      rsp ; response struct
 *      buf ; buffer to hold the response attribute data. Allocated by caller.
 *      sz ; maximum length of 'buf' */
void ZbZclReadWait(struct ZbZclClusterT *clusterPtr, ZbZclReadReqT *req, ZbZclReadRspT *rsp, void *buf, unsigned int sz);

enum ZclStatusCodeT ZbZclReadReq(struct ZbZclClusterT *clusterPtr, ZbZclReadReqT *req,
    void (*callback)(const ZbZclReadRspT *readRsp, void *cb_arg), void *arg);

typedef struct {
    /* TODO: implement a selector for structured version. */
    uint16_t attrId;
    enum ZclDataTypeT type;
    const uint8_t *value; /* in zigbee format (integers are little endian) */
    unsigned int length;
} ZbZclWriteReqDataT;

typedef struct {
    enum ZclStatusCodeT status;
    uint16_t attrId;
} ZbZclWriteRspDataT;

typedef struct {
    struct ZbApsAddrT dst;
    unsigned int count;
    ZbZclWriteReqDataT attr[ZCL_ATTRIBUTE_LIST_MAX_SZ];
} ZbZclWriteReqT;

typedef struct {
    enum ZclStatusCodeT status;
    struct ZbApsAddrT src;
    uint16_t profileId;
    uint8_t linkQuality;
    unsigned int count;
    ZbZclWriteRspDataT attr[ZCL_ATTRIBUTE_LIST_MAX_SZ];
} ZbZclWriteRspT;

void ZbZclWriteWait(struct ZbZclClusterT *clusterPtr, ZbZclWriteReqT *req, ZbZclWriteRspT *rsp);

enum ZclStatusCodeT ZbZclWriteReq(struct ZbZclClusterT *clusterPtr, ZbZclWriteReqT *req,
    void (*callback)(const ZbZclWriteRspT *writeResp, void *cb_arg), void *arg);

/*---------------------------------------------------------------
 * Attribute Discovery
 *---------------------------------------------------------------
 */
typedef struct {
    struct ZbApsAddrT dst;
    uint16_t startAttr;
    uint8_t max;
} ZbZclDiscoverAttrReqT;

typedef struct {
    uint16_t attrId;
    enum ZclDataTypeT type;
} ZbZclDiscoverAttrRspDataT;

typedef struct {
    enum ZclStatusCodeT status;
    struct ZbApsAddrT src;
    uint8_t discComplete;
    ZbZclDiscoverAttrRspDataT attrInfo[ZCL_ATTRIBUTE_LIST_MAX_SZ];
    uint8_t numAttr;
} ZbZclDiscoverAttrRspT;

enum ZclStatusCodeT ZbZclDiscoverAttrReq(struct ZbZclClusterT *clusterPtr, ZbZclDiscoverAttrReqT *req,
    void (*callback)(const ZbZclDiscoverAttrRspT *discRsp, void *cb_arg), void *arg);

void ZbZclDiscoverAttrWait(struct ZbZclClusterT *clusterPtr, ZbZclDiscoverAttrReqT *req, ZbZclDiscoverAttrRspT *rsp);

/*---------------------------------------------------------------
 * Attribute Reporting
 *---------------------------------------------------------------
 */
enum ZbZclReportDirectionT {
    /* For Configure Reporting: receiver configures attribute to send
     * reports via binding table.
     *
     * For Read Reporting: specifies whether values of the attribute are reported */
    ZCL_REPORT_DIRECTION_NORMAL = 0x00,

    /* For Configure Reporting: sender is sending reports to the receiver,
     * based on the state of the sender's bindings. Tells receiver how / when
     * it should expect reports.
     *
     * For Read Reporting: specifies whether reports of the attribute are received. */
    ZCL_REPORT_DIRECTION_REVERSE = 0x01
};

/* ZCL Reporting Configuration Record Structure. */
struct ZbZclReportConfigT {
    enum ZbZclReportDirectionT direction;
    uint16_t attributeId;
    enum ZclDataTypeT dataType;
    uint16_t minInterval;
    uint16_t maxInterval;
    union {
        long long integer;
        double floating;
    } minChange;
    uint16_t reportTimeout;
};

/* Appends a Reporting configuration record to the end of the provided buffer.
 * Returns Length of data written, or negative value (-1) on error. */
int ZbZclAppendReportConfig(struct ZbZclReportConfigT *configPtr, uint8_t *payload, unsigned int max_len);

/*---------------------------------------------------------------
 * Attribute Persistence
 *---------------------------------------------------------------
 */
/* If an attribute is modified outside of the normal ZCL Write
 * mechanism, the application must call this function to inform
 * the stack to persist the new attribute data. */
bool ZbZclAttrPersist(struct ZbZclClusterT *clusterPtr, uint16_t attr_id);

/*---------------------------------------------------------------
 * Cluster Request helpers
 *---------------------------------------------------------------
 */
struct ZbZclClusterCommandReqT {
    /* Destination for command */
    struct ZbApsAddrT dst;
    /* Command ID */
    uint8_t cmdId;
    /* If noDefaultResp is TRUE, disables a Default Response on status = SUCCESS. */
    enum ZbZclNoDefaultResponseT noDefaultResp;
    /* ZCL Request Command Payload */
    uint8_t *payload;
    unsigned int length;
};

/* ZbZclClusterCommandReq and ZbZclClusterCommandWait are wrappers to ZbZclCommandReq. */
/* clusterPtr = The cluster that is originating this message. Information from the cluster is used when
 * sending the command (source addressing, APS TX Options).
 * "callback" may be NULL */
enum ZclStatusCodeT ZbZclClusterCommandReq(struct ZbZclClusterT *clusterPtr, struct ZbZclClusterCommandReqT *req,
    void (*callback)(struct ZbZclCommandRspT *zcl_rsp, void *arg), void *arg);

/* Blocking version of ZbZclClusterCommandReq */
/* Response Info (rsp) may be NULL. If not NULL, make sure to provide a valid buffer pointer
 * to rsp->payload and specify the maximum length to rsp->length. */
enum ZclStatusCodeT ZbZclClusterCommandWait(struct ZbZclClusterT *clusterPtr, struct ZbZclClusterCommandReqT *req,
    struct ZbZclCommandRspT *zcl_rsp);

/*---------------------------------------------------------------
 * Cluster Response helpers
 *---------------------------------------------------------------
 */
/* ZbZclClusterCommandRsp sends a cluster-specific response to the destination provided.
 * There is no checking if the originating request was sent to broadcast, etc. That
 * checking must be done by the caller before this function is called.
 *
 * Returns ZCL_STATUS_SUCCESS if the message was queued to the stack, or an error status
 * otherwise. */
enum ZclStatusCodeT ZbZclClusterCommandRsp(struct ZbZclClusterT *clusterPtr, struct ZbZclAddrInfoT *dstInfo,
    uint8_t cmdId, ZbApsBufT *payloads, uint8_t numPayloads);

enum ZclStatusCodeT ZbZclClusterCommandRspWithCb(struct ZbZclClusterT *clusterPtr, struct ZbZclAddrInfoT *dstInfo,
    uint8_t cmdId, ZbApsBufT *payloads, uint8_t numPayloads, void (*callback)(ZbApsdeDataConfT *conf, void *arg), void *arg);

/* ZbZclSendClusterStatusResponse is a wrapper to ZbZclClusterCommandRsp. The parameters zclPayload and zclPaylen must
 * be populated and the first byte must represent a status code of some sort with success == 0x00. If the request was
 * broadcast (address or endpoint) and status != 0x00, then the response will not be sent. */
enum ZclStatusCodeT ZbZclSendClusterStatusResponse(struct ZbZclClusterT *clusterPtr,
    ZbApsdeDataIndT *dataIndPtr, struct ZbZclHeaderT *zclHdrPtr, uint8_t cmdId,
    uint8_t *zclPayload, uint8_t zclPaylen);

/* Send a Default Response. */
void ZbZclSendDefaultResponse(struct ZbZclClusterT *clusterPtr, ZbApsdeDataIndT *dataIndPtr,
    struct ZbZclHeaderT *zclHdrPtr, enum ZclStatusCodeT status);
/* Different version of ZbZclSendDefaultResponse, but takes in ZbZclAddrInfoT rather than
 * ZbApsdeDataIndT and ZbZclHeaderT */
void ZbZclSendDefaultResponse2(struct ZbZclClusterT *clusterPtr, struct ZbZclAddrInfoT *dstInfo,
    uint8_t cmdId, enum ZclStatusCodeT status);

/*---------------------------------------------------------------
 * Bind a cluster so it can receive messages directly from the APS layer
 *---------------------------------------------------------------
 */
/* Binds the cluster structure to a particular endpoint and optional remote
 * address, and sets up a packet filter to handle the command reception. */
enum ZclStatusCodeT ZbZclClusterBind(struct ZbZclClusterT *clusterPtr, uint8_t endpoint,
    uint16_t profileId, enum ZbZclDirectionT direction);
void ZbZclClusterUnbind(struct ZbZclClusterT *clusterPtr);

enum ZclStatusCodeT ZbZclClusterLoopbackBind(struct ZbZclClusterT *clusterPtr, struct ZbApsFilterT *filter);
void ZbZclClusterLoopbackUnbind(struct ZbZclClusterT *clusterPtr, struct ZbApsFilterT *filter);

/*---------------------------------------------------------------
 * Device Log (whitelist)
 *---------------------------------------------------------------
 */
/* Since the Trust Center address is not known ahead of time, joiners using CBKE will automatically
 * add the Trust Center to the Device Log, so they can perform CBKE if Device Log is enabled.
 * The TC is removed if CBKE fails. */
void ZbZclDeviceLogEnable(struct ZigBeeT *zb, bool enable);
bool ZbZclDeviceLogAdd(struct ZigBeeT *zb, uint64_t ext_addr);
bool ZbZclDeviceLogRemove(struct ZigBeeT *zb, uint64_t ext_addr);
void ZbZclDeviceLogClear(struct ZigBeeT *zb);

/*---------------------------------------------------------------
 * ZCL Internal Use Only
 *---------------------------------------------------------------
 */
enum ZclStateReqReturn {
    ZCL_STATE_CONTINUE = 0, /**< Return zero to continue waiting for responses. */
    ZCL_STATE_CLEANUP /**< Return one to cleanup the state. */
};

typedef enum ZclStateReqReturn (*ZbZclHandlerFuncT)(struct ZbZclCommandRspT *cmdRsp, void *callback, void *arg);

enum ZclStatusCodeT ZbZclStateBegin(struct ZigBeeT *zb, ZbApsdeDataReqT *apsReq, struct ZbZclHeaderT *zclHdr,
    unsigned int timeout, ZbZclHandlerFuncT handler, void *callback, void *arg);

/*---------------------------------------------------------------
 * Helper Functions
 *---------------------------------------------------------------
 */
/* Get the next ZCL sequence number to use in a request/notify message. */
uint8_t ZbZclGetNextSeqnum(void);

/* Helper functions to SET cluster parameters */
void ZbZclClusterSetCallbackArg(struct ZbZclClusterT *clusterPtr, void *app_cb_arg);
void ZbZclClusterSetMfrCode(struct ZbZclClusterT *clusterPtr, uint16_t mfrCode);
void ZbZclClusterSetProfileId(struct ZbZclClusterT *clusterPtr, uint16_t profileId);
/* Sets the minimum security level for incoming frames, and also adjusts
 * the tx options to match (assuming symmetrical security).
 * minSecurity can be one of: ZB_APS_STATUS_UNSECURED, ZB_APS_STATUS_SECURED_NWK_KEY or ZB_APS_STATUS_SECURED_LINK_KEY  */
bool ZbZclClusterSetMinSecurity(struct ZbZclClusterT *clusterPtr, enum ZbStatusCodeT minSecurity);
/* e.g. ZB_APSDE_DATAREQ_TXOPTIONS_ACK, ZB_APSDE_DATAREQ_TXOPTIONS_SECURITY */
void ZbZclClusterSetTxOptions(struct ZbZclClusterT *clusterPtr, uint16_t txOptions);
void ZbZclClusterSetDiscoverRoute(struct ZbZclClusterT *clusterPtr, bool discoverRoute);
void ZbZclClusterSetRadius(struct ZbZclClusterT *clusterPtr, uint8_t radius);
/* Set the maximum ASDU length for the cluster. The ASDU length includes
 * fragmentation, if enabled in the cluster's tx options. */
bool ZbZclClusterSetMaxAsduLength(struct ZbZclClusterT *clusterPtr, uint16_t maxAsduLength);

/* Helper functions to initialize requests based on cluster parameters */
void ZbZclClusterInitCommandReq(struct ZbZclClusterT *clusterPtr, ZbZclCommandReqT *cmdReq);
void ZbZclClusterInitApsdeReq(struct ZbZclClusterT *clusterPtr, ZbApsdeDataReqT *apsReq, ZbApsdeDataIndT *dataIndPtr);
/* Helper to generate proper APS TX Options (e.g. ZB_APSDE_DATAREQ_TXOPTIONS_SECURITY)
 * for a response, based on the given (incoming message) security status code. */
uint16_t ZbZclTxOptsFromSecurityStatus(enum ZbStatusCodeT security_status);

/* Helper functions to GET cluster parameters */
uint8_t ZbZclClusterGetEndpoint(struct ZbZclClusterT *clusterPtr);
enum ZbZclClusterIdT ZbZclClusterGetClusterId(struct ZbZclClusterT *clusterPtr);
uint16_t ZbZclClusterGetProfileId(struct ZbZclClusterT *clusterPtr);
uint16_t ZbZclClusterGetTxOptions(struct ZbZclClusterT *clusterPtr);
enum ZbZclDirectionT ZbZclClusterGetDirection(struct ZbZclClusterT *clusterPtr);
const char * ZbZclClusterGetDirectionStr(struct ZbZclClusterT *clusterPtr);
uint8_t ZbZclClusterGetRadius(struct ZbZclClusterT *clusterPtr);
unsigned int ZbZclClusterGetMaxAsduLength(struct ZbZclClusterT *clusterPtr);

void ZbZclClusterReportCallbackAttach(struct ZbZclClusterT *clusterPtr,
    void (*callback)(struct ZbZclClusterT *clusterPtr, ZbApsdeDataIndT *dataIndPtr,
        uint16_t attr_id, enum ZclDataTypeT data_type, const uint8_t *in_payload, uint16_t in_len));

/* Send an alarm from a cluster as if it originated from the alarms cluster
 * on the same endpoint. Typically, src_endpoint = ZbZclClusterGetEndpoint(clusterPtr).
 * If the cluster appears on multiple endpoints (e.g. Basic Cluster), the src_endpoint
 * is required to know which one to actually send the Alarm Command from.
 * The alarm message is sent via APS binding(s). */
void ZbZclClusterSendAlarm(struct ZbZclClusterT *clusterPtr, uint8_t src_endpoint, uint8_t alarm_code);

/*---------------------------------------------------------------
 * Exegin Internal ZCL Loopback Commands
 *---------------------------------------------------------------
 */
/* Our internal Manufacturer Code (ZCL_FRAMECTRL_MANUFACTURER).
 * This code is never sent over the air. */
enum {
    ZCL_MANUF_CODE_INTERNAL = 0xfffe
};

/* Exegin's Manufacturer Specific Global Commands
 * ZCL_FRAMECTRL_MANUFACTURER && ZCL_FRAMETYPE_PROFILE && (Manufacturer Code == ZCL_MANUF_CODE_INTERNAL) */
enum {
    /* For Scene Store Command (ZCL_SCENES_COMMAND_STORE_SCENE)
     * Payload for Request (to Server): None
     * Payload for Response: [CLUSTER(2) | EXT_LEN(1) | EXT_ATTR_DATA(N)] */
    ZCL_CMD_MANUF_INTERNAL_GET_SCENE_EXTDATA, /* get_scene_data() */

    /* For Scene Recall Command (ZCL_SCENES_COMMAND_RECALL_SCENE)
     * Payload for Request (to Server): [EXT_LEN(1) | EXT_ATTR_DATA(N)]
     * Payload for Response: [STATUS(1)] */
    ZCL_CMD_MANUF_INTERNAL_SET_SCENE_EXTDATA, /* set_scene_data() */

    /* ZCL Cluster Persistence: Profile-Wide Manufacturer-Specific command
     * sent to a cluster to restore persistence. */
    ZCL_CMD_MANUF_INTERNAL_ATTR_PERSIST_SET
};

/* Offsets into ZCL_CMD_MANUF_INTERNAL_SET_SCENE_EXTDATA message */
#define SET_SCENE_EXTDATA_OFFSET_EXT_LEN                4U
#define SET_SCENE_EXTDATA_OFFSET_EXT_FIELD              5U
#define SET_SCENE_EXTDATA_HEADER_LEN                    (4U + 1U)

enum {
    ZCL_PERSIST_SVR_CMD_PUSH
};

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ZCL_H */