Update snapshot(2017-12-14)
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / tizen / caleclient.c
index 1666724..a829960 100644 (file)
 #include <pthread.h>
 #include <gio/gio.h>
 
-#include "camutex.h"
+#include "octhread.h"
 #include "uarraylist.h"
 #include "caqueueingthread.h"
 #include "caadapterutils.h"
-#include "cafragmentation.h"
 #include "cagattservice.h"
 #include "oic_string.h"
 #include "oic_malloc.h"
@@ -45,6 +44,7 @@
 #define TAG "OIC_CA_LE_CLIENT"
 
 #define MICROSECS_PER_SEC 1000000
+#define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC
 
 uint64_t const TIMEOUT = 30 * MICROSECS_PER_SEC;
 
@@ -61,7 +61,7 @@ static u_arraylist_t *g_multicastDataList = NULL;
 /**
  * Mutex to synchronize the access to Pending multicast data list.
  */
-static ca_mutex g_multicastDataListMutex = NULL;
+static oc_mutex g_multicastDataListMutex = NULL;
 
 /**
  * List of devices discovered.
@@ -71,17 +71,17 @@ static u_arraylist_t *g_deviceDiscoveredList = NULL;
 /**
  * Mutex to synchronize the access to discovered devices list.
  */
-static ca_mutex g_deviceDiscoveredListMutex = NULL;
+static oc_mutex g_deviceDiscoveredListMutex = NULL;
 
 /**
  * Condition to start the timer for scanning.
  */
-static ca_cond g_startTimerCond = NULL;
+static oc_cond g_startTimerCond = NULL;
 
 /**
  * Condition for scanning Time interval.
  */
-static ca_cond g_scanningTimeCond = NULL;
+static oc_cond g_scanningTimeCond = NULL;
 
 /**
  * This contains the list of OIC services a client connect tot.
@@ -91,7 +91,7 @@ static LEServerInfoList *g_LEServerList = NULL;
 /**
  * Mutex to synchronize access to BleServiceList.
  */
-static ca_mutex g_LEServerListMutex = NULL;
+static oc_mutex g_LEServerListMutex = NULL;
 
 /**
  * Boolean variable to keep the state of the GATT Client.
@@ -102,24 +102,39 @@ static bool g_isLEGattClientStarted = false;
  * Mutex to synchronize access to the requestResponse callback to be called
  * when the data needs to be sent from GATTClient.
  */
-static ca_mutex g_LEReqRespClientCbMutex = NULL;
+static oc_mutex g_LEReqRespClientCbMutex = NULL;
 
 /**
  * Mutex to synchronize access to the requestResponse callback to be called
  * when the data needs to be sent from GATTClient.
  */
-static ca_mutex g_LEClientConnectMutex = NULL;
+static oc_mutex g_LEClientConnectMutex = NULL;
 
 /**
  * Mutex to synchronize the calls to be done to the platform from GATTClient
  * interfaces from different threads.
  */
-static ca_mutex g_LEClientStateMutex = NULL;
+static oc_mutex g_LEClientStateMutex = NULL;
 
 /**
  * Mutex to synchronize the task to be pushed to thread pool.
  */
-static ca_mutex g_LEClientThreadPoolMutex = NULL;
+static oc_mutex g_LEClientThreadPoolMutex = NULL;
+
+/**
+ * Mutex to synchronize the task to write characteristic one packet after another.
+ */
+static oc_mutex g_threadWriteCharacteristicMutex = NULL;
+
+/**
+ * Condition for Writing characteristic.
+ */
+static oc_cond g_threadWriteCharacteristicCond = NULL;
+
+/**
+ * Flag to check status of write characteristic.
+ */
+static bool g_isSignalSetFlag = false;
 
 /**
  * Maintains the callback to be notified on receival of network packets from other
@@ -142,29 +157,74 @@ static GMainLoop *g_eventLoop = NULL;
  */
 static ca_thread_pool_t g_LEClientThreadPool = NULL;
 
