Added Telegesis & Zigbee Wrappers, mapping logic, and plugin interface. 71/2771/12
authorJoseph Morrow <joseph.l.morrow@intel.com>
Sun, 20 Sep 2015 20:57:00 +0000 (13:57 -0700)
committerPatrick Lankswert <patrick.lankswert@intel.com>
Sun, 20 Sep 2015 21:55:02 +0000 (21:55 +0000)
These additions encompass the first pre-release of the plugin
interface.

A unit test, server, client application are also included.

Change-Id: Ia61a01223f611ffc1e38e79b8e3a8317fb3f34cd
Signed-off-by: Mandeep Shetty <mandeep.shetty@intel.com>
Signed-off-by: Thuyen Tran <thuyen.c.tran@intel.com>
Signed-off-by: Joseph Morrow <joseph.l.morrow@intel.com>
Reviewed-by: Jon A. Cruz <jonc@osg.samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2771
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Patrick Lankswert <patrick.lankswert@intel.com>
22 files changed:
plugins/SConscript
plugins/include/internal/pluginlist.h [moved from plugins/include/internal/plugininterfaceinternal.h with 56% similarity]
plugins/include/internal/plugintranslatortypes.h
plugins/include/plugininterface.h
plugins/include/plugintypes.h
plugins/samples/linux/IotivityandZigbeeClient.c
plugins/samples/linux/IotivityandZigbeeClient.h
plugins/samples/linux/IotivityandZigbeeServer.c
plugins/samples/linux/SConscript
plugins/src/SConscript
plugins/src/plugininterface.c
plugins/src/pluginlist.c [new file with mode: 0644]
plugins/unittests/plugininterfacetest.cpp
plugins/zigbee_wrapper/SConscript
plugins/zigbee_wrapper/include/zigbee_wrapper.h [new file with mode: 0644]
plugins/zigbee_wrapper/src/SConscript [new file with mode: 0644]
plugins/zigbee_wrapper/src/zigbee_wrapper.c [new file with mode: 0644]
plugins/zigbee_wrapper/telegesis_wrapper/SConscript
plugins/zigbee_wrapper/telegesis_wrapper/include/telegesis_wrapper.h
plugins/zigbee_wrapper/telegesis_wrapper/src/SConscript
plugins/zigbee_wrapper/telegesis_wrapper/src/telegesis_wrapper.c
resource/csdk/logger/src/logger.c

index 74b4bb8..cb4050f 100644 (file)
@@ -1,21 +1,44 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 ##
 # Plugin Interface build script
 ##
 
+import os.path
+
 Import('env')
 
 target_os = env.get('TARGET_OS')
+build_sample = env.get('BUILD_SAMPLE')
+src_dir = env.get('SRC_DIR')
 
 if target_os not in ['android', 'arduino', 'darwin', 'ios']:
-    transport = env.get('TARGET_TRANSPORT')
-    build_sample = env.get('BUILD_SAMPLE')
 
-    env.SConscript('./src/SConscript')
+    SConscript(os.path.join('zigbee_wrapper', 'SConscript'))
+
+    SConscript(os.path.join('src', 'SConscript'))
 
-    env.SConscript('./unittests/SConscript')
+    SConscript(os.path.join('unittests', 'SConscript'))
 
     if build_sample == 'ON':
            if target_os in ['linux']:
                    target_path = target_os
-                   env.SConscript('./samples/' + target_path + '/SConscript')
+                   SConscript(os.path.join('samples', target_path, 'SConscript'))
 
similarity index 56%
rename from plugins/include/internal/plugininterfaceinternal.h
rename to plugins/include/internal/pluginlist.h
index 8882281..b722f2e 100644 (file)
@@ -1,6 +1,6 @@
 //******************************************************************
 //
-// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 //
 /**
  * @file
  *
- * This file contains APIs for PIPlugin module to be implemented.
+ * This file contains the accessors and setters for the PluginList
  */
 
-#ifndef PLUGININTERFACEINTERNAL_H_
-#define PLUGININTERFACEINTERNAL_H_
+#ifndef PLUGINLIST_H_
+#define PLUGINLIST_H_
 
-#include "plugintypes.h"
 #include "plugintranslatortypes.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
-/**
- *
- * Called from PIProcess. Gives cycles for Zigbee Wrapper'
- * internal operation.
- *
- */
-OCStackResult ProcessZigbee(PIPlugin_Zigbee * plugin);
+OCStackResult AddPlugin(PIPluginBase * plugin);
+
+OCStackResult DeletePlugin(PIPluginBase * plugin);
+
+OCStackResult DeletePluginList();
+
+OCStackResult GetResourceFromHandle(PIPluginBase * plugin, PIResource ** piResource,
+                                    OCResourceHandle * resourceHandle);
+
+OCStackResult AddResourceToPlugin(PIPluginBase * plugin, PIResourceBase * resource);
+
+OCStackResult DeleteResource(PIPluginBase * plugin, PIResourceBase * resource);
+
+OCStackResult DeleteResourceList(PIPluginBase * plugin);
 
 #ifdef __cplusplus
 }
 #endif // __cplusplus
 
-#endif /* PLUGININTERFACEINTERNAL_H_ */
+#endif /* PLUGINLIST_H_ */
index 6d37325..19ab945 100644 (file)
 /**
  * @file
  *
- * This file contains the definition, types and APIs for resource(s) be
- * implemented.
+ * This file contains the definition, types and APIs for all operations
+ * required to translate plugin's respective devices to an OCResource.
  */
 
 #ifndef PLUGINTRANSLATORTYPES_H_
 #define PLUGINTRANSLATORTYPES_H_
 
-#include "octypes.h"
+#include "plugintypes.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
-// This file will hold structs which will help aid in abstraction of zigbee
-// protocol to a PIPlugin.:
+#define PI_ZIGBEE_PREFIX "/zb"
 
+// Forward definitions to support inter-linking between structs in this file
+// and the following callback.
+// Note: If there are issues with either of the following two structs, please
+//       manually check these structs and their uses for valid operation.
+struct PIPluginBase;
+struct PIResourceBase;
+
+/**
+ *
+ * This callback will be called when a new resource is created by radio wrapper.
+ *
+ */
+typedef void (* PINewResourceFound)(struct PIPluginBase * plugin,
+                                    struct PIResourceBase *newResource);
+
+/**
+ *
+ * This function type is used by the radio's mapping implementation against IoTivity.
+ * The mapping implementation must implement this function to handle GET & PUT requests.
+ *
+ */
+typedef OCEntityHandlerResult (* PIProcessRequest) (struct PIPluginBase * plugin,
+                                                    OCEntityHandlerRequest *ehRequest,
+                                                    OCRepPayload **payload);
+
+/**
+ * Parameter list for a plugin.
+ */
+typedef struct PIPluginBase
+{
+    /** The type of plugin this represents. */
+    PIPluginType type;
+
+    /** The file location which represents the interface of the plugin.  */
+    char * comPort;
+
+    /** Linked list of plugins. */
+    struct PIPluginBase * next;
+
+    /** Callback to be used when a new resource has been found. */
+    PINewResourceFound NewResourceFoundCB;
+
+    /** Function Pointer to be invoked upon an incoming IoTivity request. */
+    PIProcessRequest processEHRequest;
+
+    /** All resources which exist within the context of this plugin. */
+    struct PIResourceBase * resourceList;
+
+    // Any other common internal properties between plugins can be placed here.
+} PIPluginBase;
+
+/**
+ * The inherite plugin type to be associated with the ZigBee radio and its
+ * implementation.
+ */
+// Note: Although ZigBee has no new members for it's Plugin Type, other radio
+// implementations should follow this paradigm where each radio type has
+// inherited from the PIPluginBase type.
 typedef struct
 {
-    PIPluginBase * header;
-    struct PIResource_Zigbee * resource; // All resources which exist within this context.
-    //Todo: Whatever other zigbee plugin specific stuff...
-    //Todo:  zigbee_homeautomationprofile profile;
+    PIPluginBase header;
 } PIPlugin_Zigbee;
 
 /**
- *  Header for all PIResources.
+ * Parameter list for a new OCResource. This will be handed up in the
+ * PINewResource callback.
  */
 typedef struct
 {
+    OCResourceHandle resourceHandle;
+    char *resourceTypeName;
+    char *resourceInterfaceName;
+    char *uri;
+    OCEntityHandler entityHandler;
+    void* callbackParam;
+    uint8_t resourceProperties;
+} PIResource;
+
+/**
+ *  Header for all PIResources.
+ */
+typedef struct PIResourceBase
+{
+    PIResource piResource;
     struct PIResourceBase * next; // Linked list of resources.
     PIPluginBase * plugin; // Context this resource exists.
-    OCResourceHandle * resourceHandle; // Handle to OIC Resource.
 } PIResourceBase;
 
 typedef struct
@@ -68,9 +137,11 @@ typedef struct
  */
 typedef struct
 {
-    PIResourceBase * header;
-    PIPlugin_Zigbee * plugin; // Context which this Zigbee device exists.
-    PIZigbeeProfile zigbeeProfile; // Representation of a Zigbee Device.
+    PIResourceBase header;
+    char * eui;
+    char * nodeId;
+    char * endpointId;
+    char * clusterId;
 } PIResource_Zigbee;
 
 #ifdef __cplusplus
index 501f07b..e66d1d9 100644 (file)
 extern "C" {
 #endif // __cplusplus
 
-// Todo: The following APIs can be modified as needed. This just a loose
-// declaration to illustrate how we can manage our plugins. The types are
-// defined in plugintypes.h.
-
 /**
  *
- * Makes any required calls to instantiate IoTivity and/or plugin's radio.
+ * Makes any required calls to instantiate plugin's radio.
  *
+ * @param[in]  comPort The com port which this plugin is located.
  * @param[in]  pluginType The type of plugin to start.
  * @param[out] plugin The plugin handle that will be started.
- *   Note: Please note that the plugin will need to be managed in the
- *         application space.
+ *
  */
-OCStackResult PIStartPlugin(PIPluginType pluginType, PIPluginBase ** plugin);
+OCStackResult PIStartPlugin(const char * comPort, PIPluginType pluginType, PIPlugin ** plugin);
 
 /**
  *
- * Makes any required calls to stop plugin's radio.
+ * Makes any required calls to stop plugin.
+ *
+ * @param[in] plugin The plugin to be stopped.
  *
- * @param[in] PIStopPlugin The plugin to be stopped.
- *           Note: If NULL Makes any required calls to stop IoTivity and ALL
- *                 plugin radios.
  */
-OCStackResult PIStopPlugin(PIPluginBase * plugin);
+OCStackResult PIStopPlugin(PIPlugin * plugin);
+
+/**
+ *
+ * Makes any required calls to stop all plugins.
+ *
+ */
+OCStackResult PIStopAll();
 
 /**
  *
  * Called in main loop of application. Gives cycles for Plugin Interface'
  * internal operation.
  *
+ * @param[in] plugin The plugin to get cycles from this function's invocation.
+ *
  */
-OCStackResult PIProcess(PIPluginBase * plugin);
+OCStackResult PIProcess(PIPlugin * plugin);
 
 #ifdef __cplusplus
 }
index d17f3eb..825908f 100644 (file)
@@ -41,19 +41,15 @@ extern "C" {
 typedef enum
 {
     PLUGIN_UNKNOWN = 0,
-    /** Zigbee */
     PLUGIN_ZIGBEE = 1
 
 } PIPluginType;
 
+
 /**
- * Parameter list for a plugin.
+ * Handle to a plugin.
  */
-typedef struct
-{
-    PIPluginType type;
-// Todo: Any other common properties between plugins can be placed here.
-} PIPluginBase;
+typedef struct PIPlugin {} PIPlugin;
 
 #ifdef __cplusplus
 }
index 06a085e..3c7e565 100644 (file)
@@ -1,3 +1,23 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
 // The source file for sample application "IotivityandZigbee".
 
 // This application will utilize our interface (ie. zpluginz.h).
 // OCDeleteResource(), EntityHandler()..etc.)
 
 #include "IotivityandZigbeeClient.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include "ocstack.h"
+#include "logger.h"
+#include "ocpayload.h"
+#include "payload_logging.h"
+#include "oic_string.h"
+
+#define DEFAULT_CONTEXT_VALUE       (0x99)
+#define MAX_QUERY_SIZE              (1024)
+#define MAX_URI_SIZE                (256)
+#define MAX_RESOURCE_TYPE_SIZE      (32)
+#define MAX_RESOURCE_TYPE_LENGTH    (MAX_RESOURCE_TYPE_SIZE - 1)
+#define MAX_RESOURCES_REMEMBERED    (10)
+
+#define TAG "oc_zb_client"
+
+static uint32_t countDiscoveredResources = 0;
+static bool promptUser = false;
+
+static const char*      coapServerIP    = "255.255.255.255";
+static       uint32_t   coapServerPort  = 5683;
+
+typedef struct
+{
+    char uri[MAX_URI_SIZE];
+    char resourceType[MAX_RESOURCE_TYPE_SIZE];
+
+} DiscoveredResourceInfo;
+
+static DiscoveredResourceInfo g_discoveredResources[MAX_RESOURCES_REMEMBERED];
+
+static void PrintTestCases()
+{
+    printf("\nTest Cases:\n");
+    printf ("\n\t0 : Quit    1: GET    2: Build PUT payload\n\n");
+    printf ("\t3 : Turn binary switch for light ON\n");
+    printf ("\t4 : Turn binary switch for light OFF\n");
+    printf ("\t5 : Change light brightness\n");
+}
+
+static void PrintResources ()
+{
+    printf("\nResources: \n");
+    for (int i = 0; i < countDiscoveredResources; ++i)
+    {
+        printf("\t# : %u \t URI: %s \t Type:%s\n", i, g_discoveredResources[i].uri,
+            g_discoveredResources[i].resourceType);
+    }
+}
+
+void rememberDiscoveredResources (OCClientResponse *clientResponse)
+{
+    OCResourcePayload* itr = NULL;
+    if(!(OCDiscoveryPayload*)clientResponse->payload)
+    {
+        OC_LOG (INFO, TAG, "No resources discovered.");
+        return;
+    }
+
+    itr = ((OCDiscoveryPayload*)(clientResponse->payload))->resources;
+
+    while(itr && itr != itr->next)
+    {
+        if (countDiscoveredResources == MAX_RESOURCES_REMEMBERED)
+        {
+            OC_LOG_V (INFO, TAG, "Only remembering %u resources. Ignoring rest.",
+                MAX_RESOURCES_REMEMBERED);
+            break;
+        }
+        strncpy (g_discoveredResources[countDiscoveredResources].uri,
+            itr->uri, MAX_URI_SIZE - 1);
+        strncpy (g_discoveredResources[countDiscoveredResources].resourceType,
+            itr->types->value, MAX_RESOURCE_TYPE_SIZE - 1);
+        ++countDiscoveredResources;
+        itr = itr->next;
+    }
+}
+
+OCStackResult InvokeOCDoResource (char *query,
+                                 OCPayload *payload,
+                                 OCMethod method,
+                                 OCClientResponseHandler cb)
+{
+    OCCallbackData cbData = {
+                                .context = (void*)DEFAULT_CONTEXT_VALUE,
+                                .cb = cb
+                            };
+
+    OCDoHandle handle = NULL;
+
+    OCStackResult ret = OCDoResource(&handle, method, query, 0, payload,
+                        CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0);
+
+    if (ret != OC_STACK_OK)
+    {
+        promptUser = true;
+        OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
+    }
+    return ret;
+}
+
+OCStackApplicationResult responseCallbacks(void* ctx,
+                OCDoHandle handle,
+                OCClientResponse * clientResponse)
+{
+    (void)handle;
+    if(clientResponse == NULL)
+    {
+        OC_LOG(INFO, TAG, "responseCallbacks received NULL clientResponse");
+        return   OC_STACK_DELETE_TRANSACTION;
+    }
+
+    OC_LOG_PAYLOAD(INFO, clientResponse->payload);
+    promptUser = true;
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+int InitGetRequest (const char *resourceUri)
+{
+    char query[MAX_QUERY_SIZE] = {0};
+    snprintf (query, sizeof(query), "coap://%s:%u%s", coapServerIP,
+                                            coapServerPort,resourceUri);
+
+    OC_LOG_V(INFO, TAG, "Executing %s queryString is: %s", __func__, query);
+
+    return (InvokeOCDoResource(query, NULL, OC_REST_GET, responseCallbacks));
+}
+
+int InitPutRequest (const char *resourceUri, OCPayload* payload)
+{
+    char query[MAX_QUERY_SIZE] = {0};
+    snprintf (query, sizeof(query), "coap://%s:%u%s", coapServerIP, coapServerPort,
+                                                            resourceUri);
+    OC_LOG_V(INFO, TAG, "Executing %s queryString is: %s", __func__, query);
+
+    return (InvokeOCDoResource(query, payload, OC_REST_PUT, responseCallbacks));
+}
+
+OCPayload * getSwitchStatePayload (bool state)
+{
+    OCRepPayload* payload = OCRepPayloadCreate();
+    if(!payload)
+    {
+       OC_LOG (ERROR, TAG, "Failed to create payload object");
+       exit(1);
+    }
+    OCRepPayloadSetPropBool(payload, "value", state);
+    return (OCPayload*) payload;
+}
+
+OCPayload* getChangeLevelPayload(uint32_t level)
+{
+    OCRepPayload* payload = OCRepPayloadCreate();
+    if(!payload)
+    {
+        OC_LOG (ERROR, TAG, "Failed to create payload object");
+        exit(1);
+    }
+
+    OC_LOG_V(INFO, TAG, "Setting level to : %u", level);
+    OCRepPayloadSetPropInt(payload, "dimmingSetting", level);
+    return (OCPayload*) payload;
+}
+
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
+                            OCClientResponse * clientResponse)
+{
+    (void)handle;
+    if (!clientResponse)
+    {
+        OC_LOG(INFO, TAG, "Discovery response is NULL");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    OC_LOG_PAYLOAD(INFO, clientResponse->payload);
+    OC_LOG_V(INFO, TAG, "Discovered @ %s:%d", clientResponse->devAddr.addr,
+                                clientResponse->devAddr.port);
+
+    coapServerIP   = OICStrdup (clientResponse->devAddr.addr);
+    coapServerPort = clientResponse->devAddr.port;
+
+    rememberDiscoveredResources (clientResponse);
+
+    promptUser = true;
+
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCPayload* getCustomPutPayload ()
+{
+    OCRepPayload* payload = OCRepPayloadCreate();
+    if(!payload)
+    {
+        OC_LOG (ERROR, TAG, "Failed to create payload object");
+        exit(1);
+    }
+
+    char key[100] = {0};
+    char input[100] = {0};
+    char valueString[100] = {0};
+    int value = 0;
+    double valueDouble = 0.0;
+    int type = -1;
+
+    printf("\nEnter key value pairs as:\t<type(int)> <key> <value>\n");
+    printf("\nType: 0:bool \t 1:int \t 2:double\n");
+    while (true)
+    {
+        printf ("Blank line / press ENTER to finish :");
+        char *ret = fgets (input, sizeof(input), stdin);
+        (void) ret;
+        int inCount = sscanf (input, "%d %s %s", &type, key, valueString);
+
+        if (inCount <= 0)
+        {
+            break;
+        }
+        if (inCount != 3)
+        {
+            printf("Invalid input\n");
+            OCRepPayloadDestroy (payload);
+            promptUser = true;
+            return NULL;
+        }
+
+        if (type == 0)  //bool
+        {
+            if (sscanf(valueString, "%d", &value) == 1)
+            {
+                OCRepPayloadSetPropBool(payload, key, value);
+            }
+        }
+        else if (type == 1)  //int
+        {
+            if (sscanf(valueString, "%d", &value) == 1)
+            {
+                OCRepPayloadSetPropInt(payload, key, value);
+            }
+        }
+        else if (type == 2)  //double
+        {
+            if (sscanf(valueString, "%lf", &valueDouble) == 1)
+            {
+                OCRepPayloadSetPropDouble(payload, key, valueDouble);
+            }
+        }
+        else
+        {
+            OC_LOG(ERROR, TAG, "Invalid entry. Stopping accepting key-values");
+            OCRepPayloadDestroy (payload);
+            promptUser = true;
+            return NULL;
+        }
+        memset (input, 0, sizeof (input));
+        memset (key, 0, sizeof (key));
+        memset (valueString, 0, sizeof (valueString));
+    }
+
+    if (payload->values)
+    {
+        return (OCPayload *) payload;
+    }
+    else
+    {
+        OCRepPayloadDestroy (payload);
+        return NULL;
+    }
+}
+
+void processUserInput (int resourceNo, int testCase)
+{
+    switch (testCase)
+    {
+        case TEST_GET:
+            InitGetRequest (g_discoveredResources[resourceNo].uri);
+            break;
+
+        case TEST_CUSTOM_PUT:
+        {
+            OCPayload *payload = getCustomPutPayload ();
+            if (payload)
+            {
+                InitPutRequest (g_discoveredResources[resourceNo].uri, payload);
+            }
+            else
+            {
+                OC_LOG(ERROR, TAG, "Error creating payload. Not sending PUT request");
+                promptUser = true;
+            }
+            break;
+        }
+        case TEST_TURN_SWITCH_ON:
+            InitPutRequest (g_discoveredResources[resourceNo].uri, getSwitchStatePayload (true));
+            break;
+
+        case TEST_TURN_SWITCH_OFF:
+            InitPutRequest (g_discoveredResources[resourceNo].uri, getSwitchStatePayload (false));
+            break;
+
+        case TEST_SET_LIGHT_BRIGHTNESS:
+            printf ("Change bulb level [0-100] to ? :");
+            int level = 0;
+            if (scanf ("%d", &level) > 0)
+            {
+                InitPutRequest (g_discoveredResources[resourceNo].uri,
+                    getChangeLevelPayload (level));
+            }
+            else
+            {
+                printf("Invalid value\n");
+                promptUser = true;
+            }
+            break;
+
+        case TEST_QUIT:
+            raise (SIGINT);
+            break;
+
+        default:
+            promptUser = true;
+            OC_LOG(INFO, TAG, "Invalid test case");
+    }
+}
+
+void getTestCaseFromUser ()
+{
+    PrintResources ();
+    PrintTestCases ();
+    printf("\nUsage:<resource number> <test case> :");
+
+    char input[10] = {0};
+    int resourceNo = 0;
+    int testCase = 0;
+
+    char * ret = fgets (input, sizeof(input), stdin);
+    (void) ret;
+    int inCount = sscanf (input, "%d %d", &resourceNo, &testCase);
+
+    if (inCount != 2)
+    {
+        printf("Invalid input\n");
+        promptUser = true;
+        return;
+    }
+    if (resourceNo >= countDiscoveredResources)
+    {
+        printf("Invalid resource\n");
+        promptUser = true;
+        return;
+    }
+    processUserInput (resourceNo, testCase);
+}
+
+OCStackResult DiscoverResources ()
+{
+    OCCallbackData cbData = {
+                                .context = (void*)DEFAULT_CONTEXT_VALUE,
+                                .cb = discoveryReqCB
+                            };
+
+    OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, OC_RSRVD_WELL_KNOWN_URI,
+                        0, 0, CT_ADAPTER_IP,OC_LOW_QOS, &cbData, NULL, 0);
+
+    if (ret != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCDoResource error");
+    }
+    return ret;
+}
+
+bool processSignal(bool set)
+{
+    static sig_atomic_t signal = 0;
+    if (set)
+    {
+        signal = 1;
+    }
+    return signal == 1;
+}
+
+void processCancel(int signal)
+{
+    if(signal == SIGINT)
+    {
+        processSignal(true);
+    }
+}
 
 int main(int argc, char* argv[])
 {
+    OCStackResult result;
+    OC_LOG(INFO, TAG, "Initializing IoTivity...");
+
+    result = OCInit(NULL, 0, OC_CLIENT);
+    if (result != OC_STACK_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "OCInit Failed %d", result);
+        return -1;
+    }
+
+    DiscoverResources ();
+
+    if (signal(SIGINT, processCancel) == SIG_ERR)
+    {
+        OC_LOG(ERROR, TAG, "Unable to catch SIGINT, terminating...");
+    }
+    else
+    {
+        OC_LOG(INFO, TAG, "Press Ctrl-C to terminate");
+        // Loop until sigint
+        while (!processSignal(false) && result == OC_STACK_OK)
+        {
+            result = OCProcess();
+            if (result != OC_STACK_OK)
+            {
+                OC_LOG_V(ERROR, TAG, "OCProcess Failed: %d", result);
+                break;
+            }
+
+            if (promptUser)
+            {
+                promptUser = false;
+                getTestCaseFromUser ();
+            }
+        }
+    }
+
+    OC_LOG(INFO, TAG, "Stopping IoTivity...");
+    result = OCStop();
+    if (result != OC_STACK_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "OCStop Failed: %d", result);
+    }
+
     return 0;
 }
