Commit 9472bf98 authored by Larry Sachs's avatar Larry Sachs

UpnpBridge using IoTivity-Constrained

Requires that iotivity-constrained is built using

make DYNAMIC=1 TCP=1 IPV4=1 SECURE=0

Change-Id: I0f404f4112b8f0e64abcee15217b9b96ea648e41
Signed-off-by: Larry Sachs's avatarLarry Sachs <larry.j.sachs@intel.com>
parent 66899385
......@@ -26,7 +26,9 @@ BUILD_TYPE = 'debug'
# Specify the location of the IoTivity project
# example IOTIVITY_BASE = '/home/john/iotivity'
# example IOTIVITY_LITE_BASE = '/home/john/iotivity-constrained'
#IOTIVITY_BASE = '/path/to/IOTIVITY_BASE'
#IOTIVITY_LITE_BASE = '/path/to/IOTIVITY_LITE_BASE'
# The build variant of the IoTivity library
# Values 'debug' or 'release'
......
......@@ -20,6 +20,7 @@
vars = Variables('BuildOptions.txt')
vars.Add(EnumVariable('BUILD_TYPE', 'Specify release or debug build', 'debug', ['debug','release']))
vars.Add(PathVariable('IOTIVITY_LITE_BASE', 'Location of the iotivity lite project', None, PathVariable.PathAccept))
vars.Add(PathVariable('IOTIVITY_BASE', 'Location of the iotivity project', None, PathVariable.PathAccept))
vars.Add(EnumVariable('IOTIVITY_LIB_TYPE', 'Specify release or debug build', 'release', ['debug','release']))
vars.Add(EnumVariable('TARGET_ARCH', 'Target architecture', 'x86_64', ['x86_64']))
......
......@@ -38,5 +38,7 @@ examples_bins.extend(env_samples.Program('Observer.cpp'))
env.SConscript('iotApp/SConscript', exports= ['env', 'iotivity_resource_inc_paths'], duplicate=0)
env.SConscript('iot-lite/SConscript', exports= ['env'], duplicate=0)
env.Install('#/${BUILD_DIR}/bin', examples_bins)
env.Install('#/${BUILD_DIR}/bin', 'BundleConfig.xml')
#******************************************************************
#
# Copyright 2018 Intel Corporation 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.
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Import('env')
iotivity_lite_inc_paths = ['${IOTIVITY_LITE_BASE}',
'${IOTIVITY_LITE_BASE}/include',
'${IOTIVITY_LITE_BASE}/messaging/coap',
'${IOTIVITY_LITE_BASE}/port/linux',
]
#iot_lite_libs = ['iotivity-constrained-server', 'iotivity-constrained-client', 'iotivity-constrained-client-server']
iot_lite_libs = ['iotivity-constrained-server']
env_upnp_iot_lite_bridge = env.Clone()
env_upnp_iot_lite_bridge['CPPPATH'] = iotivity_lite_inc_paths
env_upnp_iot_lite_bridge.AppendUnique(CPPPATH = [
'/usr/include/glib-2.0',
'/usr/lib/glib-2.0/include',
'/usr/lib64/glib-2.0/include',
'/usr/lib/x86_64-linux-gnu/glib-2.0/include/',
'/usr/include/gssdp-1.0',
'/usr/include/gssdp-1.0/libgssdp',
'/usr/include/gupnp-1.0',
'/usr/include/gupnp-1.0/libgupnp',
'/usr/include/libsoup-2.4',
'/usr/include/libsoup-2.4/libsoup',
'/usr/include/libxml2'])
env_upnp_iot_lite_bridge.AppendUnique(CPPPATH = ['#/include/'])
env_upnp_iot_lite_bridge['LIBS'] = [iot_lite_libs, 'pthread', 'boost_regex', 'glib-2.0', 'gobject-2.0', 'gssdp-1.0', 'gupnp-1.0', 'soup-2.4']
env_upnp_iot_lite_bridge['LIBPATH'] = ['/usr/local/lib', '${IOTIVITY_LITE_BASE}/port/linux']
upnp_iot_lite_bridge_cpp = ['UpnpBridgeIotLite.cpp',
'UpnpConnector.cpp',
'UpnpManager.cpp',
'UpnpResource.cpp',
'UpnpDevice.cpp',
'UpnpService.cpp',
'UpnpDimmingService.cpp',
'UpnpPowerSwitchService.cpp',
'UpnpException.cpp']
upnp_iot_lite_bridge_obj = env_upnp_iot_lite_bridge.Object(upnp_iot_lite_bridge_cpp)
upnp_iot_lite_bridge_bins = env_upnp_iot_lite_bridge.Program('UpnpBridgeIotLite', upnp_iot_lite_bridge_obj)
env_upnp_iot_lite_bridge.Install('#/${BUILD_DIR}/bin', upnp_iot_lite_bridge_bins)
//******************************************************************
//
// Copyright 2018 Intel Corporation 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 "UpnpConnector.h"
#define OC_SERVER
#include <oc_api.h>
#include <pthread.h>
#include <signal.h>
static pthread_mutex_t mutex;
static pthread_cond_t cv;
static struct timespec ts;
static int quit = 0;
static UpnpConnector *connector;
static int
app_init(void)
{
int ret = oc_init_platform("Intel", NULL, NULL);
ret |= oc_add_device("/oic/d", "oic.d.bridge", "UPnP Bridge", "ocf.1.0.0",
"ocf.res.1.0.0,ocf.sh.1.0.0", NULL, NULL);
return ret;
}
static void
signal_event_loop(void)
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mutex);
}
static void
register_resources(void)
{
connector = new UpnpConnector();
connector->connect();
}
static void
handle_signal(int signal)
{
(void)signal;
signal_event_loop();
quit = 1;
}
int main()
{
int init;
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = handle_signal;
sigaction(SIGINT, &sa, NULL);
static const oc_handler_t handler = {.init = app_init,
.signal_event_loop = signal_event_loop,
.register_resources = register_resources};
oc_clock_time_t next_event;
init = oc_main_init(&handler);
if (init < 0)
return init;
while (! quit) {
next_event = oc_main_poll();
pthread_mutex_lock(&mutex);
if (next_event == 0) {
pthread_cond_wait(&cv, &mutex);
} else {
ts.tv_sec = (next_event / OC_CLOCK_SECOND);
ts.tv_nsec = (next_event % OC_CLOCK_SECOND) * 1.e09 / OC_CLOCK_SECOND;
pthread_cond_timedwait(&cv, &mutex, &ts);
}
pthread_mutex_unlock(&mutex);
}
if (connector) {
connector->disconnect();
delete connector;
}
oc_main_shutdown();
return 0;
}
This diff is collapsed.
//******************************************************************
//
// Copyright 2018 Intel Corporation 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.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#ifndef UPNP_CONNECTOR_H_
#define UPNP_CONNECTOR_H_
#include <gupnp-context-manager.h>
#include <gupnp-control-point.h>
#include <gupnp-device-proxy.h>
#include <gupnp-service-proxy.h>
#define OC_SERVER
#include <oc_api.h>
using namespace std;
class UpnpConnector
{
public:
UpnpConnector();
virtual ~UpnpConnector();
void connect();
void disconnect();
private:
void gupnpStart();
void gupnpStop();
static void startDiscovery(GUPnPControlPoint *controlPoint);
// static is necessary for callbacks defined with the c gupnp functions (c code)
static void onContextAvailable(GUPnPContextManager *manager, GUPnPContext *context);
static void onDeviceProxyAvailable(GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy, gpointer userData);
static void onDeviceProxyUnavailable(GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy);
static void onServiceProxyAvailable(GUPnPControlPoint *cp, GUPnPServiceProxy *proxy);
static void onServiceProxyUnavailable(GUPnPControlPoint *cp, GUPnPServiceProxy *proxy);
static int checkRequestQueue(gpointer data);
static void onIntrospectionAvailable(GUPnPServiceInfo *serviceInfo,
GUPnPServiceIntrospection *introspection,
const GError *error,
gpointer userContext);
static void unregisterDeviceResource(string udn);
static void initResourceCallbackHandler();
static oc_resource_t *createResource(int device, const string name, const string uri,
const string resourceType, const string resourceInterface, GUPnPServiceInfo *serviceInfo);
};
#endif
//******************************************************************
//
// Copyright 2018 Intel Corporation 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 "UpnpConstants.h"
#include "UpnpException.h"
#include "UpnpInternal.h"
#include "UpnpDevice.h"
#include "UpnpHelper.h"
#include "UpnpService.h"
using namespace std;
static const string MODULE = "UpnpDevice";
UpnpDevice::UpnpDevice(GUPnPDeviceInfo *deviceInfo,
UpnpRequestState *requestState)
{
m_proxy = nullptr;
m_requestState = requestState;
m_udn = gupnp_device_info_get_udn(deviceInfo);
m_deviceType = gupnp_device_info_get_device_type(deviceInfo);
m_resourceType = findResourceType(m_deviceType);
if (m_resourceType == "")
{
throw logic_error(DEVICE_TYPE + string(": ") + m_deviceType + string(" not implemented!"));
return;
}
m_name = getStringField(gupnp_device_info_get_friendly_name, deviceInfo);
string udnWithoutPrefix;
if (m_udn.find(UPNP_PREFIX_UDN) == 0)
{
udnWithoutPrefix = m_udn.substr(UPNP_PREFIX_UDN.size());
}
else
{
udnWithoutPrefix = m_udn;
}
m_uri = UpnpUriPrefixMap[m_resourceType] + udnWithoutPrefix;
if (m_uri.length() > MAX_URI_LENGTH)
{
ERROR_PRINT("URI too long " << m_uri << "( " << m_uri.length());
throw BadUriException("UpnpDevice::ctor: uri length too long");
return;
}
m_interface = UpnpInterfaceMap[m_resourceType];
m_registered = false;
m_deviceList.clear();
m_serviceList.clear();
}
UpnpDevice::~UpnpDevice()
{
m_deviceList.clear();
m_serviceList.clear();
}
void UpnpDevice::insertDevice(string udn)
{
m_deviceList.push_back(udn);
}
void UpnpDevice::insertService(string id)
{
m_serviceList.push_back(id);
}
std::vector<string> &UpnpDevice::getDeviceList()
{
return m_deviceList;
}
std::vector<string> &UpnpDevice::getServiceList()
{
return m_serviceList;
}
static const map< string, function< char *(GUPnPDeviceInfo *deviceInfo)>> s_deviceInfo2AttributesMap
=
{
{"n", gupnp_device_info_get_friendly_name},
{"manufacturer", gupnp_device_info_get_manufacturer},
{"manufacturer_url", gupnp_device_info_get_manufacturer_url},
{"model_number", gupnp_device_info_get_model_number},
{"model_name", gupnp_device_info_get_model_name},
{"model_description", gupnp_device_info_get_model_description},
{"model_url", gupnp_device_info_get_model_url},
{"serial_number", gupnp_device_info_get_serial_number},
{"presentation_url", gupnp_device_info_get_presentation_url},
{"upc", gupnp_device_info_get_upc}
};
void UpnpDevice::setProxy(GUPnPDeviceProxy *proxy)
{
m_proxy = proxy;
}
GUPnPDeviceProxy *UpnpDevice::getProxy()
{
return m_proxy;
}
void UpnpDevice::setParent(const string udn)
{
m_parent = udn;
}
const string UpnpDevice::getParent()
{
return m_parent;
}
// TODO" This should probably live in some UpnpUtil class
string UpnpDevice::getStringField(function< char *(GUPnPDeviceInfo *deviceInfo)> f,
GUPnPDeviceInfo *deviceInfo)
{
char *c_field = f(deviceInfo);
if (c_field != NULL)
{
string s_field = string(c_field);
g_free(c_field);
return s_field;
}
return "";
}
void UpnpDevice::addDeviceCallback(void *data)
{
if (data == NULL)
{
ERROR_PRINT("device data is null");
return;
}
GUPnPDeviceInfo *deviceInfo = (GUPnPDeviceInfo *)data;
// TODO: need a way to remove dead devices
if (! GUPNP_IS_DEVICE_INFO(deviceInfo))
{
DEBUG_PRINT("invalid device info (TODO: remove this device)");
return;
}
oc_set_custom_device_property(DEVICE_TYPE.c_str(), gupnp_device_info_get_device_type(deviceInfo));
DEBUG_PRINT(DEVICE_TYPE << ": " << gupnp_device_info_get_device_type(deviceInfo));
oc_set_custom_device_property(UDN.c_str(), gupnp_device_info_get_udn(deviceInfo));
DEBUG_PRINT(UDN << ": " << gupnp_device_info_get_udn(deviceInfo));
for (auto const &kv : s_deviceInfo2AttributesMap)
{
char *c_field = kv.second(deviceInfo);
if (c_field != NULL)
{
oc_set_custom_device_property(kv.first.c_str(), c_field);
DEBUG_PRINT(kv.first << ": " << c_field);
g_free(c_field);
}
}
}
//******************************************************************
//
// Copyright 2018 Intel Corporation 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.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#ifndef UPNP_DEVICE_H_
#define UPNP_DEVICE_H_
#include <gupnp.h>
#include "UpnpRequest.h"
#include "UpnpResource.h"
#include "UpnpService.h"
using namespace std;
static const string DEVICE_TYPE = "deviceType";
static const string UDN = "udn";
// for icons
static const string OIC_TYPE_ICON = "oic.r.icon";
static const string MIMETYPE = "mimetype";
static const string MEDIA = "media";
static const string ICON_WIDTH = "width";
static const string ICON_HEIGHT = "height";
struct _iconLink {
string href;
string rel;
string rt;
string mimetype;
string media;
int width;
int height;
};
class UpnpDevice: public UpnpResource
{
public:
UpnpDevice(GUPnPDeviceInfo *deviceInfo,
UpnpRequestState *requestState);
virtual ~UpnpDevice();
void insertDevice(string udn);
void insertService(string id);
void setProxy(GUPnPDeviceProxy *proxy);
GUPnPDeviceProxy *getProxy();
const string getParent();
void setParent(const string parent);
std::vector<string> &getDeviceList();
std::vector<string> &getServiceList();
static void addDeviceCallback(void *data);
private:
GUPnPDeviceProxy *m_proxy;
string m_parent;
string m_deviceType;
// UDNs of embedded devices
std::vector<string> m_deviceList;
// IDs of embedded services
std::vector<string> m_serviceList;
UpnpRequestState *m_requestState;
string getStringField(function< char *(GUPnPDeviceInfo *deviceInfo)> f,
GUPnPDeviceInfo *deviceInfo);
};
#endif
//******************************************************************
//
// Copyright 2018 Intel Corporation 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 "UpnpDimmingService.h"
static const string MODULE = "UpnpDimmingService";
// Brightness service
static const char* brightnessLevelName = "brightness";
void UpnpDimming::processGetRequest(oc_request_t *request, oc_interface_mask_t interface, void *user_data)
{
DEBUG_PRINT("request->resource->name=" << oc_string(request->resource->name));
GUPnPServiceInfo *serviceInfo = (GUPnPServiceInfo *)user_data;
GUPnPServiceProxy *proxy = GUPNP_SERVICE_PROXY(serviceInfo);
int64_t brightnessLevelValue = 0;
GError *error = NULL;
if (! gupnp_service_proxy_send_action(proxy, "GetLoadLevelStatus", &error,
// IN args (none)
NULL,
// OUT args
"retLoadlevelStatus", G_TYPE_UINT, &brightnessLevelValue,
NULL))
{
ERROR_PRINT("GetLoadLevelStatus action failed");
if (error)
{
DEBUG_PRINT("Error message: " << error->message);
g_error_free(error);
}
oc_send_response(request, OC_STATUS_INTERNAL_SERVER_ERROR);
return;
}
oc_rep_start_root_object();
oc_process_baseline_interface(request->resource);
DEBUG_PRINT("oc_rep_set_int " << brightnessLevelName << " " << brightnessLevelValue);
oc_rep_set_int(root, brightness, brightnessLevelValue);
oc_rep_end_root_object();
oc_send_response(request, OC_STATUS_OK);
}
void UpnpDimming::processPostRequest(oc_request_t *request, oc_interface_mask_t interface, void *user_data)
{
DEBUG_PRINT("request->resource->name=" << oc_string(request->resource->name));
GUPnPServiceInfo *serviceInfo = (GUPnPServiceInfo *)user_data;
GUPnPServiceProxy *proxy = GUPNP_SERVICE_PROXY(serviceInfo);
int64_t brightnessLevelValue = 0;
oc_rep_t *rep = request->request_payload;
while (rep) {
DEBUG_PRINT("key=" << oc_string(rep->name) << ", rep type=" << rep->type);
char *key = (char *)(rep->name).ptr;
// DEBUG_PRINT("char *key=" << key);
if (strncmp(key, brightnessLevelName, (rep->name).size) == 0) {
switch (rep->type)
{
case OC_REP_INT:
brightnessLevelValue = rep->value.integer;
DEBUG_PRINT("New " << brightnessLevelName << ": " << brightnessLevelValue);
break;
default:
DEBUG_PRINT("Unexpected rep type: " << rep->type);