-bt_scan_filter_h g_scanFilter = NULL;
+bool CALEIsHaveService(bt_adapter_le_device_scan_result_info_s* scanInfo, char* service_uuid)
+{
+    bool ret = false;
+    char **uuids = NULL;
+    int count = 0;
+    int result = 0;
+
+    // For arduino servers, scan response will give the UUIDs advertised.
+    result = bt_adapter_le_get_scan_result_service_uuids(scanInfo,
+                                                         BT_ADAPTER_LE_PACKET_SCAN_RESPONSE,
+                                                         &uuids, &count);
+    if (result == BT_ERROR_NONE && NULL != uuids)
+    {
+        int i;
+        for (i = 0; i < count; i++)
+        {
+            if (0 == strcasecmp(uuids[i], service_uuid))
+            {
+                OIC_LOG_V(DEBUG, TAG, "Service[%s] Found in %s",
+                          uuids[i], scanInfo->remote_address);
+                ret = true;
+            }
+            OICFree(uuids[i]);
+        }
+        OICFree(uuids);
+    }
+
+    // For android/tizen servers, advertising packet will give the UUIDs.
+    result = bt_adapter_le_get_scan_result_service_uuids(scanInfo,
+                                                         BT_ADAPTER_LE_PACKET_ADVERTISING,
+                                                         &uuids, &count);
+    if (result == BT_ERROR_NONE && NULL != uuids)
+    {
+        int i;
+        for (i = 0; i < count; i++)
+        {
+            if (0 == strcasecmp(uuids[i], service_uuid))
+            {
+                OIC_LOG_V(DEBUG, TAG, "Service[%s] Found in %s",
+                          uuids[i], scanInfo->remote_address);
+                ret = true;
+            }
+            OICFree(uuids[i]);
+        }
+        OICFree(uuids);
+    }
+
+    return ret;
+}
 
 bool CALEIsDeviceDiscovered(const char * address)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
     if (g_deviceDiscoveredList)
     {
-        ca_mutex_lock(g_deviceDiscoveredListMutex);
+        oc_mutex_lock(g_deviceDiscoveredListMutex);
         uint32_t arrayLength = u_arraylist_length(g_deviceDiscoveredList);
-        for (int i = 0; i < arrayLength; i++)
+        for (uint32_t i = 0; i < arrayLength; i++)
         {
             char *deviceAddr = u_arraylist_get(g_deviceDiscoveredList, i);
             if (0 == strcasecmp(deviceAddr, address))
             {
-                OIC_LOG(DEBUG, TAG, "Device Found");
-                ca_mutex_unlock(g_deviceDiscoveredListMutex);
+                oc_mutex_unlock(g_deviceDiscoveredListMutex);
                 return true;
             }
 
         }
-        ca_mutex_unlock(g_deviceDiscoveredListMutex);
+        oc_mutex_unlock(g_deviceDiscoveredListMutex);
     }
-    OIC_LOG(DEBUG, TAG, "OUT");
     return false;
 }
 
@@ -172,35 +232,60 @@ void CALEGattCharacteristicChangedCb(bt_gatt_h characteristic,
                                      char *value,
                                      int valueLen, void *userData)
 {
+    (void)characteristic;
+
     OIC_LOG(DEBUG, TAG, "IN");
     OIC_LOG_V(DEBUG, TAG, "Changed characteristic value length [%d]", valueLen);
 
-    ca_mutex_lock(g_LEReqRespClientCbMutex);
+    oc_mutex_lock(g_LEReqRespClientCbMutex);
     if (NULL == g_LEClientDataReceivedCallback)
     {
         OIC_LOG(ERROR, TAG, "Request response callback is not set");
-        ca_mutex_unlock(g_LEReqRespClientCbMutex);
+        oc_mutex_unlock(g_LEReqRespClientCbMutex);
         return;
     }
 
     uint32_t sentLength = 0;
     g_LEClientDataReceivedCallback(userData, (uint8_t *)value, valueLen, &sentLength);
 
-    OIC_LOG_V(DEBUG, TAG, "Sent data Length is %d", sentLength);
+    OIC_LOG_V(DEBUG, TAG, "Recv data Length is %d", sentLength);
 
-    ca_mutex_unlock(g_LEReqRespClientCbMutex);
+    oc_mutex_unlock(g_LEReqRespClientCbMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
 void CALEGattCharacteristicWriteCb(int result, bt_gatt_h reqHandle, void *userData)
 {
+    (void)reqHandle;
+    (void)userData;
+
     OIC_LOG(DEBUG, TAG, "IN ");
+
+    if (BT_ERROR_NONE != result)
+    {
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, "", 0, -1,
+                           false, "writeChar failure");
+
+        OIC_LOG(ERROR, TAG, "Write failed Need Retry ");
+        //Need to Implement retry mechanism
+    }
+    else
+    {
+        oc_mutex_lock(g_threadWriteCharacteristicMutex);
+        OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal");
+        g_isSignalSetFlag = true;
+        oc_cond_signal(g_threadWriteCharacteristicCond);
+        oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, "", 0, -1,
+                           true, "writeChar success");
+    }
+
     OIC_LOG(DEBUG, TAG, "OUT ");
 }
 