+
index f8f3e9d..217440d 100644 (file)
@@ -1,8 +1,44 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
 // The source file for sample application "IotivityandZigbeeServer".
 
 // This application will utilize our interface (ie. zpluginz.h).
 // The application may still be responsible for making any IoTivity API calls,
 // except for resource-specific IoTivity APIs (ie. OCCreateResource(),
 // OCDeleteResource(), EntityHandler()..etc.)
+#ifndef OCZBCLIENT_H_
+#define OCZBCLIENT_H_
 
+#include "ocstack.h"
 #include "plugininterface.h"
+
+typedef enum
+{
+    TEST_QUIT = 0,
+    TEST_GET  = 1,
+    TEST_CUSTOM_PUT,
+    TEST_TURN_SWITCH_ON,
+    TEST_TURN_SWITCH_OFF,
+    TEST_SET_LIGHT_BRIGHTNESS,
+    MAX_TESTS
+} CLIENT_TEST;
+
+#endif
index 443d6c8..5f05ead 100644 (file)
 #include <logger.h>
 
 #define TAG "IoTivityZigbeeServer"
-
-int main(int argc, char* argv[])
+#define defaultComPort "/dev/ttyUSB0"
+int main()
 {
-    OCStackResult result;
     OC_LOG(INFO, TAG, "Initializing IoTivity...");
-
-    // Initialize Stack
-    result = OCInit(NULL, 0, OC_SERVER);
+    OCStackResult result = OCInit(NULL, 0, OC_SERVER);
     if (result != OC_STACK_OK)
     {
         OC_LOG_V(ERROR, TAG, "OCInit Failed %d", result);
         return -1;
     }
 
-    // Set Platform info
     result = SetPlatformInfo();
     if (result != OC_STACK_OK)
     {
@@ -46,14 +42,13 @@ int main(int argc, char* argv[])
         goto IotivityStop;
     }
 
-    // Set Device Info
     result  = SetDeviceInfo();
     if (result != OC_STACK_OK)
     {
         OC_LOG_V(ERROR, TAG, "SetPlatformInfo Failed: %d", result);
         goto IotivityStop;
     }
-    // Start Presence
+
     result  = OCStartPresence(0);
     if (result != OC_STACK_OK)
     {
@@ -62,9 +57,9 @@ int main(int argc, char* argv[])
     }
 
     // PIStartPlugin
-    PIPluginBase* plugin = NULL;
+    PIPlugin* plugin = NULL;
     OC_LOG(INFO, TAG, "IoTivity Initialized properly, Starting Zigbee Plugin...");
-    result = PIStartPlugin(PLUGIN_ZIGBEE, &plugin);
+    result = PIStartPlugin(defaultComPort, PLUGIN_ZIGBEE, &plugin);
     if (result != OC_STACK_OK)
     {
         OC_LOG_V(ERROR, TAG, "Zigbee Plugin Start Failed: %d", result);
@@ -116,6 +111,7 @@ IotivityStop:
     }
 
     OC_LOG(INFO, TAG, "Application Completed Successfully");
+    return 0;
 }
 
 OCStackResult SetPlatformInfo()
index 27179c2..dea9b7f 100644 (file)
@@ -30,12 +30,11 @@ pi_dir = os.path.join(src_dir, 'plugins')
 # Build flags
 ######################################################################
 samples_env.PrependUnique(CPPPATH = [
-               '../../../resource/oc_logger/include',
-               '../../../resource/csdk/logger/include',
-               '../../../resource/csdk/stack/include',
-               '../../../extlibs/cjson',
+               os.path.join(src_dir, 'resource', 'oc_logger', 'include'),
+               os.path.join(src_dir, 'resource', 'csdk', 'logger', 'include'),
+               os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include'),
                 os.path.join(pi_dir, 'include')
-               ])
+                ])
 
 samples_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-Wextra', '-Werror'])
 samples_env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
index 06a7b55..55f0b7d 100644 (file)
@@ -1,3 +1,22 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 ##
 # Plugin Interface build script
 ##
@@ -10,15 +29,24 @@ target_os = env.get('TARGET_OS')
 src_dir = env.get('SRC_DIR')
 pi_path = os.path.join(src_dir, 'plugins')
 
-#####################################################################
-# Source files and Target(s)
-######################################################################
-
 print"Reading PI script"
 
-env.PrependUnique(CPPPATH = [ os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include') ])
+######################################################################
+# Build flags
+######################################################################
+
+env.PrependUnique(CPPPATH = [ os.path.join(src_dir, 'resource', 'c_common', 'oic_malloc', 'include'),
+                              os.path.join(src_dir, 'resource', 'c_common', 'oic_string', 'include'),
+                              os.path.join(src_dir, 'resource', 'oc_logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'connectivity', 'lib', 'libcoap-4.1.1')
+                            ])
 env.AppendUnique(CPPPATH = [ os.path.join(pi_path, 'include'),
-                             os.path.join(pi_path, 'include', 'internal') ])
+                             os.path.join(pi_path, 'include', 'internal'),
+                             os.path.join(pi_path, 'zigbee_wrapper', 'include'),
+                             os.path.join(pi_path, 'include', 'internal')
+                           ])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
        env.AppendUnique(CPPDEFINES = ['WITH_POSIX'])
@@ -26,9 +54,23 @@ if target_os not in ['arduino', 'windows', 'winrt']:
 if target_os in ['darwin','ios']:
        env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE'])
 
+env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-Wextra', '-Werror'])
+env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
+env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
+
+env.PrependUnique(LIBS = ['zigbee_wrapper'])
+
+if env.get('LOGGING'):
+       env.AppendUnique(CPPDEFINES = ['TB_LOG'])
+
+#####################################################################
+# Source files and Target(s)
+######################################################################
 pi_src = [
-       'plugininterface.c',
-       ]
+         os.path.join(src_dir, 'resource', 'csdk', 'logger', 'src', 'logger.c'),
+         'pluginlist.c',
+         'plugininterface.c',
+            ]
 
 env.AppendUnique(PI_SRC = pi_src)
 
index 9896c02..e94f040 100644 (file)
@@ -1,6 +1,6 @@
 //******************************************************************
 //
-// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 //
  */
 
 #include "plugininterface.h"
-#include "plugininterfaceinternal.h"
 #include "plugintranslatortypes.h"
+#include "pluginlist.h"
+#include "zigbee_wrapper.h"
+#include "oic_string.h"
+#include "oic_malloc.h"
+#include "ocstack.h"
+#include "ocpayload.h"
+#include "logger.h"
 
-// Internal Note: This API will try to start IoTivity. If it is already
-//                started, nothing will occur. The IoTivity stack will not
-//                allow another instance to occur within the same program space
-//                and will even return a soft success when we try (ie.
-//                OC_STACK_OK).
-OCStackResult PIStartPlugin(PIPluginType pluginType, PIPluginBase** plugin)
+#include <string.h>
+#include <stdlib.h>
+
+#define TAG PCF("pluginInterface")
+
+/**
+ * Entity handler callback that fills the resPayload of the entityHandlerRequest.
+ */
+OCEntityHandlerResult PluginInterfaceEntityHandler(OCEntityHandlerFlag flag,
+                                                   OCEntityHandlerRequest * entityHandlerRequest,
+                                                   void* callbackParam)
 {
-    return OC_STACK_NOTIMPL;
+    if (!entityHandlerRequest)
+    {
+        OC_LOG (ERROR, TAG, "Invalid request pointer");
+        return OC_EH_ERROR;
+    }
+
+    OCEntityHandlerResult ehResult = OC_EH_ERROR;
+    OCStackResult result = OC_STACK_ERROR;
+    PIPluginBase * plugin = (PIPluginBase *) callbackParam;
+
+    OCEntityHandlerResponse * response =
+                        (OCEntityHandlerResponse *) OICCalloc(1, sizeof(*response));
+
+    if (!response)
+    {
+        return OC_EH_ERROR;
+    }
+
+    OCRepPayload* payload = (OCRepPayload *) entityHandlerRequest->payload;
+
+    if (flag & OC_REQUEST_FLAG)
+    {
+        if (plugin->processEHRequest)
+        {
+            ehResult = plugin->processEHRequest(plugin, entityHandlerRequest, &payload);
+        }
+    }
+
+    // If the result isn't an error or forbidden, send response
+    if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
+    {
+        // Format the response.  Note this requires some info about the request
+        response->requestHandle = entityHandlerRequest->requestHandle;
+        response->resourceHandle = entityHandlerRequest->resource;
+        response->ehResult = ehResult;
+        response->payload = (OCPayload*) payload;
+        // Indicate that response is NOT in a persistent buffer
+        response->persistentBufferFlag = 0;
+
+        result = OCDoResponse(response);
+        if (result != OC_STACK_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Error sending response %u", result);
+            ehResult = OC_EH_ERROR;
+        }
+    }
+    else
+    {
+        OC_LOG_V(ERROR, TAG, "Error handling request %u", ehResult);
+    }
+
+    OCPayloadDestroy(response->payload);
+    OICFree(response);
+    return ehResult;
 }
 
-OCStackResult PIStopPlugin(PIPluginBase * plugin)
+void piNewResourceCB(PIPluginBase * p_plugin, PIResourceBase * r_newResource)
 {
-    return OC_STACK_NOTIMPL;
+    if (!p_plugin || !r_newResource)
+    {
+        return;
+    }
+
+    r_newResource->piResource.resourceProperties = OC_DISCOVERABLE;
+    OCStackResult result = OCCreateResource(&r_newResource->piResource.resourceHandle,
+                                            r_newResource->piResource.resourceTypeName,
+                                            r_newResource->piResource.resourceInterfaceName,
+                                            r_newResource->piResource.uri,
+                                            PluginInterfaceEntityHandler,
+                                            (void *) p_plugin,
+                                            r_newResource->piResource.resourceProperties);
+    if (result != OC_STACK_OK)
+    {
+        OICFree (r_newResource->piResource.uri);
+        OICFree (r_newResource);
+        return;
+    }
+    OC_LOG_V(INFO, TAG, "Created resource of type: %s\n",
+        r_newResource->piResource.resourceTypeName);
+
+    result = AddResourceToPlugin(p_plugin, r_newResource);
 }
 
-OCStackResult PIProcess(PIPluginBase * plugin)
+OCStackResult PIStartPlugin(const char * comPort, PIPluginType pluginType, PIPlugin ** plugin)
 {
-    OCStackResult result = OC_STACK_OK;
-    if(!plugin)
+    if (!plugin || !comPort || strlen(comPort) == 0)
     {
         return OC_STACK_INVALID_PARAM;
     }
-    if(plugin->type == PLUGIN_ZIGBEE)
+    OCStackResult result = OC_STACK_ERROR;
+    if (pluginType == PLUGIN_ZIGBEE)
     {
-        result = ProcessZigbee((PIPlugin_Zigbee *) plugin);
-        if(result != OC_STACK_OK)
+        result = ZigbeeInit(comPort, (PIPlugin_Zigbee **) plugin, piNewResourceCB);
+        if (result != OC_STACK_OK)
         {
             return result;
         }
+        if (!*plugin)
+        {
+            return OC_STACK_ERROR;
+        }
+        result = AddPlugin((PIPluginBase *) *plugin);
+        if (result == OC_STACK_OK)
+        {
+            result = ZigbeeDiscover((PIPlugin_Zigbee *) plugin);
+        }
     }
-    else
+    return result;
+}
+
+OCStackResult PIStopPlugin(PIPlugin * plugin)
+{
+    if (!plugin)
     {
-        return OC_STACK_ERROR;
+        return OC_STACK_INVALID_PARAM;
     }
-    return result;
+
+    return DeletePlugin((PIPluginBase *) plugin);
 }
 
-OCStackResult ProcessZigbee(PIPlugin_Zigbee * plugin)
+OCStackResult PIStopAll()
 {
-    return OC_STACK_OK;
+    return DeletePluginList();
 }
+
+OCStackResult PIProcess(PIPlugin * p_plugin)
+{
+    PIPluginBase * plugin = (PIPluginBase *) p_plugin;
+    if (!plugin)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    OCStackResult result = OC_STACK_ERROR;
+    if (plugin->type == PLUGIN_ZIGBEE)
+    {
+        result = ZigbeeProcess((PIPlugin_Zigbee *)plugin);
+    }
+    return result;
+}
+
diff --git a/plugins/src/pluginlist.c b/plugins/src/pluginlist.c
new file mode 100644 (file)
index 0000000..3acd75e
--- /dev/null
@@ -0,0 +1,160 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "pluginlist.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "zigbee_wrapper.h"
+#include "utlist.h"
+#include "oic_malloc.h"
+
+static PIPluginBase * pluginList = NULL;
+
+OCStackResult AddPlugin (PIPluginBase * plugin)
+{
+    if (!plugin)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    LL_APPEND(pluginList, plugin);
+    return OC_STACK_OK;
+}
+
+OCStackResult DeletePlugin(PIPluginBase * plugin)
+{
+    OCStackResult result = OC_STACK_ERROR;
+    if (!plugin)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    DeleteResourceList(plugin);
+    LL_DELETE(pluginList, plugin);
+    if (plugin->type == PLUGIN_ZIGBEE)
+    {
+        result = ZigbeeStop((PIPlugin_Zigbee *) plugin);
+    }
+    return result;
+}
+
+
+OCStackResult DeletePluginList()
+{
+    OCStackResult result = OC_STACK_OK;
+    PIPluginBase * out = NULL;
+    PIPluginBase * tmp = NULL;
+    LL_FOREACH_SAFE(pluginList, out, tmp)
+    {
+        result = DeletePlugin(out);
+        if (result != OC_STACK_OK)
+        {
+            break;
+        }
+    }
+    if (result == OC_STACK_OK)
+    {
+        pluginList = NULL;
+    }
+    return result;
+}
+
+OCStackResult GetResourceFromHandle(PIPluginBase * plugin, PIResource ** piResource,
+                                    OCResourceHandle * resourceHandle)
+{
+    if (!plugin || !resourceHandle || !piResource)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    PIResourceBase * out = NULL;
+    PIResourceBase * tmp = NULL;
+    LL_FOREACH_SAFE(plugin->resourceList, out, tmp)
+    {
+        if (out->piResource.resourceHandle == resourceHandle)
+        {
+            *piResource = (PIResource *) out;
+            return OC_STACK_OK;
+        }
+    }
+    return OC_STACK_NO_RESOURCE;
+}
+
+OCStackResult AddResourceToPlugin (PIPluginBase * plugin, PIResourceBase * resource)
+{
+    if (!plugin || !resource)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    LL_APPEND(plugin->resourceList, resource);
+
+    return OC_STACK_NO_MEMORY;
+}
+
+OCStackResult DeleteResource(PIPluginBase * plugin, PIResourceBase * resource)
+{
+    if (!plugin || !resource)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    //Todo: Free all of resource allocations.
+    PIResourceBase * resourceList = ((PIResourceBase *) plugin->resourceList);
+
+    LL_DELETE(resourceList, resource);
+
+    OICFree (resource->piResource.uri);
+    if (plugin->type == PLUGIN_ZIGBEE)
+    {
+        OICFree (((PIResource_Zigbee *)resource)->eui);
+        OICFree (((PIResource_Zigbee *)resource)->nodeId);
+        OICFree (((PIResource_Zigbee *)resource)->endpointId);
+        OICFree (((PIResource_Zigbee *)resource)->clusterId);
+    }
+    OICFree (resource);
+    return OC_STACK_OK;
+}
+
+OCStackResult DeleteResourceList(PIPluginBase * plugin)
+{
+    if (!plugin)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCStackResult result = OC_STACK_OK;
+    PIResourceBase * out = NULL;
+    PIResourceBase * tmp = NULL;
+
+    LL_FOREACH_SAFE(plugin->resourceList, out, tmp)
+    {
+        result = DeleteResource(plugin, out);
+        if (result != OC_STACK_OK)
+        {
+            break;
+        }
+    }
+    if (result == OC_STACK_OK)
+    {
+        plugin->resourceList = NULL;
+    }
+    return result;
+}
index 05c6e90..44a45b1 100644 (file)
@@ -20,7 +20,6 @@
 
 
 #include "plugininterface.h"
-
 #include "gtest/gtest.h"
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -56,29 +55,26 @@ std::chrono::seconds const SHORT_TEST_TIMEOUT = std::chrono::seconds(5);
 TEST(PITests, StartPluginTest)
 {
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
-    EXPECT_EQ(OC_STACK_NOTIMPL, PIStartPlugin(PLUGIN_UNKNOWN, NULL));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, PIStartPlugin(NULL, PLUGIN_UNKNOWN, NULL));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, PIStartPlugin("", PLUGIN_UNKNOWN, NULL));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, PIStartPlugin("", PLUGIN_UNKNOWN, NULL));
+// Note: The following test is invalid for unit tests. Please do not enable tests which
+//       actually enable hardware radios.
+//    EXPECT_EQ(OC_STACK_INVALID_PARAM, PIStartPlugin("/dev/ttyUSB0", PLUGIN_ZIGBEE, NULL));
 }
 
 // Plugin Interface API PIStopPlugin()
 TEST(PITests, StopPluginTest)
 {
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
-    EXPECT_EQ(OC_STACK_NOTIMPL, PIStopPlugin(NULL));
+    EXPECT_EQ(OC_STACK_INVALID_PARAM, PIStopPlugin(NULL));
 }
 
 // Plugin Interface API PIProcess()
 TEST(PITests, ProcessTest)
 {
-    PIPluginBase zigbeePlugin;
-    zigbeePlugin.type = PLUGIN_ZIGBEE;
-
-    PIPluginBase invalidPlugin;
-    invalidPlugin.type = PLUGIN_UNKNOWN;
-
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
     EXPECT_EQ(OC_STACK_INVALID_PARAM, PIProcess(NULL));
-    EXPECT_EQ(OC_STACK_OK, PIProcess(&zigbeePlugin));
-    EXPECT_EQ(OC_STACK_ERROR, PIProcess(&invalidPlugin));
 }
 
 
index 1376832..6631faf 100644 (file)
@@ -1,10 +1,32 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 ##
 # Zigbee Wrapper build script
 ##
 
+import os.path
+
 Import('env')
 
-Print "Reading top Zigbee Wrapper."
+print "Reading top Zigbee Wrapper."
 
-env.SConscript('./telegesis_wrapper/SConscript')
+env.SConscript(os.path.join('telegesis_wrapper', 'SConscript'))
 
