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 /src | |
download | uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.gz uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.bz2 uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.tar.xz uca-kiro-1f04383dca16af05697812e634b1e34811f045a6.zip |
Init Git repo
Diffstat (limited to 'src')
-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 |
3 files changed, 1208 insertions, 0 deletions
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 |