Browse Source

Init Git repo

Timo Dritschler 8 years ago
commit
1f04383dca

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+# Object files
+*.o
+*.ko
+
+# Libraries
+*.lib
+*.a
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# Folders
+build

+ 64 - 0
CMakeLists.txt

@@ -0,0 +1,64 @@
+cmake_minimum_required(VERSION 2.6)
+project(KIROCS C)
+
+set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
+
+set(TARNAME "kiro-camera-server")
+set(LIBKIROCS_VERSION_MAJOR "0")
+set(LIBKIROCS_VERSION_MINOR "0")
+set(LIBKIROCS_VERSION_PATCH "1")
+set(LIBKIROCS_VERSION_RELEASE "0")
+set(LIBKIROCS_VERSION_STRING "${LIBKIROCS_VERSION_MAJOR}.${LIBKIROCS_VERSION_MINOR}.${LIBKIROCS_VERSION_PATCH}")
+set(VERSION "${LIBKIROCS_VERSION_STRING}")
+set(LIBKIROCS_DESCRIPTION "Small InfiniBand communication Server and Client")
+
+# Increase the ABI version when binary compatibility cannot be guaranteed, e.g.
+# symbols have been removed, function signatures, structures, constants etc.
+# changed.
+set(LIBKIROCS_ABI_VERSION "1")
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/common/cmake")
+
+include(ConfigurePaths)
+include(PkgConfigVars)
+configure_paths(KIROCS)
+
+find_package(PkgConfig)
+pkg_check_modules(GLIB2 glib-2.0>=2.32 REQUIRED)
+pkg_check_modules(GOBJECT2 gobject-2.0>=2.32 REQUIRED)
+pkg_check_modules(GMODULE2 gmodule-2.0>=2.32 REQUIRED)
+pkg_check_modules(GIO2 gio-2.0>=2.32 REQUIRED)
+pkg_check_modules(LIBUCA libuca>=2.0 REQUIRED)
+pkg_check_modules(KIRO kiro>=1.4 REQUIRED)
+
+include_directories(
+    SYSTEM
+    ${CMAKE_CURRENT_SOURCE_DIR}/src
+    ${GLIB2_INCLUDE_DIRS}
+    ${GOBJECT2_INCLUDE_DIRS}
+    ${GMODULE2_INCLUDE_DIRS}
+    ${GIO2_INCLUDE_DIRS}
+    ${LIBUCA_INCLUDE_DIR}
+    ${KIRO_INCLUDE_DIR})
+
+link_directories(
+    ${GLIB2_LIBDIR}
+    ${GOBJECT2_LIBDIR}
+    ${GMODULE2_LIBDIR}
+    ${GIO2_LIBDIR}
+    ${LIBUCA_LIBDIR}
+    ${KIRO_LIBDIR})
+
+set(KIROCS_DEPS
+    ${GLIB2_LIBRARIES}
+    ${GOBJECT2_LIBRARIES}
+    ${GMODULE2_LIBRARIES}
+    ${GIO2_LIBRARIES}
+    ${LIBUCA_LIBRARIES}
+    ${KIRO_LIBRARIES})
+
+set(LIBKIROCS_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+add_definitions(-Wall -Wextra -std=c99)
+
+add_subdirectory(bin)

+ 10 - 0
bin/CMakeLists.txt

@@ -0,0 +1,10 @@
+include_directories(${KIROCS_SOURCE_DIR})
+link_directories(${KIROCS_BINARY_DIR})
+
+add_executable(kiro-camera-server kiro-camera-server.c)
+target_link_libraries(kiro-camera-server ${KIROCS_DEPS})
+
+add_executable(test-camera-server test-server.c)
+target_link_libraries(test-camera-server ${KIROCS_DEPS})
+
+install(TARGETS kiro-camera-server RUNTIME DESTINATION ${KIROCS_BINDIR})

+ 380 - 0
bin/kiro-camera-server.c

@@ -0,0 +1,380 @@
+/* Copyright (C) 2015 Timo Dritschler <timo.dritschler@kit.edu>
+   (Karlsruhe Institute of Technology)
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by the
+   Free Software Foundation; either version 2.1 of the License, or (at your
+   option) any later version.
+
+   This library is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+   details.
+
+   You should have received a copy of the GNU Lesser General Public License along
+   with this library; if not, write to the Free Software Foundation, Inc., 51
+   Franklin St, Fifth Floor, Boston, MA 02110, USA
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "kiro-camera-server.h"
+#include "uca/uca-plugin-manager.h"
+
+
+typedef struct {
+    gboolean exit_flag;
+    UcaCamera *cam;
+    KiroMessenger *messenger;
+    gulong peer_rank;
+    gulong *signal_handlers;
+    GParamSpec **properties;
+} KiroCsData;
+
+
+static gulong
+pspec_size (GType type)
+{
+    gulong ret = 0;
+
+    switch (type) {
+        case G_TYPE_BOOLEAN:
+            ret = sizeof (GParamSpecBoolean);
+            break;
+        case G_TYPE_CHAR:
+            ret = sizeof (GParamSpecChar);
+            break;
+        case G_TYPE_INT:
+            ret = sizeof (GParamSpecInt);
+            break;
+        case G_TYPE_UINT:
+            ret = sizeof (GParamSpecUInt);
+            break;
+        case G_TYPE_LONG:
+            ret = sizeof (GParamSpecLong);
+            break;
+        case G_TYPE_ULONG:
+            ret = sizeof (GParamSpecULong);
+            break;
+        case G_TYPE_INT64:
+            ret = sizeof (GParamSpecInt64);
+            break;
+        case G_TYPE_UINT64:
+            ret = sizeof (GParamSpecUInt64);
+            break;
+        case G_TYPE_FLOAT:
+            ret = sizeof (GParamSpecFloat);
+            break;
+        case G_TYPE_DOUBLE:
+            ret = sizeof (GParamSpecDouble);
+            break;
+        default:
+            ret = sizeof (GParamSpec);    
+    }
+
+    return ret;
+}
+
+static gulong
+gtype_size (GType type)
+{
+    gulong ret = 0;
+
+    switch (type) {
+        case G_TYPE_BOOLEAN:
+            ret = sizeof (gboolean);
+            break;
+        case G_TYPE_CHAR:
+            ret = sizeof (gchar);
+            break;
+        case G_TYPE_INT:
+            ret = sizeof (gint);
+            break;
+        case G_TYPE_ENUM:
+            ret = sizeof (gint);
+            break;
+        case G_TYPE_UINT:
+            ret = sizeof (guint);
+            break;
+        case G_TYPE_LONG:
+            ret = sizeof (glong);
+            break;
+        case G_TYPE_ULONG:
+            ret = sizeof (gulong);
+            break;
+        case G_TYPE_INT64:
+            ret = sizeof (gint64);
+            break;
+        case G_TYPE_UINT64:
+            ret = sizeof (guint64);
+            break;
+        case G_TYPE_FLOAT:
+            ret = sizeof (gfloat);
+            break;
+        case G_TYPE_DOUBLE:
+            ret = sizeof (gdouble);
+            break;
+        default:
+            //ERROR
+            break;
+    }
+
+    return ret;
+}
+
+
+gint
+property_id_from_name(const gchar* name)
+{
+    gint idx = 0;
+    gboolean found = FALSE;
+    for (;idx < N_BASE_PROPERTIES; ++idx) {
+        if (0 == g_strcmp0(name, uca_camera_props[idx])) {
+            found = TRUE;
+            break;
+        }
+    }
+    return found ? idx : -1;
+}
+
+static void
+print_cam_name (gchar *name, gpointer unused)
+{
+    (void) unused;
+    g_print ("-- %s\n", name);
+}
+
+
+static void
+peer_inform_update (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
+{
+    g_print ("Updated %s.\n", pspec->name); 
+
+    GError *error = NULL;
+
+    GVariant *tmp = read_property_scalar (G_OBJECT (cam), pspec->name, pspec->value_type);
+    gsize data_size = g_variant_get_size (tmp);
+
+    PropUpdate *test = g_malloc0 (sizeof (PropUpdate) + data_size);
+    test->id = property_id_from_name (pspec->name);
+    test->type[0] = gtype_to_gvariant_class (pspec->value_type);
+    test->size = data_size;
+    g_variant_store (tmp, test->val);
+    g_variant_unref (tmp);
+
+    KiroMessage message;
+    message.peer_rank = data->peer_rank;
+    message.msg = KIROCS_UPDATE;
+    message.payload = test;
+    message.size = sizeof (PropUpdate) + data_size;
+
+    kiro_messenger_send_blocking (data->messenger, &message, &error);
+    if (error) {
+        g_free (test);
+        g_error ("Oh shit! (%s)", error->message);
+    }
+
+    g_free (test);
+}
+
+
+static gulong
+setup_signal_handler (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
+{
+    GString *signal_name = g_string_new ("notify::");
+    signal_name = g_string_append (signal_name, pspec->name);
+    gulong ret = g_signal_connect (cam, signal_name->str, G_CALLBACK (peer_inform_update), data);
+    g_string_free (signal_name, TRUE);
+    return ret;
+}
+
+
+static void
+null_callback (gpointer unused)
+{
+    (void)unused;
+}
+
+
+static inline gpointer
+unpack_scalar (PropUpdate *src)
+{
+    //Alloc max scalar size
+    gpointer out = g_malloc0 (sizeof (guint64));
+
+    GVariant *var = g_variant_new_from_data ((const GVariantType *)src->type, src->val, \
+            src->size, TRUE, null_callback, NULL);
+    g_variant_get (var, src->type, out);
+    g_variant_unref (var);
+    return out;
+}     
+
+static KiroContinueFlag
+connect_callback (gulong rank, gulong *storage)
+{
+    *storage = rank;
+    return KIRO_CALLBACK_REMOVE;
+}
+
+
+// MAIN HANDLER //
+static KiroContinueFlag
+receive_callback (KiroMessageStatus *status, KiroCsData *data)
+{
+    PropUpdate *update = (PropUpdate *)status->message->payload; 
+
+    if (status->message->msg == KIROCS_EXIT) {
+        g_message ("Peer requested shut down...");
+        data->exit_flag = TRUE;
+    }
+
+    if (status->message->msg == KIROCS_UPDATE) {
+        g_debug ("Unpacking ID %u\n", update->id);
+        gpointer unpacked = unpack_scalar (update); 
+
+        //Don't forget the -1, because the index starts at 0, but property IDs
+        //start at 1...
+        update_property_scalar (G_OBJECT (data->cam),
+                                data->properties[update->id -1]->name,
+                                data->properties[update->id -1]->value_type,
+                                data->signal_handlers[update->id],
+                                unpacked);
+        g_free (unpacked);
+
+    }
+
+    status->request_cleanup = TRUE;
+
+    return KIRO_CALLBACK_CONTINUE;
+}
+
+
+int main (int argc, char *argv[])
+{
+
+    GOptionContext *context;
+    GError *error = NULL;
+
+    static gchar *camera_name = "mock";
+    static gchar *addr = "127.0.0.1";
+    static gchar *port = "60010";
+    static gboolean list = FALSE;
+
+    static GOptionEntry entries[] = {
+        { "camera", 'c', 0, G_OPTION_ARG_STRING, &camera_name, "Uca camera plugin to load", NULL },
+        { "address", 'a', 0, G_OPTION_ARG_STRING, &addr, "Address to listen on", NULL },
+        { "port", 'p', 0, G_OPTION_ARG_STRING, &port, "Port to listen on", NULL },
+        { "list", 'l', 0, G_OPTION_ARG_NONE, &list, "List all available plugins and exit", NULL },
+        { NULL }
+    };
+
+#if !(GLIB_CHECK_VERSION (2, 36, 0))
+    g_type_init ();
+#endif
+
+    context = g_option_context_new ("-l | [-c <CAMERA PLUGIN>] [-a <ADDRESS>] [-p <PORT>]");
+    g_option_context_set_summary (context, "kiro-camera-server provides a remote control host for libuca cameras.\n\
+Once the server is started, you can use the uca-kiro-camera plugin to connect to the server\n\
+over an InfiniBand network and control the loaded remote camera as if it was connected locally.");
+    g_option_context_add_main_entries (context, entries, NULL);
+
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_print ("Error parsing options: %s\n", error->message);
+        exit (-1);
+    }
+
+    if (argc >= 2) {
+        g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
+        exit (0);
+    }
+
+    KiroCsData data;
+    data.exit_flag = FALSE;
+    data.peer_rank = 0;
+
+    UcaPluginManager *pm = uca_plugin_manager_new ();
+    if (list) {
+        GList *names = uca_plugin_manager_get_available_cameras (pm);
+        if (!names) {
+            g_print ("No available plugins found.\n");
+        }
+        else {
+            g_print ("The following Uca camera plugins are available:\n");
+            g_list_foreach (names, (GFunc) print_cam_name, NULL);
+            g_list_free_full (names, g_free);
+        }
+        g_object_unref (pm);
+        exit (0);
+    }
+
+    data.cam = uca_plugin_manager_get_camera (pm, camera_name, &error, NULL);
+    if (!(data.cam)) {
+        g_print ("Failed to load plugin '%s': %s. Exiting.\n", camera_name, error->message);
+        g_object_unref (pm);
+        exit (-1);
+    }
+    g_object_unref (pm);
+
+
+    data.messenger = kiro_messenger_new ();
+    kiro_messenger_start_listen (data.messenger, addr, port, (KiroConnectCallbackFunc) connect_callback, &(data.peer_rank), &error);
+    if (error) {
+        g_print ("Failed to launch Kiro Server: %s Exiting.\n", error->message);
+        g_object_unref (data.cam);
+        exit (-1);
+    }
+
+    // wait for the first peer
+    while (data.peer_rank == 0) {};
+
+    guint num_properties = 0;
+    data.signal_handlers = NULL;
+    data.properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (data.cam), &num_properties);
+    if (!(*data.properties)) {
+        g_object_unref (data.messenger);
+        g_object_unref (data.cam);
+        g_error ("No properties exposed by camera '%s'.", camera_name);
+    }
+    else {
+        data.signal_handlers = g_malloc0 (sizeof (gulong) * (num_properties + 1)); //0 is not a valid property ID
+
+        for (guint idx=0; idx < num_properties; idx++) {
+
+            gint prop_id = property_id_from_name (data.properties[idx]->name);
+            if (0 >= prop_id) {
+                //NONE Base Property.
+                //Inform peer and setup
+                continue;
+            }
+
+            data.signal_handlers[prop_id] = setup_signal_handler (data.cam, data.properties[idx], &data);
+        }
+    }
+
+    //All done. Send READY
+    KiroMessage message;
+    message.peer_rank = data.peer_rank;
+    message.msg = KIROCS_READY;
+    message.size = 0;
+    message.payload = NULL;
+
+    if (!kiro_messenger_send_blocking (data.messenger, &message, &error)) {
+        g_error ("Oh shit!");
+        //TODO
+        //Things
+    }
+
+
+    kiro_messenger_add_receive_callback (data.messenger, (KiroMessageCallbackFunc)receive_callback, &data);
+    while (!(data.exit_flag)) {};
+
+
+    g_free (data.properties);
+    g_free (data.signal_handlers);
+    kiro_messenger_free (data.messenger);
+    g_object_unref (data.cam);
+    return 0;
+};
+
+

+ 236 - 0
bin/kiro-camera-server.h

@@ -0,0 +1,236 @@
+#include "uca/uca-camera.h"
+#include "kiro/kiro-messenger.h"
+
+typedef enum {
+    KIROCS_UPDATE,
+    KIROCS_INSTALL,
+    KIROCS_READY,
+    KIROCS_RPC,
+    KIROCS_EXIT
+}KiroCsCommands;
+
+typedef struct {
+    guint32 id;
+    guint32 size;
+    gboolean scalar;
+    gchar type[2];
+    gchar val[1];
+} PropUpdate;
+
+typedef struct {
+    guint32 str_len;
+    gchar str[1];
+}StrProp;
+
+typedef struct {
+    GType value_type;
+    guint32 name_len;
+    union PSpecs {
+        GParamSpecBoolean bool_spec;
+        GParamSpecChar char_spec;
+        GParamSpecInt int_spec;
+        GParamSpecUInt uint_spec;
+        GParamSpecLong long_spec;
+        GParamSpecULong ulong_spec;
+        GParamSpecInt64 int64_spec;
+        GParamSpecUInt64 uint64_spec;
+        GParamSpecFloat float_spec;
+        GParamSpecDouble double_spec;
+        StrProp str_spec;
+    } spec;
+    gchar name[1];
+} PropertyRequisition;
+
+
+//Forward declaration of the trigger enums for type handling
+GType uca_camera_trigger_source_get_type (void) G_GNUC_CONST;
+#define UCA_TYPE_CAMERA_TRIGGER_SOURCE (uca_camera_trigger_source_get_type ())
+GType uca_camera_trigger_type_get_type (void) G_GNUC_CONST;
+#define UCA_TYPE_CAMERA_TRIGGER_TYPE (uca_camera_trigger_type_get_type ())
+
+
+gchar
+gtype_to_gvariant_class (GType type)
+{
+    gchar ret = '*';
+
+    switch (type) {
+        case G_TYPE_BOOLEAN:
+            ret = G_VARIANT_CLASS_BOOLEAN;
+            break;
+        case G_TYPE_CHAR:
+            ret = G_VARIANT_CLASS_BYTE;
+            break;
+        case G_TYPE_INT:
+            ret = G_VARIANT_CLASS_INT32;
+            break;
+        case G_TYPE_ENUM:
+            ret = G_VARIANT_CLASS_INT32;
+            break;
+        case G_TYPE_UINT:
+            ret = G_VARIANT_CLASS_UINT32;
+            break;
+        case G_TYPE_LONG:
+            ret = G_VARIANT_CLASS_INT64;
+            break;
+        case G_TYPE_ULONG:
+            ret = G_VARIANT_CLASS_UINT64;
+            break;
+        case G_TYPE_INT64:
+            ret = G_VARIANT_CLASS_INT64;
+            break;
+        case G_TYPE_UINT64:
+            ret = G_VARIANT_CLASS_UINT64;
+            break;
+        case G_TYPE_FLOAT:
+            ret = G_VARIANT_CLASS_DOUBLE;
+            break;
+        case G_TYPE_DOUBLE:
+            ret = G_VARIANT_CLASS_DOUBLE;
+            break;
+        default:
+            //ERROR
+            break;
+    }
+
+    return ret;
+}
+
+
+#define GOBJECT_SET(OBJ, PROP, TYPE, DATA) { \
+    g_object_set (OBJ, \
+                  PROP, *(TYPE *)DATA, \
+                  NULL); \
+}
+
+void
+update_property_scalar (GObject *cam, const gchar *prop, GType type, gulong handler, gpointer data)
+{
+    g_debug ("Updating %s, with handler %lu", prop, handler);
+
+    g_signal_handler_block (cam, handler);
+
+    switch (type) {
+        case G_TYPE_BOOLEAN:
+            GOBJECT_SET (cam, prop, gboolean, data);
+            break;
+        case G_TYPE_CHAR:
+            GOBJECT_SET (cam, prop, gchar, data);
+            break;
+        case G_TYPE_INT:
+            GOBJECT_SET (cam, prop, gint, data);
+            break;
+        case G_TYPE_ENUM:
+            GOBJECT_SET (cam, prop, gint, data);
+            break;
+        case G_TYPE_UINT:
+            GOBJECT_SET (cam, prop, guint, data);
+            break;
+        case G_TYPE_LONG:
+            GOBJECT_SET (cam, prop, glong, data);
+            break;
+        case G_TYPE_ULONG:
+            GOBJECT_SET (cam, prop, gulong, data);
+            break;
+        case G_TYPE_INT64:
+            GOBJECT_SET (cam, prop, gint64, data);
+            break;
+        case G_TYPE_UINT64:
+            GOBJECT_SET (cam, prop, guint64, data);
+            break;
+        case G_TYPE_FLOAT:
+            GOBJECT_SET (cam, prop, gfloat, data);
+            break;
+        case G_TYPE_DOUBLE:
+            GOBJECT_SET (cam, prop, gdouble, data);
+            break;
+        default:
+            //TRIGGER_TYPE and TRIGGER_SOURCE are not statically typed and can
+            //not be used in a switch statement...
+            if (type == UCA_TYPE_CAMERA_TRIGGER_SOURCE) {
+                GOBJECT_SET (cam, prop, gint, data);
+                break;
+            }
+
+            if (type ==  UCA_TYPE_CAMERA_TRIGGER_TYPE) {
+                GOBJECT_SET (cam, prop, gint, data);
+                break;
+            }
+
+            g_critical ("Type %s not handled! (SET)", g_type_name (type));
+            break;
+    }
+
+    g_signal_handler_unblock (cam, handler);
+}
+
+
+#define GOBJECT_GET(OBJ, PROP, TYPE, GTYPE) { \
+    TYPE tmp; \
+    gchar *gvclass = g_malloc0 (2); \
+    gvclass[0] = gtype_to_gvariant_class (GTYPE); \
+    g_object_get (OBJ, \
+                  PROP, &tmp, \
+                  NULL); \
+    ret = g_variant_new (gvclass, tmp); \
+    g_free (gvclass); \
+}
+
+GVariant*
+read_property_scalar (GObject *cam, const gchar *prop, GType type)
+{
+    GVariant *ret = NULL;
+
+    switch (type) {
+        case G_TYPE_BOOLEAN:
+            GOBJECT_GET (cam, prop, gboolean, type);
+            break;
+        case G_TYPE_CHAR:
+            GOBJECT_GET (cam, prop, gchar, type);
+            break;
+        case G_TYPE_INT:
+            GOBJECT_GET (cam, prop, gint, type);
+            break;
+        case G_TYPE_ENUM:
+            GOBJECT_GET (cam, prop, gint, type);
+            break;
+        case G_TYPE_UINT:
+            GOBJECT_GET (cam, prop, guint, type);
+            break;
+        case G_TYPE_LONG:
+            GOBJECT_GET (cam, prop, glong, type);
+            break;
+        case G_TYPE_ULONG:
+            GOBJECT_GET (cam, prop, gulong, type);
+            break;
+        case G_TYPE_INT64:
+            GOBJECT_GET (cam, prop, gint64, type);
+            break;
+        case G_TYPE_UINT64:
+            GOBJECT_GET (cam, prop, guint64, type);
+            break;
+        case G_TYPE_FLOAT:
+            GOBJECT_GET (cam, prop, gfloat, type);
+            break;
+        case G_TYPE_DOUBLE:
+            GOBJECT_GET (cam, prop, gdouble, type);
+            break;
+        default:
+            //TRIGGER_TYPE and TRIGGER_SOURCE are not statically typed and can
+            //not be used in a switch statement...
+            if (type == UCA_TYPE_CAMERA_TRIGGER_SOURCE) {
+                GOBJECT_GET (cam, prop, gint, type);
+                break;
+            }
+
+            if (type ==  UCA_TYPE_CAMERA_TRIGGER_TYPE) {
+                GOBJECT_GET (cam, prop, gint, type);
+                break;
+            }
+
+            g_critical ("Type %s not handled! (GET)", g_type_name (type));
+            break;
+    }
+
+    return ret;
+}

+ 71 - 0
bin/test-server.c

@@ -0,0 +1,71 @@
+#include "kiro-camera-server.h"
+
+
+static KiroContinueFlag
+receive_callback (KiroMessageStatus *status, gpointer user_data)
+{
+    g_message ("Received a message of type: %u", status->message->msg);
+    *(gboolean *)user_data = TRUE;
+    return KIRO_CALLBACK_CONTINUE;
+}
+
+
+int main (int argc, char **argv)
+{
+    GError *error = NULL;
+
+    KiroMessenger *messenger = kiro_messenger_new ();
+
+    gboolean flag = FALSE;
+    kiro_messenger_add_receive_callback (messenger, receive_callback, &flag);
+
+    gulong rank = 0;
+    kiro_messenger_connect (messenger, "127.0.0.1", "60010", &rank, &error);
+    if (error) {
+        kiro_messenger_free (messenger);
+        g_error ("Oh shit! (%s)", error->message);
+    }
+
+    while (!flag) {};
+    flag = FALSE;
+
+
+    GVariant *tmp = g_variant_new ("i", UCA_CAMERA_TRIGGER_SOURCE_SOFTWARE);
+    gsize data_size = g_variant_get_size (tmp);
+
+    PropUpdate *test = g_malloc0 (sizeof (PropUpdate) + data_size);
+    test->id = 11;
+    test->type[0] = 'i';
+    test->size = data_size;
+    g_variant_store (tmp, test->val);
+    //g_object_unref (tmp);
+
+    KiroMessage message;
+    message.peer_rank = rank;
+    message.msg = KIROCS_UPDATE;
+    message.payload = test;
+    message.size = sizeof (PropUpdate) + data_size;
+
+    kiro_messenger_send_blocking (messenger, &message, &error);
+    if (error) {
+        kiro_messenger_free (messenger);
+        g_error ("Oh shit! (%s)", error->message);
+    }
+
+    message.msg = KIROCS_EXIT;
+    message.size = 0;
+    message.payload = NULL;
+
+    kiro_messenger_send_blocking (messenger, &message, &error);
+    if (error) {
+        kiro_messenger_free (messenger);
+        g_error ("Oh shit! (%s)", error->message);
+    }
+
+    kiro_messenger_free (messenger);
+
+    return 0;
+
+
+
+}

+ 90 - 0
common/cmake/ConfigurePaths.cmake

@@ -0,0 +1,90 @@
+# - pre-configured paths for CMake
+#
+# Usage:
+#   configure_paths(<PREFIX>)
+#
+# Checks if configure-like prefix and installation paths were passed by the user
+# and sets up corresponding variables for use in install() commands and to fill
+# out .pc files:
+#
+#   PREFIX_PREFIX       defaults to ...     CMAKE_INSTALL_PREFIX
+#   PREFIX_EPREFIX                          PREFIX_PREFIX
+#   PREFIX_SBINDIR                          PREFIX_EPREFIX/sbin
+#   PREFIX_SYSCONFDIR                       PREFIX_PREFIX/etc
+#   PREFIX_LOCALSTATEDIR                    PREFIX_PREFIX/var
+#   PREFIX_BINDIR                           PREFIX_EPREFIX/bin
+#   PREFIX_LIBDIR                           PREFIX_EPREFIX/lib
+#   PREFIX_INCLUDEDIR                       PREFIX_PREFIX/include
+#   PREFIX_PKGCONFIGDIR                     PREFIX_LIBDIR/pkgconfig
+#   PREFIX_TYPELIBDIR                       PREFIX_LIBDIR/girepository-1.0
+#   PREFIX_DATAROOTDIR                      PREFIX_PREFIX/share
+#   PREFIX_DATADIR                          PREFIX_DATAROOTDIR
+#   PREFIX_INFODIR                          PREFIX_DATAROOTDIR/info
+#   PREFIX_MANDIR                           PREFIX_DATAROOTDIR/man
+#   PREFIX_LOCALEDIR                        PREFIX_DATAROOTDIR/locale
+#   PREFIX_GIRDIR                           PREFIX_DATAROOTDIR/gir-1.0
+
+# Copyright (C) 2013 Matthias Vogelgesang <matthias.vogelgesang@gmail.com>
+#
+# Redistribution and use, with or without modification, are permitted
+# provided that the following conditions are met:
+# 
+#    1. Redistributions must retain the above copyright notice, this
+#       list of conditions and the following disclaimer.
+#    2. The name of the author may not be used to endorse or promote
+#       products derived from this software without specific prior
+#       written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+if(__configure_paths)
+    return()
+endif()
+
+set(__configure_paths YES)
+
+macro(_set_var _prefix _var _user _override _description)
+    set(_name "${_prefix}_${_var}")
+
+    set("${_name}" "${_user}")
+
+    if("${_name}" STREQUAL "")
+        set("${_name}" "${_override}")
+    endif()
+
+    set(${_name} "${${_name}}" CACHE PATH "${_description}")
+    mark_as_advanced(${_name})
+endmacro()
+
+function(configure_paths _prefix)
+    _set_var("${_prefix}" "PREFIX"          "${PREFIX}"         "${CMAKE_INSTALL_PREFIX}"               "install architecture-independent files in PREFIX")
+    _set_var("${_prefix}" "EPREFIX"         "${EXEC_PREFIX}"    "${${_prefix}_PREFIX}"                  "install architecture-dependent files in EPREFIX")
+
+    _set_var("${_prefix}" "SBINDIR"         "${SBINDIR}"        "${${_prefix}_EPREFIX}/sbin"            "system admin executabls")
+    _set_var("${_prefix}" "SYSCONFDIR"      "${SYSCONFDIR}"     "${${_prefix}_PREFIX}/etc"              "read-only single-machine data")
+    _set_var("${_prefix}" "LOCALSTATEDIR"   "${LOCALSTATEDIR}"  "${${_prefix}_PREFIX}/var"              "modifiable single-machine data")
+    _set_var("${_prefix}" "BINDIR"          "${BINDIR}"         "${${_prefix}_EPREFIX}/bin"             "user executables")
+    _set_var("${_prefix}" "LIBDIR"          "${LIBDIR}"         "${${_prefix}_EPREFIX}/lib"             "object code libraries")
+    _set_var("${_prefix}" "INCLUDEDIR"      "${INCLUDEDIR}"     "${${_prefix}_PREFIX}/include"          "C header files")
+    _set_var("${_prefix}" "PKGCONFIGDIR"    "${PKGCONFIGDIR}"   "${${_prefix}_LIBDIR}/pkgconfig"        "pkg-config files")
+    _set_var("${_prefix}" "TYPELIBDIR"      "${TYPELIBDIR}"     "${${_prefix}_LIBDIR}/girepository-1.0" "GObject run-time introspection data")
+    _set_var("${_prefix}" "DATAROOTDIR"     "${DATAROOTDIR}"    "${${_prefix}_PREFIX}/share"            "read-only arch.-independent data root")
+    _set_var("${_prefix}" "DATADIR"         "${DATADIR}"        "${${_prefix}_DATAROOTDIR}"             "read-only architecture-independent data")
+    _set_var("${_prefix}" "INFODIR"         "${INFODIR}"        "${${_prefix}_DATAROOTDIR}/info"        "info documentation")
+    _set_var("${_prefix}" "MANDIR"          "${MANDIR}"         "${${_prefix}_DATAROOTDIR}/man"         "man documentation")
+    _set_var("${_prefix}" "LOCALEDIR"       "${LOCALEDIR}"      "${${_prefix}_DATAROOTDIR}/locale"      "locale-dependent data")
+    _set_var("${_prefix}" "GIRDIR"          "${GIRDIR}"         "${${_prefix}_DATAROOTDIR}/gir-1.0"     "GObject introspection data")
+endfunction()
+
+# vim: tw=0:

+ 30 - 0
common/cmake/PkgConfigVars.cmake

@@ -0,0 +1,30 @@
+# - determine variables defined in pkg-config files
+#
+# Usage:
+#   pkg_check_variable(<PKG_NAME> <VARIABLE_NAME>)
+#
+# Checks for a variable in the given package and translates to a call such as
+# `pkg-config --variable=<VARIABLE_NAME> <PKG_NAME>`. The output is a cached
+# variable named
+#
+#   <PKG_NAME>_<VARIABLE_NAME>
+#
+# Note that both names are uppercased and any dashes replaced by underscores.
+#
+
+find_package(PkgConfig REQUIRED)
+
+function(pkg_check_variable _pkg _name)
+    string(TOUPPER ${_pkg} _pkg_upper)
+    string(TOUPPER ${_name} _name_upper)
+    string(REPLACE "-" "_" _pkg_upper ${_pkg_upper})
+    string(REPLACE "-" "_" _name_upper ${_name_upper})
+    set(_output_name "${_pkg_upper}_${_name_upper}")
+
+    execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${_name} ${_pkg}
+                    OUTPUT_VARIABLE _pkg_result
+                    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    set("${_output_name}" "${_pkg_result}" CACHE STRING "pkg-config variable
+    ${_name} of ${_pkg}")
+endfunction()

+ 13 - 0
src/CMakeLists.txt

@@ -0,0 +1,13 @@
+include_directories(${KIROCS_SOURCE_DIR})
+link_directories(${KIROCS_BINARY_DIR})
+
+add_library(libucakiro SHARED uca-kiro-camera.c)
+target_link_libraries(libucakiro ${KIROCS_DEPS})
+
+set_target_properties(libucakiro PROPERTIES
+    VERSION "${LIBKIROCS_VERSION_MAJOR}.${LIBKIROCS_VERSION_MINOR}"
+    SOVERSION ${LIBKIROCS_VERSION_PATCH}
+)
+
+install(FILES uca-kiro-camera.h DESTINATION ${KIROCS_BINDIR})
+install(TARGETS uca-kiro-camera LIBRARY DESTINATION ${LIBUCA_LIBDIR}/uca)

+ 1115 - 0
src/uca-kiro-camera.cpp

@@ -0,0 +1,1115 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+   (Karlsruhe Institute of Technology)
+
+   This library is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by the
+   Free Software Foundation; either version 2.1 of the License, or (at your
+   option) any later version.
+
+   This library is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+   details.
+
+   You should have received a copy of the GNU Lesser General Public License along
+   with this library; if not, write to the Free Software Foundation, Inc., 51
+   Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+
+#include <tango.h>
+
+extern "C" {
+#include <gmodule.h>
+#include <gio/gio.h>
+#include <string.h>
+#include <math.h>
+#include <kiro/kiro-sb.h>
+#include "uca-kiro-camera.h"
+} // EXTERN  C
+
+#define UCA_KIRO_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UCA_TYPE_KIRO_CAMERA, UcaKiroCameraPrivate))
+
+static void uca_kiro_initable_iface_init (GInitableIface *iface);
+GError *initable_iface_error = NULL;
+
+G_DEFINE_TYPE_WITH_CODE (UcaKiroCamera, uca_kiro_camera, UCA_TYPE_CAMERA,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                uca_kiro_initable_iface_init))
+
+
+/**
+ * UcaCameraError:
+   @UCA_KIRO_CAMERA_ERROR_MISSING_TANGO_ADDRESS: No TANGO address ('kiro-tango-address') property was supplied during camera creation
+   @UCA_KIRO_CAMERA_ERROR_TANGO_CONNECTION_FAILED: Could not connect to the given TANGO address
+   @UCA_KIRO_CAMERA_ERROR_KIRO_CONNECTION_FAILED: Failed to establish a KIRO connection to the given TANGO server
+   @UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED: A TANGO exception was raised during communication with the server
+   @UCA_KIRO_CAMERA_ERROR_BAD_CAMERA_INTERFACE: The given TANGO server does not expose the expected UcaCamera base interface
+ */
+GQuark uca_kiro_camera_error_quark()
+{
+    return g_quark_from_static_string ("uca-kiro-camera-error-quark");
+}
+
+
+enum {
+    PROP_KIRO_ADDRESS = N_BASE_PROPERTIES,
+    PROP_KIRO_PORT,
+    PROP_KIRO_TANGO_ADDRESS,
+    PROP_KIRO_REMOTE_NAME,
+    N_PROPERTIES
+};
+
+static const gint kiro_overrideables[] = {
+    PROP_NAME,
+    0,
+};
+
+static GParamSpec *kiro_properties[N_PROPERTIES] = { NULL, };
+
+struct _UcaKiroCameraPrivate {
+    guint8 *dummy_data;
+    guint current_frame;
+    gchar *kiro_address;
+    gchar *kiro_port;
+    guint kiro_port_uint;
+    gchar *kiro_tango_address;
+    gchar *remote_name;
+    Tango::DeviceProxy *tango_device;
+    GParamSpec **kiro_dynamic_attributes;
+
+    gboolean thread_running;
+    gboolean kiro_connected;
+    gboolean construction_error;
+
+    GThread *grab_thread;
+    KiroSb *receive_buffer;
+
+    guint roi_height;
+    guint roi_width;
+    guint bytes_per_pixel;
+};
+
+static gpointer
+kiro_grab_func(gpointer data)
+{
+    UcaKiroCamera *kiro_camera = UCA_KIRO_CAMERA (data);
+    g_return_val_if_fail (UCA_IS_KIRO_CAMERA (kiro_camera), NULL);
+
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (kiro_camera);
+    UcaCamera *camera = UCA_CAMERA (kiro_camera);
+    gdouble fps;
+    g_object_get (G_OBJECT (data), "frames-per-second", &fps, NULL);
+    const gulong sleep_time = (gulong) G_USEC_PER_SEC / fps;
+
+    while (priv->thread_running) {
+        camera->grab_func (NULL, camera->user_data);
+        g_usleep (sleep_time);
+    }
+
+    return NULL;
+}
+
+static void
+uca_kiro_camera_start_recording(UcaCamera *camera, GError **error)
+{
+    gboolean transfer_async = FALSE;
+    UcaKiroCameraPrivate *priv;
+    g_return_if_fail(UCA_IS_KIRO_CAMERA (camera));
+
+    priv = UCA_KIRO_CAMERA_GET_PRIVATE (camera);
+    g_object_get (G_OBJECT(camera),
+            "transfer-asynchronously", &transfer_async,
+            NULL);
+
+    //'Cache' ROI settings from TANGO World
+    g_object_get (G_OBJECT(camera),
+            "roi-width", &priv->roi_width,
+            NULL);
+    g_object_get (G_OBJECT(camera),
+            "roi-height", &priv->roi_height,
+            NULL);
+
+    size_t bits = 0;
+    g_object_get (G_OBJECT(camera),
+            "sensor-bitdepth", &bits,
+            NULL);
+
+    priv->bytes_per_pixel = 1;
+    if (bits > 8) priv->bytes_per_pixel++;
+    if (bits > 16) priv->bytes_per_pixel++;
+    if (bits > 24) priv->bytes_per_pixel++;
+
+    Tango::DevState state;
+    g_object_get (G_OBJECT(camera),
+            "State", &state,
+            NULL);
+    try {
+        if (Tango::DevState::STANDBY == state)
+            priv->tango_device->command_inout ("StartRecording");
+    }
+    catch (Tango::DevFailed &e) {
+        g_warning ("Failed to execute 'StartRecording' on the remote camera due to a TANGO exception.\n");
+        g_set_error (error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED,
+                     "A TANGO exception was raised: '%s'", (const char *)e.errors[0].desc);
+        return;
+    }
+
+
+    /*
+     * In case asynchronous transfer is requested, we start a new thread that
+     * invokes the grab callback, otherwise nothing will be done here.
+     */
+    if (transfer_async) {
+        GError *tmp_error = NULL;
+        priv->thread_running = TRUE;
+        priv->grab_thread = g_thread_create (kiro_grab_func, camera, TRUE, &tmp_error);
+
+        if (tmp_error != NULL) {
+            priv->thread_running = FALSE;
+            g_propagate_error (error, tmp_error);
+            try {
+                priv->tango_device->command_inout ("StopRecording");
+            }
+            catch (Tango::DevFailed &e) {
+                g_warning ("Failed to execute 'StopRecording' on the remote camera due to a TANGO exception: '%s'\n", (const char *)e.errors[0].desc);
+            }
+        }
+    }
+
+    kiro_sb_thaw (priv->receive_buffer);
+}
+
+static void
+uca_kiro_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+    g_return_if_fail(UCA_IS_KIRO_CAMERA (camera));
+    UcaKiroCameraPrivate *priv;
+    priv = UCA_KIRO_CAMERA_GET_PRIVATE (camera);
+
+    Tango::DevState state;
+    g_object_get (G_OBJECT(camera),
+            "State", &state,
+            NULL);
+
+    try {
+        if (Tango::DevState::RUNNING == state)
+            priv->tango_device->command_inout ("StopRecording");
+    }
+    catch (Tango::DevFailed &e) {
+        g_warning ("Failed to execute 'StopRecording' on the remote camera due to a TANGO exception.\n");
+        g_set_error (error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED,
+                     "A TANGO exception was raised: '%s'", (const char *)e.errors[0].desc);
+    }
+
+    gboolean transfer_async = FALSE;
+    g_object_get(G_OBJECT (camera),
+            "transfer-asynchronously", &transfer_async,
+            NULL);
+
+    if (transfer_async) {
+        priv->thread_running = FALSE;
+        g_thread_join (priv->grab_thread);
+    }
+
+    kiro_sb_freeze (priv->receive_buffer);
+    g_free (priv->dummy_data);
+}
+
+static void
+uca_kiro_camera_trigger (UcaCamera *camera, GError **error)
+{
+}
+
+static gboolean
+uca_kiro_camera_grab (UcaCamera *camera, gpointer data, GError **error)
+{
+    g_return_val_if_fail (UCA_IS_KIRO_CAMERA (camera), FALSE);
+
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (camera);
+
+    //This is a hack to make sure we actually wait for a new frame;
+    gpointer frame = kiro_sb_get_data_blocking (priv->receive_buffer);
+
+    kiro_sb_freeze (priv->receive_buffer);
+    //Element 0 might still be in the process of being written. 
+    //Therefore, we take Element 1, to be sure this one is finished.
+    if (data)
+        g_memmove (data, frame, priv->roi_width * priv->roi_height * priv->bytes_per_pixel);
+    kiro_sb_thaw (priv->receive_buffer);
+
+    return TRUE;
+}
+
+
+
+// ---------------------------------------------------------- //
+//                      TANGO <-> GLib                        //
+// ---------------------------------------------------------- //
+gboolean
+unpack_gvaluearray_from_tango (GValue *value, Tango::DeviceAttribute &t_attr, GParamSpec *pspec)
+{
+    GType value_type = ((GParamSpecValueArray*)pspec)->element_spec->value_type;
+    if (G_TYPE_UINT != value_type) {
+        g_print ("Array type attribue '%s' holds elements of type '%s' which can't be handled.\n", pspec->name, g_type_name (value_type) );
+        return FALSE;
+    }
+
+    guint array_length = t_attr.get_dim_x ();
+    GValueArray *gvalarray = g_value_array_new (array_length);
+
+    //Convenience Macro to prevent either having to rewrite this block
+    //of code over and over again, or creating two almost identical
+    // switch-cases...
+    //UNPACK TANGO GVALUEARRAY
+    #define __U_T_GVA(__GTYPE, __GFUNC) { \
+        vector<__GTYPE> t_vect; \
+        t_attr >> t_vect; \
+        for (guint idx = 0; idx < array_length; idx++) { \
+            g_value_array_append (gvalarray, NULL); \
+            GValue *val = g_value_array_get_nth (gvalarray, idx); \
+            g_value_init (val, value_type); \
+            __GFUNC (val, t_vect[idx]); \
+        } \
+    }
+
+    switch (value_type) {
+        case G_TYPE_BOOLEAN:
+            //We need to to this manualy since there is no implicit conversion from c++ bool to gboolean
+            {
+                vector<bool> t_vect;
+                t_attr >> t_vect;
+                for (guint idx = 0; idx < array_length; idx++) {
+                    g_value_array_append (gvalarray, NULL);
+                    GValue *val = g_value_array_get_nth (gvalarray, idx);
+                    g_value_init (val, value_type);
+                    g_value_set_boolean (val, (t_vect[idx] ? TRUE : FALSE));
+                }
+            }
+            break;
+        case G_TYPE_STRING:
+            //We need to to this manualy since there is no implicit conversion from c++ string to gchar*
+            {
+                vector<string> t_vect;
+                t_attr >> t_vect;
+                for (guint idx = 0; idx < array_length; idx++) {
+                    g_value_array_append (gvalarray, NULL);
+                    GValue *val = g_value_array_get_nth (gvalarray, idx);
+                    g_value_init (val, value_type);
+                    g_value_set_string (val, t_vect[idx].c_str ());
+                }
+            }
+            break;
+        case G_TYPE_UCHAR:
+            __U_T_GVA (guchar, g_value_set_uchar);
+            break;
+        case G_TYPE_INT:
+            __U_T_GVA (gint, g_value_set_int);
+            break;
+        case G_TYPE_UINT:
+            __U_T_GVA (guint, g_value_set_uint);
+            break;
+        case G_TYPE_INT64:
+            __U_T_GVA (gint64, g_value_set_int64);
+            break;
+        case G_TYPE_UINT64:
+            __U_T_GVA (guint64, g_value_set_uint64);
+            break;
+        case G_TYPE_LONG:
+            __U_T_GVA (glong, g_value_set_long);
+            break;
+        case G_TYPE_ULONG:
+            __U_T_GVA (gulong, g_value_set_ulong);
+            break;
+        case G_TYPE_FLOAT:
+            __U_T_GVA (gfloat, g_value_set_float);
+            break;
+        case G_TYPE_DOUBLE:
+            __U_T_GVA (gdouble, g_value_set_double);
+            break;
+        default:
+            g_print ("Array type attribue '%s' holds elements of type '%s' which can't be handled.\n", pspec->name, g_type_name (value_type) );
+            return FALSE;
+    }
+
+    g_value_set_boxed_take_ownership (value, gvalarray);
+    return TRUE;
+}
+
+
+void
+try_handle_read_tango_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+    Tango::DeviceAttribute t_attr;
+    UcaKiroCamera *camera = UCA_KIRO_CAMERA (object);
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (camera);
+
+    bool property_is_handled = (property_id >= N_PROPERTIES) ? (bool)priv->kiro_dynamic_attributes[property_id] : (bool)kiro_properties[property_id];
+
+    if (property_is_handled) {
+        try {
+            priv->tango_device->read_attribute (pspec->name, t_attr);
+        }
+        catch (Tango::DevFailed &e) {
+            g_warning ("Property '%s' could not be read due to an unexpected TANGO error...\n", pspec->name);
+            Tango::Except::print_exception (e);
+            return;
+        }
+
+        //Stupid workaround for TANGO::State attribute...
+        //Because they just HAD to make a special case
+        //for that one specific Enum...
+        if (0 == g_strcmp0 (pspec->name, "State")) {
+            Tango::DevState state;
+            t_attr >> state;
+            g_value_set_uint (value, (unsigned int)state);
+            return;
+        }
+
+        //Convenience Macro to prevent having to write this block
+        //of code over and over again
+        #define T_TO_G_CONVERT(GTYPE, T_ATTR, FUNCTION, TARGET) { \
+            GTYPE t_val; \
+            T_ATTR >> t_val; \
+            FUNCTION (TARGET, t_val); \
+        }
+
+        // 17.06.2015
+        // Somehow the implicit conversions from the glib types to any datatype
+        // known by TANGO got broken. We need to use the explicit C++ types here
+        // to make TANGO happy and then rely on the implicit conversion back to
+        // glib types when the call to g_value_set_XXX occurs...
+        switch (value->g_type) {
+        case G_TYPE_FLOAT:
+            T_TO_G_CONVERT (float, t_attr, g_value_set_float, value);
+            break;
+        case G_TYPE_DOUBLE:
+            T_TO_G_CONVERT (double, t_attr, g_value_set_double, value);
+            break;
+        case G_TYPE_UCHAR:
+            T_TO_G_CONVERT (unsigned char, t_attr, g_value_set_uchar, value);
+            break;
+        case G_TYPE_INT:
+            T_TO_G_CONVERT (short int, t_attr, g_value_set_int, value);
+            break;
+        case G_TYPE_UINT:
+            T_TO_G_CONVERT (unsigned short int, t_attr, g_value_set_uint, value);
+            break;
+        case G_TYPE_LONG:
+            T_TO_G_CONVERT (long int, t_attr, g_value_set_long, value);
+            break;
+        case G_TYPE_ULONG:
+            T_TO_G_CONVERT (unsigned long int, t_attr, g_value_set_ulong, value);
+            break;
+        case G_TYPE_INT64:
+            T_TO_G_CONVERT (int64_t, t_attr, g_value_set_int64, value);
+            break;
+        case G_TYPE_UINT64:
+            T_TO_G_CONVERT (uint64_t, t_attr, g_value_set_uint64, value);
+            break;
+        case G_TYPE_BOOLEAN:
+            {
+                bool t_val;
+                t_attr >> t_val;
+                g_value_set_boolean (value, (t_val ? TRUE : FALSE));
+            }
+            break;
+        case G_TYPE_STRING:
+            {
+                string t_val;
+                t_attr >> t_val;
+                g_value_set_string (value, t_val.c_str ());
+            }
+            break;
+        default:
+            {
+                if (g_type_parent (value->g_type) == G_TYPE_ENUM) {
+                    T_TO_G_CONVERT (gint, t_attr, g_value_set_enum, value);
+                    break;
+                }
+
+                if (G_TYPE_VALUE_ARRAY == value->g_type) {
+                    if (Tango::AttrDataFormat::SPECTRUM != t_attr.get_data_format ()) {
+                        g_warning ("TANGO attribute '%s' is not of type SPECTRUM! (Not a 1-dimensional array, yet libuca was expecting one.)\n", pspec->name);
+                        return;
+                    }
+
+                    if (0 == unpack_gvaluearray_from_tango (value, t_attr, pspec))
+                        g_warning ("Failed to read property '%s'\n", pspec->name);
+
+                    return;
+                }
+
+                GType unhandled = pspec->value_type;
+                if (G_TYPE_GTYPE == unhandled) {
+                    unhandled = ((GParamSpecGType*)pspec)->is_a_type;
+                }
+                g_print ("GType '%s' can't be handled...\n", g_type_name (unhandled));
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            }
+        }
+    }
+    else {
+        g_print ("Unhandled property...\n");
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+
+#undef T_TO_G_CONVERT
+}
+
+
+gboolean
+pack_gvaluearray_to_tango (const GValue *value, Tango::DeviceAttribute &t_attr, GParamSpec *pspec)
+{
+
+    GType value_type = ((GParamSpecValueArray*)pspec)->element_spec->value_type;
+    GValueArray *gvalarray = (GValueArray *) g_value_get_boxed (value);
+    guint array_length = gvalarray->n_values;
+
+    //Convenience Macro to prevent either having to rewrite this block
+    //of code over and over again, or creating two almost identical
+    // switch-cases...
+    #define __P_GVA_T(__GTYPE, __GFUNC) { \
+        vector<__GTYPE> t_vect (array_length); \
+        for (guint idx = 0; idx < array_length; idx++) { \
+            GValue *val = g_value_array_get_nth (gvalarray, idx); \
+            t_vect[idx] = __GFUNC (val); \
+        } \
+        t_attr << t_vect; \
+    }
+
+    switch (value_type) {
+        case G_TYPE_BOOLEAN:
+            __P_GVA_T (bool, g_value_get_boolean); //This relys on the implicit conversion from int to c++ bool
+            break;
+        case G_TYPE_UCHAR:
+            __P_GVA_T (guchar, g_value_get_uchar);
+            break;
+        case G_TYPE_STRING:
+            __P_GVA_T (string, g_value_get_string); //This relys on the implicit conversion from char* to c++ string
+            break;
+        case G_TYPE_INT:
+            __P_GVA_T (gint, g_value_get_int);
+            break;
+        case G_TYPE_UINT:
+            __P_GVA_T (guint, g_value_get_uint);
+            break;
+        case G_TYPE_INT64:
+            __P_GVA_T (gint64, g_value_get_int64);
+            break;
+        case G_TYPE_UINT64:
+            __P_GVA_T (guint64, g_value_get_uint64);
+            break;
+        case G_TYPE_LONG:
+            __P_GVA_T (glong, g_value_get_long);
+            break;
+        case G_TYPE_ULONG:
+            __P_GVA_T (gulong, g_value_get_ulong);
+            break;
+        case G_TYPE_FLOAT:
+            __P_GVA_T (gfloat, g_value_get_float);
+            break;
+        case G_TYPE_DOUBLE:
+            __P_GVA_T (gdouble, g_value_get_double);
+            break;
+        default:
+            g_print ("Array type attribue '%s' holds elements of type '%s' which can't be handled.\n", pspec->name, g_type_name (value_type) );
+            return FALSE;
+    }
+
+    t_attr.data_format = Tango::AttrDataFormat::SPECTRUM;
+    t_attr.dim_x = array_length;
+    return TRUE;
+
+#undef __P_GVA_T
+}
+
+
+void
+try_handle_write_tango_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+    Tango::DeviceAttribute t_attr;
+    UcaKiroCamera *camera = UCA_KIRO_CAMERA (object);
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (camera);
+
+    bool property_is_handled = (property_id > N_PROPERTIES) ? (bool)priv->kiro_dynamic_attributes[property_id] : (bool)kiro_properties[property_id];
+
+    if (property_is_handled) {
+
+        // 17.06.2015
+        // Implicit conversions from glib types to TANGO C++ types are broken.
+        // We need to to a manual cast for each one to make TANGO happy again...
+        switch (value->g_type) {
+            case G_TYPE_BOOLEAN:
+                {
+                    bool t_val = (g_value_get_boolean (value) == TRUE);
+                    t_attr << t_val;
+                }
+                break;
+            case G_TYPE_INT:
+                t_attr << (int)g_value_get_int (value);
+                break;
+            case G_TYPE_FLOAT:
+                t_attr << (float)g_value_get_float (value);
+                break;
+            case G_TYPE_DOUBLE:
+                t_attr << (double)g_value_get_double (value);
+                break;
+            case G_TYPE_UINT:
+                t_attr << (unsigned short int)g_value_get_uint (value);
+                break;
+            case G_TYPE_ULONG:
+                t_attr << (unsigned long int)g_value_get_ulong (value);
+                break;
+            case G_TYPE_STRING:
+                t_attr << g_value_get_string (value);
+                break;
+            case G_TYPE_UCHAR:
+                t_attr << (unsigned char)g_value_get_uchar (value);
+                break;
+            case G_TYPE_INT64:
+                t_attr << (int64_t)g_value_get_int64 (value);
+                break;
+            case G_TYPE_UINT64:
+                t_attr << (uint64_t)g_value_get_uint64 (value);
+                break;
+            case G_TYPE_LONG:
+                t_attr << (long int)g_value_get_long (value);
+                break;
+            case G_TYPE_ENUM:
+                t_attr << g_value_get_enum (value);
+                break;
+            default:
+                {
+                    if (g_type_parent (value->g_type) == G_TYPE_ENUM) {
+                        t_attr << g_value_get_enum (value);
+                        break;
+                    }
+
+                    if (value->g_type == G_TYPE_VALUE_ARRAY) {
+                        if (0 == pack_gvaluearray_to_tango (value, t_attr, pspec)) {
+                            g_warning ("Failed to write property '%s'.\n", pspec->name);
+                            return;
+                        }
+                        break;
+                    }
+
+                    GType unhandled = value->g_type;
+                    if (G_TYPE_GTYPE == unhandled) {
+                        unhandled = ((GParamSpecGType*)pspec)->is_a_type;
+                    }
+                    g_print ("GType '%s' can't be handled...\n", g_type_name (unhandled));
+                    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                }
+                break;
+        }
+
+        t_attr.set_name (pspec->name);
+
+        try {
+            priv->tango_device->write_attribute (t_attr);
+        }
+        catch (Tango::DevFailed &e) {
+            g_warning ("Property '%s' could not be written due to a TANGO exception: '%s'\n", pspec->name, (const char *)e.errors[0].desc);
+            Tango::Except::print_exception (e);
+            return;
+        }
+    }
+    else
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+GType
+gtype_from_tango_type (Tango::CmdArgType t)
+{
+    using namespace Tango;
+        switch (t) {
+            case DEV_VOID:
+                return G_TYPE_NONE;
+            case DEV_BOOLEAN:
+                return G_TYPE_BOOLEAN;
+            case DEV_SHORT:
+                //Fall-through intentional
+            case DEV_INT:
+                //Fall-through intentional
+            case DEV_LONG:
+                return G_TYPE_INT;
+            case DEV_FLOAT:
+                return G_TYPE_FLOAT;
+            case DEV_DOUBLE:
+                return G_TYPE_DOUBLE;
+            case DEV_ULONG:
+                //return G_TYPE_ULONG;
+                //Fall-through intentional
+                //NOTE: There seems to be a bug somewhere either in TANGO or in GLib or in Pyhton that
+                //Breaks the functionality of the G_TYPE_ULONG properties. Using a G_TYPE_UINT instead
+                //works around this problem but might provoke potential overflows...
+            case DEV_USHORT:
+                return G_TYPE_UINT;
+            case CONST_DEV_STRING:
+                //Fall-through intentional
+            case DEV_STRING:
+                return G_TYPE_STRING;
+            case DEV_UCHAR:
+                return G_TYPE_UCHAR;
+            case DEV_LONG64:
+                return G_TYPE_INT64;
+            case DEV_ULONG64:
+                return G_TYPE_UINT64;
+            case DEV_STATE:
+                return G_TYPE_UINT;
+            /*
+            DEV_ENCODED
+            DEVVAR_CHARARRAY
+            DEVVAR_SHORTARRAY
+            DEVVAR_LONGARRAY
+            DEVVAR_FLOATARRAY
+            DEVVAR_DOUBLEARRAY
+            DEVVAR_USHORTARRAY
+            DEVVAR_ULONGARRAY
+            DEVVAR_STRINGARRAY
+            DEVVAR_LONGSTRINGARRAY
+            DEVVAR_DOUBLESTRINGARRAY
+            DEVVAR_BOOLEANARRAY
+            DEVVAR_LONG64ARRAY
+            DEVVAR_ULONG64ARRAY
+            */
+            default:
+                return G_TYPE_INVALID;
+        };
+}
+
+
+gint
+get_property_id_from_name(const gchar* name)
+{
+    guint idx = 0;
+    gboolean found = FALSE;
+    for (;idx < N_PROPERTIES; ++idx) {
+        if (0 == g_strcmp0(name, uca_camera_props[idx])) {
+            found = TRUE;
+            break;
+        }
+    }
+    return (TRUE == found) ? idx : -1;
+}
+
+
+void
+build_param_spec(GParamSpec **pspec, const Tango::AttributeInfoEx *attrInfo)
+{
+    GType type = gtype_from_tango_type ((Tango::CmdArgType)attrInfo->data_type);
+    const gchar *name = attrInfo->name.c_str ();
+    GParamFlags flags = G_PARAM_READABLE;
+    if (attrInfo->writable == Tango::AttrWriteType::WRITE)
+        flags = (GParamFlags) G_PARAM_READWRITE;
+
+
+    //Convenience Macro to prevent having to rewrite this block
+    //of code over and over again..
+    #define __M_PSCPEC(__SPEC_TYPE, __LIMITS_1, __LIMITS_2, __LIMITS_3) { \
+        *pspec = \
+        __SPEC_TYPE (name, \
+            attrInfo->description.c_str (), \
+            g_strconcat ("KIRO TANGO <-> GLib interface of ", name, NULL), \
+            __LIMITS_1, __LIMITS_2, __LIMITS_3,\
+            flags); \
+    }
+
+    switch (type) {
+        case G_TYPE_INT:
+            __M_PSCPEC (g_param_spec_int, G_MININT32, G_MAXINT32, 0);
+            break;
+        case G_TYPE_FLOAT:
+            __M_PSCPEC (g_param_spec_float, G_MINFLOAT, G_MAXFLOAT, 0.);
+            break;
+        case G_TYPE_DOUBLE:
+            __M_PSCPEC (g_param_spec_double, G_MINDOUBLE, G_MAXDOUBLE, 0.)
+            break;
+        case G_TYPE_UINT:
+            __M_PSCPEC (g_param_spec_uint, 0, G_MAXUINT, 0)
+            break;
+        case G_TYPE_ULONG:
+            __M_PSCPEC (g_param_spec_ulong, 0, G_MAXULONG, 0)
+            break;
+        case G_TYPE_UCHAR:
+            __M_PSCPEC (g_param_spec_uchar, 0x00, 0xff, 0x42)
+            break;
+        case G_TYPE_INT64:
+            __M_PSCPEC (g_param_spec_int64, G_MININT64, G_MAXINT64, 0)
+            break;
+        case G_TYPE_UINT64:
+            __M_PSCPEC (g_param_spec_uint64, 0, G_MAXUINT64, 0)
+            break;
+        case G_TYPE_LONG:
+            __M_PSCPEC (g_param_spec_long, G_MININT64, G_MAXINT64, 1)
+            break;
+        case G_TYPE_ENUM:
+            __M_PSCPEC (g_param_spec_int, 0, G_MAXUINT, 0)
+            break;
+        case G_TYPE_STRING:
+            *pspec =
+            g_param_spec_string (name,
+                attrInfo->description.c_str (),
+                g_strconcat ("KIRO TANGO <-> GLib interface of ", name, NULL),
+                "DEFAULT",
+                flags);
+            break;
+        case G_TYPE_BOOLEAN:
+            *pspec =
+            g_param_spec_boolean (name,
+                attrInfo->description.c_str (),
+                g_strconcat ("KIRO TANGO <-> GLib interface of ", name, NULL),
+                FALSE,
+                flags);
+            break;
+        default:
+            *pspec =
+            g_param_spec_gtype (name,
+                attrInfo->description.c_str (),
+                g_strconcat ("KIRO TANGO <-> GLib interface of ", name, NULL),
+                type,
+                flags);
+    }
+
+#undef __M_PSCPEC
+}
+
+
+void
+uca_kiro_camera_clone_interface(const gchar* address, UcaKiroCamera *kiro_camera)
+{
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (kiro_camera);
+    UcaKiroCameraClass *klass = UCA_KIRO_CAMERA_GET_CLASS (kiro_camera);
+    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    gboolean start_found, stop_found, readout_found, unit_found = FALSE;
+
+    try {
+        Tango::CommandInfoList *cmd_list = priv->tango_device->command_list_query ();
+        for (vector<Tango::CommandInfo>::iterator iter = cmd_list->begin (); iter != cmd_list->end (); ++iter) {
+            gint start_cmp = g_strcmp0((*iter).cmd_name.c_str (), "StartRecording");
+            if (0 == start_cmp) {
+                start_found = TRUE;
+            }
+            gint stop_cmp = g_strcmp0 ((*iter).cmd_name.c_str (), "StopRecording");
+            if (0 == stop_cmp) {
+                stop_found = TRUE;
+            }
+            gint unit_cmp = g_strcmp0((*iter).cmd_name.c_str (), "GetAttributeUnit");
+            if (0 == unit_cmp) {
+                unit_found = TRUE;
+            }
+            gint readout_cmp = g_strcmp0((*iter).cmd_name.c_str (), "Readout");
+            if (0 == readout_cmp) {
+                readout_found = TRUE;
+            }
+        }
+
+        if ( !start_found || !stop_found ) {
+            g_warning ("The Server at '%s' does not provide the necessary 'StartRecording' and 'StopRecording' interface\n", priv->kiro_tango_address);
+            g_set_error (&initable_iface_error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_BAD_CAMERA_INTERFACE,
+                         "The Server at '%s' does not provide the necessary 'StartRecording' and 'StopRecording' interface\n", priv->kiro_tango_address);
+            priv->construction_error = TRUE;
+            return;
+        }
+
+        vector<string> *attr_list = priv->tango_device->get_attribute_list ();
+        GList *non_base_attributes = NULL;
+        guint non_base_attributes_count = 0;
+
+        for (vector<string>::iterator iter = attr_list->begin (); iter != attr_list->end (); ++iter) {
+            Tango::AttributeInfoEx attrInfo =  priv->tango_device->attribute_query (*iter);
+            gint uca_base_prop_id = get_property_id_from_name ((*iter).c_str ());
+            if (-1 < uca_base_prop_id) {
+                guint is_name_attr = g_strcmp0 ((*iter).c_str (), "name");
+                if (0 == is_name_attr) {
+                    Tango::DeviceAttribute t_attr;
+                    priv->tango_device->read_attribute ("name", t_attr);
+                    string reply_name;
+                    t_attr >> reply_name;
+                    g_free (priv->remote_name);
+                    priv->remote_name = g_strdup (reply_name.c_str ());
+                }
+                kiro_properties[uca_base_prop_id] = g_object_class_find_property (gobject_class, uca_camera_props[uca_base_prop_id]);
+                g_object_class_override_property(G_OBJECT_CLASS (UCA_KIRO_CAMERA_GET_CLASS (kiro_camera)), uca_base_prop_id, uca_camera_props[uca_base_prop_id]);
+            }
+            else {
+                non_base_attributes = g_list_append (non_base_attributes, (gpointer)(*iter).c_str ());
+                non_base_attributes_count++;
+            }
+        }
+
+        if (non_base_attributes_count > 0) {
+            priv->kiro_dynamic_attributes = new GParamSpec* [N_PROPERTIES + non_base_attributes_count];
+            UcaKiroCameraClass *klass = UCA_KIRO_CAMERA_GET_CLASS (kiro_camera);
+            GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+            for (guint idx = 0; idx < non_base_attributes_count; idx++) {
+                const gchar *attr_name = (const gchar*)g_list_nth_data (non_base_attributes, idx);
+                Tango::AttributeInfoEx attrInfo = priv->tango_device->attribute_query (string(attr_name));
+                
+                if (Tango::AttrDataFormat::IMAGE == attrInfo.data_format || Tango::AttrDataFormat::FMT_UNKNOWN == attrInfo.data_format) {
+                    g_print ("Attribute '%s' has unknown DataFormat. Skipping.\n", attr_name);
+                    continue;
+                }
+                
+                build_param_spec (&(priv->kiro_dynamic_attributes[N_PROPERTIES + idx]), &attrInfo);
+                g_object_class_install_property (gobject_class, N_PROPERTIES + idx, priv->kiro_dynamic_attributes[N_PROPERTIES + idx]);
+
+                if (unit_found) {
+                    Tango::DeviceData arg_name;
+                    arg_name << attr_name;
+                    Tango::DeviceData cmd_reply = priv->tango_device->command_inout("GetAttributeUnit", arg_name);
+                    gint unit;
+                    cmd_reply >> unit;
+                    uca_camera_register_unit (UCA_CAMERA (kiro_camera), attr_name, (UcaUnit)unit);
+                }
+            }
+        }
+    }
+    catch (Tango::DevFailed &e) {
+        Tango::Except::print_exception (e);
+        g_set_error (&initable_iface_error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED,
+                     "A TANGO exception was raised: '%s'", (const char *)e.errors[0].desc);
+        priv->construction_error = TRUE;
+    }
+}
+// ---------------------------------------------------------- //
+//                  END: TANGO <-> GLib                       //
+// ---------------------------------------------------------- //
+
+
+
+static void
+uca_kiro_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+    g_return_if_fail(UCA_IS_KIRO_CAMERA (object));
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_KIRO_TANGO_ADDRESS:
+            priv->kiro_tango_address = g_value_dup_string (value);
+            break;
+        default:
+            try_handle_write_tango_property (object, property_id, value, pspec);
+            return;
+    }
+}
+
+
+static void
+uca_kiro_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_NAME:
+            g_value_set_string (value, "KIRO camera");
+            break;
+        case PROP_KIRO_ADDRESS:
+            g_value_set_string (value, priv->kiro_address);
+            break;
+        case PROP_KIRO_PORT:
+            g_value_set_uint (value, priv->kiro_port_uint);
+            break;
+        case PROP_KIRO_TANGO_ADDRESS:
+            g_value_set_string (value, priv->kiro_tango_address);
+            break;
+        case PROP_KIRO_REMOTE_NAME:
+            g_value_set_string (value, priv->remote_name);
+            break;
+        default:
+            try_handle_read_tango_property (object, property_id, value, pspec);
+            break;
+    }
+}
+
+static void
+uca_kiro_camera_finalize(GObject *object)
+{
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE(object);
+
+    if (priv->thread_running) {
+        priv->thread_running = FALSE;
+        g_thread_join (priv->grab_thread);
+    }
+
+    if (priv->receive_buffer) {
+        kiro_sb_free (priv->receive_buffer);
+        priv->receive_buffer = NULL;
+    }
+    priv->kiro_connected = FALSE;
+
+    if (priv->dummy_data) {
+        g_free (priv->dummy_data);
+        priv->dummy_data = NULL;
+    }
+
+    if (priv->tango_device) {
+        delete (priv->tango_device);
+        priv->tango_device = NULL;
+    }
+
+    g_free (priv->kiro_address);
+    g_free (priv->kiro_port);
+    g_free (priv->kiro_tango_address);
+
+    G_OBJECT_CLASS (uca_kiro_camera_parent_class)->finalize(object);
+}
+
+static gboolean
+ufo_kiro_camera_initable_init (GInitable *initable,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+    g_return_val_if_fail (UCA_IS_KIRO_CAMERA (initable), FALSE);
+    
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (UCA_KIRO_CAMERA (initable));
+    if(priv->construction_error) {
+        g_propagate_error (error, initable_iface_error);
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+static void
+uca_kiro_initable_iface_init (GInitableIface *iface)
+{
+    iface->init = ufo_kiro_camera_initable_init;
+}
+
+static void
+uca_kiro_camera_constructed (GObject *object)
+{
+    //Initialization for the KIRO Server and TANGO Interface cloning is moved
+    //here and done early!
+    //We want to add dynamic properties and it is too late to do so in the
+    //real initable part. Therefore, we do it here and 'remember' any errors
+    //that occur and check them later in the initable part.
+    
+    UcaKiroCamera *self = UCA_KIRO_CAMERA (object);
+    UcaKiroCameraPrivate *priv = UCA_KIRO_CAMERA_GET_PRIVATE (self);
+    
+    GValue address = G_VALUE_INIT;
+    g_value_init(&address, G_TYPE_STRING);
+    uca_kiro_camera_get_property (object, PROP_KIRO_TANGO_ADDRESS, &address, NULL);
+    gint address_not_none = g_strcmp0(g_value_get_string (&address), "NONE");
+    if (0 == address_not_none) {
+        g_warning ("kiro-tango-address was not set! Can not connect to server...\n");
+        priv->construction_error = TRUE;
+        g_set_error (&initable_iface_error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_MISSING_TANGO_ADDRESS,
+             "'kiro-tango-address' property was not set during construction.");
+    }
+    else {
+        try {
+            priv->tango_device = new Tango::DeviceProxy(g_value_get_string (&address));
+            Tango::DbData kiro_credentials;
+            kiro_credentials.push_back (Tango::DbDatum("KiroAddress"));
+            kiro_credentials.push_back (Tango::DbDatum("KiroPort"));
+            priv->tango_device->get_property(kiro_credentials);
+            string kiro_address, kiro_port;
+            kiro_credentials[0] >> kiro_address;
+            kiro_credentials[1] >> kiro_port;
+
+            if (0 > kiro_sb_clone (priv->receive_buffer, kiro_address.c_str (), kiro_port.c_str ())) {
+                g_warning ("Unable to connect to server at address: %s, port: %s\n", kiro_address.c_str (), kiro_port.c_str ());
+                priv->construction_error = TRUE;
+                g_set_error (&initable_iface_error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_KIRO_CONNECTION_FAILED,
+                             "Failed to establish a KIRO InfiniBand connection.");
+            }
+            else {
+                priv->kiro_connected = TRUE;
+                uca_kiro_camera_clone_interface (g_value_get_string (&address), self);
+            }
+        }
+        catch (Tango::DevFailed &e) {
+            Tango::Except::print_exception (e);
+            g_set_error (&initable_iface_error, UCA_KIRO_CAMERA_ERROR, UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED,
+                             "A TANGO exception was raised: '%s'", (const char *)e.errors[0].desc);
+            priv->construction_error = TRUE;
+        }
+    }
+
+    G_OBJECT_CLASS (uca_kiro_camera_parent_class)->constructed(object);
+}
+
+
+
+static void
+uca_kiro_camera_class_init(UcaKiroCameraClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS( klass);
+    gobject_class->set_property = uca_kiro_camera_set_property;
+    gobject_class->get_property = uca_kiro_camera_get_property;
+    gobject_class->finalize = uca_kiro_camera_finalize;
+    gobject_class->constructed = uca_kiro_camera_constructed;
+
+    UcaCameraClass *camera_class = UCA_CAMERA_CLASS (klass);
+    camera_class->start_recording = uca_kiro_camera_start_recording;
+    camera_class->stop_recording = uca_kiro_camera_stop_recording;
+    camera_class->grab = uca_kiro_camera_grab;
+    camera_class->trigger = uca_kiro_camera_trigger;
+
+    for (guint i = 0; kiro_overrideables[i] != 0; i++)
+        g_object_class_override_property (gobject_class, kiro_overrideables[i], uca_camera_props[kiro_overrideables[i]]);
+                
+    kiro_properties[PROP_KIRO_ADDRESS] =
+        g_param_spec_string("kiro-address",
+                "KIRO Server Address",
+                "Address of the KIRO Server to grab images from",
+                "NONE",
+                G_PARAM_READABLE);
+                
+    kiro_properties[PROP_KIRO_PORT] =
+        g_param_spec_uint("kiro-port",
+                "KIRO Server Port",
+                "Port of the KIRO Server to grab images from",
+                1, 65535, 60010,
+                G_PARAM_READABLE);
+                
+    kiro_properties[PROP_KIRO_TANGO_ADDRESS] =
+        g_param_spec_string("kiro-tango-address",
+                "KIRO TANGO address",
+                "Address of the KIRO Server in the TANGO environment",
+                "NONE",
+                (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+    kiro_properties[PROP_KIRO_REMOTE_NAME] =
+        g_param_spec_string("remote-name",
+                "Name of the remot camera",
+                "Name of the camera plugin that is loaded on the KIRO remote site",
+                "NONE",
+                G_PARAM_READABLE);
+
+    for (guint id = N_BASE_PROPERTIES; id < N_PROPERTIES; id++)
+        g_object_class_install_property (gobject_class, id, kiro_properties[id]);
+
+    g_type_class_add_private (klass, sizeof(UcaKiroCameraPrivate));
+}
+
+static void
+uca_kiro_camera_init(UcaKiroCamera *self)
+{
+    self->priv = UCA_KIRO_CAMERA_GET_PRIVATE(self);
+    self->priv->grab_thread = NULL;
+    self->priv->current_frame = 0;
+    self->priv->kiro_address = g_strdup ("NONE");
+    self->priv->kiro_port = g_strdup ("NONE");
+    self->priv->remote_name = g_strdup ("NONE");
+    self->priv->kiro_port_uint = 60010;
+    self->priv->kiro_tango_address = g_strdup ("NONE");
+    self->priv->construction_error = FALSE;
+    self->priv->kiro_dynamic_attributes = NULL;
+
+    self->priv->receive_buffer = kiro_sb_new ();
+    kiro_sb_freeze (self->priv->receive_buffer);
+}
+
+
+G_MODULE_EXPORT GType
+uca_camera_get_type (void)
+{
+    return UCA_TYPE_KIRO_CAMERA;
+}
+

+ 80 - 0
src/uca-kiro-camera.h

@@ -0,0 +1,80 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+   (Karlsruhe Institute of Technology)
+
+   This library is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as published by the
+   Free Software Foundation; either version 2.1 of the License, or (at your
+   option) any later version.
+
+   This library is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+   details.
+
+   You should have received a copy of the GNU Lesser General Public License along
+   with this library; if not, write to the Free Software Foundation, Inc., 51
+   Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+#ifndef __UCA_KIRO_CAMERA_H
+#define __UCA_KIRO_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_KIRO_CAMERA             (uca_kiro_camera_get_type())
+#define UCA_KIRO_CAMERA(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_KIRO_CAMERA, UcaKiroCamera))
+#define UCA_IS_KIRO_CAMERA(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_KIRO_CAMERA))
+#define UCA_KIRO_CAMERA_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), UCA_TYPE_KIRO_CAMERA, UcaKiroCameraClass))
+#define UCA_IS_KIRO_CAMERA_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_KIRO_CAMERA))
+#define UCA_KIRO_CAMERA_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_KIRO_CAMERA, UcaKiroCameraClass))
+
+#define UCA_KIRO_CAMERA_ERROR    uca_kiro_camera_error_quark()
+
+GQuark uca_kiro_camera_error_quark(void);
+
+typedef enum {
+    UCA_KIRO_CAMERA_ERROR_MISSING_TANGO_ADDRESS = UCA_CAMERA_ERROR_END_OF_STREAM,
+    UCA_KIRO_CAMERA_ERROR_TANGO_CONNECTION_FAILED,
+    UCA_KIRO_CAMERA_ERROR_KIRO_CONNECTION_FAILED,
+    UCA_KIRO_CAMERA_ERROR_TANGO_EXCEPTION_OCCURED,
+    UCA_KIRO_CAMERA_ERROR_BAD_CAMERA_INTERFACE
+} UcaKiroCameraError;
+
+
+typedef struct _UcaKiroCamera           UcaKiroCamera;
+typedef struct _UcaKiroCameraClass      UcaKiroCameraClass;
+typedef struct _UcaKiroCameraPrivate    UcaKiroCameraPrivate;
+
+/**
+ * UcaKiroCamera:
+ *
+ * Creates #UcaKiroCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaKiroCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaKiroCamera {
+    /*< private >*/
+    UcaCamera parent;
+
+    UcaKiroCameraPrivate *priv;
+};
+
+/**
+ * UcaKiroCameraClass:
+ *
+ * #UcaKiroCamera class
+ */
+struct _UcaKiroCameraClass {
+    /*< private >*/
+    UcaCameraClass parent;
+};
+
+G_END_DECLS
+
+
+void uca_kiro_camera_clone_interface (const gchar* address, UcaKiroCamera *kiro_camera);
+
+
+#endif