+env.SConscript(os.path.join('src', 'SConscript'))
diff --git a/plugins/zigbee_wrapper/include/zigbee_wrapper.h b/plugins/zigbee_wrapper/include/zigbee_wrapper.h
new file mode 100644 (file)
index 0000000..920c079
--- /dev/null
@@ -0,0 +1,62 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "plugintranslatortypes.h"
+
+/**
+ * @file
+ *
+ * This file contains the interface for the ZigBee Radio.
+ */
+
+/**
+ * Initializes the specified ZigBee radio at location comPort.
+ *
+ * @param[in] comPort The location the ZigBee radio is located at.
+ *
+ * @param[out] plugin A pointer to the plugin that has been started.
+ *
+ * @param[in] newResourceCB A function pointer to the callback that will be
+ *                          invoked when a ZigBee cluster is found that matches
+ *                          a valid OIC resource.
+ */
+OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
+                         PINewResourceFound newResourceCB);
+
+/**
+ * Initiates the discovery operation associated with this ZigBee radio.
+ *
+ * @param[in] plugin A pointer to the current ZigBee radio context.
+ */
+OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin);
+
+/**
+ * De-Initializes the specified ZigBee radio.
+ *
+ * @param[in] plugin A pointer to the current ZigBee radio context.
+ */
+OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin);
+
+/**
+ * Called from upper layer. Gives cycles for internal operation.
+ *
+ * @param[in] plugin A pointer to the current ZigBee radio context.
+ */
+OCStackResult ZigbeeProcess(PIPlugin_Zigbee * plugin);
diff --git a/plugins/zigbee_wrapper/src/SConscript b/plugins/zigbee_wrapper/src/SConscript
new file mode 100644 (file)
index 0000000..947d66d
--- /dev/null
@@ -0,0 +1,82 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+##
+# Plugin Interface build script
+##
+
+import os
+import os.path
+
+Import('env')
+
+target_os = env.get('TARGET_OS')
+src_dir = env.get('SRC_DIR')
+zw_path = os.path.join(src_dir, 'plugins')
+
+print"Reading Zigbee Wrapper (ZW) script"
+
+######################################################################
+# Build flags
+######################################################################
+
+env.PrependUnique(CPPPATH = [ os.path.join(src_dir, 'resource', 'c_common', 'oic_malloc', 'include'),
+                              os.path.join(src_dir, 'resource', 'c_common', 'oic_string', 'include'),
+                              os.path.join(src_dir, 'resource', 'oc_logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'logger', 'include'),
+                              os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include'),
+                              ])
+env.AppendUnique(CPPPATH = [ os.path.join(zw_path, 'include'),
+                             os.path.join(zw_path, 'include', 'internal'),
+                             os.path.join(zw_path, 'zigbee_wrapper', 'include')
+                             ])
+
+if target_os not in ['arduino', 'windows', 'winrt']:
+       env.AppendUnique(CPPDEFINES = ['WITH_POSIX'])
+
+if target_os in ['darwin','ios']:
+       env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE'])
+
+env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-Wextra', '-Werror'])
+env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
+env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
+
+env.PrependUnique(LIBS = ['telegesis_wrapper'])
+
+if env.get('LOGGING'):
+       env.AppendUnique(CPPDEFINES = ['TB_LOG'])
+
+#####################################################################
+# Source files and Target(s)
+######################################################################
+
+zw_src = [
+         os.path.join(src_dir, 'resource', 'c_common', 'oic_malloc', 'src', 'oic_malloc.c'),
+         os.path.join(src_dir, 'resource', 'csdk', 'logger', 'src', 'logger.c'),
+            'zigbee_wrapper.c',
+         ]
+
+env.AppendUnique(ZW_SRC = zw_src)
+
+if target_os in ['android', 'tizen']:
+       calib = env.SharedLibrary('zigbee_wrapper', env.get('ZW_SRC'))
+else:
+       calib = env.StaticLibrary('zigbee_wrapper', env.get('ZW_SRC'))
+env.InstallTarget(calib, 'libzigbee_wrapper')
+env.UserInstallTargetLib(calib, 'libzigbee_wrapper')
diff --git a/plugins/zigbee_wrapper/src/zigbee_wrapper.c b/plugins/zigbee_wrapper/src/zigbee_wrapper.c
new file mode 100644 (file)
index 0000000..a21e561
--- /dev/null
@@ -0,0 +1,833 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/**
+ * @file
+ *
+ * This file contains defined interface for the Zigbee Radio.
+ */
+
+ #ifdef __cplusplus
+#include <cfloat>
+#else
+#include <float.h>
+#endif // __cplusplus
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h> // To convert "int64_t" to string.
+#include <math.h>
+
+#include "zigbee_wrapper.h"
+#include "telegesis_wrapper.h"
+#include "pluginlist.h"
+
+#include "ocpayload.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "logger.h"
+
+#define HexPrepend "0x"
+
+#define TAG "zigbeeWrapper"
+
+// TODO: These should eventually go into an XML/JSON/Mapping thing
+#define MAX_ATTRIBUTES                       10
+#define ZB_TEMPERATURE_CLUSTER               "0402"
+#define ZB_TEMPERATURE_ATTRIBUTE_ID          "0000"
+#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_INDICATOR_CLUSTER                 "0003"
+#define ZB_INDICATOR_ATTRIBUTE_ID            "0000"
+#define ZB_ON_OFF_CLUSTER                    "0006"
+#define ZB_ON_OFF_ATTRIBUTE_ID               "0000"
+
+#define ZB_DATA_TYPE_NULL                    "00"
+#define ZB_DATA_TYPE_1_BYTE                  "08"
+#define ZB_DATA_TYPE_2_BYTE                  "09"
+#define ZB_DATA_TYPE_3_BYTE                  "0a"
+#define ZB_DATA_TYPE_4_BYTE                  "0b"
+#define ZB_DATA_TYPE_5_BYTE                  "0c"
+#define ZB_DATA_TYPE_6_BYTE                  "0d"
+#define ZB_DATA_TYPE_7_BYTE                  "0e"
+#define ZB_DATA_TYPE_8_BYTE                  "0f"
+#define ZB_DATA_TYPE_BOOL                    "10"
+#define ZB_DATA_TYPE_SIGNED_INT_16           "29"
+#define ZB_DATA_TYPE_UNSIGNED_INT_8          "20"
+#define ZB_DATA_TYPE_UNSIGNED_INT_16         "21"
+
+#define MAX_STRLEN_INT (10)
+// DBL_MANT_DIG = Max # of digits after decimal after the leading zeros.
+// DBL_MIN_EXP = Max # of leading zeros of the mantissa.
+// Magic number '3' represents a '-' (negative sign), '0' (a possible zero), and '.' (a period).
+//       "-0." from a number like "-0.999999991245", the "-0." adds 3 unaccounted characters.
+#define MAX_STRLEN_DOUBLE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
+#define MAX_STRLEN_BOOL (1)
+
+#define DEFAULT_TRANS_TIME "0000"
+#define DEFAULT_MOVETOLEVEL_MODE "0"
+
+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_BINARY_SWITCH = "oic.r.switch.binary";
+
+static const char* OIC_TEMPERATURE_ATTRIBUTE = "temperature";
+static const char* OIC_DIMMING_ATTRIBUTE = "dimmingSetting";
+static const char* OIC_CONTACT_ATTRIBUTE = "value";
+static const char* OIC_ON_OFF_ATTRIBUTE = "value";
+
+PIPlugin_Zigbee ** gPlugin = NULL;
+
+typedef enum
+{
+    ZB_NULL,   // No Data
+    ZB_8_BIT,  // 1 byte
+    ZB_16_BIT, // 2 bytes
+    ZB_24_BIT, // 3 bytes
+    ZB_32_BIT, // 4 bytes
+    ZB_40_BIT, // 5 bytes
+    ZB_48_BIT, // 6 bytes
+    ZB_56_BIT, // 7 bytes
+    ZB_64_BIT, // 8 bytes
+    ZB_BOOL,   // boolean
+    ZB_8_BITMAP,
+    ZB_16_BITMAP,
+    ZB_24_BITMAP,
+    ZB_32_BITMAP,
+    ZB_40_BITMAP,
+    ZB_48_BITMAP,
+    ZB_56_BITMAP,
+    ZB_64_BITMAP,
+    ZB_16_SINT,
+    ZB_8_UINT,
+    ZB_16_UINT
+} ZigBeeAttributeDataType;
+
+char * getZBDataTypeString(ZigBeeAttributeDataType attrType);
+OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
+        OCRepPayload **payload);
+
+typedef enum
+{
+    OIC_ATTR_NULL,
+    OIC_ATTR_INT,
+    OIC_ATTR_DOUBLE,
+    OIC_ATTR_BOOL,
+    OIC_ATTR_STRING
+} OICAttributeType;
+
+typedef struct
+{
+    char                *oicAttribute;
+    char                *zigBeeAttribute;
+    OICAttributeType    oicType;
+    ZigBeeAttributeDataType zigbeeType;
+    union
+    {
+        int64_t i;
+        double d;
+        bool b;
+        char* str;
+    } val;
+
+} OICZigBeeAttributePair;
+
+typedef enum
+{
+    CIE_RON_OFF         = 1 << 1,
+    CIE_MOVE_TO_LEVEL   = 1 << 2
+
+} CIECommandMask;
+
+typedef struct
+{
+    uint32_t count;
+    CIECommandMask CIEMask;
+    OICZigBeeAttributePair list[MAX_ATTRIBUTES];
+} AttributeList;
+
+const char* ZigBeeClusterIDToOICResourceType (const char * clusterID);
+
+OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+                                                    AttributeList *attributeList);
+
+bool getZigBeeAttributesIfValid (char * OICResourceType,
+                                    AttributeList *attributeList,
+                                    OCRepPayload *payload);
+
+void foundZigbeeCallback(TWDevice *device)
+{
+    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));
+        if (!piResource)
+        {
+            OC_LOG (ERROR, TAG, "Out of memory");
+            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)
+        {
+            OC_LOG (ERROR, TAG, "Out of memory");
+            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)
+        {
+            OC_LOG (ERROR, TAG, "Encoding error occurred trying to build Zigbee URI.");
+        }
+        else if(ret > newUriSize)
+        {
+            OC_LOG_V (ERROR, TAG, "Did not allocate enough memory to build URI. Required Size: %d",
+                      ret);
+        }
+
+        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",
+                device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
+            OICFree(piResource->header.piResource.uri);
+            OICFree(piResource);
+            continue;
+        }
+        piResource->header.piResource.resourceInterfaceName =
+                            OC_RSRVD_INTERFACE_DEFAULT;
+
+        piResource->header.piResource.callbackParam = NULL;
+        piResource->header.piResource.resourceProperties = 0;
+        piResource->eui = OICStrdup(device->eui);
+        piResource->nodeId = OICStrdup(device->nodeId);
+        piResource->endpointId = OICStrdup(device->endpointOfInterest->endpointId);
+        piResource->clusterId =
+            OICStrdup(device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
+        (*gPlugin)->header.NewResourceFoundCB(&(*gPlugin)->header, &piResource->header);
+    }
+}
+
+OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
+                         PINewResourceFound newResourceCB)
+{
+    if(!plugin)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    *plugin = (PIPlugin_Zigbee *) OICMalloc(sizeof(PIPlugin_Zigbee) + sizeof(PIPluginBase));
+    if(!*plugin)
+    {
+        return OC_STACK_NO_MEMORY;
+    }
+    ((*plugin)->header).type = PLUGIN_ZIGBEE;
+    ((*plugin)->header).comPort = OICStrdup(comPort);
+    ((*plugin)->header).NewResourceFoundCB = newResourceCB;
+    ((*plugin)->header).next = NULL;
+    ((*plugin)->header).resourceList = NULL;
+    ((*plugin)->header).processEHRequest = ProcessEHRequest;
+
+    gPlugin = plugin;
+    return TWInitialize(comPort);
+}
+
+OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
+{
+    OCStackResult result = OC_STACK_ERROR;
+    (void)plugin;
+    TWSetDiscoveryCallback(foundZigbeeCallback);
+    result = TWDiscover(NULL);
+    OC_LOG_V (DEBUG, TAG, "ZigbeeDiscover : Status = %d\n", result);
+
+    return result;
+}
+
+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;
+}
+
+// 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
+{
+    if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
+    {
+        return OIC_TEMPERATURE_SENSOR;
+    }
+    else if (strcmp(clusterID, ZB_LEVEL_CONTROL_CLUSTER) == 0)
+    {
+        return OIC_DIMMABLE_LIGHT;
+    }
+    else if (strcmp(clusterID, ZB_CONTACT_CLUSTER) == 0)
+    {
+        return OIC_CONTACT_SENSOR;
+    }
+    else if (strcmp(clusterID, ZB_ON_OFF_CLUSTER) == 0)
+    {
+        return OIC_BINARY_SWITCH;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+const char* OICResourceToZigBeeClusterID (char *oicResourceType)
+{
+    if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
+    {
+        return ZB_TEMPERATURE_CLUSTER;
+    }
+    else if (strcmp(oicResourceType, OIC_DIMMABLE_LIGHT) == 0)
+    {
+        return ZB_LEVEL_CONTROL_CLUSTER;
+    }
+    else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
+    {
+        return ZB_CONTACT_CLUSTER;
+    }
+    else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
+    {
+        return ZB_ON_OFF_CLUSTER;
+    }
+    else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
+    {
+        return ZB_INDICATOR_CLUSTER;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+                                                    AttributeList *attributeList) // GET
+{
+    if (strcmp (OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
+    {
+        attributeList->count = 1;
+        attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
+        attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
+        attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
+        attributeList->list[0].zigbeeType = ZB_16_SINT;
+        return OC_STACK_OK;
+    }
+    else if (strcmp (OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
+    {
+        attributeList->count = 1;
+        attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
+        attributeList->list[0].zigBeeAttribute = ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY;
+        attributeList->list[0].oicType = OIC_ATTR_INT;
+        attributeList->list[0].zigbeeType = ZB_8_UINT;
+        return OC_STACK_OK;
+    }
+    else if (strcmp (OICResourceType, OIC_CONTACT_SENSOR) == 0)
+    {
+        attributeList->count = 1;
+        attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
+        attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+        attributeList->list[0].oicType = OIC_ATTR_BOOL;
+        attributeList->list[0].zigbeeType = ZB_BOOL;
+        return OC_STACK_OK;
+    }
+    else if (strcmp (OICResourceType, OIC_BINARY_SWITCH) == 0)
+    {
+        attributeList->count = 1;
+        attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
+        attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_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,
+                                    AttributeList *attributeList,
+                                    OCRepPayload *payload) // Put
+{
+    if(!OICResourceType)
+    {
+        return false;
+    }
+    if(strcmp(OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
+    {
+        // Cant really PUT on the temp sensor, but the code is still there.
+        int64_t temperature = 0;
+
+        // TODO: This if should only look for attributes it supports and ignore the rest
+        // or examine every attribute in the payload and complain about unsupported attributes?
+        if(OCRepPayloadGetPropInt(payload, OIC_TEMPERATURE_ATTRIBUTE, &temperature))
+        {
+            attributeList->count = 1;
+            attributeList->list[0].oicAttribute = OICStrdup(OIC_TEMPERATURE_ATTRIBUTE);
+            attributeList->list[0].zigBeeAttribute = ZB_TEMPERATURE_ATTRIBUTE_ID;
+            attributeList->list[0].oicType = OIC_ATTR_DOUBLE;
+            attributeList->list[0].val.d = temperature;
+            attributeList->list[0].zigbeeType = ZB_16_SINT;
+            attributeList->CIEMask = (CIECommandMask) 0;
+
+            return true;
+        }
+    }
+    else if (strcmp (OICResourceType, OIC_DIMMABLE_LIGHT) == 0)
+    {
+        int64_t onLevel = 0;
+
+        if(OCRepPayloadGetPropInt(payload, OIC_DIMMING_ATTRIBUTE, &onLevel))
+        {
+            attributeList->count = 1;
+            attributeList->list[0].oicAttribute = OICStrdup(OIC_DIMMING_ATTRIBUTE);
+            attributeList->list[0].zigBeeAttribute = ZB_ON_LEVEL_ATTRIBUTE;
+            attributeList->list[0].oicType = OIC_ATTR_INT;
+            attributeList->list[0].val.i = onLevel;
+            attributeList->list[0].zigbeeType = ZB_8_UINT;
+
+            // Level control cluster is dealing with level in the PUT payload.
+            attributeList->CIEMask = attributeList->CIEMask | CIE_MOVE_TO_LEVEL;
+            return true;
+        }
+    }
+    else if (strcmp (OICResourceType, OIC_CONTACT_SENSOR) == 0)
+    {
+        int64_t value = 0;
+
+        if(OCRepPayloadGetPropInt(payload, OIC_CONTACT_ATTRIBUTE, &value))
+        {
+            attributeList->count = 1;
+            attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
+            attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+            attributeList->list[0].oicType = OIC_ATTR_BOOL;
+            attributeList->list[0].val.i = value;
+            attributeList->list[0].zigbeeType = ZB_BOOL;
+            attributeList->CIEMask = (CIECommandMask) 0;
+
+            return true;
+        }
+    }
+    else if (strcmp (OICResourceType, OIC_BINARY_SWITCH) == 0)
+    {
+        bool value = 0;
+
+        if(OCRepPayloadGetPropBool(payload, OIC_ON_OFF_ATTRIBUTE, &value))
+        {
+            attributeList->count = 1;
+            attributeList->list[0].oicAttribute = OICStrdup(OIC_ON_OFF_ATTRIBUTE);
+            attributeList->list[0].zigBeeAttribute = ZB_ON_OFF_ATTRIBUTE_ID;
+            attributeList->list[0].oicType = OIC_ATTR_BOOL;
+            attributeList->list[0].val.b = value;
+            attributeList->list[0].zigbeeType = ZB_BOOL;
+
+            attributeList->CIEMask = attributeList->CIEMask | CIE_RON_OFF;
+            return true;
+        }
+    }
+    return false;
+}
+
+OCEntityHandlerResult processGetRequest (PIPluginBase * plugin,
+        OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
+{
+    if (!plugin || !ehRequest || !payload)
+    {
+        return OC_EH_ERROR;
+    }
+    uint32_t attributeListIndex = 0;
+    OCStackResult stackResult = OC_STACK_OK;
+    PIResource_Zigbee * piResource = NULL;
+
+    AttributeList attributeList = { 0, (CIECommandMask) 0,
+        .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } } };
+    stackResult = GetResourceFromHandle(plugin, (PIResource**) (&piResource),
+                        ehRequest->resource);
+    if (stackResult != OC_STACK_OK)
+    {
+        OC_LOG (ERROR, TAG, "Failed to get resource from handle");
+        return OC_EH_ERROR;
+    }
+    stackResult = getZigBeeAttributesForOICResource (
+        piResource->header.piResource.resourceTypeName, &attributeList);
+    if(stackResult != OC_STACK_OK)
+    {
+        OC_LOG_V (ERROR, TAG, "Failed to fetch attributes for %s",
+            piResource->header.piResource.resourceTypeName);
+        return OC_EH_ERROR;
+    }
+
+    *payload = OCRepPayloadCreate();
+    if(!payload)
+    {
+        OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload"));
+        return OC_EH_ERROR;
+    }
+    bool boolRes = OCRepPayloadSetUri(*payload, piResource->header.piResource.uri);
+    if (boolRes == false)
+    {
+        OCRepPayloadDestroy (*payload);
+        return OC_EH_ERROR;
+    }
+    for(uint32_t i = 0; i<attributeList.count; i++)
+    {
+        char * outVal = NULL;
+        uint8_t outValLength = 0;
+
+        stackResult = TWGetAttribute(piResource->eui,
+                                     piResource->nodeId,
+                                     piResource->endpointId,
+                                     piResource->clusterId,
+                                     attributeList.list[i].zigBeeAttribute,
+                                     &outVal,
+                                     &outValLength);
+
+        if (stackResult != OC_STACK_OK || !outVal)
+        {
+            stackResult = OC_EH_ERROR;
+            OCRepPayloadDestroy (*payload);
+            goto exit;
+        }
+        if (attributeList.list[i].oicType == OIC_ATTR_INT)
+        {
+            size_t hexOutValSize = strlen(HexPrepend) + strlen(outVal) + 1;
+            char * hexOutVal = (char *) OICCalloc(1, hexOutValSize);
+            if(!hexOutVal)
+            {
+                return OC_EH_ERROR;
+            }
+            OICStrcpy(hexOutVal, hexOutValSize, HexPrepend);
+            OICStrcat(hexOutVal, hexOutValSize, outVal);
+            double value = strtod(hexOutVal, NULL);
+            if(value == 0.0 || value == HUGE_VALF || value == HUGE_VALL)
+            {
+                OICFree(hexOutVal);
+                return OC_EH_ERROR;
+            }
+            if (strcmp(attributeList.list[i].oicAttribute, OIC_DIMMING_ATTRIBUTE)
+                == 0)
+            {
+                // OIC Dimming operates between 0-100, while Zigbee operates
+                // between 0-254 (ie. 0xFE).
+                if (value > 0xFE)
+                {
+                    value = 0xFE;
+                }
+                if (value <= 0xFE)
+                {
+                    value = value / 2.54;
+                }
+            }
+            boolRes = OCRepPayloadSetPropInt(*payload,
+                                             attributeList.list[i].oicAttribute,
+                                             (uint64_t) value);
+            OICFree (hexOutVal);
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
+        {
+            size_t hexOutValSize = strlen(HexPrepend) + strlen(outVal) + 1;
+            char * hexOutVal = (char *) OICCalloc(1, hexOutValSize);
+            if(!hexOutVal)
+            {
+                return OC_EH_ERROR;
+            }
+            OICStrcat(hexOutVal, hexOutValSize, HexPrepend);
+            OICStrcat(hexOutVal, hexOutValSize, outVal);
+            double value = strtod(hexOutVal, NULL);
+            if(value == 0.0 || value == HUGE_VAL || value == -HUGE_VAL)
+            {
+                OICFree(hexOutVal);
+                return OC_EH_ERROR;
+            }
+            if (strcmp(piResource->clusterId, ZB_TEMPERATURE_CLUSTER) == 0)
+            {
+                // Divide by 100 as temperature readings have a resolution of
+                // 0.01 or one hundreth of a degree celsius.
+                value = value/100;
+            }
+            boolRes = OCRepPayloadSetPropDouble(*payload,
+                                                attributeList.list[i].oicAttribute,
+                                                value);
+            OICFree(hexOutVal);
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
+        {
+            boolRes = OCRepPayloadSetPropString(*payload,
+                                                attributeList.list[i].oicAttribute,
+                                                outVal);
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
+        {
+            bool value = true;
+            if(strcmp(outVal, "0") == 0)
+            {
+                value = false;
+            }
+
+            // value is a bit mask and the LSB indicates boolean true/false.
+            value = value & 1;
+            boolRes = OCRepPayloadSetPropBool(*payload,
+                                              attributeList.list[i].oicAttribute,
+                                              value);
+        }
+        OICFree(outVal);
+    }
+
+    if (boolRes == false)
+    {
+        stackResult = OC_EH_ERROR;
+        goto exit;
+    }
+
+exit:
+    for(; attributeListIndex < attributeList.count; attributeListIndex++)
+    {
+        OICFree(attributeList.list[attributeListIndex].oicAttribute);
+    }
+    return stackResult;
+}
+
+OCEntityHandlerResult processPutRequest (PIPluginBase * plugin,
+    OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
+{
+    if (!plugin || !ehRequest || !payload)
+    {
+        return OC_EH_ERROR;
+    }
+    OCStackResult stackResult = OC_STACK_OK;
+    PIResource_Zigbee *piResource = NULL;
+    AttributeList attributeList = {
+        0,
+        (CIECommandMask) 0,
+        .list[0] = { NULL, NULL, OIC_ATTR_NULL, ZB_NULL, { .i = 0 } }
+    };
+
+    stackResult = GetResourceFromHandle(plugin,
+                                        ((PIResource **) (&piResource)),
+                                        ehRequest->resource);
+    if (stackResult != OC_STACK_OK)
+    {
+        OC_LOG (ERROR, TAG, "Failed to get resource from handle");
+        return OC_EH_ERROR;
+    }
+
+    bool boolRes = getZigBeeAttributesIfValid (
+                        piResource->header.piResource.resourceTypeName,
+                        &attributeList, *payload);
+    if(boolRes == false)
+    {
+        OC_LOG_V (ERROR, TAG, "Failed to fetch attributes for %s",
+            piResource->header.piResource.resourceTypeName);
+        return OC_EH_ERROR;
+    }
+
+    uint32_t i = 0;
+    for(; i<attributeList.count; i++)
+    {
+        if (attributeList.list[i].oicType == OIC_ATTR_INT)
+        {
+            char value[MAX_STRLEN_INT] = {};
+            if (attributeList.CIEMask || CIE_MOVE_TO_LEVEL)
+            {
+                int64_t rangeDiff = 0;
+                // OIC Dimming operates between 0-100, while Zigbee
+                // operates between 0-254 (ie. 0xFE).
+                rangeDiff = attributeList.list[i].val.i * 0xFE/100;
+                if (rangeDiff > 0xFE)
+                {
+                    rangeDiff = 0xFE;
+                }
+                if (rangeDiff < 0)
+                {
+                    rangeDiff = 0;
+                }
+                if (rangeDiff <= 0xFE)
+                {
+                    snprintf(value, sizeof(value), "%02x", (unsigned int) rangeDiff);
+                }
+                stackResult = TWMoveToLevel(piResource->nodeId, piResource->endpointId,
+                                    DEFAULT_MOVETOLEVEL_MODE, value, DEFAULT_TRANS_TIME);
+            }
+            else
+            {
+                snprintf(value, sizeof(value), "%"PRId64, attributeList.list[i].val.i);
+                stackResult = TWSetAttribute(piResource->eui,
+                    piResource->nodeId, piResource->endpointId,
+                    piResource->clusterId, attributeList.list[i].zigBeeAttribute,
+                    getZBDataTypeString(attributeList.list[i].zigbeeType), value);
+            }
+            if (stackResult != OC_STACK_OK)
+            {
+                return OC_EH_ERROR;
+            }
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_DOUBLE)
+        {
+            char value[MAX_STRLEN_DOUBLE] = {};
+            snprintf(value, sizeof(value), "%f", attributeList.list[i].val.d);
+            stackResult = TWSetAttribute(piResource->eui,
+                piResource->nodeId, piResource->endpointId,
+                 piResource->clusterId, attributeList.list[i].zigBeeAttribute,
+                 getZBDataTypeString(attributeList.list[i].zigbeeType), value);
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_STRING)
+        {
+            stackResult = TWSetAttribute(piResource->eui,
+                piResource->nodeId, piResource->endpointId,
+                piResource->clusterId, attributeList.list[i].zigBeeAttribute,
+                getZBDataTypeString(attributeList.list[i].zigbeeType),
+                attributeList.list[i].val.str);
+            if (stackResult != OC_STACK_OK)
+            {
+                return OC_EH_ERROR;
+            }
+        }
+        else if (attributeList.list[i].oicType == OIC_ATTR_BOOL)
+        {
+            char * value = attributeList.list[i].val.b ? "1" : "0";
+            if (attributeList.CIEMask || CIE_RON_OFF)
+            {
+                stackResult = TWSwitchOnOff(piResource->nodeId, piResource->endpointId, value);
+            }
+            else
+            {
+                stackResult = TWSetAttribute(piResource->eui,
+                    piResource->nodeId, piResource->endpointId,
+                    piResource->clusterId, attributeList.list[i].zigBeeAttribute,
+                    getZBDataTypeString(attributeList.list[i].zigbeeType),
+                    value);
+            }
+            if (stackResult != OC_STACK_OK)
+            {
+                return OC_EH_ERROR;
+            }
+        }
+        else
+        {
+            continue;
+        }
+    }
+
+    return processGetRequest(plugin, ehRequest, payload);
+}
+
+OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin,
+    OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
+{
+    if(!ehRequest || !payload)
+    {
+        return OC_EH_ERROR;
+    }
+    if(ehRequest->method == OC_REST_GET)
+    {
+        return processGetRequest(plugin, ehRequest, payload);
+    }
+    else if(ehRequest->method == OC_REST_PUT)
+    {
+        return processPutRequest(plugin, ehRequest, payload);
+    }
+    else
+    {
+        return OC_EH_FORBIDDEN;
+    }
+}
+
+char * getZBDataTypeString(ZigBeeAttributeDataType attrType)
+{
+    switch (attrType)
+    {
+        case ZB_NULL:
+            return ZB_DATA_TYPE_NULL;
+        case ZB_8_BIT:
+            return ZB_DATA_TYPE_1_BYTE;
+        case ZB_16_BIT:
+            return ZB_DATA_TYPE_2_BYTE;
+        case ZB_24_BIT:
+            return ZB_DATA_TYPE_3_BYTE;
+        case ZB_32_BIT:
+            return ZB_DATA_TYPE_4_BYTE;
+        case ZB_40_BIT:
+            return ZB_DATA_TYPE_5_BYTE;
+        case ZB_48_BIT:
+            return ZB_DATA_TYPE_6_BYTE;
+        case ZB_56_BIT:
+            return ZB_DATA_TYPE_7_BYTE;
+        case ZB_64_BIT:
+            return ZB_DATA_TYPE_8_BYTE;
+        case ZB_BOOL:
+            return ZB_DATA_TYPE_BOOL;
+        case ZB_8_BITMAP:
+            return ZB_DATA_TYPE_1_BYTE;
+        case ZB_16_BITMAP:
+            return ZB_DATA_TYPE_2_BYTE;
+        case ZB_24_BITMAP:
+            return ZB_DATA_TYPE_3_BYTE;
+        case ZB_32_BITMAP:
+            return ZB_DATA_TYPE_4_BYTE;
+        case ZB_40_BITMAP:
+            return ZB_DATA_TYPE_5_BYTE;
+        case ZB_48_BITMAP:
+            return ZB_DATA_TYPE_6_BYTE;
+        case ZB_56_BITMAP:
+            return ZB_DATA_TYPE_7_BYTE;
+        case ZB_64_BITMAP:
+            return ZB_DATA_TYPE_8_BYTE;
+        case ZB_16_SINT:
+            return ZB_DATA_TYPE_SIGNED_INT_16;
+        case ZB_8_UINT:
+            return ZB_DATA_TYPE_UNSIGNED_INT_8;
+        case ZB_16_UINT:
+            return ZB_DATA_TYPE_UNSIGNED_INT_16;
+        default:
+            return ZB_DATA_TYPE_NULL;
+    }
+}
index 0c1f12b..8b9a04d 100644 (file)
@@ -1,10 +1,31 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 ##
 # Telegesis Wrapper build script
 ##
 
+import os.path
+
 Import('env')
 
-Print "Reading top Telegesis Wrapper."
+print "Reading top Telegesis Wrapper."
 
-env.SConscript('./src/SConscript')
+env.SConscript(os.path.join('src', 'SConscript'))
 
index e69de29..80a1d39 100644 (file)
@@ -0,0 +1,277 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+/**
+ * @file
+ *
+ * This API only works with:
+ *      Telegesis ETRX357
+ *      CICIE R310 B110615
+ *
+ */
+
+#ifndef TELEGESISWRAPPER_H_
+#define TELEGESISWRAPPER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+#include "octypes.h"
+#include <stdint.h>
+#include <time.h>
+#include <stdbool.h>
+
+#define SIZE_EUI                    (17)
+#define SIZE_NODEID                 (5)
+#define SIZE_CLUSTERID              (5)
+#define SIZE_ENDPOINTID             (3)
+
+#define SIZE_ZONESTATUS             (5)
+#define SIZE_ZONESTATUS_EXTENDED    (3)
+#define SIZE_ZONEID                 (3)
+#define SIZE_ZONETYPE               (5)
+#define SIZE_UPDATE_DELAY_TIME      (5)
+
+/**
+ *
+ * Defines a cluster id.
+ *
+ */
+typedef struct
+{
+    char clusterId[SIZE_CLUSTERID];
+} TWClusterId;
+
+/**
+ *
+ * Defines a list of ZigBee device's clusters.
+ *
+ */
+typedef struct
+{
+    TWClusterId* clusterIds;
+    int count;
+} TWClusterList;
+
+/**
+ *
+ * Defines an endpoint of a ZigBee device.
+ *
+ */
+typedef struct
+{
+    char endpointId[SIZE_ENDPOINTID];
+    TWClusterList* clusterList;
+} TWEndpoint;
+
+/**
+ *
+ * Defines a list of endpoints of a ZigBee device.
+ *
+ */
+typedef struct
+{
+    TWEndpoint* endpoints;
+    int count;
+} TWEndpointList;
+
+/**
+ *
+ * Defines a discovered ZigBee device.
+ *
+ */
+typedef struct
+{
+    char eui[SIZE_EUI];
+    char nodeId[SIZE_NODEID];
+    TWEndpoint* endpointOfInterest;
+} TWDevice;
+
+/**
+ *
+ * Defines a ZigBee device list.
+ *
+ */
+typedef struct
+{
+    TWDevice* deviceList;
+    int count;
+} TWDeviceList;
+
+/**
+ *
+ * Defines a ZigBee device update.
+ *
+ */
+typedef struct
+{
+    char nodeId[SIZE_NODEID];
+    char endpoint[SIZE_ENDPOINTID];
+    char status[SIZE_ZONESTATUS];
+    char extendedStatus[SIZE_ZONESTATUS_EXTENDED];
+    char zoneId[SIZE_ZONEID];               //optional
+    char delay[SIZE_UPDATE_DELAY_TIME];     //optional - amount of time in quarter of seconds
+} TWUpdate;
+
+typedef struct
+{
+    char zoneId[SIZE_ZONEID];
+    char zoneType[SIZE_ZONETYPE];
+    char eui[SIZE_EUI];
+} TWEnrollee;
+
+typedef void (*TWDeviceFoundCallback)(TWDevice* device);
+typedef void (*TWEnrollmentSucceedCallback)(TWEnrollee* enrollee);
+typedef void (*TWDeviceStatusUpdateCallback)(TWUpdate* update);
+
+/**
+ *
+ * Initializes the Telegesis module.
+ *
+ * @param[in] deviceDevPath The device path at which this Telegesis module exists.
+ *
+ */
+OCStackResult TWInitialize(const char* deviceDevPath);
+
+/**
+ *
+ * Initiates necessary operations to find ZigBee devices.
+ *
+ */
+OCStackResult TWDiscover();
+
+/**
+ *
+ * Gets a value at the specified parameters.
+ *
+ * @param[in] extendedUniqueId The extended unique id of the device.
+ * @param[in] nodeId The node id of the device.
+ * @param[in] endpointId The endpoint id from which the attribute belongs.
+ * @param[in] clusterId The cluster id from which the attribute belongs.
+ * @param[in] attributeId The attribute id from which the attribute belongs.
+ * @param[out] outValue The value at the specified attribute.
+ * @param[out] outValueLength The length of the value.
+ *
+ */
+OCStackResult TWGetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
+                             char* clusterId, char* attributeId,
+                             char** outValue, uint8_t* outValueLength);
+
+/**
+ *
+ * Sets a value at the specified parameters.
+ *
+ * @param[in] extendedUniqueId The extended unique id of the device.
+ * @param[in] nodeId The node id of the device.
+ * @param[in] endpointId The endpoint id from which the attribute belongs.
+ * @param[in] clusterId The cluster id from which the attribute belongs.
+ * @param[in] attributeId The attribute id from which the attribute belongs.
+ * @param[in] attributeType The attribute type of the attribute.
+ * @param[in] newValue The value to set at the specified attribute.
+ *
+ */
+OCStackResult TWSetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
+                             char* clusterId, char* attributeId, char* attributeType,
+                             char* newValue);
+
+/**
+ *
+ * Switches a device to On/Off.
+ *
+ * @param[in] nodeId The node id of the device.
+ * @param[in] endpointId The endpoint id from which the attribute belongs.
+ * @param[in] newState Use "0" for OFF, "1" for ON, NULL for toggling.
+ *
+ */
+OCStackResult TWSwitchOnOff(char* nodeId, char* endpointId, char* newState);
+
+/**
+ *
+ * Move to a level. All parameters are null-terminated.
+ *
+ * @param[in] nodeId The node id of the device.
+ * @param[in] endpointId The endpoint id from which the attribute belongs.
+ * @param[in] onOfState A boolean type number represents if the command
+ *                      is used with On/Off. If it is set to 0, it means the command is
+ *                      implemented as Move to Level command. If it is set to 1, it
+ *                      means the command will be implemented Move to Level
+ *                      (with On/Off) command.
+ *
+ * @param[in] level The The meaning of ‘level’ is device dependent
+ *                  e.g. for a light it may mean brightness level.
+
+ * @param[in] transTime The time taken to move to the new level
+ *
+ */
+OCStackResult TWMoveToLevel(char* nodeId, char* endpointId,
+                            char* onOffState, char* level, char* transTime);
+
+/**
+ *
+ * Switches door lock state.
+ *
+ * @param[in] nodeId The node id of the device.
+ * @param[in] endpointId The endpoint id from which the attribute belongs.
+ * @param[in] newState Use "0" to Unlock, "1" to Lock ON.
+ *
+ */
+OCStackResult TWSwitchDoorLockState(char* nodeId, char* endpointId, char* newState);
+
+/**
+ *
+ * Sets discovery callback.
+ * This callback will be called when TWDiscover() discovers ZigBee device(s).
+ *
+ */
+OCStackResult TWSetDiscoveryCallback(const TWDeviceFoundCallback callback);
+
+/**
+ *
+ * Sets status update callback.
+ * This callback will be called when there is an update on remote ZigBee devices.
+ *
+ */
+OCStackResult TWSetStatusUpdateCallback(TWDeviceStatusUpdateCallback callback);
+
+/**
+ *
+ * Attempts to listen to status change updates of a remote zone device.
+ * A callback TWEnrollSucceedCallback will be invoked when this registration is fulfill.
+ * @param[in] nodeId The node id of the remote zone device.
+ * @param[in] endpointId The node id of the remote zone device.
+ *
+ *
+ */
+OCStackResult TWListenForStatusUpdates(char* nodeId, char* endpointId);
+
+/**
+ *
+ * Uninitializes the Telegesis module.
+ *
+ */
+OCStackResult TWUninitialize();
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* TELEGESISWRAPPER_H_ */
index 282d4d9..14c6ea8 100644 (file)
@@ -1,3 +1,22 @@
+#******************************************************************
+#
+# Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 ##
 # Plugin Interface build script
 ##
@@ -17,8 +36,13 @@ tw_path = os.path.join(src_dir, 'plugins')
 print"Reading Telegesis Wrapper (TW) script"
 
 env.AppendUnique(CPPPATH = [ os.path.join(tw_path, 'include'),
-                             os.path.join(tw_path, 'include', 'internal')
-                             os.path.join(tw_path, 'zigbee_wrapper', 'telegesis_wrapper', 'include' ])
+                             os.path.join(tw_path, 'include', 'internal'),
+                             os.path.join(src_dir, 'resource', 'oc_logger', 'include'),
+                             os.path.join(src_dir, 'resource', 'csdk', 'stack', 'include'),
+                             os.path.join(src_dir, 'resource', 'csdk', 'logger', 'include'),
+                             os.path.join(src_dir, 'resource', 'c_common', 'oic_string', 'include'),
+                             os.path.join(tw_path, 'zigbee_wrapper', 'telegesis_wrapper', 'include')
+                             ])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
        env.AppendUnique(CPPDEFINES = ['WITH_POSIX'])
@@ -27,8 +51,10 @@ if target_os in ['darwin','ios']:
        env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE'])
 
 tw_src = [
-       'telegesis_wrapper.c',
-       ]
+         os.path.join(src_dir, 'resource', 'c_common', 'oic_string', 'src', 'oic_string.c'),
+         os.path.join(src_dir, 'resource', 'csdk', 'logger', 'src', 'logger.c'),
+        'telegesis_wrapper.c',
+         ]
 
 env.AppendUnique(TW_SRC = tw_src)
 
index e69de29..55683f5 100644 (file)
+/******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <unistd.h>
+
+#include <termios.h>
+#include <string.h>
+#include <errno.h>
+
+#include "oic_string.h"
+#include "oic_malloc.h"
+#include "logger.h"
+
+#include "telegesis_wrapper.h"
+
+#define TAG PCF("telegesiswrapper")     // Module Name
+#define ARRAY_LENGTH            (100)
+
+#define DEVICE_BAUDRATE                 (B19200)
+#define MAX_ZIGBEE_BYTES                (512)
+#define MAX_ZIGBEE_ENROLLED_DEVICES     (255)
+
+#define TIME_OUT_00_SECOND      (0)
+#define TIME_OUT_01_SECOND      (1)
+#define TIME_OUT_05_SECONDS     (5)
+#define TIME_OUT_07_SECONDS     (7)
+#define TIME_OUT_10_SECONDS     (10)
+#define TIME_OUT_15_SECONDS     (15)
+
+#define SIMPLEDESC_RESPONSE_EXPECTED_LINES (6)
+
+#define AT_STR_ERROR_OK         "00"
+
+#define SENDMODE                "0"
+#define SEPARATOR               ","
+#define SEPARATOR_LENGTH        strlen(SEPARATOR)
+
+#define AT_CMD_RESET                "AT&F"
+#define AT_CMD_GET_NETWORK_INFO     "AT+N"
+#define AT_CMD_ESTABLISH_NETWORK    "AT+EN"
+#define AT_CMD_PERMIT_JOIN          "AT+PJOIN:"
+#define AT_CMD_MATCH_REQUEST        "AT+MATCHREQ:"
+#define AT_CMD_SIMPLE_DESC          "AT+SIMPLEDESC:"
+#define AT_CMD_WRITE_ATR            "AT+WRITEATR:"
+#define AT_CMD_READ_ATR             "AT+READATR:"
+#define AT_CMD_RUN_ON_OFF           "AT+RONOFF:"
+#define AT_CMD_MOVE_TO_LEVEL        "AT+LCMVTOLEV:"
+#define AT_CMD_DOOR_LOCK            "AT+DRLOCK:"
+#define AT_CMD_GET_LOCAL_EUI        "ATS04?"
+#define AT_CMD_REMOTE_EUI_REQUEST   "AT+EUIREQ:"
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typedefs
+//-----------------------------------------------------------------------------
+typedef enum
+{
+    ZB_STATE_UNKNOWN,
+    ZB_STATE_INIT
+} TWState;
+
+typedef struct
+{
+    TWState state;
+    uint64_t panId;
+    uint64_t extPanId;
+
+    char*   remoteAttributeValueRead;
+    uint8_t remoteAtrributeValueReadLength;
+} TWStatus;
+
+typedef enum
+{
+    TW_RESULT_OK = 0,
+
+    TW_RESULT_NO_LOCAL_PAN,
+    TW_RESULT_HAS_LOCAL_PAN,
+    TW_RESULT_NEW_LOCAL_PAN_ESTABLISHED,
+    TW_RESULT_DEVICE_JOINED,
+    TW_RESULT_FOUND_NO_MATCHED_DEVICE,
+    TW_RESULT_FOUND_MATCHED_DEVICES,
+    TW_RESULT_HAS_CLUSTERS,
+    TW_RESULT_HAS_NO_CLUSTER,
+    TW_RESULT_REMOTE_ATTR_HAS_VALUE,
+
+    TW_RESULT_UNKNOWN,
+
+    TW_RESULT_ERROR_INVALID_PARAMS,
+    TW_RESULT_ERROR_INVALID_PORT,
+    TW_RESULT_ERROR_NO_MEMORY,
+    TW_RESULT_ERROR_NOTIMPL,
+
+    TW_RESULT_ERROR = 255
+
+} TWResultCode;
+
+typedef enum
+{
+    AT_ERROR_EVERYTHING_OK  = 0,
+    AT_ERROR_NODE_IS_PART_OF_PAN = 28,
+    AT_ERROR_MESSAGE_NOT_SENT_TO_TARGET_SUCCESSFULLY   = 66,
+    AT_ERROR_INVALID_OPERATION  = 70,
+
+} TWATErrorCode;
+
+typedef enum
+{
+    TW_ENDCONTROL_OK = 0,
+    TW_ENDCONTROL_ERROR,
+    TW_ENDCONTROL_ACK,
+    TW_ENDCONTROL_SEQ,
+    TW_ENDCONTROL_MAX_VALUE
+
+} TWEndControl;
+
+typedef struct
+{
+    const char * endStr;
+    TWEndControl endControl;
+
+} TWEndControlMap;
+
+typedef TWResultCode (*TWATResultHandler)(int count, char** tokens);
+
+typedef struct
+{
+    const char *resultTxt;
+    TWATResultHandler handler;
+
+} TWATResultHandlerPair;
+
+//-----------------------------------------------------------------------------
+// Private internal function prototypes
+//-----------------------------------------------------------------------------
+
+static TWResultCode IssueATCommand(const char* command, uint8_t timeout,
+                                   uint64_t* atErrorCode,
+                                   char* responseArray[], char* promptArray[],
+                                   uint8_t* responseCount, uint8_t* promptCount);
+
+static TWResultCode HandleATResponse(char* responseArray[], int count);
+
+static TWResultCode Reset();
+static TWResultCode GetLocalEUI();
+static TWResultCode CreatePAN();
+static TWResultCode EnableJoin(bool isKeyEncrypted, uint8_t* outDeviceJoinedCount);
+static TWResultCode FindMatchNodes(uint8_t* outDeviceMatchedCount);
+static TWResultCode FindClusters(char nodeId[], char endpoint[]);
+static TWResultCode TelNetworkInfoHandler(int count, char* tokens[]);
+static TWResultCode TelJpanHandler(int count, char* tokens[]);
+static TWResultCode TelEndDeviceJoinHandler(int count, char* tokens[]);
+static TWResultCode TelMatchDescHandler(int count, char* tokens[]);
+static TWResultCode TelAddressResponseHandler(int count, char* tokens[]);
+static TWResultCode TelSimpleDescHandler(int count, char* tokens[]);
+static TWResultCode TelSimpleDescInClusterHandler(int count, char* tokens[]);
+static TWResultCode TelWriteAttrHandler(int count, char* tokens[]);
+static TWResultCode TelReadAttrHandler(int count, char* tokens[]);
+static TWResultCode TelReadAttrHandlerTemperature(int count, char* tokens[]);
+static TWResultCode TelZCLDefaultResponseHandler(int count, char* tokens[]);
+static TWResultCode TelSwitchDoorLockStateHandler(int count, char* tokens[]);
+static TWResultCode TelZoneEnrollRequestHandler(int count, char* tokens[]);
+static TWResultCode TelEnrolledHandler(int count, char* tokens[]);
+static TWResultCode TelZoneStatusHandler(int count, char* tokens[]);
+
+static TWResultCode OpenPort(int * fd);
+static TWResultCode ClosePort(int fd);
+
+static TWResultCode WriteBuffer(const char * command);
+static TWResultCode ReadBuffer(uint64_t * atErrorCode,
+                               char * responseArray[],
+                               uint8_t * count,
+                               const char * command,
+                               uint8_t timeout);
+
+static TWResultCode AsciiHexToValue(char* hexString, int length, uint64_t* value);
+static int AsciiToHex(char c);
+static int Tokenize(const char *input, const char* delimiters, char* output[]);
+
+static int SetInterfaceAttribs(int fd, int speed, int parity);
+static void SetBlocking(int fd, int should_block);
+
+static void CleanArray(char* responseArray[], char* promptArray[],
+                       uint8_t responseCount, uint8_t promptCount);
+static void PrintArray(char* responseArray[], char* promptArray[],
+                       uint8_t responseCount, uint8_t promptCount);
+
+static void PrintTWDevice(TWDevice* device);
+static void PrintTWDeviceList(TWDeviceList* list);
+static void DeallocateTWDeviceList();
+
+//-----------------------------------------------------------------------------
+// Private variables
+//-----------------------------------------------------------------------------
+
+static TWATResultHandlerPair g_TWATResultHandlerPairArray[] =
+{
+    {"+N=",         TelNetworkInfoHandler},
+    {"JPAN:",       TelJpanHandler},
+    {"RFD:",        TelEndDeviceJoinHandler},       //e.g SmartThings Open/Closed Sensor
+    {"FFD:",        TelEndDeviceJoinHandler},       //e.g SmartThings Plug
+    {"SED:",        TelEndDeviceJoinHandler},
+    {"ZED:",        TelEndDeviceJoinHandler},
+    {"MatchDesc:",  TelMatchDescHandler},
+    {"SimpleDesc:", TelSimpleDescHandler},
+    {"InCluster:",  TelSimpleDescInClusterHandler},
+    {"WRITEATTR:",  TelWriteAttrHandler},
+    {"RESPATTR:",   TelReadAttrHandler},
+    {"TEMPERATURE:",TelReadAttrHandlerTemperature},
+    {"DFTREP",      TelZCLDefaultResponseHandler},
+    {"DRLOCRSP:",   TelSwitchDoorLockStateHandler},
+    {"DRUNLOCKRSP:",TelSwitchDoorLockStateHandler},
+    {"ZENROLLREQ:", TelZoneEnrollRequestHandler},
+    {"ENROLLED:",   TelEnrolledHandler},
+    {"ZONESTATUS:", TelZoneStatusHandler},
+    {"AddrResp:",   TelAddressResponseHandler},
+    {"Unknown:",    TelNetworkInfoHandler}
+};
+
+static TWEndControlMap g_TWEndMessageMap[] =
+{
+    {"OK",      TW_ENDCONTROL_OK},
+    {"ERROR:",  TW_ENDCONTROL_ERROR},
+    {"ACK:",    TW_ENDCONTROL_ACK},
+    {"SEQ:",    TW_ENDCONTROL_SEQ}
+};
+
+//TODO: Take care of all global variables
+static const char* g_port = NULL;
+static int g_fd = 0;
+
+static char g_LocalEUI[SIZE_EUI] = "";
+static char g_WIPRemoteEUI[SIZE_EUI] = "";
+static char g_WIPRemoteNodeId[SIZE_NODEID] = "";
+
+static TWStatus g_ZigBeeStatus = {ZB_STATE_UNKNOWN,0,0,NULL,0};
+static TWDeviceList* g_FoundMatchedDeviceList = NULL;
+static TWDevice* g_WIPDevice = NULL;
+
+static TWDeviceFoundCallback g_DeviceFoundCallback = NULL;
+static TWEnrollmentSucceedCallback g_EnrollmentSucceedCallback = NULL;
+static TWDeviceStatusUpdateCallback g_DeviceStatusUpdateCallback = NULL;
+
+/*****************************************************************************/
+/*                                                                           */
+/* Public functions                                                          */
+/*                                                                           */
+/*****************************************************************************/
+OCStackResult TWInitialize(const char* deviceDevPath)
+{
+    OC_LOG_V(INFO, TAG, "Enter TWInitializeZigBee().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twCode = TW_RESULT_ERROR;
+
+    g_port = deviceDevPath;
+
+    OC_LOG_V(INFO, TAG, "Attempt to open %s", deviceDevPath);
+    twCode = OpenPort(&g_fd);
+
+    if (twCode != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "Failed to open %s because of error: %d", deviceDevPath, ret);
+        ret = OC_STACK_ERROR;
+    }
+    else
+    {
+        twCode = TW_RESULT_ERROR;
+
+        bool continueInit = true;
+        bool wantReset = false;
+
+        if (wantReset)
+        {
+            twCode = Reset();
+            if (twCode == TW_RESULT_OK)
+            {
+                OC_LOG_V(INFO, TAG, "ZigBee Initialization - Reset - OK.");
+                continueInit = true;
+            }
+            else
+            {
+                OC_LOG_V(INFO, TAG, "ZigBee Initialization - Reset - FAILED.");
+                continueInit = false;
+            }
+        }
+
+        if (continueInit)
+        {
+            twCode = CreatePAN();
+            if (twCode == TW_RESULT_OK)
+            {
+                OC_LOG_V(INFO, TAG, "CreatePan OK.");
+
+                twCode = GetLocalEUI();
+                if (twCode == TW_RESULT_OK)
+                {
+                    OC_LOG_V(INFO, TAG, "GetLocalEUI OK.");
+                    OC_LOG_V(INFO, TAG, "ZigBee Initialization - DONE.");
+                    g_ZigBeeStatus.state = ZB_STATE_INIT;
+                    ret = OC_STACK_OK;
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "GetLocalEUI FAILED.");
+                    OC_LOG_V(ERROR, TAG, "ZigBee Initialization - FAILED - MUST STOP NOW.");
+                             g_ZigBeeStatus.state = ZB_STATE_UNKNOWN;
+                     ret = OC_STACK_ERROR;
+                }
+            }
+            else
+            {
+                OC_LOG_V(ERROR, TAG, "CreatePan FAILED. Result: %d", twCode);
+                OC_LOG_V(ERROR, TAG, "ZigBee Initialization - FAILED - MUST STOP NOW.");
+                g_ZigBeeStatus.state = ZB_STATE_UNKNOWN;
+                ret = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            OC_LOG_V(ERROR, TAG, "ZigBee Initialization - FAILED - MUST STOP NOW.");
+            ret = OC_STACK_ERROR;
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWInitializeZigBee().");
+    return ret;
+}
+
+OCStackResult TWDiscover()
+{
+    OC_LOG_V(INFO, TAG, "Enter TWDiscover().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_ERROR;
+    uint8_t deviceJoinedCount = 0;
+
+    if (g_DeviceFoundCallback == NULL)
+    {
+        OC_LOG_V(ERROR, TAG, "Required TWDeviceFoundCallback.");
+        ret = OC_STACK_ERROR;
+    }
+    else
+    {
+        twRet = EnableJoin(false, &deviceJoinedCount);
+
+        if (twRet == TW_RESULT_OK)
+        {
+            OC_LOG_V(INFO, TAG, "Number of devices joined:%d.", deviceJoinedCount);
+            uint8_t nodeMatchedCount = 0;
+            twRet = FindMatchNodes(&nodeMatchedCount);
+            if (twRet == TW_RESULT_FOUND_NO_MATCHED_DEVICE)
+            {
+                ret = OC_STACK_OK;
+            }
+            else if (twRet == TW_RESULT_FOUND_MATCHED_DEVICES)
+            {
+                ret = OC_STACK_OK;
+                int i = 0;
+                for (; i < g_FoundMatchedDeviceList->count; i++)
+                {
+                    g_WIPDevice = &g_FoundMatchedDeviceList->deviceList[i];
+                    twRet = FindClusters(g_WIPDevice->nodeId,
+                            g_WIPDevice->endpointOfInterest->endpointId);
+
+                    if (twRet == TW_RESULT_HAS_CLUSTERS)
+                    {
+                        OC_LOG_V(INFO, TAG, "Attempt to invoke a callback.");
+                        g_DeviceFoundCallback(g_WIPDevice);
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG,
+                                 "ERROR finding cluster for NodeID=%s,EUI=%s,EP=%s.",
+                                 g_WIPDevice->nodeId,
+                                 g_WIPDevice->eui,
+                                 g_WIPDevice->endpointOfInterest->endpointId);
+                        ret = OC_STACK_ERROR;
+                        break;
+                    }
+                    g_WIPDevice = NULL;
+                }
+            }
+            else
+            {
+                OC_LOG_V(ERROR, TAG, "Find matched nodes.");
+                ret = OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            OC_LOG_V(ERROR, TAG, "Enable joining.");
+            ret = OC_STACK_ERROR;
+        }
+
+        //Done with wip device.
+        g_WIPDevice = NULL;
+
+        //deallocate the list of found devices.
+        //so that it's cleaned for the next TWDiscover() call.
+        DeallocateTWDeviceList();
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWDiscover().");
+    return ret;
+}
+
+OCStackResult TWSetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
+                             char* clusterId, char* attributeId, char* attributeType,
+                             char* newValue)
+{
+    //Ask:  AT+WRITEATR:5DA7,01,0,0003,0000,21,01
+
+    OC_LOG_V(INFO, TAG, "Enter TWSetAttribute().");
+
+    (void)extendedUniqueId;
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_ERROR;
+
+    int size =  strlen(AT_CMD_WRITE_ATR) + strlen(nodeId) +
+                SEPARATOR_LENGTH + strlen(endpointId) +
+                SEPARATOR_LENGTH + strlen(SENDMODE) +
+                SEPARATOR_LENGTH + strlen(clusterId) +
+                SEPARATOR_LENGTH + strlen(attributeId) +
+                SEPARATOR_LENGTH + strlen(attributeType) +
+                SEPARATOR_LENGTH + strlen(newValue) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString != NULL)
+    {
+        snprintf(cmdString, size, "%s%s,%s,%s,%s,%s,%s,%s",
+                 AT_CMD_WRITE_ATR, nodeId, endpointId, SENDMODE,
+                 clusterId, attributeId, attributeType, newValue);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+
+        OC_LOG_V(INFO, TAG, "Issued Command: %s.", cmdString);
+        twRet = IssueATCommand(cmdString, TIME_OUT_05_SECONDS,
+                               &atErrorCode,
+                               responseArray, promptArray,
+                               &responseCount, &promptCount);
+
+        if (twRet != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Failed to write: %s", cmdString);
+            ret = OC_STACK_ERROR;
+        }
+        else
+        {
+            if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+            {
+                OC_LOG_V(ERROR, TAG,
+                         "Write to a remote attribute - AT_ERROR: %" PRId64 "", atErrorCode);
+                ret = OC_STACK_ERROR;
+            }
+            else
+            {
+                OC_LOG_V(INFO, TAG, "Issue AT Command %s returned OK.", cmdString);
+                PrintArray(responseArray, promptArray, responseCount, promptCount);
+
+                //IMPORTANT NOTE:
+                //      Although responseArray is not NULL sometimes,
+                //      do not use it to check for prompt.
+                //      WRITEATTR prompt is stored in promptArray.
+                if (promptCount > 0)
+                {
+                    twRet = HandleATResponse(promptArray, promptCount);
+                    if (twRet == TW_RESULT_OK)
+                    {
+                        OC_LOG_V(INFO, TAG, "Set attribute value received a succeed prompt.");
+                        ret = OC_STACK_OK;
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG, "Set attribute value received an error prompt.");
+                        ret = OC_STACK_ERROR;
+                    }
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "Why didn't it receive WRITEATTR prompt?");
+                    ret = OC_STACK_ERROR;
+                }
+            }
+        }
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+        OICFree(cmdString);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWSetAttribute().");
+    return ret;
+}
+
+OCStackResult TWGetAttribute(char* extendedUniqueId, char* nodeId, char* endpointId,
+                             char* clusterId, char* attributeId,
+                             char** outValue, uint8_t* outValueLength)
+{
+    //Ask:  AT+READATR:FE5A,01,0,0402,0002
+
+    OC_LOG_V(INFO, TAG, "Enter TWGetAttribute().");
+
+    (void)extendedUniqueId;
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_ERROR;
+
+    int size =  strlen(AT_CMD_READ_ATR) + strlen(nodeId) +
+                SEPARATOR_LENGTH + strlen(endpointId) +
+                SEPARATOR_LENGTH + strlen(SENDMODE) +
+                SEPARATOR_LENGTH + strlen(clusterId) +
+                SEPARATOR_LENGTH + strlen(attributeId) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        OC_LOG_V(ERROR, TAG, "No Memory");
+        ret = OC_STACK_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s",
+                 AT_CMD_READ_ATR, nodeId,
+                 SEPARATOR, endpointId,
+                 SEPARATOR, SENDMODE,
+                 SEPARATOR, clusterId,
+                 SEPARATOR, attributeId);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+
+        OC_LOG_V(INFO, TAG, "Issued Command: %s.", cmdString);
+        twRet = IssueATCommand(cmdString, TIME_OUT_05_SECONDS,
+                               &atErrorCode,
+                               responseArray, promptArray,
+                               &responseCount, &promptCount);
+
+        if (twRet != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write %s", cmdString);
+            ret = OC_STACK_ERROR;
+        }
+        else
+        {
+            if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+            {
+                OC_LOG_V(ERROR, TAG,
+                         "Read a remote attribute - AT_ERROR: %" PRId64 ".", atErrorCode);
+                ret = OC_STACK_ERROR;
+            }
+            else
+            {
+                OC_LOG_V(INFO, TAG, "Issue AT Command %s returned OK.", cmdString);
+                PrintArray(responseArray, promptArray, responseCount, promptCount);
+
+                if (promptCount > 0)
+                {
+                    twRet = HandleATResponse(promptArray, promptCount);
+                    if (twRet == TW_RESULT_REMOTE_ATTR_HAS_VALUE)
+                    {
+                        OC_LOG_V(INFO, TAG, "Get attribute value received a succeed prompt.");
+                        int size = strlen(g_ZigBeeStatus.remoteAttributeValueRead) + 1;
+                        *outValue = (char*)OICMalloc(sizeof(char) * size);
+                        if (*outValue != NULL)
+                        {
+                            OICStrcpy(*outValue, size, g_ZigBeeStatus.remoteAttributeValueRead);
+                            *outValueLength = g_ZigBeeStatus.remoteAtrributeValueReadLength;
+                            ret = OC_STACK_OK;
+                        }
+                        else
+                        {
+                            ret = OC_STACK_NO_MEMORY;
+                        }
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG, "Get attribute value received an error prompt.");
+                        ret = OC_STACK_ERROR;
+                    }
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "Didn't receive READATTR prompt.");
+                    ret = OC_STACK_ERROR;
+                }
+            }
+        }
+        OICFree(cmdString);
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWGetAttribute().");
+
+    return ret;
+}
+
+OCStackResult TWSwitchOnOff(char* nodeId, char* endpointId, char* newState)
+{
+    //AT+RONOFF:<Address>,<EP>,<SendMode>[,<ON/OFF>]
+    //AT+RONOFF:9E2B,01,0,1
+    //      OK
+    //      DFTREP:9E2B,01,0006,01,00
+
+    OC_LOG_V(INFO, TAG, "Enter TWSwitchOnOff().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_UNKNOWN;
+
+    int size = 0;
+    if (newState == NULL)
+    {
+        size =  strlen(AT_CMD_RUN_ON_OFF) + strlen(nodeId) +
+                SEPARATOR_LENGTH + strlen(endpointId) +
+                SEPARATOR_LENGTH + strlen(SENDMODE) + 1;
+    }
+    else
+    {
+        size =  strlen(AT_CMD_RUN_ON_OFF) + strlen(nodeId) +
+                SEPARATOR_LENGTH + strlen(endpointId) +
+                SEPARATOR_LENGTH + strlen(SENDMODE) +
+                SEPARATOR_LENGTH + strlen(newState) + 1;
+    }
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        ret = OC_STACK_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s",
+                 AT_CMD_RUN_ON_OFF, nodeId, SEPARATOR,
+                 endpointId, SEPARATOR, SENDMODE);
+
+        if (newState != NULL)
+        {
+            OICStrcat(cmdString, size, SEPARATOR);
+            OICStrcat(cmdString, size, newState);
+        }
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+        twRet = IssueATCommand(cmdString, TIME_OUT_05_SECONDS,
+                               &atErrorCode,
+                               responseArray, promptArray,
+                               &responseCount, &promptCount);
+
+        if (twRet != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write AT+RONOFF - FAILED.");
+            ret = OC_STACK_ERROR;
+        }
+        else
+        {
+            if (atErrorCode == AT_ERROR_EVERYTHING_OK)
+            {
+                twRet = HandleATResponse(promptArray, promptCount);
+                if (twRet == TW_RESULT_OK)
+                {
+                    ret = OC_STACK_OK;
+                }
+                else
+                {
+                    ret = OC_STACK_ERROR;
+                }
+            }
+            else
+            {
+                 if (atErrorCode == AT_ERROR_MESSAGE_NOT_SENT_TO_TARGET_SUCCESSFULLY)
+                 {
+                     OC_LOG_V(ERROR, TAG,
+                              "Switch to ON/OFF - FAILED - Send to the target not succeed.");
+                 }
+                 else
+                 {
+                     OC_LOG_V(ERROR, TAG, "Switch to ON/OFF - FAILED.");
+                 }
+                 ret = OC_STACK_ERROR;
+            }
+        }
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+        OICFree(cmdString);
+    }
+    OC_LOG_V(INFO, TAG, "Leave TWSwitchOnOff().");
+    return ret;
+}
+
+OCStackResult TWMoveToLevel(char* nodeId, char* endpointId,
+                            char* onOffState, char* level, char* transTime)
+{
+    //AT+LCMVTOLEV:<Address>,<EP>,<SendMode>,<ON/OFF>,<LevelValue>,<TransTime>
+
+    OC_LOG_V(INFO, TAG, "Enter TWMoveToLevel().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_UNKNOWN;
+
+    int size = 0;
+    size =  strlen(AT_CMD_MOVE_TO_LEVEL) + strlen(nodeId) +
+            SEPARATOR_LENGTH + strlen(endpointId) +
+            SEPARATOR_LENGTH + strlen(SENDMODE) +
+            SEPARATOR_LENGTH + strlen(onOffState) +
+            SEPARATOR_LENGTH + strlen(level) +
+            SEPARATOR_LENGTH + strlen(transTime) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        ret = OC_STACK_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s%s%s",
+                 AT_CMD_MOVE_TO_LEVEL, nodeId,
+                 SEPARATOR, endpointId,
+                 SEPARATOR, SENDMODE,
+                 SEPARATOR, onOffState,
+                 SEPARATOR, level,
+                 SEPARATOR, transTime);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+        twRet = IssueATCommand(cmdString, TIME_OUT_05_SECONDS,
+                               &atErrorCode,
+                               responseArray, promptArray,
+                               &responseCount, &promptCount);
+
+        if (twRet != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write AT+RONOFF - FAILED.");
+            ret = OC_STACK_ERROR;
+        }
+        else
+        {
+            if (atErrorCode == AT_ERROR_EVERYTHING_OK)
+            {
+                twRet = HandleATResponse(promptArray, promptCount);
+                if (twRet == TW_RESULT_OK)
+                {
+                    ret = OC_STACK_OK;
+                }
+                else
+                {
+                    ret = OC_STACK_ERROR;
+                }
+            }
+            else
+            {
+                 if (atErrorCode == AT_ERROR_MESSAGE_NOT_SENT_TO_TARGET_SUCCESSFULLY)
+                 {
+                     OC_LOG_V(ERROR, TAG,
+                              "Turn To Level - FAILED - Send to the target not succeeded.");
+                 }
+                 else
+                 {
+                     OC_LOG_V(ERROR, TAG, "Turn To Level - FAILED.");
+                 }
+                 ret = OC_STACK_ERROR;
+            }
+        }
+
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+        OICFree(cmdString);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWMoveToLevel().");
+    return ret;
+}
+
+OCStackResult TWSwitchDoorLockState(char* nodeId, char* endpointId, char* newState)
+{
+    //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
+
+    OC_LOG_V(INFO, TAG, "Enter TWSwitchDoorLockState().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+    TWResultCode twRet = TW_RESULT_UNKNOWN;
+
+    int size = 0;
+    size =  strlen(AT_CMD_DOOR_LOCK) + strlen(nodeId) +
+            SEPARATOR_LENGTH + strlen(endpointId) +
+            SEPARATOR_LENGTH + strlen(SENDMODE) +
+            SEPARATOR_LENGTH + strlen(newState) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        ret = OC_STACK_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s%s%s",
+                 AT_CMD_DOOR_LOCK, nodeId,
+                 SEPARATOR, endpointId,
+                 SEPARATOR, SENDMODE,
+                 SEPARATOR, newState);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+        twRet = IssueATCommand(cmdString, TIME_OUT_05_SECONDS,
+                               &atErrorCode,
+                               responseArray, promptArray,
+                               &responseCount, &promptCount);
+
+        if (twRet != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write AT+DRLOCK - FAILED.");
+            ret = OC_STACK_ERROR;
+        }
+        else
+        {
+            if (atErrorCode == AT_ERROR_EVERYTHING_OK)
+            {
+                twRet = HandleATResponse(promptArray, promptCount);
+                if (twRet == TW_RESULT_OK)
+                {
+                    ret = OC_STACK_OK;
+                }
+                else
+                {
+                    ret = OC_STACK_ERROR;
+                }
+            }
+            else
+            {
+                if (atErrorCode == AT_ERROR_MESSAGE_NOT_SENT_TO_TARGET_SUCCESSFULLY)
+                {
+                    OC_LOG_V(ERROR, TAG,
+                             "Switch to ON/OFF - FAILED - Send to the target not succeeded.");
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "Switch to ON/OFF - FAILED.");
+                }
+                ret = OC_STACK_ERROR;
+            }
+        }
+
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+        OICFree(cmdString);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWSwitchDoorLockState().");
+    return ret;
+}
+
+OCStackResult TWSetDiscoveryCallback(const TWDeviceFoundCallback callback)
+{
+    OC_LOG_V(INFO, TAG, "Enter TWSetDiscoveryCallback().");
+    if (callback != NULL)
+    {
+        g_DeviceFoundCallback= callback;
+    }
+    else
+    {
+        g_DeviceFoundCallback = NULL;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWSetDiscoveryCallback().");
+    return OC_STACK_OK;
+}
+
+OCStackResult TWUninitialize()
+{
+    OC_LOG_V(INFO, TAG, "Enter TWUninitializeZigBee().");
+
+    OCStackResult ret = OC_STACK_ERROR;
+
+    TWResultCode twRet = ClosePort(g_fd);
+    if (twRet == TW_RESULT_OK)
+    {
+        ret = OC_STACK_OK;
+    }
+    else
+    {
+        ret = OC_STACK_ERROR;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TWUninitializeZigBee().");
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+// Internal functions
+//-----------------------------------------------------------------------------
+
+TWResultCode Reset()
+{
+    OC_LOG_V(INFO, TAG, "Enter Reset().");
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    char* responseArray[ARRAY_LENGTH] = {};
+    uint8_t responseCount = 0;
+    char* promptArray[ARRAY_LENGTH] = {};
+    uint8_t promptCount = 0;
+    uint64_t atErrorCode = 0;
+
+    ret = IssueATCommand(AT_CMD_RESET, TIME_OUT_00_SECOND,
+                         &atErrorCode,
+                         responseArray, NULL,
+                         &responseCount, NULL);
+
+    if (ret != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "TWriting error on AT&F.");
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Dongle Reset - FAILED - AT_ERROR: %" PRId64 "", atErrorCode);
+            ret = TW_RESULT_ERROR;
+        }
+        else
+        {
+            OC_LOG_V(INFO, TAG, "Dongle Reset - OK.");
+            ret = TW_RESULT_OK;
+        }
+
+    }
+
+    CleanArray(responseArray, promptArray, responseCount, promptCount);
+
+    OC_LOG_V(INFO, TAG, "Leave Reset().");
+    return ret;
+}
+
+TWResultCode GetLocalEUI()
+{
+    OC_LOG_V(INFO, TAG, "Enter GetLocalEUI().");
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    char* responseArray[ARRAY_LENGTH] = {};
+    uint8_t responseCount = 0;
+
+    char* promptArray[ARRAY_LENGTH] = {};
+    uint8_t promptCount = 0;
+
+    uint64_t atErrorCode = 0;
+
+    OC_LOG_V(INFO, TAG, "Issued Command: %s.", AT_CMD_GET_LOCAL_EUI);
+    ret = IssueATCommand(AT_CMD_GET_LOCAL_EUI, TIME_OUT_05_SECONDS,
+                         &atErrorCode,
+                         responseArray, promptArray,
+                         &responseCount, &promptCount);
+
+    if (ret != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "Write %s", AT_CMD_GET_LOCAL_EUI);
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+        {
+            OC_LOG_V(ERROR, TAG,
+                     "Get Local EUI Failed - AT_ERROR: %" PRId64 "", atErrorCode);
+            ret = TW_RESULT_ERROR;
+        }
+        else
+        {
+            OICStrcpy(g_LocalEUI, SIZE_EUI, responseArray[0]);
+            OC_LOG_V(INFO, TAG, "Local EUI: %s ", g_LocalEUI);
+            ret = TW_RESULT_OK;
+        }
+    }
+
+    CleanArray(responseArray, promptArray, responseCount, promptCount);
+
+    OC_LOG_V(INFO, TAG, "Leave GetLocalEUI().");
+    return ret;
+}
+
+TWResultCode CreatePAN()
+{
+    /*
+    //at+n
+    //      +N=NoPAN
+    //      OK
+
+    //at+n
+    //      +N=COO,26,-6,7306,133F04EA669C6B24
+    //      OK
+
+    //at+en
+    //      OK
+    //      JPAN:26,7306,133F04EA669C6B24
+
+    //at+en
+    //      ERROR:28
+    */
+
+    OC_LOG_V(INFO, TAG, "Enter CreatePAN()");
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    uint8_t responseCount1 = 0;
+    uint8_t promptCount1 = 0;
+    char* responseArray1[ARRAY_LENGTH] = {};
+    char* promptArray1[ARRAY_LENGTH] = {};
+
+    uint8_t responseCount2 = 0;
+    uint8_t promptCount2 = 0;
+    char* responseArray2[ARRAY_LENGTH] = {};
+    char* promptArray2[ARRAY_LENGTH] = {};
+
+    uint64_t atErrorCode = 0;
+
+    ret = IssueATCommand(AT_CMD_GET_NETWORK_INFO, TIME_OUT_00_SECOND,
+                         &atErrorCode,
+                         responseArray1, promptArray1,
+                         &responseCount1, &promptCount1);
+    if (ret != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "Write AT+N - FAILED.");
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Get network info - FAILED.");
+            ret = TW_RESULT_ERROR;
+        }
+        else
+        {
+            //Handle +N
+            ret = HandleATResponse(responseArray1, responseCount1);
+            if (ret == TW_RESULT_NO_LOCAL_PAN)
+            {
+                OC_LOG_V(INFO, TAG, "Attempt to write AT+EN. ");
+                ret = IssueATCommand(AT_CMD_ESTABLISH_NETWORK, TIME_OUT_01_SECOND,
+                                     &atErrorCode,
+                                     responseArray2, promptArray2,
+                                     &responseCount2, &promptCount2);
+
+                if (ret != TW_RESULT_OK)
+                {
+                    OC_LOG_V(ERROR, TAG, "Write AT+EN - FAILED.");
+                    ret = TW_RESULT_ERROR;
+                }
+                else
+                {
+                    if (atErrorCode == AT_ERROR_EVERYTHING_OK) //OK
+                    {
+                        //IMPORTANT: Special case for JPAN prompt:
+                        //JPAN prompts are stored in responseArray instead of promptArray
+                        //Handle JPAN:26,7306,133F04EA669C6B24
+                        ret = HandleATResponse(responseArray2, responseCount2);
+                        if (ret == TW_RESULT_NEW_LOCAL_PAN_ESTABLISHED)
+                        {
+                            OC_LOG_V(INFO, TAG, "New Local PAN established - OK.");
+                            ret = TW_RESULT_OK;
+                        }
+                        else
+                        {
+                            OC_LOG_V(ERROR, TAG, "Handling AT+EN.");
+                            ret = TW_RESULT_ERROR;
+                        }
+                    }
+                    else if (atErrorCode == AT_ERROR_NODE_IS_PART_OF_PAN)
+                    {
+                        OC_LOG_V(INFO, TAG, "Already Established PAN - OK.");
+                        ret = TW_RESULT_OK;
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG, "Couldn't establish PAN.");
+                        ret = TW_RESULT_ERROR;
+                    }
+                }
+            }
+            else if (ret == TW_RESULT_HAS_LOCAL_PAN)
+            {
+                OC_LOG_V(INFO, TAG, "Already established PAN - OK.");
+                ret = TW_RESULT_OK;
+            }
+            else if (atErrorCode != 0)
+            {
+                OC_LOG_V(ERROR, TAG,
+                         "CreatePAN() FAILED with AT_ERROR: %" PRId64 "", atErrorCode);
+                ret = TW_RESULT_ERROR;
+            }
+        }
+    }
+
+    CleanArray(responseArray1, promptArray1, responseCount1, promptCount1);
+    CleanArray(responseArray2, promptArray2, responseCount2, promptCount2);
+
+    OC_LOG_V(INFO, TAG, "Leave CreatePAN().");
+    return ret;
+}
+
+TWResultCode EnableJoin(bool isKeyEncrypted, uint8_t* outDeviceJoinedCount)
+{
+    //Ask:          AT+PJOIN
+    //Response:     OK
+
+    //Ask:          AT+PJOIN
+    //Response:     ERROR:70
+
+    OC_LOG_V(INFO, TAG, "Enter Enabling Join().");
+
+    (void)isKeyEncrypted;
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    if (outDeviceJoinedCount != NULL)
+    {
+        *outDeviceJoinedCount = 0;
+
+        isKeyEncrypted = false;         //TODO: for now - don't encrypt
+
+        char*   joinTimeHex     = "0F"; //TODO: for now - 15 seconds
+        uint8_t joinTimeDecimal = 15;   //TODO: for now - 15 seconds
+
+        char* broadcast = "FFFC";
+
+        int size =  strlen(AT_CMD_PERMIT_JOIN) + strlen(joinTimeHex) +
+                    SEPARATOR_LENGTH + strlen(broadcast) + 1;
+
+        char* cmdString = (char*)OICMalloc(size * sizeof(char));
+        if (cmdString == NULL)
+        {
+            ret = TW_RESULT_ERROR_NO_MEMORY;
+        }
+        else
+        {
+            snprintf(cmdString, size, "%s%s%s%s",
+                     AT_CMD_PERMIT_JOIN, joinTimeHex, SEPARATOR, broadcast);
+
+            char* responseArray[ARRAY_LENGTH] = {};
+            uint8_t responseCount = 0;
+
+            char* promptArray[ARRAY_LENGTH] = {};
+            uint8_t promptCount = 0;
+
+            uint64_t atErrorCode = 0;
+
+            OC_LOG_V(INFO, TAG, "Attempt to allow joining...");
+
+            OC_LOG_V(INFO, TAG, "Issued Command: %s.", cmdString);
+            ret = IssueATCommand(cmdString, joinTimeDecimal,
+                                 &atErrorCode,
+                                 responseArray, promptArray,
+                                 &responseCount, &promptCount);
+
+            if (ret != TW_RESULT_OK)
+            {
+                OC_LOG_V(ERROR, TAG, "Write AT+PJOIN - AT_ERROR = %" PRId64 "", atErrorCode);
+                ret = TW_RESULT_ERROR;
+            }
+            else
+            {
+                if (atErrorCode == AT_ERROR_EVERYTHING_OK)
+                {
+                    OC_LOG_V(INFO, TAG, "Enable joining - OK.");
+                    OC_LOG_V(INFO, TAG,
+                             "Joining has been allowed for %d seconds. Time's up!",
+                             joinTimeDecimal);
+                    if (promptCount > 0)    // some devices joined.
+                    {
+                        OC_LOG_V(INFO, TAG, "Number of devices joined:%d.", promptCount);
+                        *outDeviceJoinedCount = promptCount;
+
+                        //Handle SED, FFD, RFD,...
+                        ret = HandleATResponse(promptArray, promptCount);
+                    }
+                    else
+                    {
+                        ret = TW_RESULT_OK;
+                    }
+                }
+                else if (atErrorCode == AT_ERROR_INVALID_OPERATION)
+                {
+                    OC_LOG_V(ERROR, TAG, "Enable joining - FAILED - because there was no PAN.");
+                    ret = TW_RESULT_ERROR;
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "Enable joining - FAILED.");
+                    ret = TW_RESULT_ERROR;
+                }
+            }
+            CleanArray(responseArray, promptArray, responseCount, promptCount);
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave Enabling Join()");
+    return ret;
+}
+
+TWResultCode FindMatchNodes(uint8_t* outDeviceMatchedCount)
+{
+    //AT+MATCHREQ:0104,03,0003,0006,0402,00
+    //      OK
+    //      MatchDesc:0B4A,00,01
+
+    //AT+MATCHREQ:0104,03,0999,0999,0999,00
+    //      OK
+
+    OC_LOG_V(INFO, TAG, "Enter FindMatchNodes().");
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    char* profileHomeAutomation = "0104";
+    char* inClusterCount = "04";
+    char* outClusterCount = "00";
+
+    //TODO: add more clusters
+    char* clusterIdentify = "0003";
+    char* clusterOnOff = "0006";
+    char* clusterTemperatureMeasurement = "0402";
+    char* clusterIASZone = "0500";
+
+    int size = strlen(AT_CMD_MATCH_REQUEST) + strlen(profileHomeAutomation) +
+               SEPARATOR_LENGTH + strlen(inClusterCount) +
+               SEPARATOR_LENGTH + strlen(clusterIdentify) +
+               SEPARATOR_LENGTH + strlen(clusterOnOff) +
+               SEPARATOR_LENGTH + strlen(clusterTemperatureMeasurement) +
+               SEPARATOR_LENGTH + strlen(clusterIASZone) +
+               SEPARATOR_LENGTH + strlen(outClusterCount) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        ret = TW_RESULT_ERROR_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                 AT_CMD_MATCH_REQUEST, profileHomeAutomation,
+                 SEPARATOR, inClusterCount,
+                 SEPARATOR, clusterIdentify,
+                 SEPARATOR, clusterOnOff,
+                 SEPARATOR, clusterTemperatureMeasurement,
+                 SEPARATOR, clusterIASZone,
+                 SEPARATOR, outClusterCount);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+
+        OC_LOG_V(INFO, TAG, "Issued Command: %s.", cmdString);
+        ret = IssueATCommand(cmdString, TIME_OUT_10_SECONDS,
+                             &atErrorCode,
+                             responseArray, promptArray,
+                             &responseCount, &promptCount);
+
+        if (ret != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write %s - AT_ERROR = %" PRId64 ".", cmdString, atErrorCode);
+            ret = TW_RESULT_ERROR;
+        }
+        else
+        {
+            if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+            {
+                OC_LOG_V(ERROR, TAG,
+                         "AT_ERROR %" PRId64 " returned from %s", atErrorCode, cmdString);
+                ret = TW_RESULT_ERROR;
+            }
+            else
+            {
+                OC_LOG_V(INFO, TAG, "Number of found matched nodes:%d.", promptCount);
+                if (promptCount > 0)
+                {
+                    //Handle all received MatchDesc:0B4A,00,01
+                    ret = HandleATResponse(promptArray, promptCount);
+                    if (ret == TW_RESULT_OK)
+                    {
+                        OC_LOG_V(INFO, TAG, "Handle matched nodes - SUCCEED.");
+                        *outDeviceMatchedCount = promptCount;
+                        ret = TW_RESULT_FOUND_MATCHED_DEVICES;
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG, "Handle matched nodes.");
+                        ret = TW_RESULT_ERROR;
+                    }
+                }
+                else
+                {
+                    ret = TW_RESULT_FOUND_NO_MATCHED_DEVICE;
+                }
+            }
+        }
+
+        OICFree(cmdString);
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+
+        if (g_FoundMatchedDeviceList != NULL)
+        {
+            OC_LOG_V(INFO, TAG, "Found these devices via match request.");
+            PrintTWDeviceList(g_FoundMatchedDeviceList);
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave FindMatchNodes().");
+    return ret;
+}
+
+TWResultCode FindClusters(char nodeId[], char endpoint[])
+{
+    //AT+SIMPLEDESC:3746,3746,01
+    //      SEQ:97
+    //      OK
+    //
+    //      SimpleDesc:3746,00
+    //      EP:01
+    //      ProfileID:0104
+    //      DeviceID:0402v00
+    //      InCluster:0000,0001,0003,0402,0500,0020,0B05
+    //      OutCluster:0019
+    //
+    //      ACK:97
+
+    OC_LOG_V(INFO, TAG, "Enter FindClusters().");
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    int size = strlen(AT_CMD_SIMPLE_DESC) + strlen(nodeId) +
+               SEPARATOR_LENGTH + strlen(nodeId) +
+               SEPARATOR_LENGTH + strlen(endpoint) + 1;
+
+    char* cmdString = (char*)OICMalloc(size * sizeof(char));
+    if (cmdString == NULL)
+    {
+        ret = TW_RESULT_ERROR_NO_MEMORY;
+    }
+    else
+    {
+        snprintf(cmdString, size, "%s%s%s%s%s%s",
+                 AT_CMD_SIMPLE_DESC, nodeId,
+                 SEPARATOR, nodeId,
+                 SEPARATOR, endpoint);
+
+        char* responseArray[ARRAY_LENGTH] = {};
+        uint8_t responseCount = 0;
+
+        char* promptArray[ARRAY_LENGTH] = {};
+        uint8_t promptCount = 0;
+
+        uint64_t atErrorCode = 0;
+
+        OC_LOG_V(INFO, TAG, "Issued Command: %s.", cmdString);
+        ret = IssueATCommand(cmdString, TIME_OUT_07_SECONDS,
+                             &atErrorCode,
+                             responseArray, promptArray,
+                             &responseCount, &promptCount);
+
+        if (ret != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Write %s", cmdString);
+            ret = TW_RESULT_ERROR;
+        }
+        else
+        {
+            if (atErrorCode != AT_ERROR_EVERYTHING_OK)
+            {
+                OC_LOG_V(ERROR, TAG,
+                         "AT_ERROR %" PRId64 " returned from %s", atErrorCode, cmdString);
+                ret = TW_RESULT_ERROR;
+            }
+            else
+            {
+                if (promptCount == SIMPLEDESC_RESPONSE_EXPECTED_LINES)
+                {
+                    //Handle - SimpleDesc...
+                    ret = HandleATResponse(promptArray, promptCount);
+                    if (ret == TW_RESULT_OK)
+                    {
+                        OC_LOG_V(INFO, TAG,
+                                 "Succeed handling clusters for nodeid %s.", nodeId);
+                        ret = TW_RESULT_HAS_CLUSTERS;
+                    }
+                    else
+                    {
+                        OC_LOG_V(ERROR, TAG, "Error handling clusters for nodeid %s.", nodeId);
+                        ret = TW_RESULT_ERROR;
+                    }
+                }
+                else
+                {
+                    OC_LOG_V(ERROR, TAG, "Received an invalid Simple Descriptor prompt.");
+                    PrintArray(responseArray, promptArray, responseCount, promptCount);
+                    ret = TW_RESULT_ERROR;
+                }
+            }
+        }
+        CleanArray(responseArray, promptArray, responseCount, promptCount);
+        OICFree(cmdString);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave FindClusters().");
+
+    return ret;
+}
+
+OCStackResult TWListenForStatusUpdates(char* nodeId, char* endpointId)
+{
+    OC_LOG_V(INFO, TAG, "Enter TWListenForStatusUpdates().");
+
+    char* zoneClusterID = "0500";
+    char* zoneAttributeID = "0010";
+    char* attributeDateType = "F0";
+
+    OCStackResult ret = TWSetAttribute(NULL, nodeId, endpointId,
+                                       zoneClusterID, zoneAttributeID, attributeDateType,
+                                       g_LocalEUI);
+
+    OC_LOG_V(INFO, TAG, "Leave TWListenForStatusUpdates().");
+
+    return ret;
+}
+
+TWResultCode HandleATResponse(char* responseArray[], int count)
+{
+    OC_LOG_V(INFO, TAG, "Enter HandleATResponse().");
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    int32_t i = 0;
+    for (; i < count; i++)
+    {
+        uint32_t k = 0;
+        for (; k < sizeof(g_TWATResultHandlerPairArray)/sizeof(TWATResultHandlerPair); ++k)
+        {
+            if (strncmp(responseArray[i],
+                        g_TWATResultHandlerPairArray[k].resultTxt,
+                        strlen(g_TWATResultHandlerPairArray[k].resultTxt)
+                        ) == 0)
+            {
+                char* tokens[ARRAY_LENGTH] = {};
+                const char* delimiters = ",\r";
+                int paramCount = Tokenize(responseArray[i] +
+                                           strlen(g_TWATResultHandlerPairArray[k].resultTxt),
+                                           delimiters, tokens);
+                if (paramCount > 0)
+                {
+                    ret = g_TWATResultHandlerPairArray[k].handler(paramCount, tokens);
+                }
+
+                int n = 0;
+                for (; n < paramCount; n++)
+                {
+                    OICFree(tokens[n]);
+                }
+
+                break;
+            }
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave HandleATResponse().");
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+// Internal functions - AT Response/Prompt Handlers
+//-----------------------------------------------------------------------------
+
+TWResultCode TelAddressResponseHandler(int count, char* tokens[])
+{
+    //AddrResp:<errorcode>[,<NodeID>,<EUI64>]
+    //AddrResp:00,15ED,000D6F00040574B8
+
+    if(!tokens || count <= 3)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+
+    OC_LOG_V(INFO, TAG, "Enter TelAddressResponseHandler()");
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    if (strcmp(tokens[0], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "AddrResp prompt contained error status.");
+    }
+    else
+    {
+        OICStrcpy(g_WIPRemoteNodeId, SIZE_NODEID, tokens[1]);
+        OICStrcpy(g_WIPRemoteEUI, SIZE_EUI, tokens[2]);
+        ret = TW_RESULT_OK;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelAddressResponseHandler()");
+
+    return ret;
+}
+
+TWResultCode TelNetworkInfoHandler(int count, char* tokens[])
+{
+    // Ask:         AT+N
+    // Response:    +N=COO,24,-6,9726,12BB200F073AB573
+    //                          or
+    //              +N=NoPAN
+    //
+    //              +N=<devicetype>,<channel>,<power>,<PANID>,<EPANID>
+
+    OC_LOG_V(INFO, TAG, "Enter TelNetworkInfoHandler()");
+    if(!tokens || count <= 4)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    int i = 0;
+    for (; i < count; ++i)
+    {
+        if (tokens[i] != NULL)
+        {
+            printf ("Token[%d] = %s", i, tokens[i]);
+        }
+    }
+
+    char* temp = tokens[0];
+    if (strcmp(temp, "NoPAN") == 0)
+    {
+        OC_LOG_V(INFO, TAG, "TelNetworkInfoHandler(): It is NoPan.");
+        ret = TW_RESULT_NO_LOCAL_PAN;
+    }
+    else
+    {
+        OC_LOG_V(INFO, TAG, "TelNetworkInfoHandler(): already have an established network.");
+        ret = AsciiHexToValue(tokens[3], 2, &g_ZigBeeStatus.panId);
+        if(ret != TW_RESULT_OK)
+        {
+            return ret;
+        }
+        ret = AsciiHexToValue(tokens[4], 8, &g_ZigBeeStatus.extPanId);
+        if(ret != TW_RESULT_OK)
+        {
+            return ret;
+        }
+        OC_LOG_V(INFO, TAG,
+                 "TelNetworkInfoHandler(): PanId=%" PRId64 "", g_ZigBeeStatus.panId);
+        OC_LOG_V(INFO, TAG,
+                 "TelNetworkInfoHandler(): ExtPanId=%" PRId64 "", g_ZigBeeStatus.extPanId);
+
+        OC_LOG_V(INFO, TAG, "TelNetworkInfoHandler(): PanId=%s", tokens[3]);
+        OC_LOG_V(INFO, TAG, "TelNetworkInfoHandler(): ExtPanId=%s", tokens[4]);
+
+        OC_LOG_V(INFO, TAG, "TelNetworkInfoHandler set ExtPanId to %08X%08X",
+                 (unsigned int)(g_ZigBeeStatus.extPanId >> 32),
+                 (unsigned int)(g_ZigBeeStatus.extPanId & 0xFFFFFFFF));
+
+        ret = TW_RESULT_HAS_LOCAL_PAN;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelNetworkInfoHandler()");
+    return ret;
+}
+
+TWResultCode TelJpanHandler(int count, char* tokens[])
+{
+    //Ask:        AT+EN:[<channel>],[<POWER>],[<PANID>]
+    //Response:   JPAN:<channel>,<PANID>,<EPANID>
+
+    OC_LOG_V(INFO, TAG, "Enter TelJpanHandler().");
+    if(!tokens || count <= 2)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    ret = AsciiHexToValue(tokens[1], 2, &g_ZigBeeStatus.panId);
+    if(ret != TW_RESULT_OK)
+    {
+        return ret;
+    }
+    ret = AsciiHexToValue(tokens[2], 8, &g_ZigBeeStatus.extPanId);
+    if(ret != TW_RESULT_OK)
+    {
+        return ret;
+    }
+    OC_LOG_V(INFO, TAG, "PanId = %" PRId64 "", g_ZigBeeStatus.panId);
+    OC_LOG_V(INFO, TAG, "ExtPanId = %" PRId64 "", g_ZigBeeStatus.extPanId);
+    ret = TW_RESULT_NEW_LOCAL_PAN_ESTABLISHED;
+
+    OC_LOG_V(INFO, TAG, "Leave TelJpanHandler().");
+    return ret;
+}
+
+TWResultCode TelEndDeviceJoinHandler(int count, char* tokens[])
+{
+    //Ask:      AT+PJOIN
+    //
+    //Prompt:   RFD:<IEEE Address>,<NodeID>
+    //Prompt:   FFD:<IEEE Address>,<NodeID>
+    //Prompt:   SED:<IEEE Address>,<NodeID>
+    //Prompt:   ZED:<IEEE Address>,<NodeID>
+
+    OC_LOG_V(INFO, TAG, "Enter TelEndDeviceJoinHandler().");
+    if(!tokens || count <= 1)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    //TODO: Might need to add into the list if needed - log it for now.
+    OC_LOG_V(INFO, TAG, "Just Joined - EUI:%s; NodeID:%s.", tokens[0], tokens[1]);
+
+    ret = TW_RESULT_OK;
+
+    OC_LOG_V(INFO, TAG, "Leave TelEndDeviceJoinHandler().");
+    return ret;
+}
+
+TWResultCode TelMatchDescHandler(int count, char* tokens[])
+{
+    //Prompt:       MatchDesc:0B4A,00,01
+
+    OC_LOG_V(INFO, TAG, "Enter TelMatchDescHandler().");
+    if(!tokens || count <= 2)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    if (strcmp(tokens[1], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "MatchDesc prompt contained error status.");
+    }
+    else
+    {
+        //Create TWDevice
+        TWDevice* device = (TWDevice*)OICCalloc(1, sizeof(TWDevice));
+        if (device == NULL)
+        {
+            ret = TW_RESULT_ERROR_NO_MEMORY;
+        }
+        else
+        {
+            device->endpointOfInterest = (TWEndpoint*)OICCalloc(1, sizeof(TWEndpoint));
+            if (device->endpointOfInterest == NULL)
+            {
+                OICFree(device);
+                ret = TW_RESULT_ERROR_NO_MEMORY;
+            }
+            else
+            {
+                //OICStrcpy(device->eui, SIZE_EUI, remoteEUI);
+                OICStrcpy(device->nodeId, SIZE_NODEID, tokens[0]);
+                OICStrcpy(device->endpointOfInterest->endpointId, SIZE_ENDPOINTID, tokens[2]);
+
+                if (g_FoundMatchedDeviceList == NULL)
+                {
+                    //Create a list of promptCount entries
+                    g_FoundMatchedDeviceList = (TWDeviceList*)OICMalloc(sizeof(TWDeviceList));
+                    if (g_FoundMatchedDeviceList == NULL)
+                    {
+                        OICFree(device->endpointOfInterest);
+                        OICFree(device);
+                        ret = TW_RESULT_ERROR_NO_MEMORY;
+                    }
+                    else
+                    {
+                        g_FoundMatchedDeviceList->count = 1;
+                        g_FoundMatchedDeviceList->deviceList =
+                                (TWDevice*)OICMalloc(sizeof(TWDevice));
+                        if (g_FoundMatchedDeviceList->deviceList == NULL)
+                        {
+                            OICFree(device->endpointOfInterest);
+                            OICFree(device);
+                            ret = TW_RESULT_ERROR_NO_MEMORY;
+                        }
+                        else
+                        {
+                            memcpy(g_FoundMatchedDeviceList->deviceList,
+                                   device,
+                                   sizeof(TWDevice));
+                            ret = TW_RESULT_OK;
+                        }
+                    }
+                }
+                else
+                {
+                    //Expand the list
+                    int newSize = sizeof(TWDevice) * (g_FoundMatchedDeviceList->count + 1);
+                    TWDevice* temp = (TWDevice*)realloc(g_FoundMatchedDeviceList->deviceList,
+                                                        newSize);
+                    if (temp == NULL)
+                    {
+                        OICFree(device->endpointOfInterest);
+                        OICFree(device);
+                        ret =TW_RESULT_ERROR_NO_MEMORY;
+                    }
+                    else
+                    {
+                        g_FoundMatchedDeviceList->deviceList = temp;
+
+                        //Add to the end of list
+                        int count = g_FoundMatchedDeviceList->count;
+                        memcpy(&g_FoundMatchedDeviceList->deviceList[count],
+                               device,
+                               sizeof(TWDevice));
+
+                        //Increase the count
+                        g_FoundMatchedDeviceList->count++;
+
+                        ret = TW_RESULT_OK;
+                    }
+                }
+            }
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelMatchDescHandler().");
+    return ret;
+}
+
+TWResultCode TelSimpleDescHandler(int count, char* tokens[])
+{
+    //AT+SIMPLEDESC:3746,3746,01
+    //      SEQ:97
+    //      OK
+    //
+    //      SimpleDesc:3746,00              <<<<<<<---------------------
+    //      EP:01
+    //      ProfileID:0104
+    //      DeviceID:0402v00
+    //      InCluster:0000,0001,0003,0402,0500,0020,0B05
+    //      OutCluster:0019
+    //      ACK:97
+
+    OC_LOG_V(INFO, TAG, "Enter TelSimpleDescHandler().");
+    if(!tokens || count <= 1)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    if (strcmp(tokens[1], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "SimpleDesc: prompt contained error status %s.", tokens[1]);
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        if (strcmp(tokens[0], g_WIPDevice->nodeId) == 0)
+        {
+            OC_LOG_V(INFO, TAG, "Got simple descriptor for nodeid %s", tokens[0]);
+            ret = TW_RESULT_OK;
+        }
+        else
+        {
+            OC_LOG_V(ERROR, TAG,
+                     "Finding simple descriptor for non existing nodeid %s.", tokens[0]);
+            ret = TW_RESULT_ERROR;
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelSimpleDescHandler().");
+    return ret;
+}
+
+TWResultCode TelSimpleDescInClusterHandler(int count, char* tokens[])
+{
+    //AT+SIMPLEDESC:3746,3746,01
+    //      SEQ:97
+    //      OK
+    //
+    //      SimpleDesc:3746,00
+    //      EP:01
+    //      ProfileID:0104
+    //      DeviceID:0402v00
+    //      InCluster:0000,0001,0003,0402,0500,0020,0B05        <<<<<<<<--------------
+    //      OutCluster:0019
+    //      ACK:97
+
+    OC_LOG_V(INFO, TAG, "Enter TelSimpleDescInClusterHandler().");
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    //Add found clusters for the node.
+    if (g_WIPDevice->endpointOfInterest->clusterList == NULL)
+    {
+        g_WIPDevice->endpointOfInterest->clusterList =
+                (TWClusterList*)OICCalloc(sizeof(TWClusterList), 1);
+        if (g_WIPDevice->endpointOfInterest->clusterList == NULL)
+        {
+            ret = TW_RESULT_ERROR_NO_MEMORY;
+        }
+        else
+        {
+            g_WIPDevice->endpointOfInterest->clusterList->clusterIds =
+                    (TWClusterId*)OICCalloc(sizeof(TWClusterId) * count, 1);
+            if (g_WIPDevice->endpointOfInterest->clusterList->clusterIds == NULL)
+            {
+                OICFree(g_WIPDevice->endpointOfInterest->clusterList);
+                ret = TW_RESULT_ERROR_NO_MEMORY;
+            }
+            else
+            {
+                int i = 0;
+                for (; i < count; i++)
+                {
+                    OICStrcpy(g_WIPDevice->endpointOfInterest->clusterList->
+                                clusterIds[i].clusterId,
+                                SIZE_CLUSTERID,
+                                tokens[i]);
+
+                    OC_LOG_V(INFO, TAG, "ClusterIds[%d]=%s",
+                             i,
+                             g_WIPDevice->endpointOfInterest->
+                             clusterList->clusterIds[i].clusterId);
+                }
+                g_WIPDevice->endpointOfInterest->clusterList->count = count;
+                ret = TW_RESULT_OK;
+            }
+        }
+    }
+    else
+    {
+        OC_LOG_V(ERROR, TAG, "Expected an empty cluster list.");
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelSimpleDescInClusterHandler().");
+    return ret;
+}
+
+TWResultCode TelWriteAttrHandler(int count, char* tokens[])
+{
+    //AT+WRITEATR:3A3D,01,0,0003,0000,21,00
+    //      OK
+    //      WRITEATTR:3A3D,01,0003,,00
+
+    OC_LOG_V(INFO, TAG, "Enter TelWriteAttrHandler().");
+    if(!tokens || count <= 3)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    if (strcmp(tokens[3], AT_STR_ERROR_OK) == 0)
+    {
+        ret = TW_RESULT_OK;
+    }
+    else
+    {
+        ret = TW_RESULT_ERROR;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelWriteAttrHandler().");
+    return ret;
+}
+
+TWResultCode TelReadAttrHandlerTemperature(int count, char* tokens[])
+{
+    //AT+READATR:F2D7,01,0,0402,0002
+    //      OK
+    //      TEMPERATURE:F2D7,01,0002,00,1770
+    //
+    //AT+READATR:F2D7,01,0,0402,0002
+    //      OK
+    //      ERROR:66
+
+    OC_LOG_V(INFO, TAG, "Enter TelReadAttrHandlerTemperature().");
+    if(!tokens || count <= 4)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    if (strcmp(tokens[3], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "TEMPERATURE prompt contained error status.");
+    }
+    else
+    {
+        // AttrInfo is 16-bit value representing (100 * Degrees Celsius)
+        // so 0x812 = 20.66 C = 69.188 F
+        if (g_ZigBeeStatus.remoteAttributeValueRead != NULL)
+        {
+            OICFree(g_ZigBeeStatus.remoteAttributeValueRead);
+        }
+        OC_LOG_V(INFO, TAG, "Read Attribute Value: %s.", tokens[4]);
+        g_ZigBeeStatus.remoteAttributeValueRead =
+                (char*)OICMalloc(sizeof(char) * strlen(tokens[4]));
+        if (g_ZigBeeStatus.remoteAttributeValueRead == NULL)
+        {
+            ret = TW_RESULT_ERROR_NO_MEMORY;
+        }
+        else
+        {
+            strcpy(g_ZigBeeStatus.remoteAttributeValueRead, tokens[4]);
+            g_ZigBeeStatus.remoteAtrributeValueReadLength = strlen(tokens[4]);
+            ret = TW_RESULT_REMOTE_ATTR_HAS_VALUE;
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelReadAttrHandlerTemperature().");
+
+    return ret;
+}
+
+TWResultCode TelReadAttrHandler(int count, char* tokens[])
+{
+    //AT+READATR:F2D7,01,0,0402,0002
+    //      OK
+    //      RESPATTR:<NodeID>,<EP>,<ClusterID>,<AttrID>,<Status>,<AttrInfo>
+    //
+    //AT+READATR:F2D7,01,0,0402,0002
+    //      OK
+    //      ERROR:66
+
+    OC_LOG_V(INFO, TAG, "Enter TelReadAttrHandler().");
+    if(!tokens || count <= 5)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    if (strcmp(tokens[4], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "READATTR prompt contained error status.");
+    }
+    else
+    {
+        if (g_ZigBeeStatus.remoteAttributeValueRead != NULL)
+        {
+            OICFree(g_ZigBeeStatus.remoteAttributeValueRead);
+        }
+        OC_LOG_V(INFO, TAG, "Read Attribute Value: %s.", tokens[5]);
+        g_ZigBeeStatus.remoteAttributeValueRead =
+                (char*)OICMalloc(sizeof(char) * strlen(tokens[5]));
+        if (g_ZigBeeStatus.remoteAttributeValueRead != NULL)
+        {
+            strcpy(g_ZigBeeStatus.remoteAttributeValueRead, tokens[5]);
+            g_ZigBeeStatus.remoteAtrributeValueReadLength = strlen(tokens[5]);
+            ret = TW_RESULT_REMOTE_ATTR_HAS_VALUE;
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelReadAttrHandler().");
+
+    return ret;
+}
+
+TWResultCode TelZCLDefaultResponseHandler(int count, char* tokens[])
+{
+    //AT+RONOFF:<Address>,<EP>,<SendMode>[,<ON/OFF>]
+    //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
+    //
+    //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
+    //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
+    //
+    //AT+LCMVTOLEV:<Address>,<EP>,<SendMode>,<ON/OFF>,<LevelValue>,<TransTime>
+    //      DFTREP:<NodeID>,<EP>,<ClusterID>,<CMD>,<Status>
+
+    OC_LOG_V(INFO, TAG, "Enter TelZCLDefaultResponseHandler().");
+    if(!tokens || count <= 4)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+
+    OC_LOG_V(INFO, TAG,
+             "DFTREP prompt succeed for NodeId:%s, EP:%s, ClusterId:%s, CMD:%s.",
+             tokens[0], tokens[1], tokens[2], tokens[3]);
+
+    if (strcmp(tokens[4], AT_STR_ERROR_OK) != 0)
+    {
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        ret = TW_RESULT_OK;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelZCLDefaultResponseHandler().");
+
+    return ret;
+}
+
+TWResultCode TelSwitchDoorLockStateHandler(int count, char* tokens[])
+{
+    //AT+DRLOCK:<Address>,<EP>,<SendMode>,<Lock/Unlock>
+    //      DRLOCRSP:<nodeID>,<ep>,<status>
+    //      or
+    //      DRUNLOCKRSP:<nodeID>,<ep>,<status>
+
+    OC_LOG_V(INFO, TAG, "Enter TelSwitchDoorLockStateHandler().");
+    if(!tokens || count <= 4)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_UNKNOWN;
+    if (strcmp(tokens[2], AT_STR_ERROR_OK) != 0)
+    {
+        OC_LOG_V(ERROR, TAG,
+                 "DRLOCRSP/DRUNLOCKRSP prompt contained error status %s.", tokens[4]);
+        ret = TW_RESULT_ERROR;
+    }
+    else
+    {
+        OC_LOG_V(INFO, TAG, "DRLOCRSP/DRUNLOCKRSP prompt succeed for nodeId:%s, ep:%s.",
+                 tokens[0], tokens[1]);
+        ret = TW_RESULT_OK;
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelSwitchDoorLockStateHandler().");
+
+    return ret;
+}
+
+TWResultCode TelZoneEnrollRequestHandler(int count, char* tokens[])
+{
+    //ZENROLLREQ:<NodeID>,<EndPoint>,<ZoneType>,<ManufactureCode>
+
+    OC_LOG_V(INFO, TAG, "Enter TelZoneEnrollRequestHandler().");
+    if(!tokens || count <= 3)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_OK;
+
+    OC_LOG_V(INFO, TAG, "Received zone request from:");
+    OC_LOG_V(INFO, TAG, "Node:%s", tokens[0]);
+    OC_LOG_V(INFO, TAG, "EP:%s", tokens[1]);
+    OC_LOG_V(INFO, TAG, "ZoneType:%s", tokens[2]);
+    OC_LOG_V(INFO, TAG, "ManufactureCode:%s", tokens[3]);
+
+    OC_LOG_V(INFO, TAG, "Leave TelZoneEnrollRequestHandler().");
+
+    return ret;
+
+}
+
+TWResultCode TelEnrolledHandler(int count, char* tokens[])
+{
+    //ENROLLED:<ZID>,<ZoneType>,<EUI>
+
+    OC_LOG_V(INFO, TAG, "Enter TelEnrolledHandler().");
+    if(!tokens || count <= 2)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    (void)count;
+
+    TWResultCode ret = TW_RESULT_OK;
+
+    OC_LOG_V(INFO, TAG, "Received zone request from:");
+    OC_LOG_V(INFO, TAG, "ZID:%s", tokens[0]);
+    OC_LOG_V(INFO, TAG, "ZoneType:%s", tokens[1]);
+    OC_LOG_V(INFO, TAG, "EUI:%s", tokens[2]);
+
+    TWEnrollee enrollee;
+    OICStrcpy(enrollee.zoneId, SIZE_ZONEID, tokens[0]);
+    OICStrcpy(enrollee.zoneType, SIZE_ZONETYPE, tokens[1]);
+    OICStrcpy(enrollee.eui, SIZE_EUI, tokens[2]);
+
+    if (g_EnrollmentSucceedCallback != NULL)
+    {
+        g_EnrollmentSucceedCallback(&enrollee);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelEnrolledHandler().");
+
+    return ret;
+}
+
+TWResultCode TelZoneStatusHandler(int count, char* tokens[])
+{
+    //ZONESTATUS:<NodeID>,<EP>,<ZoneStatus>,<ExtendStatus>[,<ZoneID>,<Delay>]
+    //ZONESTATUS:5FBA,01,0021,00,01,00AF
+
+    OC_LOG_V(INFO, TAG, "Enter TelZoneStatusHandler().");
+    if(!tokens || count <= 3)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    TWResultCode ret = TW_RESULT_OK;
+
+    TWUpdate update;
+    OICStrcpy(update.nodeId, SIZE_NODEID, tokens[0]);
+    OICStrcpy(update.endpoint, SIZE_NODEID, tokens[1]);
+    OICStrcpy(update.status, SIZE_NODEID, tokens[2]);
+    OICStrcpy(update.extendedStatus, SIZE_NODEID, tokens[3]);
+
+    if (count == 6)
+    {
+        OICStrcpy(update.zoneId, SIZE_NODEID, tokens[4]);
+        OICStrcpy(update.delay, SIZE_NODEID, tokens[5]);
+    }
+
+    if (g_DeviceStatusUpdateCallback != NULL)
+    {
+        g_DeviceStatusUpdateCallback(&update);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave TelZoneStatusHandler().");
+
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+// Internal functions - Helpers
+//-----------------------------------------------------------------------------
+
+/**
+ *
+ * Tokenize 'input' parameter by 'delimiters' into 'output' array.
+ *
+ */
+int Tokenize(const char *input, const char* delimiters, char* output[])
+{
+    OC_LOG_V(INFO, TAG, "Enter Tokenize()");
+
+    if (output == NULL)
+    {
+        OC_LOG_V(INFO, TAG, "Invalid parameter.");
+        return -1;
+    }
+
+    int length = strlen(input);
+    char * str = (char *) OICCalloc(1, length + 1);
+    OICStrcpy(str, length+1, input);
+
+    char* savePtr = NULL;
+    char* p   = strtok_r(str, delimiters, &savePtr);
+    int index = 0;
+    while (p && index <= ARRAY_LENGTH)
+    {
+        int size = strlen(p) + 1;   //for null char
+        output[index] = (char*)OICCalloc(size, sizeof(char));
+        OICStrcpy(output[index], size, p);
+
+        p = strtok_r (NULL, delimiters, &savePtr);
+        index++;
+    }
+
+    OICFree(str);
+    OC_LOG_V(INFO, TAG, "Leave Tokenize()");
+    return index;
+}
+
+int AsciiToHex(char c)
+{
+    int num = (int) c;
+    if(c >= '0' && c <= '9')
+    {
+        return num - '0';
+    }
+
+    if(num >= 'A' && num <= 'F')
+    {
+        return num - 'A' + 10;
+    }
+    return -1;
+}
+
+TWResultCode AsciiHexToValue(char* hexString, int length, uint64_t* value)
+{
+    if(!hexString || !value || length < 0)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    int retVal = AsciiToHex(hexString[0]);
+    if(retVal == -1)
+    {
+        OC_LOG(ERROR, TAG, "Bad conversion from ASCII To Hex.");
+        return TW_RESULT_ERROR;
+    }
+    *value = (uint64_t)retVal;
+    for (int i = 1; i < length*2; ++i)
+    {
+        if (sizeof(hexString) > (uint32_t)i)
+        {
+            *value <<= 4;
+            retVal = AsciiToHex(hexString[i]);
+            if(retVal == -1)
+            {
+                OC_LOG(ERROR, TAG, "Bad conversion from ASCII To Hex.");
+                return TW_RESULT_ERROR;
+            }
+            *value |= (uint64_t)retVal;
+        }
+    }
+    return TW_RESULT_OK;
+}
+
+/**
+ *
+ * Apply interface attribute values to terminal settings.
+ *
+ */
+int SetInterfaceAttribs(int fd, int speed, int parity)
+{
+    struct termios tty;
+    memset (&tty, 0, sizeof tty);
+    if (tcgetattr (fd, &tty) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "SetInterfaceAttribs: Error %d from tcgetattr", errno);
+        return -1;
+    }
+
+    cfsetospeed (&tty, speed);
+    cfsetispeed (&tty, speed);
+
+    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
+    // disable IGNBRK for mismatched speed tests;
+    //otherwise receive break as \000 chars
+    tty.c_iflag &= ~IGNBRK;         // disable break processing
+    tty.c_lflag = 0;                // no signaling chars, no echo,
+                                    // no canonical processing
+    tty.c_oflag = 0;                // no re-mapping, no delays
+    tty.c_cc[VMIN]  = 0;            // read doesn't block
+    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout
+
+    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
+
+    tty.c_cflag |= (CLOCAL | CREAD);    // ignore modem controls, enable reading
+    tty.c_cflag &= ~(PARENB | PARODD);  // shut off parity
+    tty.c_cflag |= parity;
+    tty.c_cflag &= ~CSTOPB;
+    tty.c_cflag &= ~CRTSCTS;
+
+    if (tcsetattr (fd, TCSANOW, &tty) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "SetInterfaceAttribs: Error %d from tcsetattr", errno);
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ *
+ * Apply blocking value to terminal settings.
+ *
+ */
+void SetBlocking (int fd, int should_block)
+{
+    struct termios tty;
+    memset (&tty, 0, sizeof tty);
+    if (tcgetattr (fd, &tty) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "SetBlocking: Error %d from tcgetattr", errno);
+        return;
+    }
+
+    tty.c_cc[VMIN]  = should_block ? 1 : 0;
+    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout
+
+    if (tcsetattr (fd, TCSANOW, &tty) != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "SetBlocking: Error %d setting terminal attributes", errno);
+    }
+}
+
+/**
+ *
+ * Issues an AT Command to the Telegesis Dongle. Waits for response unless
+ * a timeout is specified. Blocks until operation is completed. Responses are
+ * in placed responseArray, while prompts are placed in promptArray.
+ *
+ * @param[out] atErrorCode The AT Error code received as Hex. 0 on success,
+ *                       otherwise refer to Telegesis manual.
+ * @param[out] responseArray Array corresponding to response lines received in
+ *                           the buffer during a write/read. (ie. A synchronous
+ *                           AT result.)
+ * @param[out] promptArray Array corresponding to prompt lines received in
+ *                         the buffer post write/read. (ie. An asynchronous AT
+ *                         result.)
+ * @param[out] responseCount The number of responses in the response array.
+ * @param[out] promptCount The number of prompts in the prompt array.
+ * @param[in] command The AT Command you wish to issue.
+ * @param[in] timeout The allotted time (seconds) you expect the AT Command's
+ *                    prompt results to reach the buffer.
+ *
+ */
+TWResultCode IssueATCommand(const char * command,
+                            uint8_t timeout,
+                            uint64_t * atErrorCode,
+                            char * responseArray[],
+                            char * promptArray[],
+                            uint8_t * responseCount,
+                            uint8_t * promptCount)
+{
+    TWResultCode ret = TW_RESULT_ERROR;
+
+    ret = WriteBuffer(command);
+    if(ret != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "Failed to write to buffer with result: %d", ret);
+        return ret;
+    }
+
+    ret = ReadBuffer(atErrorCode,
+                     responseArray,
+                     responseCount,
+                     command,
+                     0);
+    if(ret != TW_RESULT_OK)
+    {
+        OC_LOG_V(ERROR, TAG, "Failed to read from buffer with result: %d", ret);
+        return ret;
+    }
+    if(timeout != 0)
+    {
+        sleep(timeout);
+        ret = ReadBuffer(atErrorCode,
+                         promptArray,
+                         promptCount,
+                         NULL,
+                         timeout);
+        if(ret != TW_RESULT_OK)
+        {
+            OC_LOG_V(ERROR, TAG, "Failed to read from buffer with result: %d", ret);
+            return ret;
+        }
+    }
+    return ret;
+}
+
+/**
+ *
+ * Returns file descriptor by reference based on the global comPort specified
+ * at the top of this file.
+ *
+ * @param[out] fd The file descriptor associated with the comport specified.
+ *
+ */
+TWResultCode OpenPort(int * fd)
+{
+    if(g_port == NULL)
+    {
+        OC_LOG_V(ERROR, TAG, "No port specified.");
+        return TW_RESULT_ERROR_INVALID_PORT;
+    }
+    if(!fd)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    int tw_fd = open(g_port, O_RDWR | O_NOCTTY | O_SYNC);
+    *fd = tw_fd;
+    if(tw_fd <= 0)
+    {
+        OC_LOG_V(ERROR, TAG, "Could not open port. Errno is: %d", errno);
+        return TW_RESULT_ERROR;
+    }
+
+    SetInterfaceAttribs(tw_fd, DEVICE_BAUDRATE, 0); // set speed to 19,200 bps, 8n1 (no parity)
+    SetBlocking(tw_fd, 0); // set no blocking
+
+    return TW_RESULT_OK;
+}
+
+/**
+ *
+ * Closes port based on the specified file descriptor.
+ *
+ *  Returns TW_RESULT_OK on success.
+ *
+ * @param[in] The file descriptor to be closed.
+ *
+ */
+TWResultCode ClosePort(int fd)
+{
+    int ret = close(fd);
+    if(ret != 0)
+    {
+        OC_LOG_V(ERROR, TAG, "Could not close port. Errno is: %d", errno);
+        return TW_RESULT_ERROR;
+    }
+    return TW_RESULT_OK;
+}
+
+bool IsThisAValidLine(char * singleLine, bool * endControlHit, uint64_t * atErrorCode)
+{
+    if(!singleLine || !endControlHit || !atErrorCode)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    size_t singleLineSize = strlen(singleLine);
+    int i = 0;
+    size_t endStrSize = 0;
+    size_t strSize = 0;
+    TWResultCode ret = TW_RESULT_ERROR;
+    for(; i<TW_ENDCONTROL_MAX_VALUE; i++)
+    {
+        endStrSize = strlen(g_TWEndMessageMap[i].endStr);
+        strSize = singleLineSize >= endStrSize ? endStrSize : singleLineSize;
+        // Found a single EndControl string.
+        if (strncmp(singleLine, g_TWEndMessageMap[i].endStr, strSize) == 0)
+        {
+            //endControlHit = true;
+            if (g_TWEndMessageMap[i].endControl == TW_ENDCONTROL_OK)
+            {
+               *atErrorCode = 0x0000;
+               *endControlHit = true;
+            }
+            else if (g_TWEndMessageMap[i].endControl == TW_ENDCONTROL_ERROR)
+            {
+                ret = AsciiHexToValue(&singleLine[strSize],
+                                      strlen(&singleLine[strSize])-1,
+                                      atErrorCode);
+                if(ret != TW_RESULT_OK)
+                {
+                    return false;
+                }
+                *endControlHit = true;
+            }
+            else if (g_TWEndMessageMap[i].endControl == TW_ENDCONTROL_SEQ)
+            {
+                //endControlHit = false;
+            }
+            else if (g_TWEndMessageMap[i].endControl == TW_ENDCONTROL_ACK)
+            {
+                //endControlHit = false;
+            }
+            return false;
+            //break;
+        }
+    }
+    return true;
+
+}
+
+char * myStrTok(char* readData, const char* tokens, bool * endControlHit,
+                 uint64_t * atErrorCode, char ** savePtr)
+{
+    if(!tokens || !endControlHit || !atErrorCode || !savePtr)
+    {
+        return NULL;
+    }
+    char * buf = strtok_r(readData, tokens, savePtr);
+    if(!buf)
+    {
+        return NULL;
+    }
+    bool valid = false;
+    valid = IsThisAValidLine(buf, endControlHit, atErrorCode);
+    if(valid == true)
+    {
+        return buf;
+    }
+    else
+    {
+        return myStrTok(NULL, tokens, endControlHit, atErrorCode, savePtr);
+    }
+}
+
+/**
+ *
+ * Reads an entire buffer, parses the buffer into individual lines, and places
+ * these individual lines into the response array.
+ *
+ * The original command echo'd back is ignored. Any endControl items are also
+ * ignored.
+ *
+ * If a timeout is specified greater than zero, it means you expect prompts in
+ * the buffer.
+ *
+ * @param[out] atErrorCode The AT Error code received as Hex. 0 on success,
+ *                       otherwise refer to Telegesis manual.
+ * @param[out] responseArray Each individual line from read() is placed in this
+                             array.
+ * @param[out] count The number of items in the response array.
+ * @param[in] command The AT command that was already issued. Used to ignore
+ *                    when it is echo'd back in the read buffer.
+ * @param[in] timeout If not zero, it is used as a flag to determine if
+ *                    blocking on read() should occur.
+ *
+ */
+TWResultCode ReadBuffer(uint64_t * atErrorCode,
+                        char * responseArray[],
+                        uint8_t * count,
+                        const char * command,
+                        uint8_t timeout)
+{
+
+    TWResultCode ret = TW_RESULT_OK;
+    char readData[1000] = {};
+    char itrData[200] = {};
+
+    ssize_t readDataBytes = 0;
+    ssize_t itrDataBytes = 0;
+    bool endControlHit = false;
+    uint8_t responseArrayPos = 0;
+    while(itrDataBytes == 0)
+    {
+        itrDataBytes += read(g_fd, itrData, sizeof(itrData)-1);
+        if(itrDataBytes < 0)
+        {
+            OC_LOG_V(ERROR, TAG, "Could not read from port. Errno is: %d", errno);
+            return TW_RESULT_ERROR;
+        }
+
+        if(command)
+        {
+            size_t itrDataIndexLength = (strlen(itrData) - 1);
+            if(strncmp(itrData, command, strlen(command)) == 0 &&
+               itrData[itrDataIndexLength] == '\r')
+            {
+                memset(itrData, 0, sizeof(itrData));
+                itrDataBytes = 0; // Ignore any single line which only echo'd
+                                  // the command. This allows us to block on read().
+            }
+        }
+        if(itrDataBytes > 0 &&
+           readDataBytes < (ssize_t)sizeof(readData) &&
+           (readDataBytes + itrDataBytes) <= (ssize_t)sizeof(readData))
+        {
+            readDataBytes += itrDataBytes;
+            OICStrcat(readData, sizeof(readData), itrData);
+            if(itrDataBytes == sizeof(itrData))
+            {
+reread:
+                memset(itrData, 0, sizeof(itrData));
+                itrDataBytes = 0;
+            }
+        }
+
+        if(timeout != 0)
+        {
+            break; // Don't block on read as there are no prompts waiting in the buffer.
+        }
+    }
+    if(readDataBytes > 0)
+    {
+        char * savePtr = NULL;
+        char * singleLine = myStrTok(readData, "\r\n", &endControlHit, atErrorCode, &savePtr);
+        while(singleLine)
+        {
+            // Stop on endControl items. Also leave function when an endControl is found.
+            //singleLine = myStrTok(NULL, "\r", &endControlHit, atErrorCode, &savePtr);
+            if(singleLine)
+            {
+                // Ignore the echo'd command line if it was passed in.
+                if(!command || (command && strcmp(singleLine, command) != 0))
+                {
+                    responseArray[responseArrayPos] = (char *) OICMalloc((strlen(singleLine)+1) *
+                                                      sizeof(char));
+                    if(!responseArray[responseArrayPos])
+                    {
+                        return TW_RESULT_ERROR_NO_MEMORY;
+                    }
+                    memset(responseArray[responseArrayPos],
+                           0,
+                           (strlen(singleLine)+1) * sizeof(char));
+                    strcpy(responseArray[responseArrayPos], singleLine);
+                    responseArrayPos++;
+                }
+                singleLine = myStrTok(NULL, "\r\n", &endControlHit, atErrorCode, &savePtr);
+            }
+        }
+        *count = responseArrayPos;
+    }
+    if(endControlHit == false && timeout == 0)
+    {
+       memset(readData, 0, sizeof(readData));
+       readDataBytes = 0;
+       goto reread;
+    }
+    return ret;
+}
+
+/**
+ *
+ * Writes AT command to buffer.
+ *
+ * @param[in] command The command to be written to the buffer.
+ *
+ */
+TWResultCode WriteBuffer(const char * command)
+{
+    TWResultCode ret = TW_RESULT_OK;
+
+    if(!command)
+    {
+        return TW_RESULT_ERROR_INVALID_PARAMS;
+    }
+    size_t sendCommandSize = (strlen(command) + 2) * sizeof(char);
+    char * sendCommand = (char *) OICMalloc(sendCommandSize);
+    if(!sendCommand)
+    {
+        return TW_RESULT_ERROR_NO_MEMORY;
+    }
+    memset(sendCommand, 0, sendCommandSize);
+    sprintf(sendCommand, "%s\r", command);
+    size_t expectedWrittenBytes = strlen(sendCommand);
+    size_t actualWrittenBytes = write(g_fd, sendCommand, expectedWrittenBytes);
+    if(actualWrittenBytes <= 0)
+    {
+        OC_LOG_V(ERROR, TAG, "Could not write to port. Errno is: %d", errno);
+        ret =  TW_RESULT_ERROR;
+        goto exit;
+    }
+    if(actualWrittenBytes != expectedWrittenBytes)
+    {
+        ret = TW_RESULT_ERROR;
+        goto exit;
+    }
+
+exit:
+    OICFree(sendCommand);
+    return ret;
+}
+
+/**
+ *
+ * Deallocate items in the given arrays.
+ *
+ */
+void CleanArray(char* responseArray[], char* promptArray[],
+                uint8_t responseCount, uint8_t promptCount)
+{
+    OC_LOG_V(INFO, TAG, "Enter CleanArray().");
+
+    if(responseCount > ARRAY_LENGTH || promptCount > ARRAY_LENGTH)
+    {
+        OC_LOG_V(ERROR, TAG, "Trying to access arrays out of bounds.");
+        return;
+    }
+
+    OC_LOG_V(INFO, TAG, "Attempt to free responseArray and promptArray.");
+    int i = 0;
+    if (responseArray)
+    {
+        for (; i < responseCount; i++)
+        {
+            OC_LOG_V(INFO, TAG, "Free responseArray[%d]: %s", i, responseArray[i]);
+            OICFree(responseArray[i]);
+        }
+    }
+
+    if (promptArray)
+    {
+        i = 0;
+        for (; i < promptCount; i++)
+        {
+            OC_LOG_V(INFO, TAG, "Free promptArray[%d]: %s", i, promptArray[i]);
+            OICFree(promptArray[i]);
+        }
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave CleanArray().");
+}
+
+/**
+ *
+ * Print the given arrays.
+ *
+ */
+void PrintArray(char* responseArray[], char* promptArray[],
+                uint8_t responseCount, uint8_t promptCount)
+{
+    OC_LOG_V(INFO, TAG, "Enter PrintArray().");
+
+    if(responseCount > ARRAY_LENGTH || promptCount > ARRAY_LENGTH)
+    {
+        OC_LOG_V(ERROR, TAG, "Trying to access arrays out of bounds.");
+        return;
+    }
+
+    int n = 0;
+    OC_LOG_V(INFO, TAG, "responseCount=%d", responseCount);
+    for (; n < responseCount; n++)
+    {
+        OC_LOG_V(INFO, TAG, "responseArray[%d]=%s", n, responseArray[n]);
+    }
+
+    OC_LOG_V(INFO, TAG, "promptCount=%d", promptCount);
+    for (n = 0; n < promptCount; n++)
+    {
+        OC_LOG_V(INFO, TAG, "promptArray[%d]=%s", n, promptArray[n]);
+    }
+
+    OC_LOG_V(INFO, TAG, "Leave PrintArray().");
+}
+
+
+/**
+ *
+ * Print the given device.
+ *
+ */
+void PrintTWDevice(TWDevice* device)
+{
+    if (device != NULL)
+    {
+        OC_LOG_V(INFO, TAG, "Device - NodeID=%s", device->nodeId);
+        OC_LOG_V(INFO, TAG, "Device - EPID=%s", device->endpointOfInterest->endpointId);
+    }
+    else
+    {
+        OC_LOG_V(ERROR, TAG, "Received a NULL device - CAN'T PRINT IT.");
+    }
+}
+
+/**
+ *
+ * Print the given device list.
+ *
+ */
+void PrintTWDeviceList(TWDeviceList* list)
+{
+    int i = 0;
+    for (; i < list->count; i++)
+    {
+        PrintTWDevice(&list->deviceList[i]);
+    }
+}
+
+/**
+ *
+ * Deallocate device list.
+ *
+ */
+void DeallocateTWDeviceList()
+{
+    if (g_FoundMatchedDeviceList == NULL)
+    {
+        return;
+    }
+
+    if (g_FoundMatchedDeviceList->deviceList == NULL)
+    {
+        OICFree(g_FoundMatchedDeviceList);
+        g_FoundMatchedDeviceList = NULL;
+        return;
+    }
+
+    if (g_FoundMatchedDeviceList->deviceList->endpointOfInterest == NULL)
+    {
+        OICFree(g_FoundMatchedDeviceList->deviceList);
+        g_FoundMatchedDeviceList->deviceList = NULL;
+
+        OICFree(g_FoundMatchedDeviceList);
+        g_FoundMatchedDeviceList = NULL;
+        return;
+    }
+
+    if (g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList == NULL)
+    {
+        OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
+        g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
+
+        OICFree(g_FoundMatchedDeviceList->deviceList);
+        g_FoundMatchedDeviceList->deviceList = NULL;
+
+        OICFree(g_FoundMatchedDeviceList);
+        g_FoundMatchedDeviceList = NULL;
+        return;
+    }
+
+    if (g_FoundMatchedDeviceList->deviceList->endpointOfInterest-> clusterList->clusterIds == NULL)
+    {
+        OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList);
+        g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList = NULL;
+
+        OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
+        g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
+
+        OICFree(g_FoundMatchedDeviceList->deviceList);
+        g_FoundMatchedDeviceList->deviceList = NULL;
+
+        OICFree(g_FoundMatchedDeviceList);
+        g_FoundMatchedDeviceList = NULL;
+        return;
+    }
+
+    OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest-> clusterList->clusterIds);
+    g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList->clusterIds = NULL;
+
+    OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList);
+    g_FoundMatchedDeviceList->deviceList->endpointOfInterest->clusterList = NULL;
+
+    OICFree(g_FoundMatchedDeviceList->deviceList->endpointOfInterest);
+    g_FoundMatchedDeviceList->deviceList->endpointOfInterest = NULL;
+
+    OICFree(g_FoundMatchedDeviceList->deviceList);
+    g_FoundMatchedDeviceList->deviceList = NULL;
+
+    OICFree(g_FoundMatchedDeviceList);
+    g_FoundMatchedDeviceList = NULL;
+}
index 8e21e33..b75147d 100644 (file)
@@ -132,7 +132,7 @@ static void osalGetTime(int *min,int *sec, int *ms)
     if (min && sec && ms)
     {
 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
-        struct timespec when = {0};
+        struct timespec when = { .tv_sec = 0 };
         clockid_t clk = CLOCK_REALTIME;
 #ifdef CLOCK_REALTIME_COARSE
         clk = CLOCK_REALTIME_COARSE;