-void CALEGattConnectionStateChangedCb(int result, bool connected,
-                                      const char *remoteAddress, void *userData)
+void CALEGattConnectionStateChanged(bool connected, const char *remoteAddress)
 {
     OIC_LOG(DEBUG, TAG, "IN ");
 
@@ -213,35 +298,43 @@ void CALEGattConnectionStateChangedCb(int result, bool connected,
         OIC_LOG(ERROR, TAG, "CALEGattStartDeviceDiscovery Failed");
     }
     // Signal the start timer.
-    ca_cond_signal(g_scanningTimeCond);
+    oc_cond_signal(g_scanningTimeCond);
 
     if (!connected)
     {
         OIC_LOG_V(DEBUG, TAG, "DisConnected from [%s] ", remoteAddress);
+        oc_mutex_lock(g_LEServerListMutex);
+        CARemoveLEServerInfoFromList(&g_LEServerList, remoteAddress);
+        oc_mutex_unlock(g_LEServerListMutex);
     }
     else
     {
         OIC_LOG_V(DEBUG, TAG, "Connected to [%s] ", remoteAddress);
 
         char *addr = OICStrdup(remoteAddress);
+        if (NULL == addr)
+        {
+            OIC_LOG(ERROR, TAG, "addr is NULL");
+            return;
+        }
 
-        ca_mutex_lock(g_LEClientThreadPoolMutex);
+        oc_mutex_lock(g_LEClientThreadPoolMutex);
         if (NULL == g_LEClientThreadPool)
         {
             OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
             OICFree(addr);
-            ca_mutex_unlock(g_LEClientThreadPoolMutex);
+            oc_mutex_unlock(g_LEClientThreadPoolMutex);
             return;
         }
 
         ret = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
-                                      addr);
+                                      addr, NULL);
         if (CA_STATUS_OK != ret)
         {
             OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", ret);
             OICFree(addr);
         }
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
     }
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -249,6 +342,8 @@ void CALEGattConnectionStateChangedCb(int result, bool connected,
 void CALEAdapterScanResultCb(int result, bt_adapter_le_device_scan_result_info_s *scanInfo,
                              void *userData)
 {
+    (void)userData;
+
     OIC_LOG(DEBUG, TAG, "IN");
 
     VERIFY_NON_NULL_VOID(scanInfo, TAG, "scanInfo");
@@ -268,18 +363,30 @@ void CALEAdapterScanResultCb(int result, bt_adapter_le_device_scan_result_info_s
         return;
     }
 
-    // Stop the scan before invoking bt_gatt_connect().
-    CALEGattStopDeviceScanning();
-
-    ca_mutex_lock(g_deviceDiscoveredListMutex);
-    // Add the the device Discovered list.
-    if (NULL == g_deviceDiscoveredList)
+    if (!CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID))
     {
-        g_deviceDiscoveredList = u_arraylist_create();
+        oc_mutex_lock(g_deviceDiscoveredListMutex);
+        // Add the the device Discovered list.
+        if (NULL == g_deviceDiscoveredList)
+        {
+            g_deviceDiscoveredList = u_arraylist_create();
+        }
+        char *deviceAddr = OICStrdup(scanInfo->remote_address);
+        if (NULL == deviceAddr)
+        {
+            OIC_LOG_V(ERROR, TAG, "Device address is NULL");
+            oc_mutex_unlock(g_deviceDiscoveredListMutex);
+            return;
+        }
+
+        u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
+        oc_mutex_unlock(g_deviceDiscoveredListMutex);
+        OIC_LOG_V(INFO, TAG, "Device[%s] is don't have service", scanInfo->remote_address);
+        return;
     }
-    char *deviceAddr = OICStrdup(scanInfo->remote_address);
-    u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
-    ca_mutex_unlock(g_deviceDiscoveredListMutex);
+
+    // Stop the scan before invoking bt_gatt_connect().
+    CALEGattStopDeviceScanning();
 
     size_t len = strlen(scanInfo->remote_address);
 
@@ -291,23 +398,23 @@ void CALEAdapterScanResultCb(int result, bt_adapter_le_device_scan_result_info_s
     OIC_LOG_V(DEBUG, TAG,
               "Trying to do Gatt connection to [%s]", addr);
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
     if (NULL == g_LEClientThreadPool)
     {
         OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
         OICFree(addr);
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
         return;
     }
 
-    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr);
+    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr, NULL);
     if (CA_STATUS_OK != res)
     {
         OIC_LOG_V(ERROR, TAG,
                   "ca_thread_pool_add_task failed with ret [%d]", res);
         OICFree(addr);
     }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
@@ -315,9 +422,9 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
     g_LEClientThreadPool = handle;
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -326,11 +433,11 @@ void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEReqRespClientCbMutex);
+    oc_mutex_lock(g_LEReqRespClientCbMutex);
 
     g_LEClientDataReceivedCallback = callback;
 
