9b0981444697d099bcc6cfcbd1cc840e0f125327
[platform/upstream/iotivity.git] / plugins / zigbee_wrapper / src / zigbee_wrapper.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 /**
22  * @file
23  *
24  * This file contains defined interface for the Zigbee Radio.
25  */
26
27  #ifdef __cplusplus
28 #include <cfloat>
29 #else
30 #include <float.h>
31 #endif // __cplusplus
32
33 #include <stdbool.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <inttypes.h> // To convert "int64_t" to string.
37 #include <math.h>
38 #include <errno.h>
39
40 // The following #define must be here under "math.h".
41 // This ifdef ensures that "__STDC_IEC_559__" is defined. If it is defined,
42 // then we are guaranteed that the 'double' type is 64-bit. Otherwise, the
43 // compilation of this file should fail because we are no longer guaranteed.
44 #ifndef __STDC_IEC_559__
45 #error "Requires IEEE 754 floating point!"
46 #endif
47
48 #include "zigbee_wrapper.h"
49 #include "telegesis_wrapper.h"
50 #include "pluginlist.h"
51
52 #include "ocpayload.h"
53 #include "oic_malloc.h"
54 #include "oic_string.h"
55 #include "logger.h"
56
57 #define HexPrepend "0x"
58
59 #define TAG "zigbeeWrapper"
60
61 // TODO: These should eventually go into an XML/JSON/Mapping thing
62 #define MAX_ATTRIBUTES                       10
63 #define ZB_TEMPERATURE_CLUSTER               "0402"
64 #define ZB_TEMPERATURE_ATTRIBUTE_ID          "0000"
65 #define ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY  "0000"
66 #define ZB_ON_LEVEL_ATTRIBUTE                "0011"
67 #define ZB_LEVEL_CONTROL_CLUSTER             "0008"
68 #define ZB_IAS_ZONE_CLUSTER                  "0500"
69 #define ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID      "0002"
70 #define ZB_INDICATOR_CLUSTER                 "0003"
71 #define ZB_INDICATOR_ATTRIBUTE_ID            "0000"
72 #define ZB_ON_OFF_CLUSTER                    "0006"
73 #define ZB_ON_OFF_ATTRIBUTE_ID               "0000"
74 #define ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID        "0001"
75 #define ZB_COLOR_CONTROL_CLUSTER             "0300"
76 #define ZB_COLOR_TEMPERATURE_ATTRIBUTE_ID    "0007"
77
78 #define IAS_ZONE_TYPE_MOTION_SENSOR          "000D"
79 #define IAS_ZONE_TYPE_CONTACT_SENSOR         "0015"
80 #define IAS_ZONE_TYPE_WATER_SENSOR           "002A"
81
82 #define ZB_DATA_TYPE_NULL                    "00"
83 #define ZB_DATA_TYPE_1_BYTE                  "08"
84 #define ZB_DATA_TYPE_2_BYTE                  "09"
85 #define ZB_DATA_TYPE_3_BYTE                  "0a"
86 #define ZB_DATA_TYPE_4_BYTE                  "0b"
87 #define ZB_DATA_TYPE_5_BYTE                  "0c"
88 #define ZB_DATA_TYPE_6_BYTE                  "0d"
89 #define ZB_DATA_TYPE_7_BYTE                  "0e"
90 #define ZB_DATA_TYPE_8_BYTE                  "0f"
91 #define ZB_DATA_TYPE_BOOL                    "10"
92 #define ZB_DATA_TYPE_SIGNED_INT_16           "29"
93 #define ZB_DATA_TYPE_UNSIGNED_INT_8          "20"
94 #define ZB_DATA_TYPE_UNSIGNED_INT_16         "21"
95
96 #define MAX_STRLEN_INT (10)
97 // DBL_MANT_DIG = Max # of digits after decimal after the leading zeros.
98 // DBL_MIN_EXP = Max # of leading zeros of the mantissa.
99 // Magic number '3' represents a '-' (negative sign), '0' (a possible zero), and '.' (a period).
100 //       "-0." from a number like "-0.999999991245", the "-0." adds 3 unaccounted characters.
101 #define MAX_STRLEN_DOUBLE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
102 #define MAX_STRLEN_BOOL (1)
103
104 #define DEFAULT_TRANS_TIME "0000"
105 #define DEFAULT_MOVETOLEVEL_MODE "0"
106
107 static const char* OIC_TEMPERATURE_SENSOR = "oic.r.temperature";
108 static const char* OIC_DIMMABLE_LIGHT = "oic.r.light.dimming";
109 static const char* OIC_CONTACT_SENSOR = "oic.r.sensor.contact";
110 static const char* OIC_MOTION_SENSOR = "oic.r.sensor.motion";
111 static const char* OIC_WATER_SENSOR = "oic.r.sensor.water";
112 static const char* OIC_BINARY_SWITCH = "oic.r.switch.binary";
113 static const char* OIC_CHROMA_LIGHT = "oic.r.colour.chroma";
114
115 static const char* OIC_TEMPERATURE_ATTRIBUTE = "temperature";
116 static const char* OIC_DIMMING_ATTRIBUTE = "dimmingSetting";
117 static const char* OIC_CONTACT_ATTRIBUTE = "value";
118 static const char* OIC_WATER_ATTRIBUTE = "value";
119 static const char* OIC_MOTION_ATTRIBUTE = "value";
120 static const char* OIC_ON_OFF_ATTRIBUTE = "value";
121 static const char* OIC_COLOUR_TEMPERATURE_ATTRIBUTE = "colourspacevalue";
122
123 PIPlugin_Zigbee ** gPlugin = NULL;
124
125 typedef enum
126 {
127     ZB_NULL,   // No Data
128     ZB_8_BIT,  // 1 byte
129     ZB_16_BIT, // 2 bytes
130     ZB_24_BIT, // 3 bytes
131     ZB_32_BIT, // 4 bytes
132     ZB_40_BIT, // 5 bytes
133     ZB_48_BIT, // 6 bytes
134     ZB_56_BIT, // 7 bytes
135     ZB_64_BIT, // 8 bytes
136     ZB_BOOL,   // boolean
137     ZB_8_BITMAP,
138     ZB_16_BITMAP,
139     ZB_24_BITMAP,
140     ZB_32_BITMAP,
141     ZB_40_BITMAP,
142     ZB_48_BITMAP,
143     ZB_56_BITMAP,
144     ZB_64_BITMAP,
145     ZB_16_SINT,
146     ZB_8_UINT,
147     ZB_16_UINT
148 } ZigBeeAttributeDataType;
149
150 char * getZBDataTypeString(ZigBeeAttributeDataType attrType);
151 OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
152         OCRepPayload **payload);
153
154 typedef enum
155 {
156     OIC_ATTR_NULL,
157     OIC_ATTR_INT,
158     OIC_ATTR_DOUBLE,
159     OIC_ATTR_BOOL,
160     OIC_ATTR_STRING
161 } OICAttributeType;
162
163 typedef struct
164 {
165     char                *oicAttribute;
166     char                *zigBeeAttribute;
167     OICAttributeType    oicType;
168     ZigBeeAttributeDataType zigbeeType;
169     union
170     {
171         int64_t i;
172         double d;
173         bool b;
174         char* str;
175     } val;
176
177 } OICZigBeeAttributePair;
178
179 typedef enum
180 {
181     CIE_RON_OFF         = 1 << 1,
182     CIE_MOVE_TO_LEVEL   = 1 << 2
183
184 } CIECommandMask;
185
186 typedef struct
187 {
188     uint32_t count;
189     CIECommandMask CIEMask;
190     OICZigBeeAttributePair list[MAX_ATTRIBUTES];
191 } AttributeList;
192
193 const char* ZigBeeClusterIDToOICResourceType(const char * clusterID);
194
195 OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
196                                                     AttributeList *attributeList);
197
198 bool getZigBeeAttributesIfValid(const char * OICResourceType,
199                                     AttributeList *attributeList,
200                                     OCRepPayload *payload);
201
202 const char * getResourceTypeForIASZoneType(TWDevice *device)
203 {
204     if (!device)
205     {
206         return NULL;
207     }
208     char *IASZoneType = NULL;
209     const char *resourceType = NULL;
210     uint8_t length = 0;
211
212     OCStackResult ret = TWGetAttribute(
213         NULL,
214         device->nodeId,
215         device->endpointOfInterest->endpointId,
216         ZB_IAS_ZONE_CLUSTER,
217         ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID,
218         &IASZoneType,
219         &length,
220         *gPlugin
221     );
222
223     if (ret != OC_STACK_OK || !IASZoneType)
224     {
225         OC_LOG_V(ERROR, TAG, "Error %u getting IAS Zone Type", ret);
226         return NULL;
227     }
228
229     if (strcmp(IASZoneType, IAS_ZONE_TYPE_CONTACT_SENSOR) == 0)
230     {
231         resourceType = OIC_CONTACT_SENSOR;
232     }
233     else if (strcmp(IASZoneType, IAS_ZONE_TYPE_MOTION_SENSOR) == 0)
234     {
235         resourceType = OIC_MOTION_SENSOR;
236     }
237     else if (strcmp(IASZoneType, IAS_ZONE_TYPE_WATER_SENSOR) == 0)
238     {
239         resourceType = OIC_WATER_SENSOR;
240     }
241     else
242     {
243         OC_LOG_V(ERROR, TAG, "Unsupported Zone Type %s", IASZoneType);
244         resourceType = NULL;
245     }
246
247     OICFree(IASZoneType);
248
249     return resourceType;
250 }
251
252 OCStackResult buildURI(char ** output,
253                        const char * prefix,
254                        const char * nodeId,
255                        const char * endpointId,
256                        const char * clusterId)
257 {
258     if (!output || !prefix || !nodeId || !endpointId || !clusterId)
259     {
260         return OC_STACK_INVALID_PARAM;
261     }
262     const char LEN_SEPARATOR[] = "/";
263     size_t lenSeparatorSize = sizeof(LEN_SEPARATOR) - 1;
264     size_t newUriSize = strlen(prefix) + lenSeparatorSize +
265                         strlen(nodeId) + lenSeparatorSize +
266                         strlen(endpointId) + lenSeparatorSize +
267                         strlen(clusterId)
268                         + 1; // NULL Terminator
269     *output = (char *) OICCalloc(1, newUriSize);
270
271     if (!*output)
272     {
273         OC_LOG(ERROR, TAG, "Out of memory");
274         return OC_STACK_NO_MEMORY;
275     }
276
277     char * temp = OICStrcpy(*output, newUriSize, prefix);
278     if (temp != *output)
279     {
280         goto exit;
281     }
282     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
283     if (temp != *output)
284     {
285         goto exit;
286     }
287     temp = OICStrcat(*output, newUriSize, nodeId);
288     if (temp != *output)
289     {
290         goto exit;
291     }
292     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
293     if (temp != *output)
294     {
295         goto exit;
296     }
297     temp = OICStrcat(*output, newUriSize, endpointId);
298     if (temp != *output)
299     {
300         goto exit;
301     }
302     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
303     if (temp != *output)
304     {
305         goto exit;
306     }
307     temp = OICStrcat(*output, newUriSize, clusterId);
308     if (temp != *output)
309     {
310         goto exit;
311     }
312
313     return OC_STACK_OK;
314
315 exit:
316     OICFree(*output);
317     *output = NULL;
318     return OC_STACK_NO_MEMORY;
319 }
320
321 void foundZigbeeCallback(TWDevice *device)
322 {
323     if (!device)
324     {
325         OC_LOG(ERROR, TAG, "foundZigbeeCallback: Invalid parameter.");
326         return;
327     }
328     int count = device->endpointOfInterest->clusterList->count;
329     for (int i=0; i < count; i++)
330     {
331         PIResource_Zigbee *piResource = (PIResource_Zigbee *) OICMalloc(sizeof(*piResource));
332         if (!piResource)
333         {
334             OC_LOG(ERROR, TAG, "Out of memory");
335             return;
336         }
337         piResource->header.plugin = (PIPluginBase *)gPlugin;
338
339         OCStackResult result = buildURI(&piResource->header.piResource.uri,
340                                 PI_ZIGBEE_PREFIX,
341                                 device->nodeId,
342                                 device->endpointOfInterest->endpointId,
343                                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
344
345         if (result != OC_STACK_OK)
346         {
347             OICFree(piResource);
348             return;
349         }
350
351         char * foundClusterID =
352             device->endpointOfInterest->clusterList->clusterIds[i].clusterId;
353
354         if (strcmp(foundClusterID, ZB_IAS_ZONE_CLUSTER) == 0)
355         {
356             piResource->header.piResource.resourceTypeName
357                 = getResourceTypeForIASZoneType(device);
358
359             OCStackResult ret = TWListenForStatusUpdates(device->nodeId,
360                                                           device->endpointOfInterest->endpointId,
361                                                           *gPlugin);
362
363             if (ret != OC_STACK_OK)
364             {
365                 // Just log it and move on if this fails?
366                 // or not create this resource at all?
367                 OC_LOG(ERROR, TAG, "Command to listen for status updates failed");
368             }
369         }
370         else
371         {
372             piResource->header.piResource.resourceTypeName =
373                     (char *) ZigBeeClusterIDToOICResourceType(foundClusterID);
374         }
375
376         if (piResource->header.piResource.resourceTypeName == NULL)
377         {
378             OC_LOG_V(ERROR, TAG, "unsupported clusterId : %s",
379                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
380             OICFree(piResource->header.piResource.uri);
381             OICFree(piResource);
382             continue;
383         }
384         piResource->header.piResource.resourceInterfaceName =
385                             OC_RSRVD_INTERFACE_DEFAULT;
386
387         piResource->header.piResource.callbackParam = NULL;
388         piResource->header.piResource.resourceProperties = 0;
389         piResource->eui = OICStrdup(device->eui);
390         piResource->nodeId = OICStrdup(device->nodeId);
391         piResource->endpointId = OICStrdup(device->endpointOfInterest->endpointId);
392         piResource->clusterId =
393             OICStrdup(device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
394         (*gPlugin)->header.NewResourceFoundCB(&(*gPlugin)->header, &piResource->header);
395     }
396 }
397
398 void zigbeeZoneStatusUpdate(TWUpdate * update)
399 {
400     if (!update)
401     {
402         return;
403     }
404
405     char * uri = NULL;
406     OCStackResult result = buildURI(&uri,
407                                     PI_ZIGBEE_PREFIX,
408                                     update->nodeId,
409                                     update->endpoint,
410                                     ZB_IAS_ZONE_CLUSTER);
411     if (result != OC_STACK_OK || !uri)
412     {
413         OC_LOG_V(ERROR, TAG, "Failed to build URI with result: %d", result);
414         return;
415     }
416
417     (*gPlugin)->header.ObserveNotificationUpdate((PIPluginBase *)*gPlugin, uri);
418     OICFree(uri);
419 }
420
421 OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
422                          PINewResourceFound newResourceCB,
423                          PIObserveNotificationUpdate observeNotificationUpdate)
424 {
425     if (!plugin)
426     {
427         return OC_STACK_INVALID_PARAM;
428     }
429     *plugin = (PIPlugin_Zigbee *) OICMalloc(sizeof(PIPlugin_Zigbee) + sizeof(PIPluginBase));
430     if (!*plugin)
431     {
432         return OC_STACK_NO_MEMORY;
433     }
434     ((*plugin)->header).type = PLUGIN_ZIGBEE;
435     ((*plugin)->header).comPort = comPort;
436     ((*plugin)->header).NewResourceFoundCB = newResourceCB;
437     ((*plugin)->header).ObserveNotificationUpdate = observeNotificationUpdate;
438     ((*plugin)->header).next = NULL;
439     ((*plugin)->header).resourceList = NULL;
440     ((*plugin)->header).processEHRequest = ProcessEHRequest;
441
442     gPlugin = plugin;
443     OCStackResult result = TWInitialize(*gPlugin, comPort);
444     if (result != OC_STACK_OK)
445     {
446         return result;
447     }
448
449     return TWSetStatusUpdateCallback(zigbeeZoneStatusUpdate, *gPlugin);
450 }
451
452 OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
453 {
454     OCStackResult result = OC_STACK_ERROR;
455     TWSetDiscoveryCallback(foundZigbeeCallback, plugin);
456     result = TWDiscover(plugin);
457     OC_LOG_V(DEBUG, TAG, "ZigbeeDiscover : Status = %d\n", result);
458
459     return result;
460 }
461
462 OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin)
463 {
464     OCStackResult ret = TWUninitialize(plugin);
465     free(plugin);
466     return ret;
467 }
468
469 OCStackResult ZigbeeProcess(PIPlugin_Zigbee * plugin)
470 {
471     return TWProcess(plugin);
472 }
473
474 // Function returns an OIC Smart Home resource Type
475 // from the cluster ID. If the cluster is not supported, null is
476 // returned.
477 // NOTE: The returned string is NOT malloc'ed.
478 const char* ZigBeeClusterIDToOICResourceType(const char * clusterID) //Discovery/CreateResource
479 {
480     if (!clusterID)
481     {
482         return NULL;
483     }
484     if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
485     {
486         return OIC_TEMPERATURE_SENSOR;
487     }
488     else if (strcmp(clusterID, ZB_LEVEL_CONTROL_CLUSTER) == 0)
489     {
490         return OIC_DIMMABLE_LIGHT;
491     }
492     else if (strcmp(clusterID, ZB_IAS_ZONE_CLUSTER) == 0)
493     {
494         return OIC_CONTACT_SENSOR;
495     }
496     else if (strcmp(clusterID, ZB_ON_OFF_CLUSTER) == 0)
497     {
498         return OIC_BINARY_SWITCH;
499     }
500     else if (strcmp(clusterID, ZB_COLOR_CONTROL_CLUSTER) == 0)
501     {
502         return OIC_CHROMA_LIGHT;
503     }
504     else
505     {
506         return NULL;
507     }
508 }
509
510 const char* OICResourceToZigBeeClusterID(char *oicResourceType)
511 {
512     if (!oicResourceType)
513     {
514         return NULL;
515     }
516     if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
517     {
518         return ZB_TEMPERATURE_CLUSTER;
519     }
520     else if (strcmp(oicResourceType, OIC_DIMMABLE_LIGHT) == 0)
521     {
522         return ZB_LEVEL_CONTROL_CLUSTER;
523     }
524     else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
525     {
526         return ZB_IAS_ZONE_CLUSTER;
527     }
528     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
529     {
530         return ZB_ON_OFF_CLUSTER;
531     }
532     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
533     {
534         return ZB_INDICATOR_CLUSTER;
535     }
536     else if (strcmp(oicResourceType, OIC_CHROMA_LIGHT) == 0)
537     {
538         return ZB_COLOR_CONTROL_CLUSTER;
539     }
540     else
541     {
542         return NULL;
543     }
544 }
545
546 OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
547                                                     AttributeList *attributeList) // GET
548 {
549     if (!OICResourceType || !attributeList)
550     {
551         return OC_STACK_INVALID_PARAM;
552     }
553     if (strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
554     {
555         attributeList->count = 1;
556         attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
557         attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
558         attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
559         attributeList->list[0].zigbeeType = ZB_16_SINT;
560         return OC_STACK_OK;
561     }
562     else if (strcmp(OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
563     {
564         attributeList->count = 1;
565         attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
566         attributeList->list[0].zigBeeAttribute = ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY;
567         attributeList->list[0].oicType = OIC_ATTR_INT;
568         attributeList->list[0].zigbeeType = ZB_8_UINT;
569         return OC_STACK_OK;
570     }
571     else if (strcmp(OICResourceType, OIC_CONTACT_SENSOR) == 0)
572     {
573         attributeList->count = 1;
574         attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
575         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
576         attributeList->list[0].oicType = OIC_ATTR_BOOL;
577         attributeList->list[0].zigbeeType = ZB_BOOL;
578         return OC_STACK_OK;
579     }
580     else if (strcmp(OICResourceType, OIC_WATER_SENSOR) == 0)
581     {
582         attributeList->count = 1;
583         attributeList->list[0].oicAttribute = OICStrdup(OIC_WATER_ATTRIBUTE);
584         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
585         attributeList->list[0].oicType = OIC_ATTR_BOOL;
586         attributeList->list[0].zigbeeType = ZB_BOOL;
587         return OC_STACK_OK;
588     }
589     else if (strcmp(OICResourceType, OIC_MOTION_SENSOR) == 0)
590     {
591         attributeList->count = 1;
592         attributeList->list[0].oicAttribute = OICStrdup(OIC_MOTION_ATTRIBUTE);
593         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
594         attributeList->list[0].oicType = OIC_ATTR_BOOL;
595         attributeList->list[0].zigbeeType = ZB_BOOL;
596         return OC_STACK_OK;
597     }
598     else if (strcmp(OICResourceType, OIC_BINARY_SWITCH) == 0)
599     {
600         attributeList->count = 1;
601         attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
602         attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
603         attributeList->list[0].oicType = OIC_ATTR_BOOL;
604         attributeList->list[0].zigbeeType = ZB_BOOL;
605         return OC_STACK_OK;
606     }
607     else if (strcmp(OICResourceType, OIC_CHROMA_LIGHT) == 0)
608     {
609         attributeList->count = 1;
610         attributeList->list[0].oicAttribute = OICStrdup(OIC_COLOUR_TEMPERATURE_ATTRIBUTE);
611         attributeList->list[0].zigBeeAttribute = ZB_COLOR_TEMPERATURE_ATTRIBUTE_ID;
612         attributeList->list[0].oicType = OIC_ATTR_INT;
613         attributeList->list[0].zigbeeType = ZB_16_UINT;
614         return OC_STACK_OK;
615     }
616
617     return OC_STACK_ERROR;
618 }
619
620 bool getZigBeeAttributesIfValid(const char * OICResourceType,
621                                     AttributeList *attributeList,
622                                     OCRepPayload *payload) // Put
623 {
624     if (!OICResourceType)
625     {
626         return false;
627     }
628     if (strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
629     {
630         // Cant really PUT on the temp sensor, but the code is still there.
631         int64_t temperature = 0;
632
633         // TODO: This if should only look for attributes it supports and ignore the rest
634         // or examine every attribute in the payload and complain about unsupported attributes?
635         if (OCRepPayloadGetPropInt(payload, OIC_TEMPERATURE_ATTRIBUTE, &temperature))
636         {
637             attributeList->count = 1;
638             attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
639             attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
640             attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
641             attributeList->list[0].val.d = temperature;
642             attributeList->list[0].zigbeeType = ZB_16_SINT;
643             attributeList->CIEMask = (CIECommandMask) 0;
644
645             return true;
646         }
647     }
648     else if (strcmp(OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
649     {
650         int64_t onLevel = 0;
651
652         if (OCRepPayloadGetPropInt(payload, OIC_DIMMING_ATTRIBUTE, &onLevel))
653         {
654             attributeList->count = 1;
655             attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
656             attributeList->list[0].zigBeeAttribute = ZB_ON_LEVEL_ATTRIBUTE;
657             attributeList->list[0].oicType = OIC_ATTR_INT;
658             attributeList->list[0].val.i = onLevel;
659             attributeList->list[0].zigbeeType = ZB_8_UINT;
660
661             // Level control cluster is dealing with level in the PUT payload.
662             attributeList->CIEMask = attributeList->CIEMask | CIE_MOVE_TO_LEVEL;
663             return true;
664         }
665     }
666     else if (strcmp(OICResourceType, OIC_CONTACT_SENSOR) == 0)
667     {
668         int64_t value = 0;
669
670         if (OCRepPayloadGetPropInt(payload, OIC_CONTACT_ATTRIBUTE, &value))
671         {
672             attributeList->count = 1;
673             attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
674             attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
675             attributeList->list[0].oicType = OIC_ATTR_BOOL;
676             attributeList->list[0].val.i = value;
677             attributeList->list[0].zigbeeType = ZB_BOOL;
678             attributeList->CIEMask = (CIECommandMask) 0;
679
680             return true;
681         }
682     }
683     else if (strcmp(OICResourceType, OIC_WATER_SENSOR) == 0)
684     {
685         int64_t value = 0;
686
687         if (OCRepPayloadGetPropInt(payload, OIC_WATER_ATTRIBUTE, &value))
688         {
689             attributeList->count = 1;
690             attributeList->list[0].oicAttribute = OICStrdup(OIC_WATER_ATTRIBUTE);
691             attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
692             attributeList->list[0].oicType = OIC_ATTR_BOOL;
693             attributeList->list[0].val.i = value;
694             attributeList->list[0].zigbeeType = ZB_BOOL;
695             attributeList->CIEMask = (CIECommandMask) 0;
696
697             return true;
698         }
699     }
700     else if (strcmp(OICResourceType, OIC_BINARY_SWITCH) == 0)
701     {
702         bool value = 0;
703
704         if (OCRepPayloadGetPropBool(payload, OIC_ON_OFF_ATTRIBUTE, &value))
705         {
706             attributeList->count = 1;
707             attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
708             attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
709             attributeList->list[0].oicType = OIC_ATTR_BOOL;
710             attributeList->list[0].val.b = value;
711             attributeList->list[0].zigbeeType = ZB_BOOL;
712
713             attributeList->CIEMask = attributeList->CIEMask | CIE_RON_OFF;
714             return true;
715         }
716     }
717     else if (strcmp(OICResourceType, OIC_CHROMA_LIGHT) == 0)
718     {
719         char * value = 0;
720         if (OCRepPayloadGetPropString(payload, OIC_COLOUR_TEMPERATURE_ATTRIBUTE, &value))
721         {
722             attributeList->count = 1;
723             attributeList->list[0].oicAttribute = OICStrdup(OIC_COLOUR_TEMPERATURE_ATTRIBUTE);
724             attributeList->list[0].zigBeeAttribute = ZB_COLOR_TEMPERATURE_ATTRIBUTE_ID;
725             attributeList->list[0].oicType = OIC_ATTR_STRING;
726             attributeList->list[0].val.str = value;
727             attributeList->list[0].zigbeeType = ZB_16_UINT;
728             attributeList->CIEMask = (CIECommandMask) 0;
729
730             return true;
731         }
732     }
733     return false;
734 }
735
736 OCEntityHandlerResult getDoubleValueFromString(const char *str, double *outDouble)
737 {
738     if (!str || !outDouble)
739     {
740         return OC_EH_ERROR;
741     }
742     size_t hexOutValSize = strlen(HexPrepend) + strlen(str) + 1;
743     char * hexOutVal = (char *) OICCalloc(1, hexOutValSize);
744     if (!hexOutVal)
745     {
746         return OC_EH_ERROR;
747     }
748     OICStrcpy(hexOutVal, hexOutValSize, HexPrepend);
749     OICStrcat(hexOutVal, hexOutValSize, str);
750
751     char *endPtr = NULL;
752     errno = 0;
753     double value = strtod(hexOutVal, &endPtr);
754
755     if (errno != 0 || *endPtr != 0 || value == HUGE_VALF || value == HUGE_VALL)
756     {
757         OICFree(hexOutVal);
758         return OC_EH_ERROR;
759     }
760
761     OICFree(hexOutVal);
762     *outDouble = value;
763     return OC_EH_OK;
764
765 }
766
767 OCEntityHandlerResult getColourTemperatureFromString(const char* str, int64_t* outVal)
768 {
769     if (!str || !outVal)
770     {
771         return OC_EH_ERROR;
772     }
773     // str comes in as "X,Y,T" where "T" is the colour temperature.
774     // Iterate 3 times to retrieve the last value.
775     char * strstr = OICStrdup(str);
776     char * savePtr = NULL;
777     char * temp = NULL;
778     for (int i=0; i<3; i++)
779     {
780         temp = strtok_r(strstr, ",", &savePtr);
781         if (!temp)
782         {
783             *outVal = 0;
784             OICFree(strstr);
785             return OC_EH_ERROR;
786         }
787     }
788     OCStackResult result = getDoubleValueFromString(temp, (double *)outVal);
789     OICFree(strstr);
790     return result;
791 }
792
793 OCEntityHandlerResult processGetRequest(PIPluginBase * plugin,
794         OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
795 {
796     if (!plugin || !ehRequest || !payload)
797     {
798         return OC_EH_ERROR;
799     }
800     uint32_t attributeListIndex = 0;
801     OCStackResult stackResult = OC_STACK_OK;
802     PIResource_Zigbee * piResource = NULL;
803
804     AttributeList attributeList = { 0, (CIECommandMask) 0,
805         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } } };
806     stackResult = GetResourceFromHandle(plugin, (PIResource**) (&piResource),
807                         ehRequest->resource);
808     if (stackResult != OC_STACK_OK)
809     {
810         OC_LOG(ERROR, TAG, "Failed to get resource from handle");
811         return OC_EH_ERROR;
812     }
813     stackResult = getZigBeeAttributesForOICResource(
814         piResource->header.piResource.resourceTypeName, &attributeList);
815     if (stackResult != OC_STACK_OK)
816     {
817         OC_LOG_V(ERROR, TAG, "Failed to fetch attributes for %s",
818             piResource->header.piResource.resourceTypeName);
819         return OC_EH_ERROR;
820     }
821
822     *payload = OCRepPayloadCreate();
823     if (!payload)
824     {
825         OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload"));
826         return OC_EH_ERROR;
827     }
828     bool boolRes = OCRepPayloadSetUri(*payload, piResource->header.piResource.uri);
829     if (boolRes == false)
830     {
831         OCRepPayloadDestroy(*payload);
832         return OC_EH_ERROR;
833     }
834     for (uint32_t i = 0; i<attributeList.count; i++)
835     {
836         char * outVal = NULL;
837         uint8_t outValLength = 0;
838
839         stackResult = TWGetAttribute(piResource->eui,
840                                      piResource->nodeId,
841                                      piResource->endpointId,
842                                      piResource->clusterId,
843                                      attributeList.list[i].zigBeeAttribute,
844                                      &outVal,
845                                      &outValLength,
846                                      *gPlugin);
847
848         if (stackResult != OC_STACK_OK || !outVal)
849         {
850             stackResult = OC_EH_ERROR;
851             OCRepPayloadDestroy(*payload);
852             goto exit;
853         }
854         if (attributeList.list[i].oicType == OIC_ATTR_INT)
855         {
856             char *endPtr = NULL;
857             errno = 0;
858             // Third arg is 16 as outVal is a hex Number
859             uint64_t value = strtol(outVal, &endPtr, 16);
860
861             if (*endPtr != 0 || errno != 0)
862             {
863                 return OC_EH_ERROR;
864             }
865             if (!attributeList.list[i].oicAttribute)
866             {
867                 return OC_EH_ERROR;
868             }
869             if (strcmp(attributeList.list[i].oicAttribute, OIC_DIMMING_ATTRIBUTE) == 0)
870             {
871                 // OIC Dimming operates between 0-100, while Zigbee operates
872                 // between 0-254 (ie. 0xFE).
873                 if (value > 0xFE)
874                 {
875                     value = 0xFE;
876                 }
877                 if (value <= 0xFE)
878                 {
879                     value = value / 2.54;
880                 }
881             }
882             else if (strcmp(attributeList.list[i].oicAttribute, OIC_COLOUR_TEMPERATURE_ATTRIBUTE) == 0)
883             {
884                 // OIC Chroma requires: Hue, Saturation, and ColorSpaceValue (color space value is
885                 // "chromaX, chromaY, colourTemperature").
886                 // ZigBee HA requires: "currentX", "currentY", while we're trying to map a specific
887                 // device which goes against the HA spec and ONLY implements "ColorTemperature".
888                 // Because of the misalignments between OIC Smart Home and ZigBee HA specs, the
889                 // follow assumption is required:
890                 // - *X and *Y will be zero, and therefore ignored (or passed as zero where
891                 // applicable).
892                 // OIC ColorTemperature operates between 0-1000 (degrees Kelvin) in string form,
893                 // while ZigBee operates between 0-65279 (bits, with an operating range
894                 // 15.32-1,000,000 (degrees Kelvin)).
895                 // ZigBee HA states: ColorTemperature(bits) = 1,000,000/ColorTemperature(Kelvin)
896                 // Invalid: ColorTemperature==0 || ColorTemperature==65535
897                 // However the specific bulb we're mapping only operates between 2700-6500 (Kelvin)
898                 // which equates to 0x0099-0x0172 (ie. 153-370; giving a resolution of 217 bits).
899                 // Conversion from ZigBee HA specific bulb to OIC temporary mapping:
900                 // OIC Value: 0-100  ZigBee Value: (0-217)+153
901                 // OICValue = (ZigBeeValue-153)/2.17
902
903                 value = (value-153)/2.17;
904             }
905             boolRes = OCRepPayloadSetPropInt(*payload,
906                                              attributeList.list[i].oicAttribute,
907                                              (uint64_t) value);
908         }
909         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
910         {
911             double value = 0;
912
913             if (getDoubleValueFromString(outVal, &value) != OC_EH_OK)
914             {
915                 return OC_EH_ERROR;
916             }
917             if (!piResource->clusterId)
918             {
919                 return OC_EH_ERROR;
920             }
921             if (strcmp(piResource->clusterId, ZB_TEMPERATURE_CLUSTER) == 0)
922             {
923                 // Divide by 100 as temperature readings have a resolution of
924                 // 0.01 or one hundreth of a degree celsius.
925                 value = value/100;
926             }
927             boolRes = OCRepPayloadSetPropDouble(*payload,
928                                                 attributeList.list[i].oicAttribute,
929                                                 value);
930         }
931         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
932         {
933             boolRes = OCRepPayloadSetPropString(*payload,
934                                                 attributeList.list[i].oicAttribute,
935                                                 outVal);
936         }
937         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
938         {
939             char *endPtr = NULL;
940             errno = 0;
941             // Third arg is 16 as outVal is a hex Number
942             uint64_t value = strtol(outVal, &endPtr, 16);
943
944             if (errno != 0 || *endPtr != 0)
945             {
946                 return OC_EH_ERROR;
947             }
948             // value COULD be a bit mask and the LSB indicates boolean true/false.
949             // If not a bit mask, it'll be plain 0 or 1.
950             value = value & 1;
951             boolRes = OCRepPayloadSetPropBool(*payload,
952                                               attributeList.list[i].oicAttribute,
953                                               value);
954         }
955
956         OICFree(outVal);
957     }
958
959     if (boolRes == false)
960     {
961         stackResult = OC_EH_ERROR;
962         goto exit;
963     }
964
965 exit:
966     for (; attributeListIndex < attributeList.count; attributeListIndex++)
967     {
968         OICFree(attributeList.list[attributeListIndex].oicAttribute);
969     }
970     return stackResult;
971 }
972
973 OCEntityHandlerResult processPutRequest(PIPluginBase * plugin,
974     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
975 {
976     if (!plugin || !ehRequest || !payload)
977     {
978         return OC_EH_ERROR;
979     }
980     OCStackResult stackResult = OC_STACK_OK;
981     PIResource_Zigbee *piResource = NULL;
982     AttributeList attributeList = {
983         0,
984         (CIECommandMask) 0,
985         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } }
986     };
987
988     stackResult = GetResourceFromHandle(plugin,
989                                         ((PIResource **) (&piResource)),
990                                         ehRequest->resource);
991     if (stackResult != OC_STACK_OK)
992     {
993         OC_LOG(ERROR, TAG, "Failed to get resource from handle");
994         return OC_EH_ERROR;
995     }
996
997     bool boolRes = getZigBeeAttributesIfValid(
998                         piResource->header.piResource.resourceTypeName,
999                         &attributeList, *payload);
1000     if (boolRes == false)
1001     {
1002         OC_LOG_V(ERROR, TAG, "Failed to fetch attributes for %s",
1003             piResource->header.piResource.resourceTypeName);
1004         return OC_EH_ERROR;
1005     }
1006
1007     uint32_t i = 0;
1008     for (; i<attributeList.count; i++)
1009     {
1010         if (attributeList.list[i].oicType == OIC_ATTR_INT)
1011         {
1012             char value[MAX_STRLEN_INT] = {};
1013             if (attributeList.CIEMask || CIE_MOVE_TO_LEVEL)
1014             {
1015                 int64_t rangeDiff = 0;
1016                 // OIC Dimming operates between 0-100, while Zigbee
1017                 // operates between 0-254 (ie. 0xFE).
1018                 rangeDiff = attributeList.list[i].val.i * 0xFE/100;
1019                 if (rangeDiff > 0xFE)
1020                 {
1021                     rangeDiff = 0xFE;
1022                 }
1023                 if (rangeDiff < 0)
1024                 {
1025                     rangeDiff = 0;
1026                 }
1027                 if (rangeDiff <= 0xFE)
1028                 {
1029                     errno = 0;
1030                     int strRet = snprintf(value, sizeof(value), "%02x", (unsigned int) rangeDiff);
1031                     if (strRet <= 0)
1032                     {
1033                         OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1034                         return OC_EH_ERROR;
1035                     }
1036                 }
1037                 stackResult = TWMoveToLevel(piResource->nodeId, piResource->endpointId,
1038                                     DEFAULT_MOVETOLEVEL_MODE, value, DEFAULT_TRANS_TIME,
1039                                     (PIPlugin_Zigbee*)plugin);
1040             }
1041             else
1042             {
1043                 errno = 0;
1044                 int strRet = snprintf(value,
1045                                       sizeof(value),
1046                                       "%"PRId64,
1047                                       attributeList.list[i].val.i);
1048                 if (strRet <= 0)
1049                 {
1050                     OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1051                     return OC_EH_ERROR;
1052                 }
1053                 stackResult = TWSetAttribute(piResource->eui,
1054                     piResource->nodeId, piResource->endpointId,
1055                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1056                     getZBDataTypeString(attributeList.list[i].zigbeeType), value,
1057                     (PIPlugin_Zigbee*)plugin);
1058             }
1059             if (stackResult != OC_STACK_OK)
1060             {
1061                 return OC_EH_ERROR;
1062             }
1063         }
1064         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
1065         {
1066             char value[MAX_STRLEN_DOUBLE] = {};
1067             errno = 0;
1068             int strRet = snprintf(value, sizeof(value), "%f", attributeList.list[i].val.d);
1069             if (strRet <= 0)
1070             {
1071                 OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1072                 return OC_EH_ERROR;
1073             }
1074             stackResult = TWSetAttribute(piResource->eui,
1075                 piResource->nodeId, piResource->endpointId,
1076                  piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1077                  getZBDataTypeString(attributeList.list[i].zigbeeType), value,
1078                  (PIPlugin_Zigbee*)plugin);
1079         }
1080         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
1081         {
1082             if (strcmp(attributeList.list[i].oicAttribute, OIC_COLOUR_TEMPERATURE_ATTRIBUTE) == 0)
1083             {
1084                 char *endPtr = NULL;
1085                 uint16_t zbVal = (uint16_t)strtod(attributeList.list[i].val.str, &endPtr);
1086                 zbVal = (zbVal*2.17)+153;
1087                 char value[5] = {0};
1088                 errno = 0;
1089                 int strRet = snprintf(value, sizeof(value), "%04x", zbVal);
1090                 if (strRet <= 0)
1091                 {
1092                     OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1093                     return OC_EH_ERROR;
1094                 }
1095                 stackResult =
1096                 TWColorMoveToColorTemperature(piResource->nodeId, piResource->endpointId,
1097                                               value, DEFAULT_TRANS_TIME,
1098                                               (PIPlugin_Zigbee*)plugin);
1099             }
1100             else
1101             {
1102                 stackResult = TWSetAttribute(piResource->eui,
1103                     piResource->nodeId, piResource->endpointId,
1104                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1105                     getZBDataTypeString(attributeList.list[i].zigbeeType),
1106                     attributeList.list[i].val.str,
1107                     (PIPlugin_Zigbee*)plugin);
1108             }
1109             if (stackResult != OC_STACK_OK)
1110             {
1111                 return OC_EH_ERROR;
1112             }
1113         }
1114         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
1115         {
1116             char * value = attributeList.list[i].val.b ? "1" : "0";
1117             if (attributeList.CIEMask || CIE_RON_OFF)
1118             {
1119                 stackResult = TWSwitchOnOff(piResource->nodeId, piResource->endpointId, value,
1120                                             (PIPlugin_Zigbee*)plugin);
1121             }
1122             else
1123             {
1124                 stackResult = TWSetAttribute(piResource->eui,
1125                     piResource->nodeId, piResource->endpointId,
1126                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1127                     getZBDataTypeString(attributeList.list[i].zigbeeType),
1128                     value,
1129                     (PIPlugin_Zigbee*)plugin);
1130             }
1131             if (stackResult != OC_STACK_OK)
1132             {
1133                 return OC_EH_ERROR;
1134             }
1135         }
1136         else
1137         {
1138             continue;
1139         }
1140     }
1141
1142     return processGetRequest(plugin, ehRequest, payload);
1143 }
1144
1145 OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin,
1146     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
1147 {
1148     if (!ehRequest || !payload)
1149     {
1150         return OC_EH_ERROR;
1151     }
1152     if (ehRequest->method == OC_REST_GET)
1153     {
1154         return processGetRequest(plugin, ehRequest, payload);
1155     }
1156     else if (ehRequest->method == OC_REST_PUT)
1157     {
1158         return processPutRequest(plugin, ehRequest, payload);
1159     }
1160     else
1161     {
1162         return OC_EH_FORBIDDEN;
1163     }
1164 }
1165
1166 char * getZBDataTypeString(ZigBeeAttributeDataType attrType)
1167 {
1168     switch (attrType)
1169     {
1170         case ZB_NULL:
1171             return ZB_DATA_TYPE_NULL;
1172         case ZB_8_BIT:
1173             return ZB_DATA_TYPE_1_BYTE;
1174         case ZB_16_BIT:
1175             return ZB_DATA_TYPE_2_BYTE;
1176         case ZB_24_BIT:
1177             return ZB_DATA_TYPE_3_BYTE;
1178         case ZB_32_BIT:
1179             return ZB_DATA_TYPE_4_BYTE;
1180         case ZB_40_BIT:
1181             return ZB_DATA_TYPE_5_BYTE;
1182         case ZB_48_BIT:
1183             return ZB_DATA_TYPE_6_BYTE;
1184         case ZB_56_BIT:
1185             return ZB_DATA_TYPE_7_BYTE;
1186         case ZB_64_BIT:
1187             return ZB_DATA_TYPE_8_BYTE;
1188         case ZB_BOOL:
1189             return ZB_DATA_TYPE_BOOL;
1190         case ZB_8_BITMAP:
1191             return ZB_DATA_TYPE_1_BYTE;
1192         case ZB_16_BITMAP:
1193             return ZB_DATA_TYPE_2_BYTE;
1194         case ZB_24_BITMAP:
1195             return ZB_DATA_TYPE_3_BYTE;
1196         case ZB_32_BITMAP:
1197             return ZB_DATA_TYPE_4_BYTE;
1198         case ZB_40_BITMAP:
1199             return ZB_DATA_TYPE_5_BYTE;
1200         case ZB_48_BITMAP:
1201             return ZB_DATA_TYPE_6_BYTE;
1202         case ZB_56_BITMAP:
1203             return ZB_DATA_TYPE_7_BYTE;
1204         case ZB_64_BITMAP:
1205             return ZB_DATA_TYPE_8_BYTE;
1206         case ZB_16_SINT:
1207             return ZB_DATA_TYPE_SIGNED_INT_16;
1208         case ZB_8_UINT:
1209             return ZB_DATA_TYPE_UNSIGNED_INT_8;
1210         case ZB_16_UINT:
1211             return ZB_DATA_TYPE_UNSIGNED_INT_16;
1212         default:
1213             return ZB_DATA_TYPE_NULL;
1214     }
1215 }