Merge branch 'plugin-interface' into master
authorJoseph Morrow <joseph.l.morrow@intel.com>
Mon, 5 Oct 2015 17:34:32 +0000 (10:34 -0700)
committerJoseph Morrow <joseph.l.morrow@intel.com>
Mon, 5 Oct 2015 17:34:32 +0000 (10:34 -0700)
* plugin-interface:
  Enable ZigBee eventing in Plugin Interface through to IoTivity.
  Add event feature.
  Initial prototype for optimized Telegesis read/write layer.
  Fix logic in zigbee wrapper to correctly evaluate boolean values.

Conflicts:
plugins/zigbee_wrapper/src/zigbee_wrapper.c

Change-Id: I23ea73432656197a8d79a169257ae5a57ac99718
Signed-off-by: Joseph Morrow <joseph.l.morrow@intel.com>
1  2 
plugins/zigbee_wrapper/src/zigbee_wrapper.c

  #define ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY  "0000"
  #define ZB_ON_LEVEL_ATTRIBUTE                "0011"
  #define ZB_LEVEL_CONTROL_CLUSTER             "0008"
- #define ZB_CONTACT_CLUSTER                   "0500"
- #define ZB_CONTACT_ATTRIBUTE_ID              "0002"
+ #define ZB_IAS_ZONE_CLUSTER                  "0500"
+ #define ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID      "0002"
  #define ZB_INDICATOR_CLUSTER                 "0003"
  #define ZB_INDICATOR_ATTRIBUTE_ID            "0000"
  #define ZB_ON_OFF_CLUSTER                    "0006"
  #define ZB_ON_OFF_ATTRIBUTE_ID               "0000"
+ #define ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID        "0001"
+ #define IAS_ZONE_TYPE_MOTION_SENSOR          "000d"
+ #define IAS_ZONE_TYPE_CONTACT_SENSOR         "0015"
+ #define IAS_ZONE_TYPE_WATER_SENSOR           "002a"
  
  #define ZB_DATA_TYPE_NULL                    "00"
  #define ZB_DATA_TYPE_1_BYTE                  "08"
@@@ -92,6 -97,8 +97,8 @@@
  static const char* OIC_TEMPERATURE_SENSOR = "oic.r.temperature";
  static const char* OIC_DIMMABLE_LIGHT = "oic.r.light.dimming";
  static const char* OIC_CONTACT_SENSOR = "oic.r.sensor.contact";
+ static const char* OIC_MOTION_SENSOR = "oic.r.sensor.motion";
+ static const char* OIC_WATER_SENSOR = "oic.r.sensor.water";
  static const char* OIC_BINARY_SWITCH = "oic.r.switch.binary";
  
  static const char* OIC_TEMPERATURE_ATTRIBUTE = "temperature";
@@@ -127,7 -134,7 +134,7 @@@ typedef enu
  } ZigBeeAttributeDataType;
  
  char * getZBDataTypeString(ZigBeeAttributeDataType attrType);
- OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
+ OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
          OCRepPayload **payload);
  
  typedef enum
@@@ -169,20 -176,141 +176,141 @@@ typedef struc
      OICZigBeeAttributePair list[MAX_ATTRIBUTES];
  } AttributeList;
  
- const char* ZigBeeClusterIDToOICResourceType (const char * clusterID);
+ const char* ZigBeeClusterIDToOICResourceType(const char * clusterID);
  
- OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+ OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
                                                      AttributeList *attributeList);
  
