Implemented Owned devices discovery draft. [Partially working]
authorLomtev Dmytro <d.lomtev@samsung.com>
Thu, 27 Apr 2017 14:13:46 +0000 (17:13 +0300)
committerLomtev Dmytro <d.lomtev@samsung.com>
Thu, 27 Apr 2017 14:15:01 +0000 (17:15 +0300)
network-manager/nmlib/IoT/inc/iotdevice_impl.h
network-manager/nmlib/IoT/src/iotdevice_impl.cpp
network-manager/nmlib/IoT/src/iotivity.cpp
network-manager/nmlib/ctrl_app/src/iot_dev_manager.cpp
network-manager/nmlib/include/iotivity.h
network-manager/test/test_iot_dev_manager.cpp

index f491e9a..493de7b 100644 (file)
@@ -18,7 +18,8 @@ class IoTDevice_impl: public IoTDevice
 public:
     const unsigned CALLBACK_WAIT_TIMEOUT_S = 1;
 
-    IoTDevice_impl(std::shared_ptr<OC::OCResource> device_resource);
+    IoTDevice_impl(std::shared_ptr<OC::OCResource> device_resource, bool connected = true);
+    IoTDevice_impl(const std::string& host, const std::string& uid, bool connected = true);
     ~IoTDevice_impl() override;
 
     const std::string& getUUID() override;
@@ -44,10 +45,9 @@ private:
     std::string uuid;
     std::string spec_ver;
     std::string host;
+    bool online;
     std::mutex mtx;
     std::condition_variable cond_var;
-
-    static const std::string dev_info_uri;
 };
 
 }
index d856a01..39f41b9 100644 (file)
@@ -3,16 +3,60 @@
 
 using namespace OC;
 
