|
@@ -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;
|
|
|
+}
|
|
|
+
|