Added support for BLE OnBoarding in EasySetup
authorVinil Jain <vinil.gj@samsung.com>
Tue, 15 Sep 2015 17:00:47 +0000 (22:30 +0530)
committerMadan Lanka <lanka.madan@samsung.com>
Wed, 16 Sep 2015 07:57:25 +0000 (07:57 +0000)
Mediator side changes to handle BLE onBoarding and exchange WIFI credentials over BLE.

Change-Id: I0e8be88f1ee646cdacd9a1320068c9b8b756d333
Signed-off-by: Vinil Jain <vinil.gj@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2571
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Madan Lanka <lanka.madan@samsung.com>
service/easy-setup/sampleapp/android/EasySetup/app/src/main/AndroidManifest.xml
service/easy-setup/sampleapp/android/EasySetup/app/src/main/java/org/iotivity/service/easysetup/BLEActivity.java [new file with mode: 0644]
service/easy-setup/sdk/common/common.h
service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/core/BleConnection.java [new file with mode: 0644]
service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/BLEOnBoardingConfig.java [new file with mode: 0644]
service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/EnrolleeDeviceBLEOnBoarding.java [new file with mode: 0644]
service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/EnrolleeDeviceFactory.java
service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/mediator/ble/BLEManager.java [new file with mode: 0644]
service/easy-setup/sdk/mediator/src/provisioninghandlerBLE.cpp [new file with mode: 0644]

index b2a4e26..07003ee 100755 (executable)
@@ -3,22 +3,27 @@
     package="org.iotivity.service.easysetup"
     android:versionCode="1"
     android:versionName="1.0" >
-    
+    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />    
-    <uses-feature android:name="android.hardware.camera" android:required="true" />
-       <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
-       <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
-    <uses-feature android:name="android.permission.CONNECTIVITY_INTERNAL" android:required="true"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
 
+    <uses-feature
+        android:name="android.hardware.camera"
+        android:required="true" />
+    <uses-feature
+        android:name="android.hardware.camera.autofocus"
+        android:required="false" />
+    <uses-feature
+        android:name="android.hardware.touchscreen"
+        android:required="false" />
 
+    <uses-permission android:name="android.permission.CAMERA" />
 
-    <uses-permission android:name="android.permission.CAMERA"/>
-
-
-     <application
+    <application
         android:allowBackup="true"
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         <activity
             android:name=".MainActivity"
             android:label="@string/app_name" >
+
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+
+                <data android:mimeType="text/plain" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".BLEActivity"
+            >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
-            <intent-filter>
-                               <action android:name="android.intent.action.SEND"/>
-                               <category android:name="android.intent.category.DEFAULT"/>
-                               <data android:mimeType="text/plain"/>
-                       </intent-filter>
         </activity>
     </application>
 
