summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rw-r--r--bin/CMakeLists.txt10
-rw-r--r--bin/kiro-camera-server.c380
-rw-r--r--bin/kiro-camera-server.h236
-rw-r--r--bin/test-server.c71
4 files changed, 697 insertions, 0 deletions
diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt
new file mode 100644
index 0000000..acdc243
--- /dev/null
+++ b/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})
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;
+};
+
+
diff --git a/bin/kiro-camera-server.h b/bin/kiro-camera-server.h
new file mode 100644
index 0000000..3db673f
--- /dev/null
+++ b/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;
+}
diff --git a/bin/test-server.c b/bin/test-server.c
new file mode 100644
index 0000000..32d27ef
--- /dev/null
+++ b/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;
+
+
+
+}