- bool getZigBeeAttributesIfValid (char * OICResourceType,
+ bool getZigBeeAttributesIfValid(const char * OICResourceType,
                                      AttributeList *attributeList,
                                      OCRepPayload *payload);
  
+ const char * getResourceTypeForIASZoneType(TWDevice *device)
+ {
+     if(!device)
+     {
+         return NULL;
+     }
+     char *IASZoneType = NULL;
+     const char *resourceType = NULL;
+     uint8_t length = 0;
+     OCStackResult ret = TWGetAttribute(
+         NULL,
+         device->nodeId,
+         device->endpointOfInterest->endpointId,
+         ZB_IAS_ZONE_CLUSTER,
+         ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID,
+         &IASZoneType,
+         &length
+     );
+     if (ret != OC_STACK_OK || !IASZoneType)
+     {
+         OC_LOG_V (ERROR, TAG, "Error %u getting IAS Zone Type", ret);
+         return NULL;
+     }
+     if (strcmp (IASZoneType, IAS_ZONE_TYPE_CONTACT_SENSOR) == 0)
+     {
+         resourceType = OIC_CONTACT_SENSOR;
+     }
+     else if (strcmp (IASZoneType, IAS_ZONE_TYPE_MOTION_SENSOR) == 0)
+     {
+         resourceType = OIC_MOTION_SENSOR;
+     }
+     else if (strcmp (IASZoneType, IAS_ZONE_TYPE_WATER_SENSOR) == 0)
+     {
+         resourceType = OIC_WATER_SENSOR;
+     }
+     else
+     {
+         OC_LOG_V (ERROR, TAG, "Unsupported Zone Type %s", IASZoneType);
+         resourceType = NULL;
+     }
+     OICFree(IASZoneType);
+     return resourceType;
+ }
+ OCStackResult buildURI(char ** output,
+                        const char * prefix,
+                        const char * nodeId,
+                        const char * endpointId,
+                        const char * clusterId)
+ {
+     if(!output || !prefix || !nodeId || !endpointId || !clusterId)
+     {
+         return OC_STACK_INVALID_PARAM;
+     }
+     const char LEN_SEPARATOR[] = "/";
+     size_t lenSeparatorSize = sizeof(LEN_SEPARATOR) - 1;
+     size_t newUriSize = strlen(prefix) + lenSeparatorSize +
+                         strlen(nodeId) + lenSeparatorSize +
+                         strlen(endpointId) + lenSeparatorSize +
+                         strlen(clusterId)
+                         + 1; // NULL Terminator
+     *output = (char *) OICCalloc(1, newUriSize);
+     if (!*output)
+     {
+         OC_LOG (ERROR, TAG, "Out of memory");
+         return OC_STACK_NO_MEMORY;
+     }
+     char * temp = OICStrcpy(*output, newUriSize, prefix);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, nodeId);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, endpointId);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     temp = OICStrcat(*output, newUriSize, clusterId);
+     if(temp != *output)
+     {
+         goto exit;
+     }
+     return OC_STACK_OK;
+ exit:
+     OICFree(*output);
+     *output = NULL;
+     return OC_STACK_NO_MEMORY;
+ }
  void foundZigbeeCallback(TWDevice *device)
  {
+     if(!device)
+     {
+         OC_LOG(ERROR, TAG, "foundZigbeeCallback: Invalid parameter.");
+         return;
+     }
      int count = device->endpointOfInterest->clusterList->count;
-     size_t lenSeparator = strlen ("/");
-     int ret = 0;
      for(int i=0; i < count; i++)
      {
          PIResource_Zigbee *piResource = (PIResource_Zigbee *) OICMalloc(sizeof(*piResource));
              return;
          }
          piResource->header.plugin = (PIPluginBase *)gPlugin;
-         size_t newUriSize = strlen(PI_ZIGBEE_PREFIX) + lenSeparator +
-                         sizeof(device->nodeId) + lenSeparator +
-                         sizeof(device->endpointOfInterest->endpointId) + lenSeparator +
-                         sizeof(device->endpointOfInterest->clusterList->clusterIds[i].clusterId)
-                         + 1; // NULL Terminator
-         char * newUri = (char *) OICCalloc(newUriSize, 1);
  
-         if (!newUri)
+         OCStackResult result = buildURI(&piResource->header.piResource.uri,
+                                 PI_ZIGBEE_PREFIX,
+                                 device->nodeId,
+                                 device->endpointOfInterest->endpointId,
+                                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
+         if(result != OC_STACK_OK)
          {
-             OC_LOG (ERROR, TAG, "Out of memory");
+             OICFree(piResource);
              return;
          }
  
-         ret = snprintf(newUri, newUriSize, "%s/%s/%s/%s",
-                       PI_ZIGBEE_PREFIX,
-                       device->nodeId,
-                       device->endpointOfInterest->endpointId,
-                       device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
-         if(ret < 0)
+         char * foundClusterID =
+             device->endpointOfInterest->clusterList->clusterIds[i].clusterId;
+         if (strcmp (foundClusterID, ZB_IAS_ZONE_CLUSTER) == 0)
          {
-             OC_LOG (ERROR, TAG, "Encoding error occurred trying to build Zigbee URI.");
+             piResource->header.piResource.resourceTypeName
+                 = getResourceTypeForIASZoneType (device);
+             OCStackResult ret = TWListenForStatusUpdates (device->nodeId,
+                                       device->endpointOfInterest->endpointId);
+             if (ret != OC_STACK_OK)
+             {
+                 // Just log it and move on if this fails?
+                 // or not create this resource at all?
+                 OC_LOG (ERROR, TAG, "Command to listen for status updates failed");
+             }
          }
-         else if(ret > newUriSize)
+         else
          {
-             OC_LOG_V (ERROR, TAG, "Did not allocate enough memory to build URI. Required Size: %d",
-                       ret);
+             piResource->header.piResource.resourceTypeName =
+                     (char *) ZigBeeClusterIDToOICResourceType(foundClusterID);
          }
  
-         piResource->header.piResource.uri = newUri;
-         piResource->header.piResource.resourceTypeName =
-             (char *) ZigBeeClusterIDToOICResourceType(
-                 device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
          if(piResource->header.piResource.resourceTypeName == NULL)
          {
-             OC_LOG_V (ERROR, TAG, "unsupported clusterId : %d",
+             OC_LOG_V (ERROR, TAG, "unsupported clusterId : %s",
                  device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
              OICFree(piResource->header.piResource.uri);
              OICFree(piResource);
      }
  }
  
+ void zigbeeZoneStatusUpdate(TWUpdate * update)
+ {
+     if(!update)
+     {
+         return;
+     }
+     char * uri = NULL;
+     OCStackResult result = buildURI(&uri,
+                                     PI_ZIGBEE_PREFIX,
+                                     update->nodeId,
+                                     update->endpoint,
+                                     ZB_IAS_ZONE_CLUSTER);
+     if(result != OC_STACK_OK || !uri)
+     {
+         OC_LOG_V(ERROR, TAG, "Failed to build URI with result: %d", result);
+         return;
+     }
+     (*gPlugin)->header.ObserveNotificationUpdate((PIPluginBase *)*gPlugin, uri);
+     OICFree(uri);
+ }
  OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
-                          PINewResourceFound newResourceCB)
+                          PINewResourceFound newResourceCB,
+                          PIObserveNotificationUpdate observeNotificationUpdate)
  {
      if(!plugin)
      {
          return OC_STACK_NO_MEMORY;
      }
      ((*plugin)->header).type = PLUGIN_ZIGBEE;
-     ((*plugin)->header).comPort = OICStrdup(comPort);
+     ((*plugin)->header).comPort = comPort;
      ((*plugin)->header).NewResourceFoundCB = newResourceCB;
+     ((*plugin)->header).ObserveNotificationUpdate = observeNotificationUpdate;
      ((*plugin)->header).next = NULL;
      ((*plugin)->header).resourceList = NULL;
      ((*plugin)->header).processEHRequest = ProcessEHRequest;
  
      gPlugin = plugin;
-     return TWInitialize(comPort);
+     OCStackResult result = TWInitialize(comPort);
+     if(result != OC_STACK_OK)
+     {
+         return result;
+     }
+     return TWSetStatusUpdateCallback(zigbeeZoneStatusUpdate);
  }
  
  OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
  
  OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin)
  {
-     free((plugin->header).comPort);
      free(plugin);
      return TWUninitialize();
  }
  OCStackResult ZigbeeProcess(PIPlugin_Zigbee * plugin)
  {
      (void)plugin;
-     // Invoke TelegesisProcess() at some point.
-     return OC_STACK_OK;
+     return TWProcess();
  }
  
  // Function returns an OIC Smart Home resource Type
  // from the cluster ID. If the cluster is not supported, null is
  // returned.
  // NOTE: The returned string is NOT malloc'ed.
- const char* ZigBeeClusterIDToOICResourceType (const char * clusterID) //Discovery/CreateResource
+ const char* ZigBeeClusterIDToOICResourceType(const char * clusterID) //Discovery/CreateResource
  {
      if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
      {
      {
          return OIC_DIMMABLE_LIGHT;
      }
-     else if (strcmp(clusterID, ZB_CONTACT_CLUSTER) == 0)
+     else if (strcmp(clusterID, ZB_IAS_ZONE_CLUSTER) == 0)
      {
          return OIC_CONTACT_SENSOR;
      }
      }
  }
  
- const char* OICResourceToZigBeeClusterID (char *oicResourceType)
+ const char* OICResourceToZigBeeClusterID(char *oicResourceType)
  {
      if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
      {
      }
      else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
      {
-         return ZB_CONTACT_CLUSTER;
+         return ZB_IAS_ZONE_CLUSTER;
      }
      else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
      {
      }
  }
  
- OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+ OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
                                                      AttributeList *attributeList) // GET
  {
      if (strcmp (OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
      {
          attributeList->count = 1;
          attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
-         attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+         attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
          attributeList->list[0].oicType = OIC_ATTR_BOOL;
          attributeList->list[0].zigbeeType = ZB_BOOL;
          return OC_STACK_OK;
      return OC_STACK_ERROR;
  }
  
- bool getZigBeeAttributesIfValid (char * OICResourceType,
+ bool getZigBeeAttributesIfValid(const char * OICResourceType,
                                      AttributeList *attributeList,
                                      OCRepPayload *payload) // Put
  {
          {
              attributeList->count = 1;
              attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
-             attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+             attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
              attributeList->list[0].oicType = OIC_ATTR_BOOL;
              attributeList->list[0].val.i = value;
              attributeList->list[0].zigbeeType = ZB_BOOL;
      return false;
  }
  
- // str will be a 4 digit positive hex number.
- // Prepend with 0x and use strtod to convert to double.
  OCEntityHandlerResult getDoubleValueFromString (const char *str, double *outDouble)
  {
      size_t hexOutValSize = strlen(HexPrepend) + strlen(str) + 1;
      OICStrcpy(hexOutVal, hexOutValSize, HexPrepend);
      OICStrcat(hexOutVal, hexOutValSize, str);
  
 -    char *endPtr;
 +    char *endPtr = NULL;
      errno = 0;
      double value = strtod(hexOutVal, &endPtr);
  
@@@ -571,11 -728,10 +728,11 @@@ OCEntityHandlerResult processGetReques
          if (attributeList.list[i].oicType == OIC_ATTR_INT)
          {
              char *endPtr = NULL;
 +            errno = 0;
              // Third arg is 16 as outVal is a hex Number
              uint64_t value = strtol (outVal, &endPtr, 16);
  
 -            if (*endPtr != 0)
 +            if (*endPtr != 0 || errno != 0)
              {
                  return OC_EH_ERROR;
              }
@@@ -656,7 -812,7 +813,7 @@@ exit
      return stackResult;
  }
  
- OCEntityHandlerResult processPutRequest (PIPluginBase * plugin,
+ OCEntityHandlerResult processPutRequest(PIPluginBase * plugin,
      OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
  {
      if (!plugin || !ehRequest || !payload)
      return processGetRequest(plugin, ehRequest, payload);
  }
  
- OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin,
+ OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin,
      OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
  {
      if(!ehRequest || !payload)