Add event feature.
[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 #include "zigbee_wrapper.h"
41 #include "telegesis_wrapper.h"
42 #include "pluginlist.h"
43
44 #include "ocpayload.h"
45 #include "oic_malloc.h"
46 #include "oic_string.h"
47 #include "logger.h"
48
49 #define HexPrepend "0x"
50
51 #define TAG "zigbeeWrapper"
52
53 // TODO: These should eventually go into an XML/JSON/Mapping thing
54 #define MAX_ATTRIBUTES                       10
55 #define ZB_TEMPERATURE_CLUSTER               "0402"
56 #define ZB_TEMPERATURE_ATTRIBUTE_ID          "0000"
57 #define ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY  "0000"
58 #define ZB_ON_LEVEL_ATTRIBUTE                "0011"
59 #define ZB_LEVEL_CONTROL_CLUSTER             "0008"
60 #define ZB_CONTACT_CLUSTER                   "0500"
61 #define ZB_CONTACT_ATTRIBUTE_ID              "0002"
62 #define ZB_INDICATOR_CLUSTER                 "0003"
63 #define ZB_INDICATOR_ATTRIBUTE_ID            "0000"
64 #define ZB_ON_OFF_CLUSTER                    "0006"
65 #define ZB_ON_OFF_ATTRIBUTE_ID               "0000"
66
67 #define ZB_DATA_TYPE_NULL                    "00"
68 #define ZB_DATA_TYPE_1_BYTE                  "08"
69 #define ZB_DATA_TYPE_2_BYTE                  "09"
70 #define ZB_DATA_TYPE_3_BYTE                  "0a"
71 #define ZB_DATA_TYPE_4_BYTE                  "0b"
72 #define ZB_DATA_TYPE_5_BYTE                  "0c"
73 #define ZB_DATA_TYPE_6_BYTE                  "0d"
74 #define ZB_DATA_TYPE_7_BYTE                  "0e"
75 #define ZB_DATA_TYPE_8_BYTE                  "0f"
76 #define ZB_DATA_TYPE_BOOL                    "10"
77 #define ZB_DATA_TYPE_SIGNED_INT_16           "29"
78 #define ZB_DATA_TYPE_UNSIGNED_INT_8          "20"
79 #define ZB_DATA_TYPE_UNSIGNED_INT_16         "21"
80
81 #define MAX_STRLEN_INT (10)
82 // DBL_MANT_DIG = Max # of digits after decimal after the leading zeros.
83 // DBL_MIN_EXP = Max # of leading zeros of the mantissa.
84 // Magic number '3' represents a '-' (negative sign), '0' (a possible zero), and '.' (a period).
85 //       "-0." from a number like "-0.999999991245", the "-0." adds 3 unaccounted characters.
86 #define MAX_STRLEN_DOUBLE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
87 #define MAX_STRLEN_BOOL (1)
88
89 #define DEFAULT_TRANS_TIME "0000"
90 #define DEFAULT_MOVETOLEVEL_MODE "0"
91
92 static const char* OIC_TEMPERATURE_SENSOR = "oic.r.temperature";
93 static const char* OIC_DIMMABLE_LIGHT = "oic.r.light.dimming";
94 static const char* OIC_CONTACT_SENSOR = "oic.r.sensor.contact";
95 static const char* OIC_BINARY_SWITCH = "oic.r.switch.binary";
96
97 static const char* OIC_TEMPERATURE_ATTRIBUTE = "temperature";
98 static const char* OIC_DIMMING_ATTRIBUTE = "dimmingSetting";
99 static const char* OIC_CONTACT_ATTRIBUTE = "value";
100 static const char* OIC_ON_OFF_ATTRIBUTE = "value";
101
102 PIPlugin_Zigbee ** gPlugin = NULL;
103
104 typedef enum
105 {
106     ZB_NULL,   // No Data
107     ZB_8_BIT,  // 1 byte
108     ZB_16_BIT, // 2 bytes
109     ZB_24_BIT, // 3 bytes
110     ZB_32_BIT, // 4 bytes
111     ZB_40_BIT, // 5 bytes
112     ZB_48_BIT, // 6 bytes
113     ZB_56_BIT, // 7 bytes
114     ZB_64_BIT, // 8 bytes
115     ZB_BOOL,   // boolean
116     ZB_8_BITMAP,
117     ZB_16_BITMAP,
118     ZB_24_BITMAP,
119     ZB_32_BITMAP,
120     ZB_40_BITMAP,
121     ZB_48_BITMAP,
122     ZB_56_BITMAP,
123     ZB_64_BITMAP,
124     ZB_16_SINT,
125     ZB_8_UINT,
126     ZB_16_UINT
127 } ZigBeeAttributeDataType;
128
129 char * getZBDataTypeString(ZigBeeAttributeDataType attrType);
130 OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
131         OCRepPayload **payload);
132
133 typedef enum
134 {
135     OIC_ATTR_NULL,
136     OIC_ATTR_INT,
137     OIC_ATTR_DOUBLE,
138     OIC_ATTR_BOOL,
139     OIC_ATTR_STRING
140 } OICAttributeType;
141
142 typedef struct
143 {
144     char                *oicAttribute;
145     char                *zigBeeAttribute;
146     OICAttributeType    oicType;
147     ZigBeeAttributeDataType zigbeeType;
148     union
149     {
150         int64_t i;
151         double d;
152         bool b;
153         char* str;
154     } val;
155
156 } OICZigBeeAttributePair;
157
158 typedef enum
159 {
160     CIE_RON_OFF         = 1 << 1,
161     CIE_MOVE_TO_LEVEL   = 1 << 2
162
163 } CIECommandMask;
164
165 typedef struct
166 {
167     uint32_t count;
168     CIECommandMask CIEMask;
169     OICZigBeeAttributePair list[MAX_ATTRIBUTES];
170 } AttributeList;
171
172 const char* ZigBeeClusterIDToOICResourceType (const char * clusterID);
173
174 OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
175                                                     AttributeList *attributeList);
176
177 bool getZigBeeAttributesIfValid (char * OICResourceType,
178                                     AttributeList *attributeList,
179                                     OCRepPayload *payload);
180
181 void foundZigbeeCallback(TWDevice *device)
182 {
183     int count = device->endpointOfInterest->clusterList->count;
184     size_t lenSeparator = strlen ("/");
185     int ret = 0;
186     for(int i=0; i < count; i++)
187     {
188         PIResource_Zigbee *piResource = (PIResource_Zigbee *) OICMalloc(sizeof(*piResource));
189         if (!piResource)
190         {
191             OC_LOG (ERROR, TAG, "Out of memory");
192             return;
193         }
194         piResource->header.plugin = (PIPluginBase *)gPlugin;
195         size_t newUriSize = strlen(PI_ZIGBEE_PREFIX) + lenSeparator +
196                         sizeof(device->nodeId) + lenSeparator +
197                         sizeof(device->endpointOfInterest->endpointId) + lenSeparator +
198                         sizeof(device->endpointOfInterest->clusterList->clusterIds[i].clusterId)
199                         + 1; // NULL Terminator
200         char * newUri = (char *) OICCalloc(newUriSize, 1);
201
202         if (!newUri)
203         {
204             OC_LOG (ERROR, TAG, "Out of memory");
205             return;
206         }
207
208         ret = snprintf(newUri, newUriSize, "%s/%s/%s/%s",
209                       PI_ZIGBEE_PREFIX,
210                       device->nodeId,
211                       device->endpointOfInterest->endpointId,
212                       device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
213         if(ret < 0)
214         {
215             OC_LOG (ERROR, TAG, "Encoding error occurred trying to build Zigbee URI.");
216         }
217         else if(ret > newUriSize)
218         {
219             OC_LOG_V (ERROR, TAG, "Did not allocate enough memory to build URI. Required Size: %d",
220                       ret);
221         }
222
223         piResource->header.piResource.uri = newUri;
224         piResource->header.piResource.resourceTypeName =
225
226             (char *) ZigBeeClusterIDToOICResourceType(
227                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
228
229         if(piResource->header.piResource.resourceTypeName == NULL)
230         {
231             OC_LOG_V (ERROR, TAG, "unsupported clusterId : %d",
232                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
233             OICFree(piResource->header.piResource.uri);
234             OICFree(piResource);
235             continue;
236         }
237         piResource->header.piResource.resourceInterfaceName =
238                             OC_RSRVD_INTERFACE_DEFAULT;
239
240         piResource->header.piResource.callbackParam = NULL;
241         piResource->header.piResource.resourceProperties = 0;
242         piResource->eui = OICStrdup(device->eui);
243         piResource->nodeId = OICStrdup(device->nodeId);
244         piResource->endpointId = OICStrdup(device->endpointOfInterest->endpointId);
245         piResource->clusterId =
246             OICStrdup(device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
247         (*gPlugin)->header.NewResourceFoundCB(&(*gPlugin)->header, &piResource->header);
248     }
249 }
250
251 OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
252                          PINewResourceFound newResourceCB)
253 {
254     if(!plugin)
255     {
256         return OC_STACK_INVALID_PARAM;
257     }
258     *plugin = (PIPlugin_Zigbee *) OICMalloc(sizeof(PIPlugin_Zigbee) + sizeof(PIPluginBase));
259     if(!*plugin)
260     {
261         return OC_STACK_NO_MEMORY;
262     }
263     ((*plugin)->header).type = PLUGIN_ZIGBEE;
264     ((*plugin)->header).comPort = OICStrdup(comPort);
265     ((*plugin)->header).NewResourceFoundCB = newResourceCB;
266     ((*plugin)->header).next = NULL;
267     ((*plugin)->header).resourceList = NULL;
268     ((*plugin)->header).processEHRequest = ProcessEHRequest;
269
270     gPlugin = plugin;
271     return TWInitialize(comPort);
272 }
273
274 OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
275 {
276     OCStackResult result = OC_STACK_ERROR;
277     (void)plugin;
278     TWSetDiscoveryCallback(foundZigbeeCallback);
279     result = TWDiscover(NULL);
280     OC_LOG_V (DEBUG, TAG, "ZigbeeDiscover : Status = %d\n", result);
281
282     return result;
283 }
284
285 OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin)
286 {
287     free((plugin->header).comPort);
288     free(plugin);
289     return TWUninitialize();
290 }
291
292 OCStackResult ZigbeeProcess(PIPlugin_Zigbee * plugin)
293 {
294     (void)plugin;
295     return TWProcess();
296 }
297
298 // Function returns an OIC Smart Home resource Type
299 // from the cluster ID. If the cluster is not supported, null is
300 // returned.
301 // NOTE: The returned string is NOT malloc'ed.
302 const char* ZigBeeClusterIDToOICResourceType (const char * clusterID) //Discovery/CreateResource
303 {
304     if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
305     {
306         return OIC_TEMPERATURE_SENSOR;
307     }
308     else if (strcmp(clusterID, ZB_LEVEL_CONTROL_CLUSTER) == 0)
309     {
310         return OIC_DIMMABLE_LIGHT;
311     }
312     else if (strcmp(clusterID, ZB_CONTACT_CLUSTER) == 0)
313     {
314         return OIC_CONTACT_SENSOR;
315     }
316     else if (strcmp(clusterID, ZB_ON_OFF_CLUSTER) == 0)
317     {
318         return OIC_BINARY_SWITCH;
319     }
320     else
321     {
322         return NULL;
323     }
324 }
325
326 const char* OICResourceToZigBeeClusterID (char *oicResourceType)
327 {
328     if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
329     {
330         return ZB_TEMPERATURE_CLUSTER;
331     }
332     else if (strcmp(oicResourceType, OIC_DIMMABLE_LIGHT) == 0)
333     {
334         return ZB_LEVEL_CONTROL_CLUSTER;
335     }
336     else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
337     {
338         return ZB_CONTACT_CLUSTER;
339     }
340     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
341     {
342         return ZB_ON_OFF_CLUSTER;
343     }
344     else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
345     {
346         return ZB_INDICATOR_CLUSTER;
347     }
348     else
349     {
350         return NULL;
351     }
352 }
353
354 OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
355                                                     AttributeList *attributeList) // GET
356 {
357     if (strcmp (OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
358     {
359         attributeList->count = 1;
360         attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
361         attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
362         attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
363         attributeList->list[0].zigbeeType = ZB_16_SINT;
364         return OC_STACK_OK;
365     }
366     else if (strcmp (OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
367     {
368         attributeList->count = 1;
369         attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
370         attributeList->list[0].zigBeeAttribute = ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY;
371         attributeList->list[0].oicType = OIC_ATTR_INT;
372         attributeList->list[0].zigbeeType = ZB_8_UINT;
373         return OC_STACK_OK;
374     }
375     else if (strcmp (OICResourceType, OIC_CONTACT_SENSOR) == 0)
376     {
377         attributeList->count = 1;
378         attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
379         attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
380         attributeList->list[0].oicType = OIC_ATTR_BOOL;
381         attributeList->list[0].zigbeeType = ZB_BOOL;
382         return OC_STACK_OK;
383     }
384     else if (strcmp (OICResourceType, OIC_BINARY_SWITCH) == 0)
385     {
386         attributeList->count = 1;
387         attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
388         attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
389         attributeList->list[0].oicType = OIC_ATTR_BOOL;
390         attributeList->list[0].zigbeeType = ZB_BOOL;
391         return OC_STACK_OK;
392     }
393
394     return OC_STACK_ERROR;
395 }
396
397 bool getZigBeeAttributesIfValid (char * OICResourceType,
398                                     AttributeList *attributeList,
399                                     OCRepPayload *payload) // Put
400 {
401     if(!OICResourceType)
402     {
403         return false;
404     }
405     if(strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
406     {
407         // Cant really PUT on the temp sensor, but the code is still there.
408         int64_t temperature = 0;
409
410         // TODO: This if should only look for attributes it supports and ignore the rest
411         // or examine every attribute in the payload and complain about unsupported attributes?
412         if(OCRepPayloadGetPropInt(payload, OIC_TEMPERATURE_ATTRIBUTE, &temperature))
413         {
414             attributeList->count = 1;
415             attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
416             attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
417             attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
418             attributeList->list[0].val.d = temperature;
419             attributeList->list[0].zigbeeType = ZB_16_SINT;
420             attributeList->CIEMask = (CIECommandMask) 0;
421
422             return true;
423         }
424     }
425     else if (strcmp (OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
426     {
427         int64_t onLevel = 0;
428
429         if(OCRepPayloadGetPropInt(payload, OIC_DIMMING_ATTRIBUTE, &onLevel))
430         {
431             attributeList->count = 1;
432             attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
433             attributeList->list[0].zigBeeAttribute = ZB_ON_LEVEL_ATTRIBUTE;
434             attributeList->list[0].oicType = OIC_ATTR_INT;
435             attributeList->list[0].val.i = onLevel;
436             attributeList->list[0].zigbeeType = ZB_8_UINT;
437
438             // Level control cluster is dealing with level in the PUT payload.
439             attributeList->CIEMask = attributeList->CIEMask | CIE_MOVE_TO_LEVEL;
440             return true;
441         }
442     }
443     else if (strcmp (OICResourceType, OIC_CONTACT_SENSOR) == 0)
444     {
445         int64_t value = 0;
446
447         if(OCRepPayloadGetPropInt(payload, OIC_CONTACT_ATTRIBUTE, &value))
448         {
449             attributeList->count = 1;
450             attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
451             attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
452             attributeList->list[0].oicType = OIC_ATTR_BOOL;
453             attributeList->list[0].val.i = value;
454             attributeList->list[0].zigbeeType = ZB_BOOL;
455             attributeList->CIEMask = (CIECommandMask) 0;
456
457             return true;
458         }
459     }
460     else if (strcmp (OICResourceType, OIC_BINARY_SWITCH) == 0)
461     {
462         bool value = 0;
463
464         if(OCRepPayloadGetPropBool(payload, OIC_ON_OFF_ATTRIBUTE, &value))
465         {
466             attributeList->count = 1;
467             attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
468             attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
469             attributeList->list[0].oicType = OIC_ATTR_BOOL;
470             attributeList->list[0].val.b = value;
471             attributeList->list[0].zigbeeType = ZB_BOOL;
472
473             attributeList->CIEMask = attributeList->CIEMask | CIE_RON_OFF;
474             return true;
475         }
476     }
477     return false;
478 }
479
480 OCEntityHandlerResult getDoubleValueFromString (const char *str, double *outDouble)
481 {
482     size_t hexOutValSize = strlen(HexPrepend) + strlen(str) + 1;
483     char * hexOutVal = (char *) OICCalloc(1, hexOutValSize);
484     if(!hexOutVal)
485     {
486         return OC_EH_ERROR;
487     }
488     OICStrcpy(hexOutVal, hexOutValSize, HexPrepend);
489     OICStrcat(hexOutVal, hexOutValSize, str);
490
491     char *endPtr;
492     errno = 0;
493     double value = strtod(hexOutVal, &endPtr);
494
495     if(errno != 0 || *endPtr != 0 || value == HUGE_VALF || value == HUGE_VALL)
496     {
497         OICFree(hexOutVal);
498         return OC_EH_ERROR;
499     }
500
501     OICFree(hexOutVal);
502     *outDouble = value;
503     return OC_EH_OK;
504
505 }
506
507 OCEntityHandlerResult processGetRequest (PIPluginBase * plugin,
508         OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
509 {
510     if (!plugin || !ehRequest || !payload)
511     {
512         return OC_EH_ERROR;
513     }
514     uint32_t attributeListIndex = 0;
515     OCStackResult stackResult = OC_STACK_OK;
516     PIResource_Zigbee * piResource = NULL;
517
518     AttributeList attributeList = { 0, (CIECommandMask) 0,
519         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } } };
520     stackResult = GetResourceFromHandle(plugin, (PIResource**) (&piResource),
521                         ehRequest->resource);
522     if (stackResult != OC_STACK_OK)
523     {
524         OC_LOG (ERROR, TAG, "Failed to get resource from handle");
525         return OC_EH_ERROR;
526     }
527     stackResult = getZigBeeAttributesForOICResource (
528         piResource->header.piResource.resourceTypeName, &attributeList);
529     if(stackResult != OC_STACK_OK)
530     {
531         OC_LOG_V (ERROR, TAG, "Failed to fetch attributes for %s",
532             piResource->header.piResource.resourceTypeName);
533         return OC_EH_ERROR;
534     }
535
536     *payload = OCRepPayloadCreate();
537     if(!payload)
538     {
539         OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload"));
540         return OC_EH_ERROR;
541     }
542     bool boolRes = OCRepPayloadSetUri(*payload, piResource->header.piResource.uri);
543     if (boolRes == false)
544     {
545         OCRepPayloadDestroy (*payload);
546         return OC_EH_ERROR;
547     }
548     for(uint32_t i = 0; i<attributeList.count; i++)
549     {
550         char * outVal = NULL;
551         uint8_t outValLength = 0;
552
553         stackResult = TWGetAttribute(piResource->eui,
554                                      piResource->nodeId,
555                                      piResource->endpointId,
556                                      piResource->clusterId,
557                                      attributeList.list[i].zigBeeAttribute,
558                                      &outVal,
559                                      &outValLength);
560
561         if (stackResult != OC_STACK_OK || !outVal)
562         {
563             stackResult = OC_EH_ERROR;
564             OCRepPayloadDestroy (*payload);
565             goto exit;
566         }
567         if (attributeList.list[i].oicType == OIC_ATTR_INT)
568         {
569             char *endPtr = NULL;
570             // Third arg is 16 as outVal is a hex Number
571             uint64_t value = strtol (outVal, &endPtr, 16);
572
573             if (*endPtr != 0)
574             {
575                 return OC_EH_ERROR;
576             }
577             if (strcmp(attributeList.list[i].oicAttribute, OIC_DIMMING_ATTRIBUTE) == 0)
578             {
579                 // OIC Dimming operates between 0-100, while Zigbee operates
580                 // between 0-254 (ie. 0xFE).
581                 if (value > 0xFE)
582                 {
583                     value = 0xFE;
584                 }
585                 if (value <= 0xFE)
586                 {
587                     value = value / 2.54;
588                 }
589             }
590             boolRes = OCRepPayloadSetPropInt(*payload,
591                                              attributeList.list[i].oicAttribute,
592                                              (uint64_t) value);
593         }
594         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
595         {
596             double value = 0;
597
598             if (getDoubleValueFromString (outVal, &value) != OC_EH_OK)
599             {
600                 return OC_EH_ERROR;
601             }
602             if (strcmp(piResource->clusterId, ZB_TEMPERATURE_CLUSTER) == 0)
603             {
604                 // Divide by 100 as temperature readings have a resolution of
605                 // 0.01 or one hundreth of a degree celsius.
606                 value = value/100;
607             }
608             boolRes = OCRepPayloadSetPropDouble(*payload,
609                                                 attributeList.list[i].oicAttribute,
610                                                 value);
611         }
612         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
613         {
614             boolRes = OCRepPayloadSetPropString(*payload,
615                                                 attributeList.list[i].oicAttribute,
616                                                 outVal);
617         }
618         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
619         {
620             char *endPtr = NULL;
621             errno = 0;
622             // Third arg is 16 as outVal is a hex Number
623             uint64_t value = strtol (outVal, &endPtr, 16);
624
625             if (errno != 0 || *endPtr != 0)
626             {
627                 return OC_EH_ERROR;
628             }
629             // value COULD be a bit mask and the LSB indicates boolean true/false.
630             // If not a bit mask, it'll be plain 0 or 1.
631             value = value & 1;
632             boolRes = OCRepPayloadSetPropBool(*payload,
633                                               attributeList.list[i].oicAttribute,
634                                               value);
635         }
636
637         OICFree (outVal);
638     }
639
640     if (boolRes == false)
641     {
642         stackResult = OC_EH_ERROR;
643         goto exit;
644     }
645
646 exit:
647     for(; attributeListIndex < attributeList.count; attributeListIndex++)
648     {
649         OICFree(attributeList.list[attributeListIndex].oicAttribute);
650     }
651     return stackResult;
652 }
653
654 OCEntityHandlerResult processPutRequest (PIPluginBase * plugin,
655     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
656 {
657     if (!plugin || !ehRequest || !payload)
658     {
659         return OC_EH_ERROR;
660     }
661     OCStackResult stackResult = OC_STACK_OK;
662     PIResource_Zigbee *piResource = NULL;
663     AttributeList attributeList = {
664         0,
665         (CIECommandMask) 0,
666         .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } }
667     };
668
669     stackResult = GetResourceFromHandle(plugin,
670                                         ((PIResource **) (&piResource)),
671                                         ehRequest->resource);
672     if (stackResult != OC_STACK_OK)
673     {
674         OC_LOG (ERROR, TAG, "Failed to get resource from handle");
675         return OC_EH_ERROR;
676     }
677
678     bool boolRes = getZigBeeAttributesIfValid (
679                         piResource->header.piResource.resourceTypeName,
680                         &attributeList, *payload);
681     if(boolRes == false)
682     {
683         OC_LOG_V (ERROR, TAG, "Failed to fetch attributes for %s",
684             piResource->header.piResource.resourceTypeName);
685         return OC_EH_ERROR;
686     }
687
688     uint32_t i = 0;
689     for(; i<attributeList.count; i++)
690     {
691         if (attributeList.list[i].oicType == OIC_ATTR_INT)
692         {
693             char value[MAX_STRLEN_INT] = {};
694             if (attributeList.CIEMask || CIE_MOVE_TO_LEVEL)
695             {
696                 int64_t rangeDiff = 0;
697                 // OIC Dimming operates between 0-100, while Zigbee
698                 // operates between 0-254 (ie. 0xFE).
699                 rangeDiff = attributeList.list[i].val.i * 0xFE/100;
700                 if (rangeDiff > 0xFE)
701                 {
702                     rangeDiff = 0xFE;
703                 }
704                 if (rangeDiff < 0)
705                 {
706                     rangeDiff = 0;
707                 }
708                 if (rangeDiff <= 0xFE)
709                 {
710                     snprintf(value, sizeof(value), "%02x", (unsigned int) rangeDiff);
711                 }
712                 stackResult = TWMoveToLevel(piResource->nodeId, piResource->endpointId,
713                                     DEFAULT_MOVETOLEVEL_MODE, value, DEFAULT_TRANS_TIME);
714             }
715             else
716             {
717                 snprintf(value, sizeof(value), "%"PRId64, attributeList.list[i].val.i);
718                 stackResult = TWSetAttribute(piResource->eui,
719                     piResource->nodeId, piResource->endpointId,
720                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
721                     getZBDataTypeString(attributeList.list[i].zigbeeType), value);
722             }
723             if (stackResult != OC_STACK_OK)
724             {
725                 return OC_EH_ERROR;
726             }
727         }
728         else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
729         {
730             char value[MAX_STRLEN_DOUBLE] = {};
731             snprintf(value, sizeof(value), "%f", attributeList.list[i].val.d);
732             stackResult = TWSetAttribute(piResource->eui,
733                 piResource->nodeId, piResource->endpointId,
734                  piResource->clusterId, attributeList.list[i].zigBeeAttribute,
735                  getZBDataTypeString(attributeList.list[i].zigbeeType), value);
736         }
737         else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
738         {
739             stackResult = TWSetAttribute(piResource->eui,
740                 piResource->nodeId, piResource->endpointId,
741                 piResource->clusterId, attributeList.list[i].zigBeeAttribute,
742                 getZBDataTypeString(attributeList.list[i].zigbeeType),
743                 attributeList.list[i].val.str);
744             if (stackResult != OC_STACK_OK)
745             {
746                 return OC_EH_ERROR;
747             }
748         }
749         else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
750         {
751             char * value = attributeList.list[i].val.b ? "1" : "0";
752             if (attributeList.CIEMask || CIE_RON_OFF)
753             {
754                 stackResult = TWSwitchOnOff(piResource->nodeId, piResource->endpointId, value);
755             }
756             else
757             {
758                 stackResult = TWSetAttribute(piResource->eui,
759                     piResource->nodeId, piResource->endpointId,
760                     piResource->clusterId, attributeList.list[i].zigBeeAttribute,
761                     getZBDataTypeString(attributeList.list[i].zigbeeType),
762                     value);
763             }
764             if (stackResult != OC_STACK_OK)
765             {
766                 return OC_EH_ERROR;
767             }
768         }
769         else
770         {
771             continue;
772         }
773     }
774
775     return processGetRequest(plugin, ehRequest, payload);
776 }
777
778 OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin,
779     OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
780 {
781     if(!ehRequest || !payload)
782     {
783         return OC_EH_ERROR;
784     }
785     if(ehRequest->method == OC_REST_GET)
786     {
787         return processGetRequest(plugin, ehRequest, payload);
788     }
789     else if(ehRequest->method == OC_REST_PUT)
790     {
791         return processPutRequest(plugin, ehRequest, payload);
792     }
793     else
794     {
795         return OC_EH_FORBIDDEN;
796     }
797 }
798
799 char * getZBDataTypeString(ZigBeeAttributeDataType attrType)
800 {
801     switch (attrType)
802     {
803         case ZB_NULL:
804             return ZB_DATA_TYPE_NULL;
805         case ZB_8_BIT:
806             return ZB_DATA_TYPE_1_BYTE;
807         case ZB_16_BIT:
808             return ZB_DATA_TYPE_2_BYTE;
809         case ZB_24_BIT:
810             return ZB_DATA_TYPE_3_BYTE;
811         case ZB_32_BIT:
812             return ZB_DATA_TYPE_4_BYTE;
813         case ZB_40_BIT:
814             return ZB_DATA_TYPE_5_BYTE;
815         case ZB_48_BIT:
816             return ZB_DATA_TYPE_6_BYTE;
817         case ZB_56_BIT:
818             return ZB_DATA_TYPE_7_BYTE;
819         case ZB_64_BIT:
820             return ZB_DATA_TYPE_8_BYTE;
821         case ZB_BOOL:
822             return ZB_DATA_TYPE_BOOL;
823         case ZB_8_BITMAP:
824             return ZB_DATA_TYPE_1_BYTE;
825         case ZB_16_BITMAP:
826             return ZB_DATA_TYPE_2_BYTE;
827         case ZB_24_BITMAP:
828             return ZB_DATA_TYPE_3_BYTE;
829         case ZB_32_BITMAP:
830             return ZB_DATA_TYPE_4_BYTE;
831         case ZB_40_BITMAP:
832             return ZB_DATA_TYPE_5_BYTE;
833         case ZB_48_BITMAP:
834             return ZB_DATA_TYPE_6_BYTE;
835         case ZB_56_BITMAP:
836             return ZB_DATA_TYPE_7_BYTE;
837         case ZB_64_BITMAP:
838             return ZB_DATA_TYPE_8_BYTE;
839         case ZB_16_SINT:
840             return ZB_DATA_TYPE_SIGNED_INT_16;
841         case ZB_8_UINT:
842             return ZB_DATA_TYPE_UNSIGNED_INT_8;
843         case ZB_16_UINT:
844             return ZB_DATA_TYPE_UNSIGNED_INT_16;
845         default:
846             return ZB_DATA_TYPE_NULL;
847     }
848 }