diff options
author | Timo Dritschler <timo.dritschler@kit.edu> | 2015-07-09 15:07:44 +0200 |
---|---|---|
committer | Timo Dritschler <timo.dritschler@kit.edu> | 2015-07-09 15:07:44 +0200 |
commit | 1f04383dca16af05697812e634b1e34811f045a6 (patch) | |
tree | cd7efd8141d84c042356f117a3876e9f552d4f84 | |
download | uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.gz uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.bz2 uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.xz uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.zip |
Init Git repo
-rw-r--r-- | .gitignore | 21 | ||||
-rw-r--r-- | CMakeLists.txt | 64 | ||||
-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 | ||||
-rw-r--r-- | common/cmake/ConfigurePaths.cmake | 90 | ||||
-rw-r--r-- | common/cmake/PkgConfigVars.cmake | 30 | ||||
-rw-r--r-- | src/CMakeLists.txt | 13 | ||||
-rw-r--r-- | src/uca-kiro-camera.cpp | 1115 | ||||
-rw-r--r-- | src/uca-kiro-camera.h | 80 |
11 files changed, 2110 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bdd6fdc --- /dev/null +++ b/.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 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fd0e914 --- /dev/null +++ b/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) 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; + + + +} diff --git a/common/cmake/ConfigurePaths.cmake b/common/cmake/ConfigurePaths.cmake new file mode 100644 index 0000000..df9c03c --- /dev/null +++ b/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: diff --git a/common/cmake/PkgConfigVars.cmake b/common/cmake/PkgConfigVars.cmake new file mode 100644 index 0000000..f295457 --- /dev/null +++ b/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() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..fe330b6 --- /dev/null +++ b/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) diff --git a/src/uca-kiro-camera.cpp b/src/uca-kiro-camera.cpp new file mode 100644 index 0000000..4346a9f --- /dev/null +++ b/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; +} + diff --git a/src/uca-kiro-camera.h b/src/uca-kiro-camera.h new file mode 100644 index 0000000..b1b9d42 --- /dev/null +++ b/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 |