diff --git a/service/easy-setup/sampleapp/android/EasySetup/app/src/main/java/org/iotivity/service/easysetup/BLEActivity.java b/service/easy-setup/sampleapp/android/EasySetup/app/src/main/java/org/iotivity/service/easysetup/BLEActivity.java
new file mode 100644 (file)
index 0000000..abf3157
--- /dev/null
@@ -0,0 +1,159 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package org.iotivity.service.easysetup;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import org.iotivity.service.easysetup.core.EasySetupService;
+import org.iotivity.service.easysetup.core.EasySetupStatus;
+import org.iotivity.service.easysetup.core.EnrolleeDevice;
+import org.iotivity.service.easysetup.core.EnrolleeState;
+import org.iotivity.service.easysetup.impl.BLEOnBoardingConfig;
+import org.iotivity.service.easysetup.impl.EnrolleeDeviceFactory;
+import org.iotivity.service.easysetup.impl.WiFiProvConfig;
+
+import java.io.IOException;
+
+public class BLEActivity extends Activity {
+    WiFiProvConfig mWiFiProvConfig;
+    BLEOnBoardingConfig bleOnBoardingConfig;
+    EasySetupService mEasySetupService;
+    EnrolleeDeviceFactory mDeviceFactory;
+    EnrolleeDevice mDevice;
+
+    private final int REQUEST_ENABLE_BT = 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_ble);
+
+        mDeviceFactory = EnrolleeDeviceFactory.newInstance(getApplicationContext());
+
+        mDevice = mDeviceFactory.newEnrolleeDevice(getOnBoardingWifiConfig(), getEnrollerWifiConfig());
+
+        EasySetupStatus easySetupStatus = new EasySetupStatus() {
+            @Override
+            public void onFinished(EnrolleeDevice enrolleeDevice) {
+                final String msg = mDevice.isSetupSuccessful() ? "Device configured successfully" : "Device configuration failed";
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
+                    }
+                });
+
+            }
+
+            @Override
+            public void onProgress(EnrolleeState enrolleeState) {
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        Toast.makeText(getApplicationContext(), "Device state changed", Toast.LENGTH_SHORT).show();
+                    }
+                });
+
+
+            }
+        };
+        mEasySetupService = EasySetupService.getInstance(getApplicationContext(), easySetupStatus);
+        start();
+    }
+
+    public WiFiProvConfig getEnrollerWifiConfig() {
+        mWiFiProvConfig = new WiFiProvConfig("linksysy", "12345678");
+        return mWiFiProvConfig;
+    }
+
+    public BLEOnBoardingConfig getOnBoardingWifiConfig() {
+        //TODO : Check proper configuration
+        bleOnBoardingConfig = new BLEOnBoardingConfig();
+
+        bleOnBoardingConfig.setUuid("ade3d529-c784-4f63-a987-eb69f70ee816");
+
+        return bleOnBoardingConfig;
+    }
+
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.menu_ble, menu);
+        return true;
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        // User chose not to enable Bluetooth.
+        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
+            Log.e("error enablg bluetooth", resultCode + "");
+            finish();
+            return;
+        } else try {
+            //bluetooth is  enabled, now start the setup of enrollee devices
+            mEasySetupService.startSetup(mDevice);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+
+        //noinspection SimplifiableIfStatement
+        if (id == R.id.action_settings) {
+            return true;
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    public void start() {
+        //This function starts the bluetooth adpater so that the easysetup can start scanning for BLE devices
+        //IF bluetooth is directly enabled it will directly start the setup of enrollee devices
+        final BluetoothManager bluetoothManager =
+                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
+
+        if (!mBluetoothAdapter.isEnabled()) {
+            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
+        } else try {
+            mEasySetupService.startSetup(mDevice);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
index c9f1417..7f363cc 100755 (executable)
 //The following variable determines the interface (wifi, ethernet etc.)
 //to be used for sending unicast messages. Default set to Ethernet.
 static OCConnectivityType OC_CONNTYPE = CT_IP_USE_V4;
+static OCConnectivityType OC_CONNTYPE_BLE =  CT_ADAPTER_GATT_BTLE;
 
 static const char * UNICAST_PROVISIONING_QUERY = "coap://%s:%d/oic/res?rt=oic.prov";
 static const char * UNICAST_PROV_STATUS_QUERY = "coap://%s:%d%s";
 
+static const char * UNICAST_PROVISIONING_QUERY_BLE = "coap://%s/oic/prov";
+static const char * MULTICAST_PROVISIONING_QUERY_BLE = "/oic/res?rt=oic.prov";
+
 
 /**
  * Attributes used to form a proper easysetup conforming JSON message.
diff --git a/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/core/BleConnection.java b/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/core/BleConnection.java
new file mode 100644 (file)
index 0000000..bfb3483
--- /dev/null
@@ -0,0 +1,63 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package org.iotivity.service.easysetup.core;
+
+public class BleConnection implements ConnectionInterface {
+
+    private boolean mIsConnected;
+    private String mServiceUUID;
+    private String macaddress;
+
+    public void setConnectivity(boolean connected) {
+        mIsConnected = connected;
+    }
+
+    public void setmServiceUUID(String uuid) {
+        mServiceUUID = uuid;
+    }
+
+    public String getmServiceUUID() {
+        return mServiceUUID;
+    }
+
+    public void setMacaddress(String address) {
+        macaddress = address;
+    }
+
+    public String getMacaddress() {
+        return macaddress;
+    }
+
+    @Override
+    public String getDesc() {
+        return "Description";
+    }
+
+    @Override
+    public boolean isConnected() {
+        return mIsConnected;
+    }
+
+    @Override
+    public Object getConnection() {
+        return this;
+    }
+
+}
diff --git a/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/BLEOnBoardingConfig.java b/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/BLEOnBoardingConfig.java
new file mode 100644 (file)
index 0000000..55a6214
--- /dev/null
@@ -0,0 +1,58 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package org.iotivity.service.easysetup.impl;
+
+import org.iotivity.service.easysetup.core.OnBoardingConfig;
+
+import java.util.UUID;
+
+
+public class BLEOnBoardingConfig implements OnBoardingConfig {
+    private final ConnType mConnType = ConnType.BLE;
+    private String macaddress;
+    private UUID uuid;
+
+    @Override
+    public Object getConfig() {
+        return null;
+    }
+
+    @Override
+    public ConnType getConnType() {
+        return mConnType;
+    }
+
+
+    public UUID getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = UUID.fromString(uuid);
+    }
+
+    public String getMacaddress() {
+        return macaddress;
+    }
+
+    public void setMacaddress(String macaddress) {
+        this.macaddress = macaddress;
+    }
+}
diff --git a/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/EnrolleeDeviceBLEOnBoarding.java b/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/impl/EnrolleeDeviceBLEOnBoarding.java
new file mode 100644 (file)
index 0000000..3fb508e
--- /dev/null
@@ -0,0 +1,145 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package org.iotivity.service.easysetup.impl;
+
+import android.content.Context;
+import android.util.Log;
+
+import org.iotivity.service.easysetup.core.BleConnection;
+import org.iotivity.service.easysetup.core.ConnectionInterface;
+import org.iotivity.service.easysetup.core.EnrolleeDevice;
+import org.iotivity.service.easysetup.core.EnrolleeState;
+import org.iotivity.service.easysetup.core.OnBoardingConfig;
+import org.iotivity.service.easysetup.core.ProvisioningConfig;
+import org.iotivity.service.easysetup.mediator.EasySetupManager;
+import org.iotivity.service.easysetup.mediator.EnrolleeInfo;
+import org.iotivity.service.easysetup.mediator.IOnBoardingStatus;
+import org.iotivity.service.easysetup.mediator.IProvisioningListener;
+import org.iotivity.service.easysetup.mediator.ProvisionEnrollee;
+import org.iotivity.service.easysetup.mediator.ble.BLEManager;
+
+public class EnrolleeDeviceBLEOnBoarding extends EnrolleeDevice {
+    /**
+     * @param onBoardingConfig Contains details about the connectivity to be established between
+     * the Enrollee device & Mediator device in order to perform
+     * on-boarding
+     * @param provConfig       Contains details about the network to which Enrollee device is
+     */
+    public static final String TAG = EnrolleeDeviceWiFiOnboarding.class.getName();
+
+    final Context mContext;
+    BLEManager bleManager;
+    EnrolleeInfo connectedDevice;
+    ProvisionEnrollee provisionEnrolleInstance;
+    private EasySetupManager easySetupManagerNativeInstance;
+
+
+    IOnBoardingStatus deviceScanListener = new IOnBoardingStatus() {
+
+        @Override
+        public void deviceOnBoardingStatus(EnrolleeInfo enrolleStatus) {
+            Log.d("ESBLEOnBoarding", "Entered");
+            if (enrolleStatus != null && enrolleStatus.getHWAddr() != null) {
+                String finalResult = "Easy Connect : ";
+
+                if (enrolleStatus.isReachable()) {
+                    finalResult = "Device OnBoarded" + "["
+                            + enrolleStatus.getHWAddr() + "]";
+                    connectedDevice = enrolleStatus;
+                    BleConnection conn = new BleConnection();
+                    conn.setMacaddress(connectedDevice.getHWAddr());
+                    conn.setConnectivity(true);
+                    Log.d("ESBLEOnBoarding", "Entered" + ":" + finalResult);
+                    mOnBoardingCallback.onFinished(conn);
+                    return;
+
+                }
+            }
+
+            BleConnection conn = new BleConnection();
+            conn.setConnectivity(false);
+            mOnBoardingCallback.onFinished(conn);
+
+
+        }
+    };
+
+    protected EnrolleeDeviceBLEOnBoarding(Context context, OnBoardingConfig onBoardingConfig, ProvisioningConfig provConfig) {
+        super(onBoardingConfig, provConfig);
+        mContext = context;
+        bleManager = new BLEManager(mContext, (BLEOnBoardingConfig) onBoardingConfig);
+    }
+
+    @Override
+    protected void startOnBoardingProcess() {
+        Log.i(TAG, "Starging on boarding process");
+
+        boolean status = bleManager.setupBluetooth();
+
+        Log.i(TAG, "Bluetooth started with status " + status);
+        if (status) {
+            Log.i(TAG, "Scanning available BLE devices");
+            bleManager.startScan(deviceScanListener);
+
+        }
+
+    }
+
+    @Override
+    protected void stopOnBoardingProcess() {
+
+        bleManager.stopscan();
+
+    }
+
+    @Override
+    protected void startProvisioningProcess(ConnectionInterface conn) {
+
+        Log.i("start provisioning BLE", mProvConfig.getConnType() + "");
+
+        //if (mProvConfig.getConnType() == ProvisioningConfig.ConnType.WiFi)
+        {
+
+            provisionEnrolleInstance = new ProvisionEnrollee(mContext);
+            provisionEnrolleInstance.registerProvisioningHandler(new IProvisioningListener() {
+                @Override
+                public void onFinishProvisioning(int statuscode) {
+                    mState = (statuscode == 0) ? EnrolleeState.DEVICE_PROVISIONING_SUCCESS_STATE : EnrolleeState.DEVICE_PROVISIONING_FAILED_STATE;
+                    mProvisioningCallback.onFinished(EnrolleeDeviceBLEOnBoarding.this);
+                }
+            });
+
+            BleConnection connection = (BleConnection) conn;
+            WiFiProvConfig wifiProvConfig = (WiFiProvConfig) mProvConfig;
+            if (mContext == null)
+                Log.d("BLE context is null", "");
+            else Log.d("BLE context is not null", "");
+            easySetupManagerNativeInstance = EasySetupManager.getInstance();
+
+
+            easySetupManagerNativeInstance.setApplicationContext(mContext);
+            easySetupManagerNativeInstance.initEasySetup();
+            Log.d("init", "successful");
+            easySetupManagerNativeInstance.provisionEnrollee(connection.getMacaddress(), wifiProvConfig.getSsId(), wifiProvConfig.getPassword(), 0);
+
+        }
+
+    }
+}
\ No newline at end of file
index 97363fa..7e7ae72 100644 (file)
 
 package org.iotivity.service.easysetup.impl;
 
+import android.content.Context;
+
 import org.iotivity.service.easysetup.core.EnrolleeDevice;
 import org.iotivity.service.easysetup.core.OnBoardingConfig;
 import org.iotivity.service.easysetup.core.ProvisioningConfig;
 
-import android.content.Context;
-
 /**
  * This a factory class provides the native implementation of the various Enrollee devices.
  * Application can make use of Enrollee factory if it does not want to create its own Enrollee devices.
@@ -60,10 +60,12 @@ public class EnrolleeDeviceFactory {
     public EnrolleeDevice newEnrolleeDevice(OnBoardingConfig onboardingConfig, ProvisioningConfig provConfig) {
 
         EnrolleeDevice enrolleeDevice;
-
         if (onboardingConfig.getConnType() == OnBoardingConfig.ConnType.WiFi) {
             enrolleeDevice = new EnrolleeDeviceWiFiOnboarding(mContext, onboardingConfig, provConfig);
-        } else {
+        } else if (onboardingConfig.getConnType() == OnBoardingConfig.ConnType.BLE)
+            enrolleeDevice = new EnrolleeDeviceBLEOnBoarding(mContext, onboardingConfig, provConfig);
+
+        else {
             throw new IllegalArgumentException("OnBoarding configuration is not supported");
         }
 
diff --git a/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/mediator/ble/BLEManager.java b/service/easy-setup/sdk/mediator/android/EasySetupCore/src/main/java/org/iotivity/service/easysetup/mediator/ble/BLEManager.java
new file mode 100644 (file)
index 0000000..986c92b
--- /dev/null
@@ -0,0 +1,177 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+package org.iotivity.service.easysetup.mediator.ble;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.os.Handler;
+import android.util.Log;
+
+import org.iotivity.service.easysetup.impl.BLEOnBoardingConfig;
+import org.iotivity.service.easysetup.mediator.EnrolleeInfo;
+import org.iotivity.service.easysetup.mediator.IOnBoardingStatus;
+
+import java.util.List;
+import java.util.UUID;
+
+public class BLEManager {
+    private BluetoothAdapter mBluetoothAdapter;
+    private boolean is_scanning;
+    private Context mcontext;
+    private Handler mHandler;
+    private static final long SCAN_PERIOD = 10000;
+    private BluetoothGatt gatt;
+    private BLEOnBoardingConfig bleOnBoardingConfig;
+    private IOnBoardingStatus finishlistener;
+    private boolean connection_successful = false;
+
+    public BLEManager(Context context, BLEOnBoardingConfig config) {
+        mcontext = context;
+        bleOnBoardingConfig = config;
+    }
+
+    public boolean setupBluetooth() {
+        mHandler = new Handler();
+        if (mHandler == null) return false;
+        final BluetoothManager bluetoothManager =
+                (BluetoothManager) mcontext.getSystemService(Context.BLUETOOTH_SERVICE);
+        mBluetoothAdapter = bluetoothManager.getAdapter();
+        if (mBluetoothAdapter == null) return false;
+        if (!mBluetoothAdapter.isEnabled()) {
+            Log.d("bluetooth Disabled", "");
+            return false;
+        }
+
+
+        return true;
+    }
+
+    public void startScan(IOnBoardingStatus listener) {
+
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                is_scanning = false;
+                mBluetoothAdapter.stopLeScan(mLeScanCallback);
+
+            }
+        }, SCAN_PERIOD);
+
+        is_scanning = true;
+        UUID[] uuids = {bleOnBoardingConfig.getUuid()};
+        mBluetoothAdapter.startLeScan(uuids, mLeScanCallback);
+        finishlistener = listener;
+    }
+
+    public void stopscan() {
+        mBluetoothAdapter.stopLeScan(mLeScanCallback);
+
+    }
+
+    public void connect(BluetoothDevice device) {
+        gatt = device.connectGatt(mcontext, false, gattCallback);
+
+    }
+
+
+    private BluetoothAdapter.LeScanCallback mLeScanCallback =
+            new BluetoothAdapter.LeScanCallback() {
+
+                @Override
+                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
+                    Log.d("device found", device.getAddress() + " " + device.getUuids());
+                    bleOnBoardingConfig.setMacaddress(device.getAddress());
+                    {
+                        stopscan();
+                        EnrolleeInfo result = new EnrolleeInfo();
+                        result.setReachable(true);
+                        result.setHWAddr(bleOnBoardingConfig.getMacaddress());
+                        NotifyApplication(result);
+
+                        //TODO- Device will have to be disconnected so that the multicast works while discovery resources
+                        //Not connecting to device
+                        //connect(device);
+                    }
+                }
+            };
+    private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+            super.onConnectionStateChange(gatt, status, newState);
+            Log.d("connection state:", "status" + status + ":" + newState);
+            EnrolleeInfo result = new EnrolleeInfo();
+            switch (newState) {
+                case BluetoothProfile.STATE_CONNECTED:
+                    Log.d("gattCallback", "STATE_CONNECTED");
+                    connection_successful = true;
+                    gatt.disconnect();
+                    break;
+                case BluetoothProfile.STATE_DISCONNECTED:
+                    Log.e("gattCallback", "STATE_DISCONNECTED");
+                    if (connection_successful) {
+                        result.setReachable(true);
+                        result.setHWAddr(bleOnBoardingConfig.getMacaddress());
+                        NotifyApplication(result);
+                    } else {
+                        result.setReachable(false);
+                        NotifyApplication(result);
+                    }
+                    break;
+                default:
+                    Log.e("gattCallback", "STATE_OTHER");
+            }
+        }
+
+        @Override
+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+            List<BluetoothGattService> services = gatt.getServices();
+            Log.i("onServicesDiscovered", services.toString());
+            gatt.readCharacteristic(services.get(1).getCharacteristics().get
+                    (0));
+        }
+
+        @Override
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                                         BluetoothGattCharacteristic
+                                                 characteristic, int status) {
+
+        }
+
+    };
+
+    void NotifyApplication(final EnrolleeInfo result) {
+        // Get a handler that can be used to post to the main thread
+        Handler mainHandler = new Handler(mcontext.getMainLooper());
+        Runnable myRunnable = new Runnable() {
+            @Override
+            public void run() {
+                finishlistener.deviceOnBoardingStatus(result);
+            }
+        };
+        mainHandler.post(myRunnable);
+    }
+}
diff --git a/service/easy-setup/sdk/mediator/src/provisioninghandlerBLE.cpp b/service/easy-setup/sdk/mediator/src/provisioninghandlerBLE.cpp
new file mode 100644 (file)
index 0000000..a602685
--- /dev/null
@@ -0,0 +1,830 @@
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics 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 <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include "ocpayload.h"
+#include "provisioninghandler.h"
+#include "common.h"
+// External includes
+
+#include "camutex.h"
+#include "cathreadpool.h"
+#include "logger.h"
+#include "oic_malloc.h"
+static bool sent_provision_request = false;
+/**
+ * @var g_provisioningMutex
+ * @brief Mutex to synchronize access to g_caDtlsContext.
+ */
+static ca_mutex g_provisioningMutex = NULL;
+static ca_cond g_provisioningCond = NULL;
+bool g_provisioningCondFlag = false;
+
+static EnrolleeNWProvInfo_t* netProvInfo;
+
+/**
+ * @var cbData
+ * @brief Callback for providing provisioning status callback to application
+ */
+static OCProvisioningStatusCB cbData = NULL;
+static ca_thread_pool_t g_threadPoolHandle = NULL;
+
+void ErrorCallback(ProvStatus status)
+{
+    ProvisioningInfo *provInfo = GetCallbackObjectOnError(status);
+    cbData(provInfo);
+}
+
+OCStackResult InitProvisioningHandler()
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    /* Initialize OCStack*/
+    if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack init error");
+        return ret;
+    }
+
+    g_provisioningMutex = ca_mutex_new();
+
+    OIC_LOG(DEBUG, TAG, "ca_thread_pool_init initializing");
+
+    if (CA_STATUS_OK != ca_thread_pool_init(2, &g_threadPoolHandle))
+    {
+        OIC_LOG(DEBUG, TAG, "thread_pool_init failed");
+        return OC_STACK_ERROR;
+    }
+
+    g_provisioningCond = ca_cond_new();
+    if (NULL == g_provisioningCond)
+    {
+        OIC_LOG(DEBUG, TAG, "Failed to create condition");
+        ca_mutex_free(g_provisioningMutex);
+        ca_thread_pool_free(g_threadPoolHandle);
+        return OC_STACK_ERROR;
+    }
+
+    char *string = "listeningFunc invoked in a thread";
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, listeningFunc, (void *) string))
+    {
+        OIC_LOG(DEBUG, TAG, "thread_pool_add_task failed");
+        ca_thread_pool_free(g_threadPoolHandle);
+        ca_mutex_unlock(g_provisioningMutex);
+        ca_mutex_free(g_provisioningMutex);
+        ca_cond_free(g_provisioningCond);
+        return OC_STACK_ERROR;
+    }
+    return OC_STACK_OK;
+}
+
+OCStackResult TerminateProvisioningHandler()
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    if (OCStop() != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+    }
+
+    ca_mutex_lock(g_provisioningMutex);
+    g_provisioningCondFlag = true;
+    //ca_cond_signal(g_provisioningCond);
+    ca_mutex_unlock(g_provisioningMutex);
+
+    ca_mutex_free(g_provisioningMutex);
+    g_provisioningMutex = NULL;
+
+    ca_thread_pool_free(g_threadPoolHandle);
+    g_threadPoolHandle = NULL;
+
+    ret = OC_STACK_OK;
+    return ret;
+}
+
+void listeningFunc(void *data)
+{
+    while (!g_provisioningCondFlag)
+    {
+        OCStackResult result;
+
+        ca_mutex_lock(g_provisioningMutex);
+        result = OCProcess();
+        ca_mutex_unlock(g_provisioningMutex);
+
+        if (result != OC_STACK_OK)
+        {
+            OIC_LOG(ERROR, TAG, "OCStack stop error");
+        }
+
+        // To minimize CPU utilization we may wish to do this with sleep
+        sleep(1);
+    }
+}
+
+OCStackApplicationResult ProvisionEnrolleeResponse(void* ctx, OCDoHandle handle,
+        OCClientResponse * clientResponse)
+{
+    OIC_LOG_V(DEBUG, TAG, "INSIDE ProvisionEnrolleeResponse");
+    ProvisioningInfo *provInfo;
+
+    if (!ValidateEnrolleResponse(clientResponse))
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    char* tnn;
+    char* cd;
+
+    OCRepPayload* input = (OCRepPayload*) (clientResponse->payload);
+
+    while (input)
+    {
+
+        int64_t ps;
+        if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_PS, &ps))
+        {
+
+            if (ps == 1)
+            {
+                input = input->next;
+                continue;
+            }
+            else
+            {
+                OIC_LOG_V(DEBUG, TAG, "PS is NOT proper");
+                goto Error;
+
+            }
+        }
+
+        if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_TNN, &tnn))
+        {
+            if (!strcmp(tnn, netProvInfo->netAddressInfo.WIFI.ssid))
+            {
+                OIC_LOG_V(DEBUG, TAG, "SSID is proper");
+                input = input->next;
+                continue;
+            }
+            else
+            {
+                OIC_LOG_V(DEBUG, TAG, "SSID is NOT proper");
+                goto Error;
+            }
+        }
+
+        if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CD, &cd))
+        {
+            if (!strcmp(cd, netProvInfo->netAddressInfo.WIFI.pwd))
+            {
+                OIC_LOG_V(DEBUG, TAG, "Password is proper");
+                input = input->next;
+                continue;
+            }
+            else
+            {
+                OIC_LOG_V(DEBUG, TAG, "Password is NOT proper");
+                goto Error;
+            }
+        }
+
+        LogProvisioningResponse(input->values);
+
+        input = input->next;
+
+    }
+
+    SuccessCallback(clientResponse);
+
+    return OC_STACK_KEEP_TRANSACTION;
+
+    Error:
+    {
+
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+}
+
+OCStackResult ProvisionEnrollee(OCQualityOfService qos, const char* query, const char* resUri,
+        OCDevAddr *destination)
+{
+    OIC_LOG_V(INFO, TAG, "Sleeping for 2 seconds");
+    sleep(2);
+    OIC_LOG_V(INFO, TAG, "\n\nExecuting ProvisionEnrollee%s", __func__);
+
+    OCRepPayload* payload = OCRepPayloadCreate();
+
+    OCRepPayloadSetUri(payload, resUri);
+    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_TNN, netProvInfo->netAddressInfo.WIFI.ssid);
+    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CD, netProvInfo->netAddressInfo.WIFI.pwd);
+
+    OIC_LOG_V(DEBUG, TAG, "OCPayload ready for ProvisionEnrollee");
+
+    OCStackResult ret = InvokeOCDoResource(query, OC_REST_PUT, destination, OC_HIGH_QOS,
+            ProvisionEnrolleeResponse, payload, NULL, 0);
+
+    return ret;
+}
+OCStackApplicationResult GetProvisioningStatusResponse(void* ctx, OCDoHandle handle,
+        OCClientResponse * clientResponse)
+{
+    if (sent_provision_request == true)
+        return OC_STACK_DELETE_TRANSACTION;
+    sent_provision_request = true;
+    OIC_LOG_V(DEBUG, TAG, "INside  GetProvisioningStatusResponse");
+
+    ProvisioningInfo *provInfo;
+
+    if (!ValidateEnrolleResponse(clientResponse))
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        ClearMemory();
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    OCRepPayload* input = (OCRepPayload*) (clientResponse->payload);
+
+    char query[OIC_STRING_MAX_VALUE] =
+    { '\0' };
+    char resURI[MAX_URI_LENGTH] =
+    { '\0' };
+
+    OIC_LOG_V(DEBUG, TAG, "resUri = %s", input->uri);
+
+    strncpy(resURI, input->uri, sizeof(resURI));
+
+    snprintf(query, sizeof(query), UNICAST_PROVISIONING_QUERY_BLE, clientResponse->addr->addr);
+
+    OIC_LOG_V(DEBUG, TAG, "query = %s", query);
+
+    OCDevAddr *devaddress = &clientResponse->devAddr;
+    devaddress->adapter = OC_ADAPTER_GATT_BTLE;
+
+    //OCPayloadLogRep(DEBUG,TAG,input);
+
+    if (ProvisionEnrollee(OC_HIGH_QOS, query, OC_RSRVD_ES_URI_PROV, devaddress) != OC_STACK_OK)
+    {
+        OIC_LOG(INFO, TAG,
+                "GetProvisioningStatusResponse received NULL clientResponse.Invoking Provisioing Status Callback");
+
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        ClearMemory();
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    return OC_STACK_KEEP_TRANSACTION;
+
+}
+
+OCStackResult InvokeOCDoResource(const char* query, OCMethod method, const OCDevAddr *dest,
+        OCQualityOfService qos, OCClientResponseHandler cb, OCRepPayload* payload,
+        OCHeaderOption * options, uint8_t numOptions)
+{
+    OCStackResult ret;
+    OCCallbackData cbData;
+
+    cbData.cb = cb;
+    cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
+    cbData.cd = NULL;
+
+    ret = OCDoResource(NULL, method, query, dest, (OCPayload*) payload, OC_CONNTYPE_BLE, qos,
+            &cbData, options, numOptions);
+
+    if (ret != OC_STACK_OK)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
+    }
+
+    return ret;
+}
+
+OCStackResult GetProvisioningStatus(OCQualityOfService qos, const char* query,
+        const OCDevAddr *destination)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    OIC_LOG_V(INFO, TAG, "\n\nExecuting %s %d", __func__, destination->adapter);
+    ret = InvokeOCDoResource(query, OC_REST_GET, destination, OC_HIGH_QOS,
+            GetProvisioningStatusResponse, NULL, NULL, 0);
+    return ret;
+}
+
+OCStackResult StartProvisioningProcess(const EnrolleeNWProvInfo_t *netInfo,
+        OCProvisioningStatusCB provisioningStatusCallback)
+{
+
+    OCStackResult result = OC_STACK_ERROR;
+
+    if (!ValidateEasySetupParams(netInfo, provisioningStatusCallback))
+    {
+        goto Error;
+    }
+
+    //Only basis test is done for below API
+    if (!SetProgress(provisioningStatusCallback))
+    {
+        // Device provisioning session is running already.
+        OIC_LOG(INFO, TAG, PCF("Device provisioning session is running already"));
+        goto Error;
+    }
+
+    if (!ConfigEnrolleeObject(netInfo))
+    {
+        goto Error;
+    }
+
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, FindProvisioningResource,
+            (void *) ""))
+    {
+        goto Error;
+    }
+
+    return OC_STACK_OK;
+
+    Error:
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        ClearMemory();
+        return OC_STACK_ERROR;
+    }
+
+}
+
+void StopProvisioningProcess()
+{
+    //Only basis test is done for below API
+    ResetProgress();
+}
+
+// This is a function called back when a device is discovered
+OCStackApplicationResult FindProvisioningResourceResponse(void* ctx, OCDoHandle handle,
+        OCClientResponse * clientResponse)
+{
+
+    OIC_LOG(INFO, TAG, PCF("Entering FindProvisioningResourceResponse"));
+
+    if (!ValidateFinddResourceResponse(clientResponse))
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
+
+    ProvisioningInfo *provInfo;
+    char szQueryUri[64] =
+    { 0 };
+
+    OCDiscoveryPayload* discoveryPayload = (OCDiscoveryPayload*) (clientResponse->payload);
+
+    // Need to conform if below check is required or not. As Null check of clientResponse->payload is already performed above
+    if (!discoveryPayload)
+    {
+        OIC_LOG_V(DEBUG, TAG, "Failed To parse");
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    OIC_LOG_V(DEBUG, TAG, "resUri = %s", discoveryPayload->resources->uri);
+
+    snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY_BLE,
+            clientResponse->addr->addr);
+
+    OCDevAddr *devaddress = &clientResponse->devAddr;
+    devaddress->adapter = OC_ADAPTER_GATT_BTLE;
+
+    if (strcmp(netProvInfo->netAddressInfo.WIFI.ipAddress, clientResponse->devAddr.addr))
+        OIC_LOG(INFO, TAG, "equal");
+    else
+        OIC_LOG_V(INFO, TAG, "unequal %s %s", netProvInfo->netAddressInfo.WIFI.ipAddress,
+                clientResponse->devAddr.addr);
+
+    OIC_LOG_V(DEBUG, TAG, "query before GetProvisioningStatus call = %s %d", szQueryUri,
+            devaddress->adapter);
+
+    if (GetProvisioningStatus(OC_HIGH_QOS, szQueryUri, devaddress) != OC_STACK_OK)
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        return OC_STACK_DELETE_TRANSACTION;
+    }
+
+    return OC_STACK_KEEP_TRANSACTION;
+
+}
+
+void FindProvisioningResource(void *data)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    /* Start a discovery query*/
+    char szQueryUri[64] =
+    { 0 };
+
+    snprintf(szQueryUri, sizeof(szQueryUri), MULTICAST_PROVISIONING_QUERY_BLE);
+
+    OIC_LOG_V(DEBUG, TAG, "szQueryUri = %s", szQueryUri);
+
+    OCCallbackData ocCBData;
+
+    ocCBData.cb = FindProvisioningResourceResponse;
+    ocCBData.context = (void*) DEFAULT_CONTEXT_VALUE;
+    ocCBData.cd = NULL;
+
+    ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, NULL, OC_CONNTYPE_BLE, OC_LOW_QOS,
+            &ocCBData, NULL, 0);
+
+    if (ret != OC_STACK_OK)
+    {
+        ErrorCallback( DEVICE_NOT_PROVISIONED);
+        ClearMemory();
+    }
+}
+
+OCStackApplicationResult SubscribeProvPresenceCallback(void* ctx, OCDoHandle handle,
+        OCClientResponse* clientResponse)
+{
+    OIC_LOG(INFO, TAG, PCF("Entering SubscribeProvPresenceCallback"));
+
+    OCStackApplicationResult response = OC_STACK_DELETE_TRANSACTION;
+
+    if (clientResponse->result != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+        return response;
+    }
+
+    if (clientResponse)
+    {
+        OIC_LOG(INFO, TAG, PCF("Client Response exists"));
+
+        if (clientResponse->payload && clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
+        {
+            OIC_LOG_V(DEBUG, TAG, "Incoming payload not a representation");
+            return response;
+        }
+
+        OCRepPayload* discoveryPayload = (OCRepPayload*) (clientResponse->payload);
+        if (!discoveryPayload)
+        {
+            OIC_LOG_V(DEBUG, TAG, "invalid payload");
+            return response;
+        }
+
+        char sourceIPAddr[OIC_STRING_MAX_VALUE] =
+        { '\0' };
+        snprintf(sourceIPAddr, sizeof(sourceIPAddr), "%s", clientResponse->addr->addr);
+
+        OIC_LOG_V(DEBUG, TAG, "Discovered %s @ %s", discoveryPayload->uri, sourceIPAddr);
+
+        /* Start a discovery query*/
+        char szQueryUri[64] =
+        { 0 };
+
+        snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PROVISIONING_QUERY, sourceIPAddr, IP_PORT);
+
+        /*if (FindProvisioningResource(qos, szQueryUri) != OC_STACK_OK) {
+         OIC_LOG(ERROR, TAG, "FindProvisioningResource failed");
+         return OC_STACK_KEEP_TRANSACTION;
+         }*/
+    }
+    else
+    {
+        // clientResponse is invalid
+        OIC_LOG(ERROR, TAG, PCF("Client Response is NULL!"));
+    }
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCStackResult SubscribeProvPresence(OCQualityOfService qos, const char* requestURI)
+{
+    OCStackResult ret = OC_STACK_ERROR;
+
+    OCCallbackData cbData;
+
+    cbData.cb = &SubscribeProvPresenceCallback;
+    cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
+    cbData.cd = NULL;
+
+    ret = OCDoResource(NULL, OC_REST_PRESENCE, requestURI, 0, 0, OC_CONNTYPE_BLE, OC_LOW_QOS,
+            &cbData, NULL, 0);
+
+    if (ret != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+    }
+
+    return ret;
+}
+
+OCStackResult FindNetworkResource()
+{
+    OCStackResult ret = OC_STACK_ERROR;
+    if (OCStop() != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+    }
+
+    return ret;
+}
+
+ProvisioningInfo* PrepareProvisioingStatusCB(OCClientResponse * clientResponse,
+        ProvStatus provStatus)
+{
+
+    ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
+
+    if (provInfo == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
+        return NULL;
+    }
+
+    OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
+
+    if (devAddr == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
+        return NULL;
+    }
+
+    strncpy(devAddr->addr, clientResponse->addr->addr, sizeof(devAddr->addr));
+    devAddr->port = clientResponse->addr->port;
+
+    provInfo->provDeviceInfo.addr = devAddr;
+
+    provInfo->provStatus = provStatus;
+
+    return provInfo;
+}
+
+bool ValidateEasySetupParams(const EnrolleeNWProvInfo_t *netInfo,
+        OCProvisioningStatusCB provisioningStatusCallback)
+{
+
+    if (netInfo == NULL || netInfo->netAddressInfo.WIFI.ipAddress == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Request URI is NULL");
+        return false;
+    }
+
+    if (provisioningStatusCallback == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "ProvisioningStatusCallback is NULL");
+        return false;
+    }
+
+    return true;
+
+}
+
+bool InProgress()
+{
+
+    // It means already Easy Setup provisioning session is going on.
+    if (NULL != cbData)
+    {
+        OIC_LOG(ERROR, TAG, "Easy setup session is already in progress");
+        return true;
+    }
+
+    return false;
+}
+
+bool SetProgress(OCProvisioningStatusCB provisioningStatusCallback)
+{
+    ca_mutex_lock(g_provisioningMutex);
+
+    if (InProgress())
+        return false;
+
+    cbData = provisioningStatusCallback;
+
+    ca_mutex_unlock(g_provisioningMutex);
+
+    return true;
+}
+
+bool ResetProgress()
+{
+    ca_mutex_lock(g_provisioningMutex);
+
+    cbData = NULL;
+
+    ca_mutex_unlock(g_provisioningMutex);
+}
+
+ProvisioningInfo* CreateCallBackObject()
+{
+
+    ProvisioningInfo *provInfo = (ProvisioningInfo *) OICCalloc(1, sizeof(ProvisioningInfo));
+
+    if (provInfo == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
+        return NULL;
+    }
+
+    OCDevAddr *devAddr = (OCDevAddr *) OICCalloc(1, sizeof(OCDevAddr));
+
+    if (devAddr == NULL)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to allocate memory");
+        return NULL;
+    }
+
+    provInfo->provDeviceInfo.addr = devAddr;
+
+    return provInfo;
+
+}
+
+ProvisioningInfo* GetCallbackObjectOnError(ProvStatus status)
+{
+
+    ProvisioningInfo *provInfo = CreateCallBackObject();
+    strncpy(provInfo->provDeviceInfo.addr->addr, netProvInfo->netAddressInfo.WIFI.ipAddress,
+            sizeof(provInfo->provDeviceInfo.addr->addr));
+    provInfo->provDeviceInfo.addr->port = IP_PORT;
+    provInfo->provStatus = status;
+    return provInfo;
+}
+
+ProvisioningInfo* GetCallbackObjectOnSuccess(OCClientResponse * clientResponse,
+        ProvStatus provStatus)
+{
+    ProvisioningInfo *provInfo = CreateCallBackObject();
+    strncpy(provInfo->provDeviceInfo.addr->addr, clientResponse->addr->addr,
+            sizeof(provInfo->provDeviceInfo.addr->addr));
+    provInfo->provDeviceInfo.addr->port = clientResponse->addr->port;
+    provInfo->provStatus = provStatus;
+    return provInfo;
+}
+
+bool ValidateFinddResourceResponse(OCClientResponse * clientResponse)
+{
+
+    if (!(clientResponse) || !(clientResponse->payload))
+    {
+
+        OIC_LOG_V(INFO, TAG, "ProvisionEnrolleeResponse received Null clientResponse");
+
+        return false;
+
+    }
+    return true;
+}
+
+bool ValidateEnrolleResponse(OCClientResponse * clientResponse)
+{
+
+    if (!(clientResponse) || !(clientResponse->payload))
+    {
+
+        OIC_LOG_V(INFO, TAG, "ProvisionEnrolleeResponse received Null clientResponse");
+
+        return false;
+
+    }
+
+    if (clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION)
+    {
+
+        OIC_LOG_V(DEBUG, TAG, "Incoming payload not a representation");
+        return false;
+
+    }
+
+    // If flow reachese here means no error condition hit.
+    return true;
+
+}
+
+void SuccessCallback(OCClientResponse * clientResponse)
+{
+    ProvisioningInfo *provInfo = GetCallbackObjectOnSuccess(clientResponse, DEVICE_PROVISIONED);
+    cbData(provInfo);
+}
+
+bool ClearMemory()
+{
+
+    OIC_LOG(DEBUG, TAG, "thread_pool_add_task of FindProvisioningResource failed");
+    ca_thread_pool_free(g_threadPoolHandle);
+    ca_mutex_unlock(g_provisioningMutex);
+    ca_mutex_free(g_provisioningMutex);
+    ca_cond_free(g_provisioningCond);
+
+    return true;
+
+}
+
+bool ConfigEnrolleeObject(const EnrolleeNWProvInfo_t *netInfo)
+{
+
+    //Copy Network Provisioning  Information
+    netProvInfo = (EnrolleeNWProvInfo_t *) OICCalloc(1, sizeof(EnrolleeNWProvInfo_t));
+
+    if (netProvInfo == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid input..");
+        return false;
+    }
+
+    memcpy(netProvInfo, netInfo, sizeof(EnrolleeNWProvInfo_t));
+
+    OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. SSID = %s",
+            netProvInfo->netAddressInfo.WIFI.ssid);
+
+    OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. PWD = %s",
+            netProvInfo->netAddressInfo.WIFI.pwd);
+
+    OIC_LOG_V(DEBUG, TAG, "Network Provisioning Info. MAC ADDRESS = %s",
+            netProvInfo->netAddressInfo.WIFI.ipAddress);
+
+    return true;
+
+}
+
+void LogProvisioningResponse(OCRepPayloadValue* val)
+{
+
+    switch (val->type)
+    {
+        case OCREP_PROP_NULL:
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s: NULL", val->name);
+            break;
+        case OCREP_PROP_INT:
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s(int):%lld", val->name, val->i);
+            break;
+        case OCREP_PROP_DOUBLE:
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s(double):%f", val->name, val->d);
+            break;
+        case OCREP_PROP_BOOL:
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s(bool):%s", val->name, val->b ? "true" : "false");
+            break;
+        case OCREP_PROP_STRING:
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s(string):%s", val->name, val->str);
+            break;
+        case OCREP_PROP_OBJECT:
+            // Note: Only prints the URI (if available), to print further, you'll
+            // need to dig into the object better!
+            OIC_LOG_V(DEBUG, TAG, "\t\t%s(OCRep):%s", val->name, val->obj->uri);
+            break;
+        case OCREP_PROP_ARRAY:
+            switch (val->arr.type)
+            {
+                case OCREP_PROP_INT:
+                    OIC_LOG_V(DEBUG, TAG, "\t\t%s(int array):%lld x %lld x %lld", val->name,
+                            val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
+                    break;
+                case OCREP_PROP_DOUBLE:
+                    OIC_LOG_V(DEBUG, TAG, "\t\t%s(double array):%lld x %lld x %lld", val->name,
+                            val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
+                    break;
+                case OCREP_PROP_BOOL:
+                    OIC_LOG_V(DEBUG, TAG, "\t\t%s(bool array):%lld x %lld x %lld", val->name,
+                            val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
+                    break;
+                case OCREP_PROP_STRING:
+                    OIC_LOG_V(DEBUG, TAG, "\t\t%s(string array):%lld x %lld x %lld", val->name,
+                            val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
+                    break;
+                case OCREP_PROP_OBJECT:
+                    OIC_LOG_V(DEBUG, TAG, "\t\t%s(OCRep array):%lld x %lld x %lld", val->name,
+                            val->arr.dimensions[0], val->arr.dimensions[1], val->arr.dimensions[2]);
+                    break;
+                default:
+                    //OIC_LOG_V(ERROR, TAG, "\t\t%s <-- Unknown/unsupported array type!",
+                    //  val->name);
+                    break;
+            }
+            break;
+        default:
+            /*OC_LOG_V(ERROR, TAG
+             , "\t\t%s <-- Unknown type!", val->name);*/
+            break;
+    }
+}
+