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