diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/CMakeLists.txt | 10 | ||||
-rw-r--r-- | bin/kiro-camera-server.c | 380 | ||||
-rw-r--r-- | bin/kiro-camera-server.h | 236 | ||||
-rw-r--r-- | bin/test-server.c | 71 |
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; + + + +} |