-    ca_mutex_unlock(g_LEReqRespClientCbMutex);
+    oc_mutex_unlock(g_LEReqRespClientCbMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -344,104 +451,75 @@ CAResult_t CAStartLEGattClient()
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
-    if (NULL == g_LEClientThreadPool)
-    {
-        OIC_LOG(ERROR, TAG, "gBleServerThreadPool is NULL");
-        CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return CA_STATUS_FAILED;
-    }
-
-    CAResult_t result = ca_thread_pool_add_task(g_LEClientThreadPool, CAStartLEGattClientThread,
-                                     NULL);
-    if (CA_STATUS_OK != result)
-    {
-        OIC_LOG(ERROR, TAG, "ca_thread_pool_add_task failed");
-        CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return CA_STATUS_FAILED;
-    }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
-}
-
-void CAStartLEGattClientThread(void *data)
-{
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    ca_mutex_lock(g_LEClientStateMutex);
+    oc_mutex_lock(g_LEClientStateMutex);
     if (true  == g_isLEGattClientStarted)
     {
         OIC_LOG(ERROR, TAG, "Gatt Client is already running!!");
-        ca_mutex_unlock(g_LEClientStateMutex);
-        return;
+        oc_mutex_unlock(g_LEClientStateMutex);
+        return CA_STATUS_FAILED;
     }
 
     CAResult_t  result = CALEGattSetCallbacks();
     if (CA_STATUS_OK != result)
     {
         OIC_LOG(ERROR, TAG, "CABleGattSetCallbacks Failed");
-        ca_mutex_unlock(g_LEClientStateMutex);
+        oc_mutex_unlock(g_LEClientStateMutex);
         CATerminateLEGattClient();
-        return;
+        return CA_STATUS_FAILED;
     }
 
     g_isLEGattClientStarted = true;
-    ca_mutex_unlock(g_LEClientStateMutex);
+    oc_mutex_unlock(g_LEClientStateMutex);
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
     if (NULL == g_LEClientThreadPool)
     {
         OIC_LOG(ERROR, TAG, "gBleServerThreadPool is NULL");
         CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        return CA_STATUS_FAILED;
     }
 
     result = ca_thread_pool_add_task(g_LEClientThreadPool, CAStartTimerThread,
-                                     NULL);
+                                     NULL, NULL);
     if (CA_STATUS_OK != result)
     {
         OIC_LOG(ERROR, TAG, "ca_thread_pool_add_task failed");
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+        CATerminateGattClientMutexVariables();
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
-
-    OIC_LOG(DEBUG, TAG, "Giving the control to threadPool");
-
-    GMainContext *thread_context = g_main_context_new();
-
-    g_eventLoop = g_main_loop_new(thread_context, FALSE);
-
-    g_main_context_push_thread_default(thread_context);
-
-    g_main_loop_run(g_eventLoop);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
 }
 
 void CAStartTimerThread(void *data)
 {
+    (void)data;
+
     OIC_LOG(DEBUG, TAG, "IN");
     while (g_isLEGattClientStarted)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
+        oc_mutex_lock(g_multicastDataListMutex);
         if (!g_isMulticastInProgress)
         {
             OIC_LOG(DEBUG, TAG, "waiting....");
-            ca_cond_wait(g_startTimerCond, g_multicastDataListMutex);
+            oc_cond_wait(g_startTimerCond, g_multicastDataListMutex);
             OIC_LOG(DEBUG, TAG, "Wake up");
             g_isMulticastInProgress = true;
+
+            if (!g_isLEGattClientStarted)
+            {
+               break;
+            }
         }
 
         // Timed conditional wait for stopping the scan.
-        CAWaitResult_t ret = ca_cond_wait_for(g_scanningTimeCond, g_multicastDataListMutex,
+        OCWaitResult_t ret = oc_cond_wait_for(g_scanningTimeCond, g_multicastDataListMutex,
                                               TIMEOUT);
-        if (CA_WAIT_TIMEDOUT == ret)
+        if (OC_WAIT_TIMEDOUT == ret)
         {
             OIC_LOG(DEBUG, TAG, "Scan is timed Out");
             // Call stop scan.
@@ -451,14 +529,14 @@ void CAStartTimerThread(void *data)
             u_arraylist_destroy(g_multicastDataList);
             g_multicastDataList = NULL;
 
-            ca_mutex_lock(g_deviceDiscoveredListMutex);
+            oc_mutex_lock(g_deviceDiscoveredListMutex);
             u_arraylist_destroy(g_deviceDiscoveredList);
             g_deviceDiscoveredList = NULL;
-            ca_mutex_unlock(g_deviceDiscoveredListMutex);
+            oc_mutex_unlock(g_deviceDiscoveredListMutex);
 
             g_isMulticastInProgress = false;
         }
-        ca_mutex_unlock(g_multicastDataListMutex);
+        oc_mutex_unlock(g_multicastDataListMutex);
     }
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -468,12 +546,12 @@ void CAStopLEGattClient()
 {
     OIC_LOG(DEBUG,  TAG, "IN");
 
-    ca_mutex_lock(g_LEClientStateMutex);
+    oc_mutex_lock(g_LEClientStateMutex);
 
     if (false == g_isLEGattClientStarted)
     {
         OIC_LOG(ERROR, TAG, "Gatt Client is not running to stop");
-        ca_mutex_unlock(g_LEClientStateMutex);
+        oc_mutex_unlock(g_LEClientStateMutex);
         return;
     }
 
@@ -481,33 +559,39 @@ void CAStopLEGattClient()
 
     CALEGattStopDeviceScanning();
 
+    // this flag should be set before signal g_startTimerCond.
+    // since scan thread can be stopped through this flag.
     g_isLEGattClientStarted = false;
 
     // Signal the conditions waiting in Start timer.
-    ca_cond_signal(g_startTimerCond);
-    ca_cond_signal(g_scanningTimeCond);
+    oc_cond_signal(g_startTimerCond);
+    oc_cond_signal(g_scanningTimeCond);
 
     // Destroy the multicast data list and device list if not empty.
     if (NULL != g_multicastDataList)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
+        oc_mutex_lock(g_multicastDataListMutex);
         u_arraylist_destroy(g_multicastDataList);
         g_multicastDataList = NULL;
-        ca_mutex_unlock(g_multicastDataListMutex);
+        oc_mutex_unlock(g_multicastDataListMutex);
     }
 
     if (NULL != g_deviceDiscoveredList)
     {
-        ca_mutex_lock(g_deviceDiscoveredListMutex);
+        oc_mutex_lock(g_deviceDiscoveredListMutex);
         u_arraylist_destroy(g_deviceDiscoveredList);
         g_deviceDiscoveredList = NULL;
-        ca_mutex_unlock(g_deviceDiscoveredListMutex);
+        oc_mutex_unlock(g_deviceDiscoveredListMutex);
     }
 
-    ca_mutex_lock(g_LEServerListMutex);
+    oc_mutex_lock(g_LEServerListMutex);
     CAFreeLEServerList(g_LEServerList);
     g_LEServerList = NULL;
-    ca_mutex_unlock(g_LEServerListMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
+
+    oc_mutex_lock(g_threadWriteCharacteristicMutex);
+    oc_cond_signal(g_threadWriteCharacteristicCond);
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
     CAResetRegisteredServiceCount();
 
@@ -519,7 +603,7 @@ void CAStopLEGattClient()
     }
     if (context_event_loop)
     {
-        OIC_LOG_V(DEBUG,  TAG, "g_eventLoop context %x", context_event_loop);
+        OIC_LOG_V(DEBUG,  TAG, "g_eventLoop context %p", (void *)context_event_loop);
         g_main_context_wakeup(context_event_loop);
 
         // Kill g main loops and kill threads.
@@ -530,7 +614,7 @@ void CAStopLEGattClient()
         OIC_LOG(ERROR, TAG, "g_eventLoop context is NULL");
     }
 
-    ca_mutex_unlock(g_LEClientStateMutex);
+    oc_mutex_unlock(g_LEClientStateMutex);
 
     OIC_LOG(DEBUG,  TAG, "OUT");
 }