-namespace NetworkManager {
-
-const std::string IoTDevice_impl::dev_info_uri{"/oic/d"};
+namespace
+{
+const std::string dev_info_uri{"/oic/d"};
 const std::string dev_type_resource{"oic.d."};
 const std::string dev_type_uri{"/oic/res?rt=oic.wk.d"};
+void printRepresentation(OCRepresentation rep)
+{
+    for (auto itr = rep.begin(); itr != rep.end(); ++itr)
+    {
+        std::cout << "\t" << itr->attrname() << ":\t" << itr->getValueToString() << std::endl;
+        if (itr->type() == AttributeType::Vector)
+        {
+            switch (itr->base_type())
+            {
+            case AttributeType::OCRepresentation:
+                for (auto itr2 : (*itr).getValue<std::vector<OCRepresentation> >())
+                {
+                    printRepresentation(itr2);
+                }
+                break;
+
+            case AttributeType::Integer:
+                for (auto itr2 : (*itr).getValue<std::vector<int> >())
+                {
+                    std::cout << "\t\t" << itr2 << std::endl;
+                }
+                break;
+
+            case AttributeType::String:
+                for (auto itr2 : (*itr).getValue<std::vector<std::string> >())
+                {
+                    std::cout << "\t\t" << itr2 << std::endl;
+                }
+                break;
+
+            default:
+                std::cout << "Unhandled base type " << itr->base_type() << std::endl;
+                break;
+            }
+        }
+        else if (itr->type() == AttributeType::OCRepresentation)
+        {
+            printRepresentation((*itr).getValue<OCRepresentation>());
+        }
+    }
+}
+}
+
+namespace NetworkManager {
 
 using namespace std;
 
-IoTDevice_impl::IoTDevice_impl(std::shared_ptr<OCResource> device_resource)
-    : dev(device_resource), name("unknown"), model("unknown"), type("unknown"), uuid("unknown"), spec_ver("unknown")
+IoTDevice_impl::IoTDevice_impl(std::shared_ptr<OCResource> device_resource, bool connected)
+    : dev(device_resource), name("unknown"), model("unknown"), type("unknown"), uuid("unknown"), spec_ver("unknown"), online(connected)
 {
     host = device_resource->host();
 
@@ -66,6 +110,44 @@ IoTDevice_impl::IoTDevice_impl(std::shared_ptr<OCResource> device_resource)
     cond_var.wait_for(lock, std::chrono::seconds(CALLBACK_WAIT_TIMEOUT_S));
 }
 
+IoTDevice_impl::IoTDevice_impl(const std::string& host, const std::string& uid, bool connected): name("unknown"), model("unknown"), type("unknown"), uuid(uid), spec_ver("unknown"), host(host), online(connected)
+{
+    //std::string uri{"/oic/d?di="};
+    std::string uri = dev_type_uri;
+    uri += "&di=";
+    uri += uuid;
+//    uri += "&rt=oic.wk.d";
+    std::cout << "Request: " << host << uri << std::endl;
+
+    std::unique_lock<std::mutex> lock(mtx);
+
+    auto res = OCPlatform::getDeviceInfo(host, uri, static_cast<OCConnectivityType>(CT_ADAPTER_TCP | CT_IP_USE_V4),
+        [this](const OCRepresentation& rep){
+        std::string value;
+        std::cout << "In getDeviceInfo CALLBACK" << std::endl;
+        printRepresentation(rep);
+
+        if(rep.getValue("n", value))
+        {
+            this->name = std::move(value);
+        }
+
+        if(rep.getValue("icv", value))
+        {
+            this->spec_ver = std::move(value);
+        }
+
+        if(rep.getValue("dmv", value))
+        {
+            this->model = std::move(value);
+        }
+
+        cond_var.notify_one();
+    });
+
+    cond_var.wait_for(lock, std::chrono::seconds(CALLBACK_WAIT_TIMEOUT_S));
+}
+
 IoTDevice_impl::~IoTDevice_impl() 
 {
 
@@ -98,18 +180,17 @@ const std::string& IoTDevice_impl::getHost()
 
 bool IoTDevice_impl::isOnline()
 {
-    // TODO: add implementation
-    return true;
+    return online;
 }
 
 void IoTDevice_impl::ownDevice()
 {
-
+    // TODO: Add implementation
 }
 
 void IoTDevice_impl::unOwnDevice()
 {
-
+    // TODO: Add implementation
 }
 
 }
index 7d4f827..9efe028 100644 (file)
@@ -4,6 +4,9 @@
 #include <iostream>
 #include <mutex>
 #include <condition_variable>
+#include <functional>
+#include <thread>
+#include <chrono>
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wreorder"
 
 using namespace OC;
 
-namespace NetworkManager
+namespace
 {
-
 const std::string SIGNUP = "Sign up";
 const std::string SIGNIN = "Sign in";
 const std::string SIGNOUT = "Sign out";
 
+void printRepresentation(OCRepresentation rep)
+{
+    for (auto itr = rep.begin(); itr != rep.end(); ++itr)
+    {
+        std::cout << "\t" << itr->attrname() << ":\t" << itr->getValueToString() << std::endl;
+        if (itr->type() == AttributeType::Vector)
+        {
+            switch (itr->base_type())
+            {
+            case AttributeType::OCRepresentation:
+                for (auto itr2 : (*itr).getValue<std::vector<OCRepresentation> >())
+                {
+                    printRepresentation(itr2);
+                }
+                break;
+
+            case AttributeType::Integer:
+                for (auto itr2 : (*itr).getValue<std::vector<int> >())
+                {
+                    std::cout << "\t\t" << itr2 << std::endl;
+                }
+                break;
+
+            case AttributeType::String:
+                for (auto itr2 : (*itr).getValue<std::vector<std::string> >())
+                {
+                    std::cout << "\t\t" << itr2 << std::endl;
+                }
+                break;
+
+            default:
+                std::cout << "Unhandled base type " << itr->base_type() << std::endl;
+                break;
+            }
+        }
+        else if (itr->type() == AttributeType::OCRepresentation)
+        {
+            printRepresentation((*itr).getValue<OCRepresentation>());
+        }
+    }
+}
+}
+
+namespace NetworkManager
+{
+
 const std::string IoTivity::DEFAULT_PROVIDER = "samsung";
 const int IoTivity::DEFAULT_TIMEOUT = 10;
 
@@ -31,35 +79,56 @@ struct Params
     OC::PlatformConfig config;
     OCPersistentStorage ps;
     OCAccountManager::Ptr accountMgr;
+    OCPlatform::OCPresenceHandle presenceHandle;
+    bool subscribed;
+
 };
 
 IoTivity* IoTivity::instance = nullptr;
 
 IoTivity::IoTivity(): signedIn(false)
 {
+    params = new Params{OC::PlatformConfig{
+            OC::ServiceType::InProc,
+            OC::ModeType::Client,
+            "0.0.0.0",
+            0,
+            OC::QualityOfService::HighQos
+        }
+//            ,{open_ps, fread, fwrite, fclose, unlink}
+    };
 
+    params->subscribed = false;
 }
 
-//static FILE *open_ps(const char * /*path*/, const char *mode)
-//{
-//    return fopen("/tmp/ps.dat", mode);
-//}
+IoTivity::~IoTivity()
+{
+    if (params != nullptr)
+    {
+        if (params->subscribed)
+        {
+            OCPlatform::unsubscribePresence(params->presenceHandle);
+        }
+
+        delete params;
+    }
+}
 
 IoTivity* IoTivity::getInstance()
 {
     if (instance == nullptr)
     {
-        instance = new IoTivity;
-        instance->params = new Params{OC::PlatformConfig{
-                OC::ServiceType::InProc,
-                OC::ModeType::Client,
-                "0.0.0.0",
-                0,
-                OC::QualityOfService::HighQos
-            }
-            //,{open_ps, fread, fwrite, fclose, unlink}
-        };
-        OC::OCPlatform::Configure(instance->params->config);
+        try
+        {
+            instance = new IoTivity;
+            OC::OCPlatform::Configure(instance->params->config);
+        }
+        catch (std::exception& e)
+        {
+            // TODO: log error
+            std::cerr << "Out of memory" << std::endl;
+            cleanUp();
+        }
     }
     return instance;
 }
@@ -68,7 +137,6 @@ void IoTivity::cleanUp()
 {
     if (instance != nullptr)
     {
-        if (instance->params != nullptr) delete instance->params;
         delete instance;
         instance = nullptr;
     }
@@ -98,7 +166,7 @@ void IoTivity::signIn(const std::string& host, const std::string& login, const s
         throw std::invalid_argument("Wrong login credentials");
 
     OCAccountManager::Ptr accountMgr = OCPlatform::constructAccountManagerObject(host, CT_ADAPTER_TCP);
-    instance->params->accountMgr = accountMgr;
+    params->accountMgr = accountMgr;
 
     std::mutex mtx;
     std::unique_lock<std::mutex> lock(mtx);
@@ -111,8 +179,8 @@ void IoTivity::signIn(const std::string& host, const std::string& login, const s
     bool signUpTimeout = true;
     bool signInTimeout = true;
 
-    auto signUpCb = [&](const OC::HeaderOptions & headerOptions,
-                        const OC::OCRepresentation & rep,
+    auto signUpCb = [&](const HeaderOptions & headerOptions,
+                        const OCRepresentation & rep,
                         const int resultCode)
     {
         resultCodeCb = resultCode;
@@ -140,8 +208,8 @@ void IoTivity::signIn(const std::string& host, const std::string& login, const s
 
 
 
-    auto signInCb = [&](const OC::HeaderOptions & headerOptions,
-                        const OC::OCRepresentation & rep,
+    auto signInCb = [&](const HeaderOptions & headerOptions,
+                        const OCRepresentation & rep,
                         const int resultCode)
     {
         resultCodeCb = resultCode;
@@ -166,7 +234,7 @@ void IoTivity::signOut()
         return;
     }
 
-    OCAccountManager::Ptr accountMgr = instance->params->accountMgr;
+    OCAccountManager::Ptr accountMgr = params->accountMgr;
     std::mutex mtx;
     std::unique_lock<std::mutex> lock(mtx);
     std::condition_variable condVar;
@@ -191,10 +259,69 @@ void IoTivity::signOut()
     signedIn = false;
 }
 
+void presenceCallback(IoTDevicesMap* devmap, const HeaderOptions& headerOption, const OCRepresentation& rep, const int eCode, const int seqNumber)
+{
+    try
+    {
+        if (eCode == OC_STACK_OK && seqNumber <= MAX_SEQUENCE_NUMBER)
+        {
+            std::string rep_list{"prslist"};
+
+            if (rep[rep_list].type() == AttributeType::Vector)
+            {
+                std::vector<OCRepresentation> representations = std::vector<OCRepresentation>(rep[rep_list]);
+                for (auto it : representations)
+                {
+                    std::string state{"off"};
+                    it.getValue("state", state);
+
+                    std::string di;
+
+                    if (it.getValue("di", di))
+                    {
+                        if (devmap->find(di) == devmap->end())
+                        {
+                            std::shared_ptr<IoTDevice> dev(new IoTDevice_impl(rep.getHost(), di, state == "on"));
+                            devmap->emplace(di, dev);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                // TODO: single represetation processing
+                std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" <<std::endl;
+            }
+        }
+        else
+        {
+            if (eCode != OC_STACK_OK)
+            {
+                std::cout << "presence subscribe: " << eCode << std::endl;
+            }
+        }
+    }
+    catch (std::exception &e)
+    {
+        std::cout << "Exception: " << e.what() << " in onObserve" << std::endl;
+    }
+}
 
 IoTDevicesMap IoTivity::getOwnedDevices()
 {
-    return IoTDevicesMap();
+    if (params->subscribed) OCPlatform::unsubscribePresence(params->presenceHandle);
+    IoTDevicesMap devmap{};
+    OCPlatform::subscribeDevicePresence(
+        params->presenceHandle,
+        params->accountMgr->host(),
+        {},
+        CT_DEFAULT,
+        std::bind(presenceCallback, &devmap, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)
+    );
+
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+
+    return devmap;
 }
 
 IoTDevicesMap IoTivity::getUnOwnedDevices()
index 71564fe..ad70d6a 100644 (file)
@@ -63,8 +63,9 @@ void NM_unsubscribeDeviceStateChanged(NM_hContext ctx)
 
 NM_ErrorCode NM_getOwnedDevices(NM_hContext ctx, NM_hDeviceList* dev_list)
 {
-    dev_list = nullptr;
-    return EC_NOT_IMPLEMENTED_YET;
+    if (dev_list == nullptr) return EC_NULL_POINTER;
+    *dev_list = new NM_DeviceList{ctx->instance->getOwnedDevices()};
+    return EC_OK;
 }
 
 NM_ErrorCode NM_freeDeviceList(NM_hDeviceList* dev_list)
index 829a860..c2119d0 100644 (file)
@@ -33,6 +33,7 @@ private:
     static const int DEFAULT_TIMEOUT;
 
     IoTivity();
+    ~IoTivity();
     static IoTivity* instance;
     typedef struct Params* Hparams;
     Hparams params;
index d315351..23036af 100644 (file)
@@ -3,6 +3,9 @@
 #include <nmlib.h>
 #include <string>
 #include <stdexcept>
+#include "iotivity.h"
+
+using namespace NetworkManager;
 
 class IoTDevManagerTest: public ::testing::Test
 {
@@ -10,10 +13,18 @@ public:
     void SetUp() override
     {
         ASSERT_EQ(EC_OK, NM_init(&ctx));
+        std::string login("login");
+        std::string password("password");
+        std::string host("coap+tcp://106.125.46.44:5683");
+
+        ASSERT_NO_THROW(IoTivity::getInstance()->signIn(host, login, password));
+        ASSERT_TRUE(IoTivity::getInstance()->isSignedIn());
     }
 
     void TearDown() override
     {
+        ASSERT_NO_THROW(IoTivity::getInstance()->signOut());
+        ASSERT_FALSE(IoTivity::getInstance()->isSignedIn());
         ASSERT_NO_THROW(NM_cleanup(&ctx));
     }
 protected:
@@ -25,8 +36,7 @@ void each_callback(NM_hDeviceList list, const char* uid, void* param)
     NM_DeviceInfo info;
     ASSERT_EQ(EC_OK, NM_getDeviceInfo(list, uid, &info));
 
-
-
+    std::cout << "Device uid: " << uid << std::endl;
     ASSERT_STRNE(NULL, info.name);
     std::cout << "Device name: " << info.name << std::endl;
     ASSERT_STRNE(NULL, info.model);
@@ -34,6 +44,8 @@ void each_callback(NM_hDeviceList list, const char* uid, void* param)
     ASSERT_STRNE(NULL, info.type);
     std::cout << "Device type: " << info.type << std::endl;
 
+    std::cout << "Device state: " << (info.state == DS_Online ? "online" : "offline") << std::endl;
+
     NM_freeDeviceInfo(&info);
 }
 
@@ -50,4 +62,8 @@ TEST_F(IoTDevManagerTest, unowned_dev_discovery)
     ASSERT_EQ(EC_OK, NM_deviceListForEach(dev_list, each_callback, nullptr));
     NM_freeDeviceList(nullptr);
     NM_freeDeviceList(&dev_list);
+
+    ASSERT_EQ(EC_OK, NM_getOwnedDevices(ctx, &dev_list));
+    std::cout << "Owned devices found: " << NM_getListSize(dev_list) << std::endl;
+    ASSERT_EQ(EC_OK, NM_deviceListForEach(dev_list, each_callback, nullptr));
 }