Added context for callbacks.
[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         OC_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         OC_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 * nodeId,
253                        const char * endpointId,
254                        const char * clusterId)
255 {
256     if (!output || !prefix || !nodeId || !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(nodeId) + lenSeparatorSize +
264                         strlen(endpointId) + lenSeparatorSize +
265                         strlen(clusterId)
266                         + 1; // NULL Terminator
267     *output = (char *) OICCalloc(1, newUriSize);
268
269     if (!*output)
270     {
271         OC_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, nodeId);
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         OC_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             OC_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->nodeId,
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                 OC_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             OC_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     char * uri = NULL;
404     OCStackResult result = buildURI(&uri,
405                                     PI_ZIGBEE_PREFIX,
406                                     update->nodeId,
407                                     update->endpoint,
408                                     ZB_IAS_ZONE_CLUSTER);
409     if (result != OC_STACK_OK || !uri)
410     {
411         OC_LOG_V(ERROR, TAG, "Failed to build URI with result: %d", result);
412         return;
413     }
414
415     plugin->header.ObserveNotificationUpdate((PIPluginBase *)plugin, uri);
416     OICFree(uri);
417 }
418
419 OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
420                          PINewResourceFound newResourceCB,
421                          PIObserveNotificationUpdate observeNotificationUpdate)
422 {
423     if (!plugin)
424     {
425         return OC_STACK_INVALID_PARAM;
426     }
427     *plugin = (PIPlugin_Zigbee *) OICMalloc(sizeof(PIPlugin_Zigbee) + sizeof(PIPluginBase));
428     if (!*plugin)
429     {
430         return OC_STACK_NO_MEMORY;
431     }
432     ((*plugin)->header).type = PLUGIN_ZIGBEE;
433     ((*plugin)->header).comPort = comPort;
434     ((*plugin)->header).NewResourceFoundCB = newResourceCB;
435     ((*plugin)->header).ObserveNotificationUpdate = observeNotificationUpdate;
436     ((*plugin)->header).next = NULL;
437     ((*plugin)->header).resourceList = NULL;
438     ((*plugin)->header).processEHRequest = ProcessEHRequest;
439
440     OCStackResult result = TWInitialize(*plugin, comPort);
441     if (result != OC_STACK_OK)
442     {
443         return result;
444     }
445
446     return TWSetStatusUpdateCallback(zigbeeZoneStatusUpdate, *plugin);
447 }
448
449 OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
450 {
451     OCStackResult result = OC_STACK_ERROR;
452     TWSetDiscoveryCallback(foundZigbeeCallback, plugin);
453     result = TWDiscover(plugin);
454     OC_LOG_V(DEBUG, TAG, "ZigbeeDiscover : Status = %d\n", result);
455
456     return result;
457 }
458
459 OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin)
460 {
461     OCStackResult ret = TWUninitialize(plugin);
462     free(plugin);
463     return ret;
464 }
465
466 OCStackResult ZigbeeProcess(PIPlugin_Zigbee * plugin)
467 {
468     return TWProcess(plugin);
469 }
470
471 // Function returns an OIC Smart Home resource Type
472 // from the cluster ID. If the cluster is not supported, null is
473 // returned.
474 // NOTE: The returned string is NOT malloc'ed.
475 const char* ZigBeeClusterIDToOICResourceType(const char * clusterID) //Discovery/CreateResource
476 {
477     if (!clusterID)
478     {
479         return NULL;
480     }
481     if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
482     {
483         return OIC_TEMPERATURE_SENSOR;
484     }
485     else if (strcmp(clusterID, ZB_LEVEL_CONTROL_CLUSTER) == 0)
486     {
487         return OIC_DIMMABLE_LIGHT;
488     }
489     else if (strcmp(clusterID, ZB_IAS_ZONE_CLUSTER) == 0)
490     {
491         return OIC_CONTACT_SENSOR;
492     }
493     else if (strcmp(clusterID, ZB_ON_OFF_CLUSTER) == 0)
494     {
495         return OIC_BINARY_SWITCH;
496     }
497     else if (strcmp(clusterID, ZB_COLOR_CONTROL_CLUSTER) == 0)
498     {
499         return OIC_CHROMA_LIGHT;
500     }
501     else
502     {
503         return NULL;
504     }
505 }
506
507 const char* OICResourceToZigBeeClusterID(char *oicResourceType)
508 {
509     if (!oicResourceType)
510     {
511         return NULL;
512     }
513     if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
514     {
515         return ZB_TEMPERATURE_CLUSTER;
516     }
517     else if (strcmp(oicResourceType, OIC_DIMMABLE_LIGHT) == 0)
518     {
519         return ZB_LEVEL_CONTROL_CLUSTER;
520     }
521     else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
522     {
523         return ZB_IAS_ZONE_CLUSTER;
524     }
525     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
526     {
527         return ZB_ON_OFF_CLUSTER;
528     }
529     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
530     {
531         return ZB_INDICATOR_CLUSTER;
532     }
533     else if (strcmp(oicResourceType, OIC_CHROMA_LIGHT) == 0)
534     {
535         return ZB_COLOR_CONTROL_CLUSTER;
536     }
537     else
538     {
539         return NULL;
540     }
541 }
542
543 OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
544                                                     AttributeList *attributeList) // GET
545 {
546     if (!OICResourceType || !attributeList)
547     {
548         return OC_STACK_INVALID_PARAM;
549     }
550     if (strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
551     {
552         attributeList->count = 1;
553         attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
554         attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
555         attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
556         attributeList->list[0].zigbeeType = ZB_16_SINT;
557         return OC_STACK_OK;
558     }
559     else if (strcmp(OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
560     {
561         attributeList->count = 1;
562         attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
563         attributeList->list[0].zigBeeAttribute = ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY;
564         attributeList->list[0].oicType = OIC_ATTR_INT;
565         attributeList->list[0].zigbeeType = ZB_8_UINT;
566         return OC_STACK_OK;
567     }
568     else if (strcmp(OICResourceType, OIC_CONTACT_SENSOR) == 0)
569     {
570         attributeList->count = 1;
571         attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
572         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
573         attributeList->list[0].oicType = OIC_ATTR_BOOL;
574         attributeList->list[0].zigbeeType = ZB_BOOL;
575         return OC_STACK_OK;
576     }
577     else if (strcmp(OICResourceType, OIC_WATER_SENSOR) == 0)
578     {
579         attributeList->count = 1;
580         attributeList->list[0].oicAttribute = OICStrdup(OIC_WATER_ATTRIBUTE);
581         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
582         attributeList->list[0].oicType = OIC_ATTR_BOOL;
583         attributeList->list[0].zigbeeType = ZB_BOOL;
584         return OC_STACK_OK;
585     }
586     else if (strcmp(OICResourceType, OIC_MOTION_SENSOR) == 0)
587     {
588         attributeList->count = 1;
589         attributeList->list[0].oicAttribute = OICStrdup(OIC_MOTION_ATTRIBUTE);
590         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
591         attributeList->list[0].oicType = OIC_ATTR_BOOL;
592         attributeList->list[0].zigbeeType = ZB_BOOL;
593         return OC_STACK_OK;
594     }
595     else if (strcmp(OICResourceType, OIC_BINARY_SWITCH) == 0)
596     {
597         attributeList->count = 1;
598         attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
599         attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
600         attributeList->list[0].oicType = OIC_ATTR_BOOL;
601         attributeList->list[0].zigbeeType = ZB_BOOL;
602         return OC_STACK_OK;
603     }
604     else if (strcmp(OICResourceType, OIC_CHROMA_LIGHT) == 0)
605     {
606         attributeList->count = 1;
607         attributeList->list[0].oicAttribute = OICStrdup(OIC_COLOUR_TEMPERATURE_ATTRIBUTE);
608         attributeList->list[0].zigBeeAttribute = ZB_COLOR_TEMPERATURE_ATTRIBUTE_ID;
609         attributeList->list[0].oicType = OIC_ATTR_INT;
610         attributeList->list[0].zigbeeType = ZB_16_UINT;
611         return OC_STACK_OK;
612     }
613
614     return OC_STACK_ERROR;
615 }
616
617 bool getZigBeeAttributesIfValid(const char * OICResourceType,
618                                     AttributeList *attributeList,
619                                     OCRepPayload *payload) // Put
620 {
621     if (!OICResourceType)
622     {
623         return false;
624     }
625     if (strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
626     {
627         // Cant really PUT on the temp sensor, but the code is still there.
628         int64_t temperature = 0;
629
630         // TODO: This if should only look for attributes it supports and ignore the rest
631         // or examine every attribute in the payload and complain about unsupported attributes?
632         if (OCRepPayloadGetPropInt(payload, OIC_TEMPERATURE_ATTRIBUTE, &temperature))
633         {
634             attributeList->count = 1;
635             attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
636             attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
637             attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
638             attributeList->list[0].val.d = temperature;
639             attributeList->list[0].zigbeeType = ZB_16_SINT;
640             attributeList->CIEMask = (CIECommandMask) 0;
641
642             return true;
643         }
644     }
645     else if (strcmp(OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
646     {
647         int64_t onLevel = 0;
648
649         if (OCRepPayloadGetPropInt(payload, OIC_DIMMING_ATTRIBUTE, &onLevel))
650         {
651             attributeList->count = 1;
652             attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
653             attributeList->list[0].zigBeeAttribute = ZB_ON_LEVEL_ATTRIBUTE;
654             attributeList->list[0].oicType = OIC_ATTR_INT;
655             attributeList->list[0].val.i = onLevel;
656             attributeList->list[0].zigbeeType = ZB_8_UINT;
657
658             // Level control cluster is dealing with level in the PUT payload.
659             attributeList->CIEMask = attributeList->CIEMask | CIE_MOVE_TO_LEVEL;
660             return true;
661         }
662     }
663     else if (strcmp(OICResourceType, OIC_CONTACT_SENSOR) == 0)
664     {
665         int64_t value = 0;
666
667         if (OCRepPayloadGetPropInt(payload, OIC_CONTACT_ATTRIBUTE, &value))
668         {
669             attributeList->count = 1;
670             attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
671             attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
672             attributeList->list[0].oicType = OIC_ATTR_BOOL;
673             attributeList->list[0].val.i = value;
674             attributeList->list[0].zigbeeType = ZB_BOOL;
675             attributeList->CIEMask = (CIECommandMask) 0;
676
677             return true;
678         }
679     }
680     else if (strcmp(OICResourceType, OIC_WATER_SENSOR) == 0)
681     {
682         int64_t value = 0;
683
684         if (OCRepPayloadGetPropInt(payload, OIC_WATER_ATTRIBUTE, &value))
685         {
686             attributeList->count = 1;
687             attributeList->list[0].oicAttribute = OICStrdup(OIC_WATER_ATTRIBUTE);
688             attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
689             attributeList->list[0].oicType = OIC_ATTR_BOOL;
690             attributeList->list[0].val.i = value;
691             attributeList->list[0].zigbeeType = ZB_BOOL;
692             attributeList->CIEMask = (CIECommandMask) 0;
693
694             return true;
695         }
696     }
697     else if (strcmp(OICResourceType, OIC_BINARY_SWITCH) == 0)
698     {
699         bool value = 0;
700
701         if (OCRepPayloadGetPropBool(payload, OIC_ON_OFF_ATTRIBUTE, &value))
702         {
703             attributeList->count = 1;
704             attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
705             attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
706             attributeList->list[0].oicType = OIC_ATTR_BOOL;
707             attributeList->list[0].val.b = value;
708             attributeList->list[0].zigbeeType = ZB_BOOL;
709
710             attributeList->CIEMask = attributeList->CIEMask | CIE_RON_OFF;
711             return true;
712         }
713     }
714     else if (strcmp(OICResourceType, OIC_CHROMA_LIGHT) == 0)
715     {
716         char * value = 0;
717         if (OCRepPayloadGetPropString(payload, OIC_COLOUR_TEMPERATURE_ATTRIBUTE, &value))
718         {
719             attributeList->count = 1;
720             attributeList->list[0].oicAttribute = OICStrdup(OIC_COLOUR_TEMPERATURE_ATTRIBUTE);
721             attributeList->list[0].zigBeeAttribute = ZB_COLOR_TEMPERATURE_ATTRIBUTE_ID;
722             attributeList->list[0].oicType = OIC_ATTR_STRING;
723             attributeList->list[0].val.str = value;
724             attributeList->list[0].zigbeeType = ZB_16_UINT;
725             attributeList->CIEMask = (CIECommandMask) 0;
726
727             return true;
728         }
729     }
730     return false;
731 }
732
733 OCEntityHandlerResult getDoubleValueFromString(const char *str, double *outDouble)
734 {
735     if (!str || !outDouble)
736     {
737         return OC_EH_ERROR;
738     }
739     size_t hexOutValSize = strlen(HexPrepend) + strlen(str) + 1;
740     char * hexOutVal = (char *) OICCalloc(1, hexOutValSize);
741     if (!hexOutVal)
742     {
743         return OC_EH_ERROR;
744     }
745     OICStrcpy(hexOutVal, hexOutValSize, HexPrepend);
746     OICStrcat(hexOutVal, hexOutValSize, str);
747
748     char *endPtr = NULL;
749     errno = 0;
750     double value = strtod(hexOutVal, &endPtr);
751
752     if (errno != 0 || *endPtr != 0 || value == HUGE_VALF || value == HUGE_VALL)
753     {
754         OICFree(hexOutVal);
755         return OC_EH_ERROR;
756     }
757
758     OICFree(hexOutVal);
759     *outDouble = value;
760     return OC_EH_OK;
761
762 }
763
764 OCEntityHandlerResult getColourTemperatureFromString(const char* str, int64_t* outVal)
765 {
766     if (!str || !outVal)
767     {
768         return OC_EH_ERROR;
769     }
770     // str comes in as "X,Y,T" where "T" is the colour temperature.
771     // Iterate 3 times to retrieve the last value.
772     char * strstr = OICStrdup(str);
773     char * savePtr = NULL;
774     char * temp = NULL;
775     for (int i=0; i<3; i++)
776     {
777         temp = strtok_r(strstr, ",", &savePtr);
778         if (!temp)
779         {
780             *outVal = 0;
781             OICFree(strstr);
782             return OC_EH_ERROR;
783         }
784     }
785     OCStackResult result = getDoubleValueFromString(temp, (double *)outVal);
786     OICFree(strstr);
787     return result;
788 }
789
790 OCEntityHandlerResult processGetRequest(PIPluginBase * plugin,
791         OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
792 {
793     if (!plugin || !ehRequest || !payload)
794     {
795         return OC_EH_ERROR;
796     }
797     uint32_t attributeListIndex = 0;
798     OCStackResult stackResult = OC_STACK_OK;
799     PIResource_Zigbee * piResource = NULL;
800
801     AttributeList attributeList = { 0, (CIECommandMask) 0,
802         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } } };
803     stackResult = GetResourceFromHandle(plugin, (PIResource**) (&piResource),
804                         ehRequest->resource);
805     if (stackResult != OC_STACK_OK)
806     {
807         OC_LOG(ERROR, TAG, "Failed to get resource from handle");
808         return OC_EH_ERROR;
809     }
810     stackResult = getZigBeeAttributesForOICResource(
811         piResource->header.piResource.resourceTypeName, &attributeList);
812     if (stackResult != OC_STACK_OK)
813     {
814         OC_LOG_V(ERROR, TAG, "Failed to fetch attributes for %s",
815             piResource->header.piResource.resourceTypeName);
816         return OC_EH_ERROR;
817     }
818
819     *payload = OCRepPayloadCreate();
820     if (!payload)
821     {
822         OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload"));
823         return OC_EH_ERROR;
824     }
825     bool boolRes = OCRepPayloadSetUri(*payload, piResource->header.piResource.uri);
826     if (boolRes == false)
827     {
828         OCRepPayloadDestroy(*payload);
829         return OC_EH_ERROR;
830     }
831     for (uint32_t i = 0; i<attributeList.count; i++)
832     {
833         char * outVal = NULL;
834         uint8_t outValLength = 0;
835
836         stackResult = TWGetAttribute(piResource->eui,
837                                      piResource->nodeId,
838                                      piResource->endpointId,
839                                      piResource->clusterId,
840                                      attributeList.list[i].zigBeeAttribute,
841                                      &outVal,
842                                      &outValLength,
843                                      (PIPlugin_Zigbee *)plugin);
844
845         if (stackResult != OC_STACK_OK || !outVal)
846         {
847             stackResult = OC_EH_ERROR;
848             OCRepPayloadDestroy(*payload);
849             goto exit;
850         }
851         if (attributeList.list[i].oicType == OIC_ATTR_INT)
852         {
853             char *endPtr = NULL;
854             errno = 0;
855             // Third arg is 16 as outVal is a hex Number
856             uint64_t value = strtol(outVal, &endPtr, 16);
857
858             if (*endPtr != 0 || errno != 0)
859             {
860                 return OC_EH_ERROR;
861             }
862             if (!attributeList.list[i].oicAttribute)
863             {
864                 return OC_EH_ERROR;
865             }
866             if (strcmp(attributeList.list[i].oicAttribute, OIC_DIMMING_ATTRIBUTE) == 0)
867             {
868                 // OIC Dimming operates between 0-100, while Zigbee operates
869                 // between 0-254 (ie. 0xFE).
870                 if (value > 0xFE)
871                 {
872                     value = 0xFE;
873                 }
874                 if (value <= 0xFE)
875                 {
876                     value = value / 2.54;
877                 }
878             }
879             else if (strcmp(attributeList.list[i].oicAttribute, OIC_COLOUR_TEMPERATURE_ATTRIBUTE) == 0)
880             {
881                 // OIC Chroma requires: Hue, Saturation, and ColorSpaceValue (color space value is
882                 // "chromaX, chromaY, colourTemperature").
883                 // ZigBee HA requires: "currentX", "currentY", while we're trying to map a specific
884                 // device which goes against the HA spec and ONLY implements "ColorTemperature".
885                 // Because of the misalignments between OIC Smart Home and ZigBee HA specs, the
886                 // follow assumption is required:
887                 // - *X and *Y will be zero, and therefore ignored (or passed as zero where
888                 // applicable).
889                 // OIC ColorTemperature operates between 0-1000 (degrees Kelvin) in string form,
890                 // while ZigBee operates between 0-65279 (bits, with an operating range
891                 // 15.32-1,000,000 (degrees Kelvin)).
892                 // ZigBee HA states: ColorTemperature(bits) = 1,000,000/ColorTemperature(Kelvin)
893                 // Invalid: ColorTemperature==0 || ColorTemperature==65535
894                 // However the specific bulb we're mapping only operates between 2700-6500 (Kelvin)
895                 // which equates to 0x0099-0x0172 (ie. 153-370; giving a resolution of 217 bits).
896                 // Conversion from ZigBee HA specific bulb to OIC temporary mapping:
897                 // OIC Value: 0-100  ZigBee Value: (0-217)+153
898                 // OICValue = (ZigBeeValue-153)/2.17
899
900                 value = (value-153)/2.17;
901             }
902             boolRes = OCRepPayloadSetPropInt(*payload,
903                                              attributeList.list[i].oicAttribute,
904                                              (uint64_t) value);
905         }
906         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
907         {
908             double value = 0;
909
910             if (getDoubleValueFromString(outVal, &value) != OC_EH_OK)
911             {
912                 return OC_EH_ERROR;
913             }
914             if (!piResource->clusterId)
915             {
916                 return OC_EH_ERROR;
917             }
918             if (strcmp(piResource->clusterId, ZB_TEMPERATURE_CLUSTER) == 0)
919             {
920                 // Divide by 100 as temperature readings have a resolution of
921                 // 0.01 or one hundreth of a degree celsius.
922                 value = value/100;
923             }
924             boolRes = OCRepPayloadSetPropDouble(*payload,
925                                                 attributeList.list[i].oicAttribute,
926                                                 value);
927         }
928         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
929         {
930             boolRes = OCRepPayloadSetPropString(*payload,
931                                                 attributeList.list[i].oicAttribute,
932                                                 outVal);
933         }
934         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
935         {
936             char *endPtr = NULL;
937             errno = 0;
938             // Third arg is 16 as outVal is a hex Number
939             uint64_t value = strtol(outVal, &endPtr, 16);
940
941             if (errno != 0 || *endPtr != 0)
942             {
943                 return OC_EH_ERROR;
944             }
945             // value COULD be a bit mask and the LSB indicates boolean true/false.
946             // If not a bit mask, it'll be plain 0 or 1.
947             value = value & 1;
948             boolRes = OCRepPayloadSetPropBool(*payload,
949                                               attributeList.list[i].oicAttribute,
950                                               value);
951         }
952
953         OICFree(outVal);
954     }
955
956     if (boolRes == false)
957     {
958         stackResult = OC_EH_ERROR;
959         goto exit;
960     }
961
962 exit:
963     for (; attributeListIndex < attributeList.count; attributeListIndex++)
964     {
965         OICFree(attributeList.list[attributeListIndex].oicAttribute);
966     }
967     return stackResult;
968 }
969
970 OCEntityHandlerResult processPutRequest(PIPluginBase * plugin,
971     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
972 {
973     if (!plugin || !ehRequest || !payload)
974     {
975         return OC_EH_ERROR;
976     }
977     OCStackResult stackResult = OC_STACK_OK;
978     PIResource_Zigbee *piResource = NULL;
979     AttributeList attributeList = {
980         0,
981         (CIECommandMask) 0,
982         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } }
983     };
984
985     stackResult = GetResourceFromHandle(plugin,
986                                         ((PIResource **) (&piResource)),
987                                         ehRequest->resource);
988     if (stackResult != OC_STACK_OK)
989     {
990         OC_LOG(ERROR, TAG, "Failed to get resource from handle");
991         return OC_EH_ERROR;
992     }
993
994     bool boolRes = getZigBeeAttributesIfValid(
995                         piResource->header.piResource.resourceTypeName,
996                         &attributeList, *payload);
997     if (boolRes == false)
998     {
999         OC_LOG_V(ERROR, TAG, "Failed to fetch attributes for %s",
1000             piResource->header.piResource.resourceTypeName);
1001         return OC_EH_ERROR;
1002     }
1003
1004     uint32_t i = 0;
1005     for (; i<attributeList.count; i++)
1006     {
1007         if (attributeList.list[i].oicType == OIC_ATTR_INT)
1008         {
1009             char value[MAX_STRLEN_INT] = {};
1010             if (attributeList.CIEMask || CIE_MOVE_TO_LEVEL)
1011             {
1012                 int64_t rangeDiff = 0;
1013                 // OIC Dimming operates between 0-100, while Zigbee
1014                 // operates between 0-254 (ie. 0xFE).
1015                 rangeDiff = attributeList.list[i].val.i * 0xFE/100;
1016                 if (rangeDiff > 0xFE)
1017                 {
1018                     rangeDiff = 0xFE;
1019                 }
1020                 if (rangeDiff < 0)
1021                 {
1022                     rangeDiff = 0;
1023                 }
1024                 if (rangeDiff <= 0xFE)
1025                 {
1026                     errno = 0;
1027                     int strRet = snprintf(value, sizeof(value), "%02x", (unsigned int) rangeDiff);
1028                     if (strRet <= 0)
1029                     {
1030                         OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1031                         return OC_EH_ERROR;
1032                     }
1033                 }
1034                 stackResult = TWMoveToLevel(piResource->nodeId, piResource->endpointId,
1035                                     DEFAULT_MOVETOLEVEL_MODE, value, DEFAULT_TRANS_TIME,
1036                                     (PIPlugin_Zigbee*)plugin);
1037             }
1038             else
1039             {
1040                 errno = 0;
1041                 int strRet = snprintf(value,
1042                                       sizeof(value),
1043                                       "%"PRId64,
1044                                       attributeList.list[i].val.i);
1045                 if (strRet <= 0)
1046                 {
1047                     OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1048                     return OC_EH_ERROR;
1049                 }
1050                 stackResult = TWSetAttribute(piResource->eui,
1051                     piResource->nodeId, piResource->endpointId,
1052                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1053                     getZBDataTypeString(attributeList.list[i].zigbeeType), value,
1054                     (PIPlugin_Zigbee*)plugin);
1055             }
1056             if (stackResult != OC_STACK_OK)
1057             {
1058                 return OC_EH_ERROR;
1059             }
1060         }
1061         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
1062         {
1063             char value[MAX_STRLEN_DOUBLE] = {};
1064             errno = 0;
1065             int strRet = snprintf(value, sizeof(value), "%f", attributeList.list[i].val.d);
1066             if (strRet <= 0)
1067             {
1068                 OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1069                 return OC_EH_ERROR;
1070             }
1071             stackResult = TWSetAttribute(piResource->eui,
1072                 piResource->nodeId, piResource->endpointId,
1073                  piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1074                  getZBDataTypeString(attributeList.list[i].zigbeeType), value,
1075                  (PIPlugin_Zigbee*)plugin);
1076         }
1077         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
1078         {
1079             if (strcmp(attributeList.list[i].oicAttribute, OIC_COLOUR_TEMPERATURE_ATTRIBUTE) == 0)
1080             {
1081                 char *endPtr = NULL;
1082                 uint16_t zbVal = (uint16_t)strtod(attributeList.list[i].val.str, &endPtr);
1083                 zbVal = (zbVal*2.17)+153;
1084                 char value[5] = {0};
1085                 errno = 0;
1086                 int strRet = snprintf(value, sizeof(value), "%04x", zbVal);
1087                 if (strRet <= 0)
1088                 {
1089                     OC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
1090                     return OC_EH_ERROR;
1091                 }
1092                 stackResult =
1093                 TWColorMoveToColorTemperature(piResource->nodeId, piResource->endpointId,
1094                                               value, DEFAULT_TRANS_TIME,
1095                                               (PIPlugin_Zigbee*)plugin);
1096             }
1097             else
1098             {
1099                 stackResult = TWSetAttribute(piResource->eui,
1100                     piResource->nodeId, piResource->endpointId,
1101                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1102                     getZBDataTypeString(attributeList.list[i].zigbeeType),
1103                     attributeList.list[i].val.str,
1104                     (PIPlugin_Zigbee*)plugin);
1105             }
1106             if (stackResult != OC_STACK_OK)
1107             {
1108                 return OC_EH_ERROR;
1109             }
1110         }
1111         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
1112         {
1113             char * value = attributeList.list[i].val.b ? "1" : "0";
1114             if (attributeList.CIEMask || CIE_RON_OFF)
1115             {
1116                 stackResult = TWSwitchOnOff(piResource->nodeId, piResource->endpointId, value,
1117                                             (PIPlugin_Zigbee*)plugin);
1118             }
1119             else
1120             {
1121                 stackResult = TWSetAttribute(piResource->eui,
1122                     piResource->nodeId, piResource->endpointId,
1123                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
1124                     getZBDataTypeString(attributeList.list[i].zigbeeType),
1125                     value,
1126                     (PIPlugin_Zigbee*)plugin);
1127             }
1128             if (stackResult != OC_STACK_OK)
1129             {
1130                 return OC_EH_ERROR;
1131             }
1132         }
1133         else
1134         {
1135             continue;
1136         }
1137     }
1138
1139     return processGetRequest(plugin, ehRequest, payload);
1140 }
1141
1142 OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin,
1143     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
1144 {
1145     if (!ehRequest || !payload)
1146     {
1147         return OC_EH_ERROR;
1148     }
1149     if (ehRequest->method == OC_REST_GET)
1150     {
1151         return processGetRequest(plugin, ehRequest, payload);
1152     }
1153     else if (ehRequest->method == OC_REST_PUT)
1154     {
1155         return processPutRequest(plugin, ehRequest, payload);
1156     }
1157     else
1158     {
1159         return OC_EH_FORBIDDEN;
1160     }
1161 }
1162
1163 char * getZBDataTypeString(ZigBeeAttributeDataType attrType)
1164 {
1165     switch (attrType)
1166     {
1167         case ZB_NULL:
1168             return ZB_DATA_TYPE_NULL;
1169         case ZB_8_BIT:
1170             return ZB_DATA_TYPE_1_BYTE;
1171         case ZB_16_BIT:
1172             return ZB_DATA_TYPE_2_BYTE;
1173         case ZB_24_BIT:
1174             return ZB_DATA_TYPE_3_BYTE;
1175         case ZB_32_BIT:
1176             return ZB_DATA_TYPE_4_BYTE;
1177         case ZB_40_BIT:
1178             return ZB_DATA_TYPE_5_BYTE;
1179         case ZB_48_BIT:
1180             return ZB_DATA_TYPE_6_BYTE;
1181         case ZB_56_BIT:
1182             return ZB_DATA_TYPE_7_BYTE;
1183         case ZB_64_BIT:
1184             return ZB_DATA_TYPE_8_BYTE;
1185         case ZB_BOOL:
1186             return ZB_DATA_TYPE_BOOL;
1187         case ZB_8_BITMAP:
1188             return ZB_DATA_TYPE_1_BYTE;
1189         case ZB_16_BITMAP:
1190             return ZB_DATA_TYPE_2_BYTE;
1191         case ZB_24_BITMAP:
1192             return ZB_DATA_TYPE_3_BYTE;
1193         case ZB_32_BITMAP:
1194             return ZB_DATA_TYPE_4_BYTE;
1195         case ZB_40_BITMAP:
1196             return ZB_DATA_TYPE_5_BYTE;
1197         case ZB_48_BITMAP:
1198             return ZB_DATA_TYPE_6_BYTE;
1199         case ZB_56_BITMAP:
1200             return ZB_DATA_TYPE_7_BYTE;
1201         case ZB_64_BITMAP:
1202             return ZB_DATA_TYPE_8_BYTE;
1203         case ZB_16_SINT:
1204             return ZB_DATA_TYPE_SIGNED_INT_16;
1205         case ZB_8_UINT:
1206             return ZB_DATA_TYPE_UNSIGNED_INT_8;
1207         case ZB_16_UINT:
1208             return ZB_DATA_TYPE_UNSIGNED_INT_16;
1209         default:
1210             return ZB_DATA_TYPE_NULL;
1211     }
1212 }