From 1f04383dca16af05697812e634b1e34811f045a6 Mon Sep 17 00:00:00 2001
From: Timo Dritschler <timo.dritschler@kit.edu>
Date: Thu, 9 Jul 2015 15:07:44 +0200
Subject: Init Git repo

---
 bin/kiro-camera-server.c | 380 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 380 insertions(+)
 create mode 100644 bin/kiro-camera-server.c

(limited to 'bin/kiro-camera-server.c')

diff --git a/bin/kiro-camera-server.c b/bin/kiro-camera-server.c
new file mode 100644
index 0000000..cb14332
--- /dev/null
+++ b/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;
+};
+
+
-- 
cgit v1.2.3