@@ -562,90 +646,110 @@ CAResult_t CAInitGattClientMutexVariables()
     OIC_LOG(DEBUG,  TAG, "IN");
     if (NULL == g_LEClientStateMutex)
     {
-        g_LEClientStateMutex = ca_mutex_new();
+        g_LEClientStateMutex = oc_mutex_new();
         if (NULL == g_LEClientStateMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEServerListMutex)
     {
-        g_LEServerListMutex = ca_mutex_new();
+        g_LEServerListMutex = oc_mutex_new();
         if (NULL == g_LEServerListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEReqRespClientCbMutex)
     {
-        g_LEReqRespClientCbMutex = ca_mutex_new();
+        g_LEReqRespClientCbMutex = oc_mutex_new();
         if (NULL == g_LEReqRespClientCbMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEClientThreadPoolMutex)
     {
-        g_LEClientThreadPoolMutex = ca_mutex_new();
+        g_LEClientThreadPoolMutex = oc_mutex_new();
         if (NULL == g_LEClientThreadPoolMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEClientConnectMutex)
     {
-        g_LEClientConnectMutex = ca_mutex_new();
+        g_LEClientConnectMutex = oc_mutex_new();
         if (NULL == g_LEClientConnectMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_multicastDataListMutex)
     {
-        g_multicastDataListMutex = ca_mutex_new();
+        g_multicastDataListMutex = oc_mutex_new();
         if (NULL == g_multicastDataListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_deviceDiscoveredListMutex)
     {
-        g_deviceDiscoveredListMutex = ca_mutex_new();
+        g_deviceDiscoveredListMutex = oc_mutex_new();
         if (NULL == g_deviceDiscoveredListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadWriteCharacteristicMutex)
+    {
+        g_threadWriteCharacteristicMutex = oc_mutex_new();
+        if (NULL == g_threadWriteCharacteristicMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_startTimerCond)
     {
-        g_startTimerCond = ca_cond_new();
+        g_startTimerCond = oc_cond_new();
         if (NULL == g_startTimerCond)
         {
-            OIC_LOG(ERROR, TAG, "ca_cond_new failed");
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_scanningTimeCond)
     {
-        g_scanningTimeCond = ca_cond_new();
+        g_scanningTimeCond = oc_cond_new();
         if (NULL == g_scanningTimeCond)
         {
-            OIC_LOG(ERROR, TAG, "ca_cond_new failed");
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadWriteCharacteristicCond)
+    {
+        g_threadWriteCharacteristicCond = oc_cond_new();
+        if (NULL == g_threadWriteCharacteristicCond)
+        {
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
@@ -658,33 +762,40 @@ void CATerminateGattClientMutexVariables()
 {
     OIC_LOG(DEBUG,  TAG, "IN");
 
-    ca_mutex_free(g_LEClientStateMutex);
+    oc_mutex_free(g_LEClientStateMutex);
     g_LEClientStateMutex = NULL;
 
-    ca_mutex_free(g_LEServerListMutex);
+    oc_mutex_free(g_LEServerListMutex);
     g_LEServerListMutex = NULL;
 
-    ca_mutex_free(g_LEReqRespClientCbMutex);
+    oc_mutex_free(g_LEReqRespClientCbMutex);
     g_LEReqRespClientCbMutex = NULL;
 
-    ca_mutex_free(g_LEClientConnectMutex);
+    oc_mutex_free(g_LEClientConnectMutex);
     g_LEClientConnectMutex = NULL;
 
-    ca_mutex_free(g_LEClientThreadPoolMutex);
+    oc_mutex_free(g_LEClientThreadPoolMutex);
     g_LEClientThreadPoolMutex = NULL;
 
-    ca_mutex_free(g_multicastDataListMutex);
+    oc_mutex_free(g_multicastDataListMutex);
     g_multicastDataListMutex = NULL;
 
-    ca_mutex_free(g_deviceDiscoveredListMutex);
+    oc_mutex_free(g_deviceDiscoveredListMutex);
     g_deviceDiscoveredListMutex = NULL;
 
-    ca_cond_free(g_startTimerCond);
+    oc_mutex_free(g_threadWriteCharacteristicMutex);
+    g_threadWriteCharacteristicMutex = NULL;
+
+    oc_cond_free(g_startTimerCond);
     g_startTimerCond = NULL;
 
-    ca_cond_free(g_scanningTimeCond);
+    oc_cond_free(g_scanningTimeCond);
     g_scanningTimeCond = NULL;
 
+    oc_cond_free(g_threadWriteCharacteristicCond);
+    g_threadWriteCharacteristicCond = NULL;
+    g_isSignalSetFlag = false;
+
     OIC_LOG(DEBUG,  TAG, "OUT");
 }
 
@@ -692,15 +803,6 @@ CAResult_t CALEGattSetCallbacks()
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    int ret = bt_gatt_set_connection_state_changed_cb(CALEGattConnectionStateChangedCb, NULL);
-    if (BT_ERROR_NONE != ret)
-    {
-        OIC_LOG_V(ERROR, TAG,
-                  "bt_gatt_set_connection_state_changed_cb Failed with return as [%s ]",
-                  CALEGetErrorMsg(ret));
-        return CA_STATUS_FAILED;
-    }
-
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
@@ -781,21 +883,65 @@ CAResult_t CALEGattConnect(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
-    ca_mutex_lock(g_LEClientConnectMutex);
-
-    int ret = bt_gatt_connect(remoteAddress, true);
-
+    oc_mutex_lock(g_LEClientConnectMutex);
+    bool isConnected = false;
+    int ret = bt_device_is_profile_connected(remoteAddress, BT_PROFILE_GATT, &isConnected);
     if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_gatt_connect Failed with ret value [%s] ",
+        OIC_LOG_V(ERROR, TAG, "bt_device_is_profile_connected Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
-        ca_mutex_unlock(g_LEClientConnectMutex);
+        oc_mutex_unlock(g_LEClientConnectMutex);
         return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_LEClientConnectMutex);
+
+    CAResult_t result = CA_STATUS_OK;
+    if (!isConnected)
+    {
+        ret = bt_gatt_connect(remoteAddress, true);
+
+        if (BT_ERROR_NONE != ret)
+        {
+            OIC_LOG_V(ERROR, TAG, "bt_gatt_connect Failed with ret value [%s] ",
+                      CALEGetErrorMsg(ret));
+            oc_mutex_unlock(g_LEClientConnectMutex);
+            return CA_STATUS_FAILED;
+        }
+    }
+    else
+    {
+        OIC_LOG_V(INFO, TAG, "Remote address[%s] is already connected",
+                  remoteAddress);
+        char *addr = OICStrdup(remoteAddress);
+        if (NULL == addr)
+        {
+            OIC_LOG(ERROR, TAG, "addr is NULL");
+            oc_mutex_unlock(g_LEClientConnectMutex);
+            return CA_STATUS_FAILED;
+        }
+
+        oc_mutex_lock(g_LEClientThreadPoolMutex);
+        if (NULL == g_LEClientThreadPool)
+        {
+            OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
+            OICFree(addr);
+            oc_mutex_unlock(g_LEClientThreadPoolMutex);
+            oc_mutex_unlock(g_LEClientConnectMutex);
+            return CA_STATUS_FAILED;
+        }
+
+        result = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
+                                         addr, NULL);
+        if (CA_STATUS_OK != result)
+        {
+            OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", result);
+            OICFree(addr);
+        }
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+    }
+    oc_mutex_unlock(g_LEClientConnectMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
+    return result;
 }
 
 CAResult_t CALEGattDisConnect(const char *remoteAddress)
@@ -809,7 +955,7 @@ CAResult_t CALEGattDisConnect(const char *remoteAddress)
 
     if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_gatt_disconnect Failed with ret value [%d] ",
+        OIC_LOG_V(ERROR, TAG, "bt_gatt_disconnect Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
         return CA_STATUS_FAILED;
     }
@@ -843,13 +989,50 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
+    LEServerInfo *leServerInfo = NULL;
+    CAResult_t result =  CA_STATUS_FAILED;
+
+    oc_mutex_lock(g_LEServerListMutex);
+    result = CAGetLEServerInfo(g_LEServerList, remoteAddress, &leServerInfo);
+    oc_mutex_unlock(g_LEServerListMutex);
+
+    if (CA_STATUS_OK == result)
+    {
+        OIC_LOG_V(INFO, TAG, "Device[%s] is already discovered", leServerInfo->remoteAddress);
+
+        // Send the data of pending multicast data list if any.
+        if (g_multicastDataList)
+        {
+            oc_mutex_lock(g_multicastDataListMutex);
+            uint32_t arrayLength = u_arraylist_length(g_multicastDataList);
+            for (uint32_t i = 0; i < arrayLength; i++)
+            {
+                CALEData_t *multicastData = u_arraylist_get(g_multicastDataList, i);
+                if (NULL == multicastData)
+                {
+                    OIC_LOG(DEBUG, TAG, "multicastData is NULL");
+                    continue;
+                }
+                CAUpdateCharacteristicsToGattServer(remoteAddress, multicastData->data,
+                                                    multicastData->dataLen, LE_UNICAST, 0);
+            }
+            oc_mutex_unlock(g_multicastDataListMutex);
+        }
+
+        OIC_LOG(DEBUG, TAG, "OUT");
+        return CA_STATUS_OK;
+    }
+    else
+    {
+        OIC_LOG_V(INFO, TAG, "CAGetLEServerInfo [%s] is failed, %d", remoteAddress, result);
+    }
+
     bt_gatt_client_h clientHandle = NULL;
     int32_t ret = bt_gatt_client_create(remoteAddress, &clientHandle);
     if (BT_ERROR_NONE != ret || NULL == clientHandle)
     {
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_client_create Failed with ret value [%s] ", CALEGetErrorMsg(ret));
-        CALEGattDisConnect(remoteAddress);
         return CA_STATUS_FAILED;
     }
 
@@ -860,7 +1043,6 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_client_get_service Failed with ret value [%s] ", CALEGetErrorMsg(ret));
         bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
         return CA_STATUS_FAILED;
     }
 
@@ -895,6 +1077,14 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
 
     //TODO: This data has to be freed while unsetting the callback.
     char *addr = OICStrdup(remoteAddress);
+    if (NULL == addr)
+    {
+        OIC_LOG(ERROR, TAG, "addr is NULL");
+        bt_gatt_client_destroy(clientHandle);
+        CALEGattDisConnect(remoteAddress);
+        return CA_STATUS_FAILED;
+    }
+
     ret = bt_gatt_client_set_characteristic_value_changed_cb(readChrHandle,
                                                              CALEGattCharacteristicChangedCb,
                                                              (void *)addr);
@@ -921,23 +1111,39 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     serverInfo->writeChar = writeChrHandle;
     serverInfo->remoteAddress = OICStrdup(remoteAddress);
 
-    ca_mutex_lock(g_LEServerListMutex);
-    CAResult_t result = CAAddLEServerInfoToList(&g_LEServerList, serverInfo);
+    oc_mutex_lock(g_LEServerListMutex);
+    result = CAAddLEServerInfoToList(&g_LEServerList, serverInfo);
     if (CA_STATUS_OK != result)
     {
-        OIC_LOG(ERROR, TAG, "CAAddBLEClientInfoToList failed");
+        OIC_LOG(ERROR, TAG, "CAAddLEServerInfoToList failed");
         bt_gatt_client_destroy(clientHandle);
         CALEGattDisConnect(remoteAddress);
         return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_LEServerListMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
+
+    oc_mutex_lock(g_deviceDiscoveredListMutex);
+    // Add the the device Discovered list.
+    if (NULL == g_deviceDiscoveredList)
+    {
+        g_deviceDiscoveredList = u_arraylist_create();
+    }
+    char *deviceAddr = OICStrdup(remoteAddress);
+    if (NULL == deviceAddr)
+    {
+        OIC_LOG_V(ERROR, TAG, "Device address is NULL");
+        oc_mutex_unlock(g_deviceDiscoveredListMutex);
+        return CA_STATUS_FAILED;
+    }
+    u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
+    oc_mutex_unlock(g_deviceDiscoveredListMutex);
 
     // Send the data of pending multicast data list if any.
     if (g_multicastDataList)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
+        oc_mutex_lock(g_multicastDataListMutex);
         uint32_t arrayLength = u_arraylist_length(g_multicastDataList);
-        for (int i = 0; i < arrayLength; i++)
+        for (uint32_t i = 0; i < arrayLength; i++)
         {
             CALEData_t *multicastData = u_arraylist_get(g_multicastDataList, i);
             if (NULL == multicastData)
@@ -948,7 +1154,7 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
             CAUpdateCharacteristicsToGattServer(remoteAddress, multicastData->data,
                                                 multicastData->dataLen, LE_UNICAST, 0);
         }
-        ca_mutex_unlock(g_multicastDataListMutex);
+        oc_mutex_unlock(g_multicastDataListMutex);
     }
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -972,7 +1178,7 @@ CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
     LEServerInfo *leServerInfo = NULL;
     CAResult_t ret =  CA_STATUS_FAILED;
 
-    ca_mutex_lock(g_LEServerListMutex);
+    oc_mutex_lock(g_LEServerListMutex);
     if (LE_UNICAST == type)
     {
         ret = CAGetLEServerInfo(g_LEServerList, remoteAddress, &leServerInfo);
@@ -981,7 +1187,7 @@ CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
     {
         ret = CAGetLEServerInfoByPosition(g_LEServerList, position, &leServerInfo);
     }
-    ca_mutex_unlock(g_LEServerListMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
 
     if (CA_STATUS_OK != ret)
     {
@@ -1014,6 +1220,26 @@ CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
         return CA_STATUS_FAILED;
     }
 
+    // wait for callback for write Characteristic with success to sent data
+    OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag);
+    oc_mutex_lock(g_threadWriteCharacteristicMutex);
+    if (!g_isSignalSetFlag)
+    {
+        OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success");
+        if (OC_WAIT_SUCCESS != oc_cond_wait_for(g_threadWriteCharacteristicCond,
+                                  g_threadWriteCharacteristicMutex,
+                                  WAIT_TIME_WRITE_CHARACTERISTIC))
+        {
+            OIC_LOG(ERROR, TAG, "there is no response. write has failed");
+            g_isSignalSetFlag = false;
+            oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+            return CA_SEND_FAILED;
+        }
+    }
+    // reset flag set by writeCharacteristic Callback
+    g_isSignalSetFlag = false;
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
@@ -1064,13 +1290,13 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
     memcpy(multicastData->data, data, dataLen);
     multicastData->dataLen = dataLen;
 
-    ca_mutex_lock(g_multicastDataListMutex);
+    oc_mutex_lock(g_multicastDataListMutex);
     if (NULL == g_multicastDataList)
     {
         g_multicastDataList = u_arraylist_create();
     }
     u_arraylist_add(g_multicastDataList, (void *)multicastData);
-    ca_mutex_unlock(g_multicastDataListMutex);
+    oc_mutex_unlock(g_multicastDataListMutex);
 
     // Start the scanning.
     CAResult_t result = CALEGattStartDeviceScanning();
@@ -1081,11 +1307,42 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
     }
 
     // Start the timer by signalling it.
-    ca_cond_signal(g_startTimerCond);
+    oc_cond_signal(g_startTimerCond);
 
 exit:
     OIC_LOG(DEBUG, TAG, "OUT ");
     return CA_STATUS_OK;
 }
 
+bool CALEClientIsConnected(const char* address)
+{
+    (void)address;
+    //@Todo
+    return true;
+}
+
+uint16_t CALEClientGetMtuSize(const char* address)
+{
+    VERIFY_NON_NULL_RET(address, TAG, "address is null", CA_DEFAULT_BLE_MTU_SIZE);
+    //@Todo
+    //it should be implemented after update Tizen 3.0
+    return CA_DEFAULT_BLE_MTU_SIZE;
+}
+
+CAResult_t CALEClientSetMtuSize(const char* address, uint16_t mtuSize)
+{
+    (void)mtuSize;
+
+    VERIFY_NON_NULL(address, TAG, "address is null");
+    //@Todo
+    //it should be implemented after update Tizen 3.0
+    return CA_NOT_SUPPORTED;
+}
 
+CAResult_t CALEClientSendNegotiationMessage(const char* address)
+{
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSendNegotiationMessage(%s)", address);
+    //@Todo
+    //it will be implemented when tizen public 3.0 is released.
+    return CA_NOT_SUPPORTED;
+}