summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-09-28 18:16:56 +0200
committerMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-09-28 18:16:56 +0200
commit99b737ae9f3f1d35a4696594821fa3bc39e8aa87 (patch)
tree73ed9e59018d3a8181397d5ff4afa70d5029da9a /plugins
parent0bc642a31600bbfaac15779b8d932a409283ae3f (diff)
downloaduca-99b737ae9f3f1d35a4696594821fa3bc39e8aa87.tar.gz
uca-99b737ae9f3f1d35a4696594821fa3bc39e8aa87.tar.bz2
uca-99b737ae9f3f1d35a4696594821fa3bc39e8aa87.tar.xz
uca-99b737ae9f3f1d35a4696594821fa3bc39e8aa87.zip
Fix #146: Make a new top-level directory for cams
... and build a package for each camera. Moreover, for some reason we can live without the CMake generated spec file for RPM generation. AFAICS, the RPMs are prefixed correctly.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/CMakeLists.txt5
-rw-r--r--plugins/mock/CMakeLists.txt18
-rw-r--r--plugins/mock/uca-mock-camera.c409
-rw-r--r--plugins/mock/uca-mock-camera.h65
-rw-r--r--plugins/package-plugin.sh.in1
-rw-r--r--plugins/pco/CMakeLists.txt30
-rw-r--r--plugins/pco/uca-pco-camera.c1398
-rw-r--r--plugins/pco/uca-pco-camera.h91
-rw-r--r--plugins/pf/CMakeLists.txt30
-rw-r--r--plugins/pf/uca-pf-camera.c351
-rw-r--r--plugins/pf/uca-pf-camera.h74
-rw-r--r--plugins/pylon/CMakeLists.txt24
-rw-r--r--plugins/pylon/uca-pylon-camera.c391
-rw-r--r--plugins/pylon/uca-pylon-camera.h74
-rw-r--r--plugins/ufo/CMakeLists.txt24
-rw-r--r--plugins/ufo/uca-ufo-camera.c497
-rw-r--r--plugins/ufo/uca-ufo-camera.h76
17 files changed, 3558 insertions, 0 deletions
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644
index 0000000..5131280
--- /dev/null
+++ b/plugins/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_subdirectory(mock)
+add_subdirectory(pf)
+add_subdirectory(pco)
+add_subdirectory(pylon)
+add_subdirectory(ufo)
diff --git a/plugins/mock/CMakeLists.txt b/plugins/mock/CMakeLists.txt
new file mode 100644
index 0000000..75d8635
--- /dev/null
+++ b/plugins/mock/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 2.8)
+project(ucamock)
+
+set(UCA_CAMERA_NAME "mock")
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../package-plugin.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/../../package-plugin-${UCA_CAMERA_NAME}.sh)
+
+add_library(ucamock SHARED
+ uca-mock-camera.c)
+
+target_link_libraries(ucamock
+ uca
+ ${UCA_DEPS})
+
+install(TARGETS ucamock
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca
+ COMPONENT ${UCA_CAMERA_NAME})
diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c
new file mode 100644
index 0000000..7cd4689
--- /dev/null
+++ b/plugins/mock/uca-mock-camera.c
@@ -0,0 +1,409 @@
+/* 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 <gmodule.h>
+#include <string.h>
+#include "uca-mock-camera.h"
+
+#define UCA_MOCK_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_MOCK_CAMERA, UcaMockCameraPrivate))
+
+G_DEFINE_TYPE(UcaMockCamera, uca_mock_camera, UCA_TYPE_CAMERA)
+
+enum {
+ PROP_FRAMERATE = N_BASE_PROPERTIES,
+ N_PROPERTIES
+};
+
+static const gint mock_overrideables[] = {
+ PROP_NAME,
+ PROP_SENSOR_WIDTH,
+ PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_BITDEPTH,
+ PROP_SENSOR_HORIZONTAL_BINNING,
+ PROP_SENSOR_HORIZONTAL_BINNINGS,
+ PROP_SENSOR_VERTICAL_BINNING,
+ PROP_SENSOR_VERTICAL_BINNINGS,
+ PROP_TRIGGER_MODE,
+ PROP_EXPOSURE_TIME,
+ PROP_ROI_X,
+ PROP_ROI_Y,
+ PROP_ROI_WIDTH,
+ PROP_ROI_HEIGHT,
+ PROP_ROI_HEIGHT_MULTIPLIER,
+ PROP_ROI_WIDTH_MULTIPLIER,
+ PROP_SENSOR_MAX_FRAME_RATE,
+ PROP_HAS_STREAMING,
+ PROP_HAS_CAMRAM_RECORDING,
+ 0,
+};
+
+static GParamSpec *mock_properties[N_PROPERTIES] = { NULL, };
+
+struct _UcaMockCameraPrivate {
+ guint width;
+ guint height;
+ guint roi_x, roi_y, roi_width, roi_height;
+ gfloat frame_rate;
+ gfloat max_frame_rate;
+ gdouble exposure_time;
+ guint8 *dummy_data;
+ guint current_frame;
+
+ gboolean thread_running;
+
+ GThread *grab_thread;
+ GValueArray *binnings;
+};
+
+static const char g_digits[10][20] = {
+ /* 0 */
+ { 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00 },
+ /* 1 */
+ { 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00 },
+ /* 2 */
+ { 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff },
+ /* 3 */
+ { 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00 },
+ /* 4 */
+ { 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff },
+ /* 5 */
+ { 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0x00 },
+ /* 6 */
+ { 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00 },
+ /* 7 */
+ { 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00 },
+ /* 8 */
+ { 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00 },
+ /* 9 */
+ { 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0x00 }
+};
+
+static const guint DIGIT_WIDTH = 4;
+static const guint DIGIT_HEIGHT = 5;
+
+static void print_number(gchar *buffer, guint number, guint x, guint y, guint width)
+{
+ for (int i = 0; i < DIGIT_WIDTH; i++) {
+ for (int j = 0; j < DIGIT_HEIGHT; j++) {
+ buffer[(y+j)*width + (x+i)] = g_digits[number][j*DIGIT_WIDTH+i];
+ }
+ }
+}
+
+static void print_current_frame(UcaMockCameraPrivate *priv, gchar *buffer)
+{
+ guint number = priv->current_frame;
+ guint divisor = 100000000;
+ int x = 10;
+ while (divisor > 1) {
+ print_number(buffer, number / divisor, x, 10, priv->width);
+ number = number % divisor;
+ divisor = divisor / 10;
+ x += DIGIT_WIDTH + 1;
+ }
+}
+
+static gpointer mock_grab_func(gpointer data)
+{
+ UcaMockCamera *mock_camera = UCA_MOCK_CAMERA(data);
+ g_return_val_if_fail(UCA_IS_MOCK_CAMERA(mock_camera), NULL);
+
+ UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(mock_camera);
+ UcaCamera *camera = UCA_CAMERA(mock_camera);
+ const gulong sleep_time = (gulong) G_USEC_PER_SEC / priv->frame_rate;
+
+ while (priv->thread_running) {
+ camera->grab_func(priv->dummy_data, camera->user_data);
+ g_usleep(sleep_time);
+ }
+
+ return NULL;
+}
+
+static void uca_mock_camera_start_recording(UcaCamera *camera, GError **error)
+{
+ gboolean transfer_async = FALSE;
+ UcaMockCameraPrivate *priv;
+ g_return_if_fail(UCA_IS_MOCK_CAMERA(camera));
+
+ priv = UCA_MOCK_CAMERA_GET_PRIVATE(camera);
+ /* TODO: check that roi_x + roi_width < priv->width */
+ priv->dummy_data = (guint8 *) g_malloc0(priv->roi_width * priv->roi_height);
+
+ g_object_get(G_OBJECT(camera),
+ "transfer-asynchronously", &transfer_async,
+ NULL);
+
+ /*
+ * 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(mock_grab_func, camera, TRUE, &tmp_error);
+
+ if (tmp_error != NULL) {
+ priv->thread_running = FALSE;
+ g_propagate_error(error, tmp_error);
+ }
+ }
+}
+
+static void uca_mock_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+ gboolean transfer_async = FALSE;
+ UcaMockCameraPrivate *priv;
+ g_return_if_fail(UCA_IS_MOCK_CAMERA(camera));
+
+ priv = UCA_MOCK_CAMERA_GET_PRIVATE(camera);
+ g_free(priv->dummy_data);
+ priv->dummy_data = NULL;
+
+ g_object_get(G_OBJECT(camera),
+ "transfer-asynchronously", &transfer_async,
+ NULL);
+
+ if (transfer_async) {
+ priv->thread_running = FALSE;
+ g_thread_join(priv->grab_thread);
+ }
+}
+
+static void uca_mock_camera_grab(UcaCamera *camera, gpointer *data, GError **error)
+{
+ g_return_if_fail(UCA_IS_MOCK_CAMERA(camera));
+ g_return_if_fail(data != NULL);
+
+ UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(camera);
+
+ if (*data == NULL)
+ *data = g_malloc0(priv->width * priv->height);
+
+ g_memmove(*data, priv->dummy_data, priv->width * priv->height);
+ print_current_frame(priv, *data);
+ priv->current_frame++;
+}
+
+static void uca_mock_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ g_return_if_fail(UCA_IS_MOCK_CAMERA(object));
+ UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_EXPOSURE_TIME:
+ priv->exposure_time = g_value_get_double(value);
+ break;
+ case PROP_FRAMERATE:
+ priv->frame_rate = g_value_get_float(value);
+ break;
+ case PROP_ROI_X:
+ priv->roi_x = g_value_get_uint(value);
+ break;
+ case PROP_ROI_Y:
+ priv->roi_y = g_value_get_uint(value);
+ break;
+ case PROP_ROI_WIDTH:
+ priv->roi_width = g_value_get_uint(value);
+ break;
+ case PROP_ROI_HEIGHT:
+ priv->roi_height = g_value_get_uint(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ return;
+ }
+}
+
+static void uca_mock_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_NAME:
+ g_value_set_string(value, "mock camera");
+ break;
+ case PROP_SENSOR_WIDTH:
+ g_value_set_uint(value, priv->width);
+ break;
+ case PROP_SENSOR_HEIGHT:
+ g_value_set_uint(value, priv->height);
+ break;
+ case PROP_SENSOR_BITDEPTH:
+ g_value_set_uint(value, 8);
+ break;
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_SENSOR_HORIZONTAL_BINNINGS:
+ g_value_set_boxed(value, priv->binnings);
+ break;
+ case PROP_SENSOR_VERTICAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_SENSOR_VERTICAL_BINNINGS:
+ g_value_set_boxed(value, priv->binnings);
+ break;
+ case PROP_EXPOSURE_TIME:
+ g_value_set_double(value, priv->exposure_time);
+ break;
+ case PROP_TRIGGER_MODE:
+ g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO);
+ break;
+ case PROP_ROI_X:
+ g_value_set_uint(value, priv->roi_x);
+ break;
+ case PROP_ROI_Y:
+ g_value_set_uint(value, priv->roi_y);
+ break;
+ case PROP_ROI_WIDTH:
+ g_value_set_uint(value, priv->roi_width);
+ break;
+ case PROP_ROI_HEIGHT:
+ g_value_set_uint(value, priv->roi_height);
+ break;
+ case PROP_ROI_WIDTH_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_ROI_HEIGHT_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_SENSOR_MAX_FRAME_RATE:
+ g_value_set_float(value, priv->max_frame_rate);
+ break;
+ case PROP_HAS_STREAMING:
+ g_value_set_boolean(value, TRUE);
+ break;
+ case PROP_HAS_CAMRAM_RECORDING:
+ g_value_set_boolean(value, FALSE);
+ break;
+ case PROP_FRAMERATE:
+ g_value_set_float(value, priv->frame_rate);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void uca_mock_camera_finalize(GObject *object)
+{
+ UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(object);
+
+ if (priv->thread_running) {
+ priv->thread_running = FALSE;
+ g_thread_join(priv->grab_thread);
+ }
+
+ g_free(priv->dummy_data);
+ g_value_array_free(priv->binnings);
+
+ G_OBJECT_CLASS(uca_mock_camera_parent_class)->finalize(object);
+}
+
+static void uca_mock_camera_class_init(UcaMockCameraClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property = uca_mock_camera_set_property;
+ gobject_class->get_property = uca_mock_camera_get_property;
+ gobject_class->finalize = uca_mock_camera_finalize;
+
+ UcaCameraClass *camera_class = UCA_CAMERA_CLASS(klass);
+ camera_class->start_recording = uca_mock_camera_start_recording;
+ camera_class->stop_recording = uca_mock_camera_stop_recording;
+ camera_class->grab = uca_mock_camera_grab;
+
+ for (guint i = 0; mock_overrideables[i] != 0; i++)
+ g_object_class_override_property(gobject_class, mock_overrideables[i], uca_camera_props[mock_overrideables[i]]);
+
+ mock_properties[PROP_FRAMERATE] =
+ g_param_spec_float("frame-rate",
+ "Frame rate",
+ "Number of frames per second that are taken",
+ 1.0f, 100.0f, 100.0f,
+ G_PARAM_READWRITE);
+
+ for (guint id = N_BASE_PROPERTIES; id < N_PROPERTIES; id++)
+ g_object_class_install_property(gobject_class, id, mock_properties[id]);
+
+ g_type_class_add_private(klass, sizeof(UcaMockCameraPrivate));
+}
+
+static void uca_mock_camera_init(UcaMockCamera *self)
+{
+ self->priv = UCA_MOCK_CAMERA_GET_PRIVATE(self);
+ self->priv->roi_x = 0;
+ self->priv->roi_y = 0;
+ self->priv->width = self->priv->roi_width = 640;
+ self->priv->height = self->priv->roi_height = 480;
+ self->priv->frame_rate = self->priv->max_frame_rate = 100000.0f;
+ self->priv->grab_thread = NULL;
+ self->priv->current_frame = 0;
+
+ self->priv->binnings = g_value_array_new(1);
+ GValue val = {0};
+ g_value_init(&val, G_TYPE_UINT);
+ g_value_set_uint(&val, 1);
+ g_value_array_append(self->priv->binnings, &val);
+}
+
+G_MODULE_EXPORT UcaCamera *
+uca_camera_impl_new (GError **error)
+{
+ UcaCamera *camera = UCA_CAMERA (g_object_new (UCA_TYPE_MOCK_CAMERA, NULL));
+ return camera;
+}
diff --git a/plugins/mock/uca-mock-camera.h b/plugins/mock/uca-mock-camera.h
new file mode 100644
index 0000000..9ee9190
--- /dev/null
+++ b/plugins/mock/uca-mock-camera.h
@@ -0,0 +1,65 @@
+/* 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_MOCK_CAMERA_H
+#define __UCA_MOCK_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_MOCK_CAMERA (uca_mock_camera_get_type())
+#define UCA_MOCK_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_MOCK_CAMERA, UcaMockCamera))
+#define UCA_IS_MOCK_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_MOCK_CAMERA))
+#define UCA_MOCK_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_MOCK_CAMERA, UfoMockCameraClass))
+#define UCA_IS_MOCK_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_MOCK_CAMERA))
+#define UCA_MOCK_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_MOCK_CAMERA, UcaMockCameraClass))
+
+typedef struct _UcaMockCamera UcaMockCamera;
+typedef struct _UcaMockCameraClass UcaMockCameraClass;
+typedef struct _UcaMockCameraPrivate UcaMockCameraPrivate;
+
+/**
+ * UcaMockCamera:
+ *
+ * Creates #UcaMockCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaMockCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaMockCamera {
+ /*< private >*/
+ UcaCamera parent;
+
+ UcaMockCameraPrivate *priv;
+};
+
+/**
+ * UcaMockCameraClass:
+ *
+ * #UcaMockCamera class
+ */
+struct _UcaMockCameraClass {
+ /*< private >*/
+ UcaCameraClass parent;
+};
+
+GType uca_mock_camera_get_type(void);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/package-plugin.sh.in b/plugins/package-plugin.sh.in
new file mode 100644
index 0000000..c624d52
--- /dev/null
+++ b/plugins/package-plugin.sh.in
@@ -0,0 +1 @@
+cpack -D CPACK_INSTALL_CMAKE_PROJECTS="${CMAKE_CURRENT_BINARY_DIR}/;Project;${UCA_CAMERA_NAME};/" -D CPACK_PACKAGE_FILE_NAME="uca-plugin-${UCA_CAMERA_NAME}-${UCA_VERSION_MAJOR}.${UCA_VERSION_MINOR}.${UCA_VERSION_PATCH}"
diff --git a/plugins/pco/CMakeLists.txt b/plugins/pco/CMakeLists.txt
new file mode 100644
index 0000000..7c016b9
--- /dev/null
+++ b/plugins/pco/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 2.8)
+project(ucapco)
+
+find_package(PCO)
+find_package(FgLib5)
+find_package(ClSerMe4)
+
+if (PCO_FOUND AND CLSERME4_FOUND AND FGLIB5_FOUND)
+ set(UCA_CAMERA_NAME "pco")
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../package-plugin.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/../../package-plugin-${UCA_CAMERA_NAME}.sh)
+
+ include_directories(${PCO_INCLUDE_DIRS}
+ ${CLSERME4_INCLUDE_DIR}
+ ${FGLIB5_INCLUDE_DIR})
+
+ add_library(ucapco SHARED
+ uca-pco-camera.c)
+
+ target_link_libraries(ucapco
+ ${UCA_DEPS}
+ ${PCO_LIBRARIES}
+ ${CLSERME4_LIBRARY}
+ ${FGLIB5_LIBRARY})
+
+ install(TARGETS ucapco
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca
+ COMPONENT ${UCA_CAMERA_NAME})
+endif()
diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c
new file mode 100644
index 0000000..8bf2936
--- /dev/null
+++ b/plugins/pco/uca-pco-camera.c
@@ -0,0 +1,1398 @@
+/* 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 <gmodule.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libpco/libpco.h>
+#include <libpco/sc2_defs.h>
+#include <fgrab_prototyp.h>
+#include "uca-camera.h"
+#include "uca-pco-camera.h"
+#include "uca-enums.h"
+
+#define FG_TRY_PARAM(fg, camobj, param, val_addr, port) \
+ { int r = Fg_setParameter(fg, param, val_addr, port); \
+ if (r != FG_OK) { \
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, \
+ UCA_PCO_CAMERA_ERROR_FG_GENERAL, \
+ "%s", Fg_getLastErrorDescription(fg)); \
+ g_object_unref(camobj); \
+ return NULL; \
+ } }
+
+#define FG_SET_ERROR(err, fg, err_type) \
+ if (err != FG_OK) { \
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, \
+ err_type, \
+ "%s", Fg_getLastErrorDescription(fg)); \
+ return; \
+ }
+
+#define HANDLE_PCO_ERROR(err) \
+ if ((err) != PCO_NOERROR) { \
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, \
+ UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL,\
+ "libpco error %x", err); \
+ return; \
+ }
+
+#define UCA_PCO_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_PCO_CAMERA, UcaPcoCameraPrivate))
+
+G_DEFINE_TYPE(UcaPcoCamera, uca_pco_camera, UCA_TYPE_CAMERA)
+
+#define TIMEBASE_INVALID 0xDEAD
+
+/**
+ * UcaPcoCameraRecordMode:
+ * @UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE: Store all frames and stop if necessary
+ * @UCA_PCO_CAMERA_RECORD_MODE_RING_BUFFER: Store frames in ring-buffer fashion
+ * and overwrite if necessary
+ */
+
+/**
+ * UcaPcoCameraAcquireMode:
+ * @UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO: Take all images
+ * @UCA_PCO_CAMERA_ACQUIRE_MODE_EXTERNAL: Use <acq enbl> signal
+ */
+
+/**
+ * UcaPcoCameraTimestamp:
+ * @UCA_PCO_CAMERA_TIMESTAMP_NONE: Don't embed any timestamp
+ * @UCA_PCO_CAMERA_TIMESTAMP_BINARY: Embed a BCD-coded timestamp in the first
+ * bytes
+ * @UCA_PCO_CAMERA_TIMESTAMP_ASCII: Embed a visible ASCII timestamp in the image
+ */
+
+/**
+ * UcaPcoCameraError:
+ * @UCA_PCO_CAMERA_ERROR_LIBPCO_INIT: Initializing libpco failed
+ * @UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL: General libpco error
+ * @UCA_PCO_CAMERA_ERROR_UNSUPPORTED: Camera type is not supported
+ * @UCA_PCO_CAMERA_ERROR_FG_INIT: Framegrabber initialization failed
+ * @UCA_PCO_CAMERA_ERROR_FG_GENERAL: General framegrabber error
+ * @UCA_PCO_CAMERA_ERROR_FG_ACQUISITION: Framegrabber acquisition error
+ */
+GQuark uca_pco_camera_error_quark()
+{
+ return g_quark_from_static_string("uca-pco-camera-error-quark");
+}
+
+enum {
+ PROP_SENSOR_EXTENDED = N_BASE_PROPERTIES,
+ PROP_SENSOR_WIDTH_EXTENDED,
+ PROP_SENSOR_HEIGHT_EXTENDED,
+ PROP_SENSOR_TEMPERATURE,
+ PROP_SENSOR_PIXELRATES,
+ PROP_SENSOR_PIXELRATE,
+ PROP_SENSOR_ADCS,
+ PROP_SENSOR_MAX_ADCS,
+ PROP_DELAY_TIME,
+ PROP_HAS_DOUBLE_IMAGE_MODE,
+ PROP_DOUBLE_IMAGE_MODE,
+ PROP_OFFSET_MODE,
+ PROP_RECORD_MODE,
+ PROP_ACQUIRE_MODE,
+ PROP_COOLING_POINT,
+ PROP_COOLING_POINT_MIN,
+ PROP_COOLING_POINT_MAX,
+ PROP_COOLING_POINT_DEFAULT,
+ PROP_NOISE_FILTER,
+ PROP_TIMESTAMP_MODE,
+ N_PROPERTIES
+};
+
+static gint base_overrideables[] = {
+ PROP_NAME,
+ PROP_SENSOR_WIDTH,
+ PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_BITDEPTH,
+ PROP_SENSOR_HORIZONTAL_BINNING,
+ PROP_SENSOR_HORIZONTAL_BINNINGS,
+ PROP_SENSOR_VERTICAL_BINNING,
+ PROP_SENSOR_VERTICAL_BINNINGS,
+ PROP_SENSOR_MAX_FRAME_RATE,
+ PROP_EXPOSURE_TIME,
+ PROP_TRIGGER_MODE,
+ PROP_ROI_X,
+ PROP_ROI_Y,
+ PROP_ROI_WIDTH,
+ PROP_ROI_HEIGHT,
+ PROP_ROI_WIDTH_MULTIPLIER,
+ PROP_ROI_HEIGHT_MULTIPLIER,
+ PROP_HAS_STREAMING,
+ PROP_HAS_CAMRAM_RECORDING,
+ 0
+};
+
+static GParamSpec *pco_properties[N_PROPERTIES] = { NULL, };
+
+/*
+ * This structure defines type-specific properties of PCO cameras.
+ */
+typedef struct {
+ int camera_type;
+ const char *so_file;
+ int cl_type;
+ int cl_format;
+ gfloat max_frame_rate;
+ gboolean has_camram;
+} pco_cl_map_entry;
+
+struct _UcaPcoCameraPrivate {
+ pco_handle pco;
+ pco_cl_map_entry *camera_description;
+
+ Fg_Struct *fg;
+ guint fg_port;
+ dma_mem *fg_mem;
+
+ guint frame_width;
+ guint frame_height;
+ gsize num_bytes;
+ guint16 *grab_buffer;
+
+ guint16 width, height;
+ guint16 width_ex, height_ex;
+ guint16 binning_h, binning_v;
+ guint16 roi_x, roi_y;
+ guint16 roi_width, roi_height;
+ guint16 roi_horizontal_steps, roi_vertical_steps;
+ GValueArray *horizontal_binnings;
+ GValueArray *vertical_binnings;
+ GValueArray *pixelrates;
+
+ /* The time bases are given as pco time bases (TIMEBASE_NS and so on) */
+ guint16 delay_timebase;
+ guint16 exposure_timebase;
+
+ frameindex_t last_frame;
+ guint16 active_segment;
+ guint num_recorded_images;
+ guint current_image;
+};
+
+static pco_cl_map_entry pco_cl_map[] = {
+ { CAMERATYPE_PCO_EDGE, "libFullAreaGray8.so", FG_CL_8BIT_FULL_10, FG_GRAY, 30.0f, FALSE },
+ { CAMERATYPE_PCO4000, "libDualAreaGray16.so", FG_CL_SINGLETAP_16_BIT, FG_GRAY16, 5.0f, TRUE },
+ { CAMERATYPE_PCO_DIMAX_STD, "libFullAreaGray16.so", FG_CL_SINGLETAP_8_BIT, FG_GRAY16, 1279.0f, TRUE },
+ { 0, NULL, 0, 0, 0.0f, FALSE }
+};
+
+static pco_cl_map_entry *get_pco_cl_map_entry(int camera_type)
+{
+ pco_cl_map_entry *entry = pco_cl_map;
+
+ while (entry->camera_type != 0) {
+ if (entry->camera_type == camera_type)
+ return entry;
+ entry++;
+ }
+
+ return NULL;
+}
+
+static guint fill_binnings(UcaPcoCameraPrivate *priv)
+{
+ uint16_t *horizontal = NULL;
+ uint16_t *vertical = NULL;
+ guint num_horizontal, num_vertical;
+
+ guint err = pco_get_possible_binnings(priv->pco,
+ &horizontal, &num_horizontal,
+ &vertical, &num_vertical);
+
+ GValue val = {0};
+ g_value_init(&val, G_TYPE_UINT);
+
+ if (err == PCO_NOERROR) {
+ priv->horizontal_binnings = g_value_array_new(num_horizontal);
+ priv->vertical_binnings = g_value_array_new(num_vertical);
+
+ for (guint i = 0; i < num_horizontal; i++) {
+ g_value_set_uint(&val, horizontal[i]);
+ g_value_array_append(priv->horizontal_binnings, &val);
+ }
+
+ for (guint i = 0; i < num_vertical; i++) {
+ g_value_set_uint(&val, vertical[i]);
+ g_value_array_append(priv->vertical_binnings, &val);
+ }
+ }
+
+ free(horizontal);
+ free(vertical);
+ return err;
+}
+
+static void fill_pixelrates(UcaPcoCameraPrivate *priv, guint32 rates[4], gint num_rates)
+{
+ GValue val = {0};
+ g_value_init(&val, G_TYPE_UINT);
+ priv->pixelrates = g_value_array_new(num_rates);
+
+ for (gint i = 0; i < num_rates; i++) {
+ g_value_set_uint(&val, (guint) rates[i]);
+ g_value_array_append(priv->pixelrates, &val);
+ }
+}
+
+static guint override_temperature_range(UcaPcoCameraPrivate *priv)
+{
+ int16_t default_temp, min_temp, max_temp;
+ guint err = pco_get_cooling_range(priv->pco, &default_temp, &min_temp, &max_temp);
+
+ if (err == PCO_NOERROR) {
+ GParamSpecInt *spec = (GParamSpecInt *) pco_properties[PROP_COOLING_POINT];
+ spec->minimum = min_temp;
+ spec->maximum = max_temp;
+ spec->default_value = default_temp;
+ }
+ else
+ g_warning("Unable to retrieve cooling range");
+
+ return err;
+}
+
+static void property_override_default_guint_value (GObjectClass *oclass, const gchar *property_name, guint new_default)
+{
+ GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (g_object_class_find_property (oclass, property_name));
+
+ if (pspec != NULL)
+ pspec->default_value = new_default;
+ else
+ g_warning ("pspec for %s not found\n", property_name);
+}
+
+static void override_maximum_adcs(UcaPcoCameraPrivate *priv)
+{
+ GParamSpecInt *spec = (GParamSpecInt *) pco_properties[PROP_SENSOR_ADCS];
+ spec->maximum = pco_get_maximum_number_of_adcs(priv->pco);
+}
+
+static gdouble convert_timebase(guint16 timebase)
+{
+ switch (timebase) {
+ case TIMEBASE_NS:
+ return 1e-9;
+ case TIMEBASE_US:
+ return 1e-6;
+ case TIMEBASE_MS:
+ return 1e-3;
+ default:
+ g_warning("Unknown timebase");
+ }
+ return 1e-3;
+}
+
+static void read_timebase(UcaPcoCameraPrivate *priv)
+{
+ pco_get_timebase(priv->pco, &priv->delay_timebase, &priv->exposure_timebase);
+}
+
+static gdouble get_suitable_timebase(gdouble time)
+{
+ if (time * 1e3 >= 1.0)
+ return TIMEBASE_MS;
+ if (time * 1e6 >= 1.0)
+ return TIMEBASE_US;
+ if (time * 1e9 >= 1.0)
+ return TIMEBASE_NS;
+ return TIMEBASE_INVALID;
+}
+
+static int fg_callback(frameindex_t frame, struct fg_apc_data *apc)
+{
+ UcaCamera *camera = UCA_CAMERA(apc);
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+ gpointer data = Fg_getImagePtrEx(priv->fg, frame, priv->fg_port, priv->fg_mem);
+
+ if (priv->camera_description->camera_type != CAMERATYPE_PCO_EDGE)
+ camera->grab_func(data, camera->user_data);
+ else {
+ pco_get_reorder_func(priv->pco)(priv->grab_buffer, data, priv->frame_width, priv->frame_height);
+ camera->grab_func(priv->grab_buffer, camera->user_data);
+ }
+
+ return 0;
+}
+
+static gboolean setup_fg_callback(UcaCamera *camera)
+{
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+ struct FgApcControl ctrl;
+
+ /* Jeez, as if a NULL pointer would not be good enough. */
+ ctrl.data = (struct fg_apc_data *) camera;
+ ctrl.version = 0;
+ ctrl.func = &fg_callback;
+ ctrl.flags = FG_APC_DEFAULTS;
+ ctrl.timeout = 1;
+
+ if (priv->grab_buffer)
+ g_free(priv->grab_buffer);
+
+ priv->grab_buffer = g_malloc0(priv->frame_width * priv->frame_height * sizeof(guint16));
+
+ return Fg_registerApcHandler(priv->fg, priv->fg_port, &ctrl, FG_APC_CONTROL_BASIC) == FG_OK;
+}
+
+static void uca_pco_camera_start_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PCO_CAMERA(camera));
+ guint err = PCO_NOERROR;
+
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+ guint16 binned_width, binned_height;
+ gboolean use_extended = FALSE;
+ gboolean transfer_async = FALSE;
+
+ g_object_get (camera, "sensor-extended", &use_extended, NULL);
+
+ if (use_extended) {
+ binned_width = priv->width_ex;
+ binned_height = priv->height_ex;
+ }
+ else {
+ binned_width = priv->width;
+ binned_height = priv->height;
+ }
+
+ binned_width /= priv->binning_h;
+ binned_height /= priv->binning_v;
+
+ if ((priv->roi_x + priv->roi_width > binned_width) || (priv->roi_y + priv->roi_height > binned_height)) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_UNSUPPORTED,
+ "ROI of size %ix%i @ (%i, %i) is outside of (binned) sensor size %ix%i\n",
+ priv->roi_width, priv->roi_height, priv->roi_x, priv->roi_y, binned_width, binned_height);
+ return;
+ }
+
+ /*
+ * All parameters are valid. Now, set them on the camera.
+ */
+ guint16 roi[4] = { priv->roi_x + 1, priv->roi_y + 1, priv->roi_x + priv->roi_width, priv->roi_y + priv->roi_height };
+
+ if (pco_set_roi(priv->pco, roi) != PCO_NOERROR) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL,
+ "Could not set ROI via pco_set_roi()");
+ return;
+ }
+
+ g_object_get(G_OBJECT(camera), "transfer-asynchronously", &transfer_async, NULL);
+
+ /*
+ * FIXME: We cannot set the binning here as this breaks communication with
+ * the camera. Setting the binning works _before_ initializing the frame
+ * grabber though. However, it is rather inconvenient to initialize and
+ * de-initialize the frame grabber for each recording sequence.
+ */
+
+ /* if (pco_set_binning(priv->pco, priv->binning_h, priv->binning_v) != PCO_NOERROR) */
+ /* g_warning("Cannot set binning\n"); */
+
+ if (priv->frame_width != priv->roi_width || priv->frame_height != priv->roi_height || priv->fg_mem == NULL) {
+ guint fg_width = priv->camera_description->camera_type == CAMERATYPE_PCO_EDGE ? 2 * priv->roi_width : priv->roi_width;
+
+ priv->frame_width = priv->roi_width;
+ priv->frame_height = priv->roi_height;
+ priv->num_bytes = 2;
+
+ Fg_setParameter(priv->fg, FG_WIDTH, &fg_width, priv->fg_port);
+ Fg_setParameter(priv->fg, FG_HEIGHT, &priv->frame_height, priv->fg_port);
+
+ if (priv->fg_mem)
+ Fg_FreeMemEx(priv->fg, priv->fg_mem);
+
+ const guint num_buffers = 2;
+ priv->fg_mem = Fg_AllocMemEx(priv->fg,
+ num_buffers * priv->frame_width * priv->frame_height * sizeof(uint16_t), num_buffers);
+
+ if (priv->fg_mem == NULL) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_FG_INIT,
+ "%s", Fg_getLastErrorDescription(priv->fg));
+ g_object_unref(camera);
+ return;
+ }
+ }
+
+ if (transfer_async)
+ setup_fg_callback(camera);
+
+ if ((priv->camera_description->camera_type == CAMERATYPE_PCO_DIMAX_STD) ||
+ (priv->camera_description->camera_type == CAMERATYPE_PCO4000))
+ pco_clear_active_segment(priv->pco);
+
+ priv->last_frame = 0;
+
+ err = pco_arm_camera(priv->pco);
+ HANDLE_PCO_ERROR(err);
+
+ err = pco_start_recording(priv->pco);
+ HANDLE_PCO_ERROR(err);
+
+ err = Fg_AcquireEx(priv->fg, priv->fg_port, GRAB_INFINITE, ACQ_STANDARD, priv->fg_mem);
+ FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_ACQUISITION);
+}
+
+static void uca_pco_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PCO_CAMERA(camera));
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+
+ guint err = pco_stop_recording(priv->pco);
+ HANDLE_PCO_ERROR(err);
+
+ err = Fg_stopAcquireEx(priv->fg, priv->fg_port, priv->fg_mem, STOP_SYNC);
+ FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_ACQUISITION);
+
+ err = Fg_setStatusEx(priv->fg, FG_UNBLOCK_ALL, 0, priv->fg_port, priv->fg_mem);
+ if (err == FG_INVALID_PARAMETER)
+ g_warning(" Unable to unblock all\n");
+}
+
+static void uca_pco_camera_start_readout(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PCO_CAMERA(camera));
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+
+ /*
+ * TODO: Check if readout mode is possible. This is not the case for the
+ * edge.
+ */
+
+ guint err = pco_get_active_segment(priv->pco, &priv->active_segment);
+ HANDLE_PCO_ERROR(err);
+
+ err = pco_get_num_images(priv->pco, priv->active_segment, &priv->num_recorded_images);
+ HANDLE_PCO_ERROR(err);
+
+ priv->current_image = 1;
+}
+
+static void uca_pco_camera_trigger(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PCO_CAMERA(camera));
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+
+ /* TODO: Check if we can trigger */
+ guint32 success = 0;
+ pco_force_trigger(priv->pco, &success);
+
+ if (!success)
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL,
+ "Could not trigger frame acquisition");
+}
+
+static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error)
+{
+ static const gint MAX_TIMEOUT = G_MAXINT;
+
+ g_return_if_fail(UCA_IS_PCO_CAMERA(camera));
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+
+ gboolean is_readout = FALSE;
+ g_object_get(G_OBJECT(camera), "is-readout", &is_readout, NULL);
+
+ if (is_readout) {
+ if (priv->current_image == priv->num_recorded_images) {
+ *data = NULL;
+ return;
+ }
+
+ /*
+ * No joke, the pco firmware allows to read a range of images but
+ * implements only reading single images ...
+ */
+ pco_read_images(priv->pco, priv->active_segment, priv->current_image, priv->current_image);
+ priv->current_image++;
+ }
+
+ pco_request_image(priv->pco);
+ priv->last_frame = Fg_getLastPicNumberBlockingEx(priv->fg, priv->last_frame+1, priv->fg_port, MAX_TIMEOUT, priv->fg_mem);
+
+ if (priv->last_frame <= 0) {
+ guint err = FG_OK + 1;
+ FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_GENERAL);
+ }
+
+ guint16 *frame = Fg_getImagePtrEx(priv->fg, priv->last_frame, priv->fg_port, priv->fg_mem);
+
+ if (*data == NULL)
+ *data = g_malloc0(priv->frame_width * priv->frame_height * priv->num_bytes);
+
+ if (priv->camera_description->camera_type == CAMERATYPE_PCO_EDGE)
+ pco_get_reorder_func(priv->pco)((guint16 *) *data, frame, priv->frame_width, priv->frame_height);
+ else
+ memcpy((gchar *) *data, (gchar *) frame, priv->frame_width * priv->frame_height * priv->num_bytes);
+}
+
+static void uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_SENSOR_EXTENDED:
+ {
+ guint16 format = g_value_get_boolean (value) ? SENSORFORMAT_EXTENDED : SENSORFORMAT_STANDARD;
+ pco_set_sensor_format(priv->pco, format);
+ }
+ break;
+
+ case PROP_ROI_X:
+ priv->roi_x = g_value_get_uint(value);
+ break;
+
+ case PROP_ROI_Y:
+ priv->roi_y = g_value_get_uint(value);
+ break;
+
+ case PROP_ROI_WIDTH:
+ {
+ guint width = g_value_get_uint(value);
+
+ if (width % priv->roi_horizontal_steps)
+ g_warning("ROI width %i is not a multiple of %i", width, priv->roi_horizontal_steps);
+ else
+ priv->roi_width = width;
+ }
+ break;
+
+ case PROP_ROI_HEIGHT:
+ {
+ guint height = g_value_get_uint(value);
+
+ if (height % priv->roi_vertical_steps)
+ g_warning("ROI height %i is not a multiple of %i", height, priv->roi_vertical_steps);
+ else
+ priv->roi_height = height;
+ }
+ break;
+
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ priv->binning_h = g_value_get_uint(value);
+ break;
+
+ case PROP_SENSOR_VERTICAL_BINNING:
+ priv->binning_v = g_value_get_uint(value);
+ break;
+
+ case PROP_EXPOSURE_TIME:
+ {
+ const gdouble time = g_value_get_double(value);
+
+ if (priv->exposure_timebase == TIMEBASE_INVALID)
+ read_timebase(priv);
+
+ /*
+ * Lets check if we can express the time in the current time
+ * base. If not, we need to adjust that.
+ */
+ guint16 suitable_timebase = get_suitable_timebase(time);
+
+ if (suitable_timebase == TIMEBASE_INVALID) {
+ g_warning("Cannot set such a small exposure time");
+ }
+ else {
+ if (suitable_timebase != priv->exposure_timebase) {
+ priv->exposure_timebase = suitable_timebase;
+ if (pco_set_timebase(priv->pco, priv->delay_timebase, suitable_timebase) != PCO_NOERROR)
+ g_warning("Cannot set exposure time base");
+ }
+
+ gdouble timebase = convert_timebase(suitable_timebase);
+ guint32 timesteps = time / timebase;
+ if (pco_set_exposure_time(priv->pco, timesteps) != PCO_NOERROR)
+ g_warning("Cannot set exposure time");
+ }
+ }
+ break;
+
+ case PROP_DELAY_TIME:
+ {
+ const gdouble time = g_value_get_double(value);
+
+ if (priv->delay_timebase == TIMEBASE_INVALID)
+ read_timebase(priv);
+
+ /*
+ * Lets check if we can express the time in the current time
+ * base. If not, we need to adjust that.
+ */
+ guint16 suitable_timebase = get_suitable_timebase(time);
+
+ if (suitable_timebase == TIMEBASE_INVALID) {
+ if (time == 0.0) {
+ /*
+ * If we want to suppress any pre-exposure delays, we
+ * can set the 0 seconds in whatever time base that is
+ * currently active.
+ */
+ if (pco_set_delay_time(priv->pco, 0) != PCO_NOERROR)
+ g_warning("Cannot set zero delay time");
+ }
+ else
+ g_warning("Cannot set such a small exposure time");
+ }
+ else {
+ if (suitable_timebase != priv->delay_timebase) {
+ priv->delay_timebase = suitable_timebase;
+ if (pco_set_timebase(priv->pco, suitable_timebase, priv->exposure_timebase) != PCO_NOERROR)
+ g_warning("Cannot set delay time base");
+ }
+
+ gdouble timebase = convert_timebase(suitable_timebase);
+ guint32 timesteps = time / timebase;
+ if (pco_set_delay_time(priv->pco, timesteps) != PCO_NOERROR)
+ g_warning("Cannot set delay time");
+ }
+ }
+ break;
+
+ case PROP_SENSOR_ADCS:
+ {
+ const guint num_adcs = g_value_get_uint(value);
+ if (pco_set_adc_mode(priv->pco, num_adcs) != PCO_NOERROR)
+ g_warning("Cannot set the number of ADCs per pixel\n");
+ }
+ break;
+
+ case PROP_SENSOR_PIXELRATE:
+ {
+ guint desired_pixel_rate = g_value_get_uint(value);
+ guint32 pixel_rate = 0;
+
+ for (guint i = 0; i < priv->pixelrates->n_values; i++) {
+ if (g_value_get_uint(g_value_array_get_nth(priv->pixelrates, i)) == desired_pixel_rate) {
+ pixel_rate = desired_pixel_rate;
+ break;
+ }
+ }
+
+ if (pixel_rate != 0) {
+ if (pco_set_pixelrate(priv->pco, pixel_rate) != PCO_NOERROR)
+ g_warning("Cannot set pixel rate");
+ }
+ else
+ g_warning("%i Hz is not possible. Please check the \"sensor-pixelrates\" property", desired_pixel_rate);
+ }
+ break;
+
+ case PROP_DOUBLE_IMAGE_MODE:
+ if (!pco_is_double_image_mode_available(priv->pco))
+ g_warning("Double image mode is not available on this pco model");
+ else
+ pco_set_double_image_mode(priv->pco, g_value_get_boolean(value));
+ break;
+
+ case PROP_OFFSET_MODE:
+ pco_set_offset_mode(priv->pco, g_value_get_boolean(value));
+ break;
+
+ case PROP_COOLING_POINT:
+ {
+ int16_t temperature = (int16_t) g_value_get_int(value);
+ pco_set_cooling_temperature(priv->pco, temperature);
+ }
+ break;
+
+ case PROP_RECORD_MODE:
+ {
+ /* TODO: setting this is not possible for the edge */
+ UcaPcoCameraRecordMode mode = (UcaPcoCameraRecordMode) g_value_get_enum(value);
+
+ if (mode == UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE)
+ pco_set_record_mode(priv->pco, RECORDER_SUBMODE_SEQUENCE);
+ else if (mode == UCA_PCO_CAMERA_RECORD_MODE_RING_BUFFER)
+ pco_set_record_mode(priv->pco, RECORDER_SUBMODE_RINGBUFFER);
+ else
+ g_warning("Unknown record mode");
+ }
+ break;
+
+ case PROP_ACQUIRE_MODE:
+ {
+ UcaPcoCameraAcquireMode mode = (UcaPcoCameraAcquireMode) g_value_get_enum(value);
+ unsigned int err = PCO_NOERROR;
+
+ if (mode == UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO)
+ err = pco_set_acquire_mode(priv->pco, ACQUIRE_MODE_AUTO);
+ else if (mode == UCA_PCO_CAMERA_ACQUIRE_MODE_EXTERNAL)
+ err = pco_set_acquire_mode(priv->pco, ACQUIRE_MODE_EXTERNAL);
+ else
+ g_warning("Unknown acquire mode");
+
+ if (err != PCO_NOERROR)
+ g_warning("Cannot set acquire mode");
+ }
+ break;
+
+ case PROP_TRIGGER_MODE:
+ {
+ UcaCameraTrigger trigger_mode = (UcaCameraTrigger) g_value_get_enum(value);
+
+ switch (trigger_mode) {
+ case UCA_CAMERA_TRIGGER_AUTO:
+ pco_set_trigger_mode(priv->pco, TRIGGER_MODE_AUTOTRIGGER);
+ break;
+ case UCA_CAMERA_TRIGGER_INTERNAL:
+ pco_set_trigger_mode(priv->pco, TRIGGER_MODE_SOFTWARETRIGGER);
+ break;
+ case UCA_CAMERA_TRIGGER_EXTERNAL:
+ pco_set_trigger_mode(priv->pco, TRIGGER_MODE_EXTERNALTRIGGER);
+ break;
+ }
+ }
+ break;
+
+ case PROP_NOISE_FILTER:
+ {
+ guint16 filter_mode = g_value_get_boolean(value) ? NOISE_FILTER_MODE_ON : NOISE_FILTER_MODE_OFF;
+ pco_set_noise_filter_mode(priv->pco, filter_mode);
+ }
+ break;
+
+ case PROP_TIMESTAMP_MODE:
+ {
+ guint16 modes[] = {
+ TIMESTAMP_MODE_OFF, /* 0 */
+ TIMESTAMP_MODE_BINARY, /* 1 = 1 << 0 */
+ TIMESTAMP_MODE_ASCII, /* 2 = 1 << 1 */
+ TIMESTAMP_MODE_BINARYANDASCII, /* 3 = 1 << 0 | 1 << 1 */
+ };
+ pco_set_timestamp_mode(priv->pco, modes[g_value_get_flags(value)]);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ return;
+ }
+}
+
+static void uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_SENSOR_EXTENDED:
+ {
+ guint16 format;
+ pco_get_sensor_format(priv->pco, &format);
+ g_value_set_boolean(value, format == SENSORFORMAT_EXTENDED);
+ }
+ break;
+
+ case PROP_SENSOR_WIDTH:
+ g_value_set_uint(value, priv->width);
+ break;
+
+ case PROP_SENSOR_HEIGHT:
+ g_value_set_uint(value, priv->height);
+ break;
+
+ case PROP_SENSOR_WIDTH_EXTENDED:
+ g_value_set_uint(value, priv->width_ex < priv->width ? priv->width : priv->width_ex);
+ break;
+
+ case PROP_SENSOR_HEIGHT_EXTENDED:
+ g_value_set_uint(value, priv->height_ex < priv->height ? priv->height : priv->height_ex);
+ break;
+
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ g_value_set_uint(value, priv->binning_h);
+ break;
+
+ case PROP_SENSOR_HORIZONTAL_BINNINGS:
+ g_value_set_boxed(value, priv->horizontal_binnings);
+ break;
+
+ case PROP_SENSOR_VERTICAL_BINNING:
+ g_value_set_uint(value, priv->binning_v);
+ break;
+
+ case PROP_SENSOR_VERTICAL_BINNINGS:
+ g_value_set_boxed(value, priv->vertical_binnings);
+ break;
+
+ case PROP_SENSOR_MAX_FRAME_RATE:
+ g_value_set_float(value, priv->camera_description->max_frame_rate);
+ break;
+
+ case PROP_SENSOR_BITDEPTH:
+ g_value_set_uint(value, 16);
+ break;
+
+ case PROP_SENSOR_TEMPERATURE:
+ {
+ gint32 ccd, camera, power;
+ pco_get_temperature(priv->pco, &ccd, &camera, &power);
+ g_value_set_double(value, ccd / 10.0);
+ }
+ break;
+
+ case PROP_SENSOR_ADCS:
+ {
+ /*
+ * Up to now, the ADC mode corresponds directly to the number of
+ * ADCs in use.
+ */
+ pco_adc_mode mode;
+ if (pco_get_adc_mode(priv->pco, &mode) != PCO_NOERROR)
+ g_warning("Cannot read number of ADCs per pixel");
+ g_value_set_uint(value, mode);
+ }
+ break;
+
+ case PROP_SENSOR_MAX_ADCS:
+ {
+ GParamSpecUInt *spec = (GParamSpecUInt *) pco_properties[PROP_SENSOR_ADCS];
+ g_value_set_uint(value, spec->maximum);
+ }
+ break;
+
+ case PROP_SENSOR_PIXELRATES:
+ g_value_set_boxed(value, priv->pixelrates);
+ break;
+
+ case PROP_SENSOR_PIXELRATE:
+ {
+ guint32 pixelrate;
+ pco_get_pixelrate(priv->pco, &pixelrate);
+ g_value_set_uint(value, pixelrate);
+ }
+ break;
+
+ case PROP_EXPOSURE_TIME:
+ {
+ uint32_t exposure_time;
+ pco_get_exposure_time(priv->pco, &exposure_time);
+
+ if (priv->exposure_timebase == TIMEBASE_INVALID)
+ read_timebase(priv);
+
+ g_value_set_double(value, convert_timebase(priv->exposure_timebase) * exposure_time);
+ }
+ break;
+
+ case PROP_DELAY_TIME:
+ {
+ uint32_t delay_time;
+ pco_get_delay_time(priv->pco, &delay_time);
+
+ if (priv->delay_timebase == TIMEBASE_INVALID)
+ read_timebase(priv);
+
+ g_value_set_double(value, convert_timebase(priv->delay_timebase) * delay_time);
+ }
+ break;
+
+ case PROP_HAS_DOUBLE_IMAGE_MODE:
+ g_value_set_boolean(value, pco_is_double_image_mode_available(priv->pco));
+ break;
+
+ case PROP_DOUBLE_IMAGE_MODE:
+ if (!pco_is_double_image_mode_available(priv->pco))
+ g_warning("Double image mode is not available on this pco model");
+ else {
+ bool on;
+ pco_get_double_image_mode(priv->pco, &on);
+ g_value_set_boolean(value, on);
+ }
+ break;
+
+ case PROP_OFFSET_MODE:
+ {
+ bool on;
+ pco_get_offset_mode(priv->pco, &on);
+ g_value_set_boolean(value, on);
+ }
+ break;
+
+ case PROP_HAS_STREAMING:
+ g_value_set_boolean(value, TRUE);
+ break;
+
+ case PROP_HAS_CAMRAM_RECORDING:
+ g_value_set_boolean(value, priv->camera_description->has_camram);
+ break;
+
+ case PROP_RECORD_MODE:
+ {
+ guint16 mode;
+ pco_get_record_mode(priv->pco, &mode);
+
+ if (mode == RECORDER_SUBMODE_SEQUENCE)
+ g_value_set_enum(value, UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE);
+ else if (mode == RECORDER_SUBMODE_RINGBUFFER)
+ g_value_set_enum(value, UCA_PCO_CAMERA_RECORD_MODE_RING_BUFFER);
+ else
+ g_warning("pco record mode not handled");
+ }
+ break;
+
+ case PROP_ACQUIRE_MODE:
+ {
+ guint16 mode;
+ pco_get_acquire_mode(priv->pco, &mode);
+
+ if (mode == ACQUIRE_MODE_AUTO)
+ g_value_set_enum(value, UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO);
+ else if (mode == ACQUIRE_MODE_EXTERNAL)
+ g_value_set_enum(value, UCA_PCO_CAMERA_ACQUIRE_MODE_EXTERNAL);
+ else
+ g_warning("pco acquire mode not handled");
+ }
+ break;
+
+ case PROP_TRIGGER_MODE:
+ {
+ guint16 mode;
+ pco_get_trigger_mode(priv->pco, &mode);
+
+ switch (mode) {
+ case TRIGGER_MODE_AUTOTRIGGER:
+ g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO);
+ break;
+ case TRIGGER_MODE_SOFTWARETRIGGER:
+ g_value_set_enum(value, UCA_CAMERA_TRIGGER_INTERNAL);
+ break;
+ case TRIGGER_MODE_EXTERNALTRIGGER:
+ g_value_set_enum(value, UCA_CAMERA_TRIGGER_EXTERNAL);
+ break;
+ default:
+ g_warning("pco trigger mode not handled");
+ }
+ }
+ break;
+
+ case PROP_ROI_X:
+ g_value_set_uint(value, priv->roi_x);
+ break;
+
+ case PROP_ROI_Y:
+ g_value_set_uint(value, priv->roi_y);
+ break;
+
+ case PROP_ROI_WIDTH:
+ g_value_set_uint(value, priv->roi_width);
+ break;
+
+ case PROP_ROI_HEIGHT:
+ g_value_set_uint(value, priv->roi_height);
+ break;
+
+ case PROP_ROI_WIDTH_MULTIPLIER:
+ g_value_set_uint(value, priv->roi_horizontal_steps);
+ break;
+
+ case PROP_ROI_HEIGHT_MULTIPLIER:
+ g_value_set_uint(value, priv->roi_vertical_steps);
+ break;
+
+ case PROP_NAME:
+ {
+ gchar *name = NULL;
+ pco_get_name(priv->pco, &name);
+ g_value_set_string(value, name);
+ g_free(name);
+ }
+ break;
+
+ case PROP_COOLING_POINT:
+ {
+ int16_t temperature;
+ if (pco_get_cooling_temperature(priv->pco, &temperature) != PCO_NOERROR)
+ g_warning("Cannot read cooling temperature\n");
+ g_value_set_int(value, temperature);
+ }
+ break;
+
+ case PROP_COOLING_POINT_MIN:
+ {
+ GParamSpecInt *spec = (GParamSpecInt *) pco_properties[PROP_COOLING_POINT];
+ g_value_set_int(value, spec->minimum);
+ }
+ break;
+
+ case PROP_COOLING_POINT_MAX:
+ {
+ GParamSpecInt *spec = (GParamSpecInt *) pco_properties[PROP_COOLING_POINT];
+ g_value_set_int(value, spec->maximum);
+ }
+ break;
+
+ case PROP_COOLING_POINT_DEFAULT:
+ {
+ GParamSpecInt *spec = (GParamSpecInt *) pco_properties[PROP_COOLING_POINT];
+ g_value_set_int(value, spec->default_value);
+ }
+ break;
+
+ case PROP_NOISE_FILTER:
+ {
+ guint16 mode;
+ pco_get_noise_filter_mode(priv->pco, &mode);
+ g_value_set_boolean(value, mode != NOISE_FILTER_MODE_OFF);
+ }
+ break;
+
+ case PROP_TIMESTAMP_MODE:
+ {
+ guint16 mode;
+ pco_get_timestamp_mode(priv->pco, &mode);
+
+ switch (mode) {
+ case TIMESTAMP_MODE_OFF:
+ g_value_set_flags(value, UCA_PCO_CAMERA_TIMESTAMP_NONE);
+ break;
+ case TIMESTAMP_MODE_BINARY:
+ g_value_set_flags(value, UCA_PCO_CAMERA_TIMESTAMP_BINARY);
+ break;
+ case TIMESTAMP_MODE_BINARYANDASCII:
+ g_value_set_flags(value,
+ UCA_PCO_CAMERA_TIMESTAMP_BINARY | UCA_PCO_CAMERA_TIMESTAMP_ASCII);
+ break;
+ case TIMESTAMP_MODE_ASCII:
+ g_value_set_flags(value, UCA_PCO_CAMERA_TIMESTAMP_ASCII);
+ break;
+ }
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void uca_pco_camera_finalize(GObject *object)
+{
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object);
+
+ if (priv->horizontal_binnings)
+ g_value_array_free(priv->horizontal_binnings);
+
+ if (priv->vertical_binnings)
+ g_value_array_free(priv->vertical_binnings);
+
+ if (priv->pixelrates)
+ g_value_array_free(priv->pixelrates);
+
+ if (priv->fg) {
+ if (priv->fg_mem)
+ Fg_FreeMemEx(priv->fg, priv->fg_mem);
+
+ Fg_FreeGrabber(priv->fg);
+ }
+
+ if (priv->pco)
+ pco_destroy(priv->pco);
+
+ g_free(priv->grab_buffer);
+
+ G_OBJECT_CLASS(uca_pco_camera_parent_class)->finalize(object);
+}
+
+static void uca_pco_camera_class_init(UcaPcoCameraClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property = uca_pco_camera_set_property;
+ gobject_class->get_property = uca_pco_camera_get_property;
+ gobject_class->finalize = uca_pco_camera_finalize;
+
+ UcaCameraClass *camera_class = UCA_CAMERA_CLASS(klass);
+ camera_class->start_recording = uca_pco_camera_start_recording;
+ camera_class->stop_recording = uca_pco_camera_stop_recording;
+ camera_class->start_readout = uca_pco_camera_start_readout;
+ camera_class->trigger = uca_pco_camera_trigger;
+ camera_class->grab = uca_pco_camera_grab;
+
+ for (guint i = 0; base_overrideables[i] != 0; i++)
+ g_object_class_override_property(gobject_class, base_overrideables[i], uca_camera_props[base_overrideables[i]]);
+
+ /**
+ * UcaPcoCamera:sensor-extended:
+ *
+ * Activate larger sensor area that contains surrounding pixels for dark
+ * references and dummies. Use #UcaPcoCamera:sensor-width-extended and
+ * #UcaPcoCamera:sensor-height-extended to query the resolution of the
+ * larger area.
+ */
+ pco_properties[PROP_SENSOR_EXTENDED] =
+ g_param_spec_boolean("sensor-extended",
+ "Use extended sensor format",
+ "Use extended sensor format",
+ FALSE, G_PARAM_READWRITE);
+
+ pco_properties[PROP_SENSOR_WIDTH_EXTENDED] =
+ g_param_spec_uint("sensor-width-extended",
+ "Width of extended sensor",
+ "Width of the extended sensor in pixels",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READABLE);
+
+ pco_properties[PROP_SENSOR_HEIGHT_EXTENDED] =
+ g_param_spec_uint("sensor-height-extended",
+ "Height of extended sensor",
+ "Height of the extended sensor in pixels",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READABLE);
+
+ /**
+ * UcaPcoCamera:sensor-pixelrate:
+ *
+ * Read and write the pixel rate or clock of the sensor in terms of Hertz.
+ * Make sure to query the possible pixel rates through the
+ * #UcaPcoCamera:sensor-pixelrates property. Any other value will be
+ * rejected by the camera.
+ */
+ pco_properties[PROP_SENSOR_PIXELRATE] =
+ g_param_spec_uint("sensor-pixelrate",
+ "Pixel rate",
+ "Pixel rate",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READWRITE);
+
+ pco_properties[PROP_SENSOR_PIXELRATES] =
+ g_param_spec_value_array("sensor-pixelrates",
+ "Array of possible sensor pixel rates",
+ "Array of possible sensor pixel rates",
+ pco_properties[PROP_SENSOR_PIXELRATE],
+ G_PARAM_READABLE);
+
+ pco_properties[PROP_NAME] =
+ g_param_spec_string("name",
+ "Name of the camera",
+ "Name of the camera",
+ "", G_PARAM_READABLE);
+
+ pco_properties[PROP_SENSOR_TEMPERATURE] =
+ g_param_spec_double("sensor-temperature",
+ "Temperature of the sensor",
+ "Temperature of the sensor in degree Celsius",
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE);
+
+ pco_properties[PROP_HAS_DOUBLE_IMAGE_MODE] =
+ g_param_spec_boolean("has-double-image-mode",
+ "Is double image mode supported by this model",
+ "Is double image mode supported by this model",
+ FALSE, G_PARAM_READABLE);
+
+ pco_properties[PROP_DOUBLE_IMAGE_MODE] =
+ g_param_spec_boolean("double-image-mode",
+ "Use double image mode",
+ "Use double image mode",
+ FALSE, G_PARAM_READWRITE);
+
+ pco_properties[PROP_OFFSET_MODE] =
+ g_param_spec_boolean("offset-mode",
+ "Use offset mode",
+ "Use offset mode",
+ FALSE, G_PARAM_READWRITE);
+
+ pco_properties[PROP_RECORD_MODE] =
+ g_param_spec_enum("record-mode",
+ "Record mode",
+ "Record mode",
+ UCA_TYPE_PCO_CAMERA_RECORD_MODE, UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE,
+ G_PARAM_READWRITE);
+
+ pco_properties[PROP_ACQUIRE_MODE] =
+ g_param_spec_enum("acquire-mode",
+ "Acquire mode",
+ "Acquire mode",
+ UCA_TYPE_PCO_CAMERA_ACQUIRE_MODE, UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO,
+ G_PARAM_READWRITE);
+
+ pco_properties[PROP_DELAY_TIME] =
+ g_param_spec_double("delay-time",
+ "Delay time",
+ "Delay before starting actual exposure",
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE);
+
+ pco_properties[PROP_NOISE_FILTER] =
+ g_param_spec_boolean("noise-filter",
+ "Noise filter",
+ "Noise filter",
+ FALSE, G_PARAM_READWRITE);
+
+ /**
+ * UcaPcoCamera:cooling-point:
+ *
+ * The value range is set arbitrarily, because we are not yet connected to
+ * the camera and just don't know the cooling range. We override these
+ * values in #uca_pco_camera_new().
+ */
+ pco_properties[PROP_COOLING_POINT] =
+ g_param_spec_int("cooling-point",
+ "Cooling point of the camera",
+ "Cooling point of the camera in degree celsius",
+ 0, 10, 5, G_PARAM_READWRITE);
+
+ pco_properties[PROP_COOLING_POINT_MIN] =
+ g_param_spec_int("cooling-point-min",
+ "Minimum cooling point",
+ "Minimum cooling point in degree celsius",
+ G_MININT, G_MAXINT, 0, G_PARAM_READABLE);
+
+ pco_properties[PROP_COOLING_POINT_MAX] =
+ g_param_spec_int("cooling-point-max",
+ "Maximum cooling point",
+ "Maximum cooling point in degree celsius",
+ G_MININT, G_MAXINT, 0, G_PARAM_READABLE);
+
+ pco_properties[PROP_COOLING_POINT_DEFAULT] =
+ g_param_spec_int("cooling-point-default",
+ "Default cooling point",
+ "Default cooling point in degree celsius",
+ G_MININT, G_MAXINT, 0, G_PARAM_READABLE);
+
+ pco_properties[PROP_SENSOR_ADCS] =
+ g_param_spec_uint("sensor-adcs",
+ "Number of ADCs to use",
+ "Number of ADCs to use",
+ 1, 2, 1,
+ G_PARAM_READWRITE);
+
+ pco_properties[PROP_SENSOR_MAX_ADCS] =
+ g_param_spec_uint("sensor-max-adcs",
+ "Maximum number of ADCs",
+ "Maximum number of ADCs that can be set with \"sensor-adcs\"",
+ 1, G_MAXUINT, 1,
+ G_PARAM_READABLE);
+
+ pco_properties[PROP_TIMESTAMP_MODE] =
+ g_param_spec_flags("timestamp-mode",
+ "Timestamp mode",
+ "Timestamp mode",
+ UCA_TYPE_PCO_CAMERA_TIMESTAMP, UCA_PCO_CAMERA_TIMESTAMP_NONE,
+ G_PARAM_READWRITE);
+
+ for (guint id = N_BASE_PROPERTIES; id < N_PROPERTIES; id++)
+ g_object_class_install_property(gobject_class, id, pco_properties[id]);
+
+ g_type_class_add_private(klass, sizeof(UcaPcoCameraPrivate));
+}
+
+static void uca_pco_camera_init(UcaPcoCamera *self)
+{
+ self->priv = UCA_PCO_CAMERA_GET_PRIVATE(self);
+ self->priv->fg = NULL;
+ self->priv->fg_mem = NULL;
+ self->priv->pco = NULL;
+ self->priv->horizontal_binnings = NULL;
+ self->priv->vertical_binnings = NULL;
+ self->priv->pixelrates = NULL;
+ self->priv->camera_description = NULL;
+ self->priv->last_frame = 0;
+ self->priv->grab_buffer = NULL;
+
+ self->priv->delay_timebase = TIMEBASE_INVALID;
+ self->priv->exposure_timebase = TIMEBASE_INVALID;
+}
+
+G_MODULE_EXPORT UcaCamera *
+uca_camera_impl_new (GError **error)
+{
+ pco_handle pco = pco_init();
+
+ if (pco == NULL) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_LIBPCO_INIT,
+ "Initializing libpco failed");
+ return NULL;
+ }
+
+ UcaPcoCamera *camera = g_object_new(UCA_TYPE_PCO_CAMERA, NULL);
+ UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera);
+ priv->pco = pco;
+
+ pco_get_resolution(priv->pco, &priv->width, &priv->height, &priv->width_ex, &priv->height_ex);
+ pco_get_binning(priv->pco, &priv->binning_h, &priv->binning_v);
+ pco_set_storage_mode(pco, STORAGE_MODE_RECORDER);
+ pco_set_auto_transfer(pco, 1);
+
+ guint16 roi[4];
+ pco_get_roi(priv->pco, roi);
+ pco_get_roi_steps(priv->pco, &priv->roi_horizontal_steps, &priv->roi_vertical_steps);
+
+ priv->roi_x = roi[0] - 1;
+ priv->roi_y = roi[1] - 1;
+ priv->roi_width = roi[2] - roi[0] + 1;
+ priv->roi_height = roi[3] - roi[1] + 1;
+
+ guint16 camera_type, camera_subtype;
+ pco_get_camera_type(priv->pco, &camera_type, &camera_subtype);
+ pco_cl_map_entry *map_entry = get_pco_cl_map_entry(camera_type);
+ priv->camera_description = map_entry;
+
+ if (map_entry == NULL) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_UNSUPPORTED,
+ "Camera type is not supported");
+ g_object_unref(camera);
+ return NULL;
+ }
+
+ priv->fg_port = PORT_A;
+ priv->fg = Fg_Init(map_entry->so_file, priv->fg_port);
+
+ if (priv->fg == NULL) {
+ g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_FG_INIT,
+ "%s", Fg_getLastErrorDescription(priv->fg));
+ g_object_unref(camera);
+ return NULL;
+ }
+
+ const guint32 fg_height = priv->height;
+ const guint32 fg_width = camera_type == CAMERATYPE_PCO_EDGE ? priv->width * 2 : priv->width;
+
+ FG_TRY_PARAM(priv->fg, camera, FG_CAMERA_LINK_CAMTYP, &map_entry->cl_type, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_FORMAT, &map_entry->cl_format, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_WIDTH, &fg_width, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_HEIGHT, &fg_height, priv->fg_port);
+
+ int val = FREE_RUN;
+ FG_TRY_PARAM(priv->fg, camera, FG_TRIGGERMODE, &val, priv->fg_port);
+
+ fill_binnings(priv);
+
+ /*
+ * Here we override property ranges because we didn't know them at property
+ * installation time.
+ */
+ GObjectClass *camera_class = G_OBJECT_CLASS (UCA_CAMERA_GET_CLASS (camera));
+ property_override_default_guint_value (camera_class, "roi-width", priv->width);
+ property_override_default_guint_value (camera_class, "roi-height", priv->height);
+
+ guint32 rates[4] = {0};
+ gint num_rates = 0;
+
+ if (pco_get_available_pixelrates(priv->pco, rates, &num_rates) == PCO_NOERROR) {
+ GObjectClass *pco_camera_class = G_OBJECT_CLASS (UCA_PCO_CAMERA_GET_CLASS (camera));
+
+ fill_pixelrates(priv, rates, num_rates);
+ property_override_default_guint_value (pco_camera_class, "sensor-pixelrate", rates[0]);
+ }
+
+ override_temperature_range (priv);
+ override_maximum_adcs (priv);
+
+ return UCA_CAMERA (camera);
+}
diff --git a/plugins/pco/uca-pco-camera.h b/plugins/pco/uca-pco-camera.h
new file mode 100644
index 0000000..73ae44e
--- /dev/null
+++ b/plugins/pco/uca-pco-camera.h
@@ -0,0 +1,91 @@
+/* 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_PCO_CAMERA_H
+#define __UCA_PCO_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_PCO_CAMERA (uca_pco_camera_get_type())
+#define UCA_PCO_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_PCO_CAMERA, UcaPcoCamera))
+#define UCA_IS_PCO_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_PCO_CAMERA))
+#define UCA_PCO_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UCA_TYPE_PCO_CAMERA, UcaPcoCameraClass))
+#define UCA_IS_PCO_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_PCO_CAMERA))
+#define UCA_PCO_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_PCO_CAMERA, UcaPcoCameraClass))
+
+#define UCA_PCO_CAMERA_ERROR uca_pco_camera_error_quark()
+typedef enum {
+ UCA_PCO_CAMERA_ERROR_LIBPCO_INIT,
+ UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL,
+ UCA_PCO_CAMERA_ERROR_UNSUPPORTED,
+ UCA_PCO_CAMERA_ERROR_FG_INIT,
+ UCA_PCO_CAMERA_ERROR_FG_GENERAL,
+ UCA_PCO_CAMERA_ERROR_FG_ACQUISITION
+} UcaPcoCameraError;
+
+typedef struct _UcaPcoCamera UcaPcoCamera;
+typedef struct _UcaPcoCameraClass UcaPcoCameraClass;
+typedef struct _UcaPcoCameraPrivate UcaPcoCameraPrivate;
+
+typedef enum {
+ UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE,
+ UCA_PCO_CAMERA_RECORD_MODE_RING_BUFFER,
+} UcaPcoCameraRecordMode;
+
+typedef enum {
+ UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO,
+ UCA_PCO_CAMERA_ACQUIRE_MODE_EXTERNAL
+} UcaPcoCameraAcquireMode;
+
+typedef enum {
+ UCA_PCO_CAMERA_TIMESTAMP_NONE = 0,
+ UCA_PCO_CAMERA_TIMESTAMP_BINARY = 1 << 0,
+ UCA_PCO_CAMERA_TIMESTAMP_ASCII = 1 << 1
+} UcaPcoCameraTimestamp;
+
+/**
+ * UcaPcoCamera:
+ *
+ * Creates #UcaPcoCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaPcoCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaPcoCamera {
+ /*< private >*/
+ UcaCamera parent;
+
+ UcaPcoCameraPrivate *priv;
+};
+
+/**
+ * UcaPcoCameraClass:
+ *
+ * #UcaPcoCamera class
+ */
+struct _UcaPcoCameraClass {
+ /*< private >*/
+ UcaCameraClass parent;
+};
+
+GType uca_pco_camera_get_type(void);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/pf/CMakeLists.txt b/plugins/pf/CMakeLists.txt
new file mode 100644
index 0000000..f392603
--- /dev/null
+++ b/plugins/pf/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 2.8)
+project(ucapf)
+
+find_package(PF)
+find_package(FgLib5)
+find_package(ClSerMe4)
+
+if (PF_FOUND AND CLSERME4_FOUND AND FGLIB5_FOUND)
+ set(UCA_CAMERA_NAME "pco")
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../package-plugin.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/../../package-plugin-${UCA_CAMERA_NAME}.sh)
+
+ include_directories(${PF_INCLUDE_DIRS}
+ ${CLSERME4_INCLUDE_DIR}
+ ${FGLIB5_INCLUDE_DIR})
+
+ add_library(ucapf SHARED
+ uca-pf-camera.c)
+
+ target_link_libraries(ucapf
+ ${UCA_DEPS}
+ ${PF_LIBRARIES}
+ ${CLSERME4_LIBRARY}
+ ${FGLIB5_LIBRARY})
+
+ install(TARGETS ucapf
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca
+ COMPONENT ${UCA_CAMERA_NAME})
+endif()
diff --git a/plugins/pf/uca-pf-camera.c b/plugins/pf/uca-pf-camera.c
new file mode 100644
index 0000000..35b5edd
--- /dev/null
+++ b/plugins/pf/uca-pf-camera.c
@@ -0,0 +1,351 @@
+/* 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 <gmodule.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fgrab_struct.h>
+#include <fgrab_prototyp.h>
+#include <libpf/pfcam.h>
+#include <errno.h>
+#include "uca-camera.h"
+#include "uca-pf-camera.h"
+
+#define FG_TRY_PARAM(fg, camobj, param, val_addr, port) \
+ { int r = Fg_setParameter(fg, param, val_addr, port); \
+ if (r != FG_OK) { \
+ g_set_error(error, UCA_PF_CAMERA_ERROR, \
+ UCA_PF_CAMERA_ERROR_FG_GENERAL, \
+ "%s", Fg_getLastErrorDescription(fg)); \
+ g_object_unref(camobj); \
+ return NULL; \
+ } }
+
+#define FG_SET_ERROR(err, fg, err_type) \
+ if (err != FG_OK) { \
+ g_set_error(error, UCA_PF_CAMERA_ERROR, \
+ err_type, \
+ "%s", Fg_getLastErrorDescription(fg)); \
+ return; \
+ }
+
+#define UCA_PF_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_PF_CAMERA, UcaPfCameraPrivate))
+
+G_DEFINE_TYPE(UcaPfCamera, uca_pf_camera, UCA_TYPE_CAMERA)
+
+/**
+ * UcaPfCameraError:
+ * @UCA_PF_CAMERA_ERROR_INIT: Initializing pcilib failed
+ * @UCA_PF_CAMERA_ERROR_FG_GENERAL: Frame grabber errors
+ * @UCA_PF_CAMERA_ERROR_FG_ACQUISITION: Acquisition errors related to the frame
+ * grabber
+ * @UCA_PF_CAMERA_ERROR_START_RECORDING: Starting failed
+ * @UCA_PF_CAMERA_ERROR_STOP_RECORDING: Stopping failed
+ */
+GQuark uca_pf_camera_error_quark()
+{
+ return g_quark_from_static_string("uca-pf-camera-error-quark");
+}
+
+static gint base_overrideables[] = {
+ PROP_NAME,
+ PROP_SENSOR_WIDTH,
+ PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_BITDEPTH,
+ PROP_SENSOR_HORIZONTAL_BINNING,
+ PROP_SENSOR_HORIZONTAL_BINNINGS,
+ PROP_SENSOR_VERTICAL_BINNING,
+ PROP_SENSOR_VERTICAL_BINNINGS,
+ PROP_SENSOR_MAX_FRAME_RATE,
+ PROP_EXPOSURE_TIME,
+ PROP_ROI_X,
+ PROP_ROI_Y,
+ PROP_ROI_WIDTH,
+ PROP_ROI_HEIGHT,
+ PROP_ROI_WIDTH_MULTIPLIER,
+ PROP_ROI_HEIGHT_MULTIPLIER,
+ PROP_HAS_STREAMING,
+ PROP_HAS_CAMRAM_RECORDING,
+ 0
+};
+
+enum {
+ PROP_FOO = N_BASE_PROPERTIES,
+ N_PROPERTIES
+};
+
+
+struct _UcaPfCameraPrivate {
+ guint roi_width;
+ guint roi_height;
+ guint last_frame;
+
+ Fg_Struct *fg;
+ guint fg_port;
+ dma_mem *fg_mem;
+};
+
+/*
+ * We just embed our private structure here.
+ */
+struct {
+ UcaCamera *camera;
+} fg_apc_data;
+
+static int me4_callback(frameindex_t frame, struct fg_apc_data *apc)
+{
+ UcaCamera *camera = UCA_CAMERA(apc);
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(camera);
+ camera->grab_func(Fg_getImagePtrEx(priv->fg, frame, priv->fg_port, priv->fg_mem), camera->user_data);
+ return 0;
+}
+
+static void uca_pf_camera_start_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PF_CAMERA(camera));
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(camera);
+ guint err = FG_OK;
+
+ if (priv->fg_mem == NULL) {
+ const guint num_buffers = 2;
+ priv->fg_mem = Fg_AllocMemEx(priv->fg, num_buffers * priv->roi_width * priv->roi_height, num_buffers);
+
+ if (priv->fg_mem == NULL) {
+ g_set_error(error, UCA_PF_CAMERA_ERROR, UCA_PF_CAMERA_ERROR_FG_ACQUISITION,
+ "%s", Fg_getLastErrorDescription(priv->fg));
+ g_object_unref(camera);
+ return;
+ }
+ }
+
+ gboolean transfer_async = FALSE;
+ g_object_get(G_OBJECT(camera),
+ "transfer-asynchronously", &transfer_async,
+ NULL);
+
+ if (transfer_async) {
+ struct FgApcControl ctrl = {
+ .version = 0,
+ .data = (struct fg_apc_data *) camera,
+ .func = &me4_callback,
+ .flags = FG_APC_DEFAULTS,
+ .timeout = 1
+ };
+
+ err = Fg_registerApcHandler(priv->fg, priv->fg_port, &ctrl, FG_APC_CONTROL_BASIC);
+ FG_SET_ERROR(err, priv->fg, UCA_PF_CAMERA_ERROR_FG_ACQUISITION);
+ }
+
+ err = Fg_AcquireEx(priv->fg, priv->fg_port, GRAB_INFINITE, ACQ_STANDARD, priv->fg_mem);
+ FG_SET_ERROR(err, priv->fg, UCA_PF_CAMERA_ERROR_FG_ACQUISITION);
+}
+
+static void uca_pf_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PF_CAMERA(camera));
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(camera);
+
+ guint err = Fg_stopAcquireEx(priv->fg, priv->fg_port, priv->fg_mem, STOP_SYNC);
+ FG_SET_ERROR(err, priv->fg, UCA_PF_CAMERA_ERROR_FG_ACQUISITION);
+
+ err = Fg_setStatusEx(priv->fg, FG_UNBLOCK_ALL, 0, priv->fg_port, priv->fg_mem);
+ if (err == FG_INVALID_PARAMETER)
+ g_print(" Unable to unblock all\n");
+}
+
+static void uca_pf_camera_start_readout(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PF_CAMERA(camera));
+ g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_IMPLEMENTED,
+ "This photon focus camera does not support recording to internal memory");
+}
+
+static void uca_pf_camera_grab(UcaCamera *camera, gpointer *data, GError **error)
+{
+ g_return_if_fail(UCA_IS_PF_CAMERA(camera));
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(camera);
+
+ priv->last_frame = Fg_getLastPicNumberBlockingEx(priv->fg, priv->last_frame+1, priv->fg_port, 5, priv->fg_mem);
+
+ if (priv->last_frame <= 0) {
+ guint err = FG_OK + 1;
+ FG_SET_ERROR(err, priv->fg, UCA_PF_CAMERA_ERROR_FG_GENERAL);
+ }
+
+ guint16 *frame = Fg_getImagePtrEx(priv->fg, priv->last_frame, priv->fg_port, priv->fg_mem);
+
+ if (*data == NULL)
+ *data = g_malloc0(priv->roi_width * priv->roi_height);
+
+ memcpy((gchar *) *data, (gchar *) frame, priv->roi_width * priv->roi_height);
+}
+
+static void uca_pf_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ return;
+ }
+}
+
+static void uca_pf_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SENSOR_WIDTH:
+ g_value_set_uint(value, 1280);
+ break;
+ case PROP_SENSOR_HEIGHT:
+ g_value_set_uint(value, 1024);
+ break;
+ case PROP_SENSOR_BITDEPTH:
+ g_value_set_uint(value, 8);
+ break;
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ break;
+ case PROP_SENSOR_HORIZONTAL_BINNINGS:
+ break;
+ case PROP_SENSOR_VERTICAL_BINNING:
+ break;
+ case PROP_SENSOR_VERTICAL_BINNINGS:
+ break;
+ case PROP_SENSOR_MAX_FRAME_RATE:
+ g_value_set_float(value, 488.0);
+ break;
+ case PROP_HAS_STREAMING:
+ g_value_set_boolean(value, TRUE);
+ break;
+ case PROP_HAS_CAMRAM_RECORDING:
+ g_value_set_boolean(value, FALSE);
+ break;
+ case PROP_EXPOSURE_TIME:
+ break;
+ case PROP_ROI_X:
+ g_value_set_uint(value, 0);
+ break;
+ case PROP_ROI_Y:
+ g_value_set_uint(value, 0);
+ break;
+ case PROP_ROI_WIDTH:
+ g_value_set_uint(value, 1280);
+ break;
+ case PROP_ROI_HEIGHT:
+ g_value_set_uint(value, 1024);
+ break;
+ case PROP_ROI_WIDTH_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_ROI_HEIGHT_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_NAME:
+ g_value_set_string(value, "Photon Focus MV2-D1280-640-CL");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void uca_pf_camera_finalize(GObject *object)
+{
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(object);
+
+ if (priv->fg) {
+ if (priv->fg_mem)
+ Fg_FreeMemEx(priv->fg, priv->fg_mem);
+
+ Fg_FreeGrabber(priv->fg);
+ }
+
+ G_OBJECT_CLASS(uca_pf_camera_parent_class)->finalize(object);
+}
+
+static void uca_pf_camera_class_init(UcaPfCameraClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property = uca_pf_camera_set_property;
+ gobject_class->get_property = uca_pf_camera_get_property;
+ gobject_class->finalize = uca_pf_camera_finalize;
+
+ UcaCameraClass *camera_class = UCA_CAMERA_CLASS(klass);
+ camera_class->start_recording = uca_pf_camera_start_recording;
+ camera_class->stop_recording = uca_pf_camera_stop_recording;
+ camera_class->start_readout = uca_pf_camera_start_readout;
+ camera_class->grab = uca_pf_camera_grab;
+
+ for (guint i = 0; base_overrideables[i] != 0; i++)
+ g_object_class_override_property(gobject_class, base_overrideables[i], uca_camera_props[base_overrideables[i]]);
+
+ g_type_class_add_private(klass, sizeof(UcaPfCameraPrivate));
+}
+
+static void uca_pf_camera_init(UcaPfCamera *self)
+{
+ self->priv = UCA_PF_CAMERA_GET_PRIVATE(self);
+ self->priv->fg = NULL;
+ self->priv->fg_mem = NULL;
+ self->priv->last_frame = 0;
+}
+
+G_MODULE_EXPORT UcaCamera *
+uca_camera_impl_new (GError **error)
+{
+ static const gchar *so_file = "libFullAreaGray8.so";
+ static const int camera_link_type = FG_CL_8BIT_FULL_8;
+ static const int camera_format = FG_GRAY;
+
+ /*
+ gint num_ports;
+ if (pfPortInit(&num_ports) < 0) {
+ g_set_error(error, UCA_PF_CAMERA_ERROR, UCA_PF_CAMERA_ERROR_INIT,
+ "Could not initialize ports");
+ return NULL;
+ }
+
+ if (pfDeviceOpen(0) < 0) {
+ g_set_error(error, UCA_PF_CAMERA_ERROR, UCA_PF_CAMERA_ERROR_INIT,
+ "Could not open device");
+ return NULL;
+ }
+ */
+
+ UcaPfCamera *camera = g_object_new(UCA_TYPE_PF_CAMERA, NULL);
+ UcaPfCameraPrivate *priv = UCA_PF_CAMERA_GET_PRIVATE(camera);
+
+ priv->fg_port = PORT_A;
+ priv->fg = Fg_Init(so_file, priv->fg_port);
+
+ /* TODO: get this from the camera */
+ priv->roi_width = 1280;
+ priv->roi_height = 1024;
+
+ if (priv->fg == NULL) {
+ g_set_error(error, UCA_PF_CAMERA_ERROR, UCA_PF_CAMERA_ERROR_INIT,
+ "%s", Fg_getLastErrorDescription(priv->fg));
+ g_object_unref(camera);
+ return NULL;
+ }
+
+ FG_TRY_PARAM(priv->fg, camera, FG_CAMERA_LINK_CAMTYP, &camera_link_type, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_FORMAT, &camera_format, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_WIDTH, &priv->roi_width, priv->fg_port);
+ FG_TRY_PARAM(priv->fg, camera, FG_HEIGHT, &priv->roi_height, priv->fg_port);
+
+ return UCA_CAMERA (camera);
+}
diff --git a/plugins/pf/uca-pf-camera.h b/plugins/pf/uca-pf-camera.h
new file mode 100644
index 0000000..3a309aa
--- /dev/null
+++ b/plugins/pf/uca-pf-camera.h
@@ -0,0 +1,74 @@
+/* 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_PF_CAMERA_H
+#define __UCA_PF_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_PF_CAMERA (uca_pf_camera_get_type())
+#define UCA_PF_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_PF_CAMERA, UcaPfCamera))
+#define UCA_IS_PF_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_PF_CAMERA))
+#define UCA_PF_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UCA_TYPE_PF_CAMERA, UcaPfCameraClass))
+#define UCA_IS_PF_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_PF_CAMERA))
+#define UCA_PF_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_PF_CAMERA, UcaPfCameraClass))
+
+#define UCA_PF_CAMERA_ERROR uca_pf_camera_error_quark()
+typedef enum {
+ UCA_PF_CAMERA_ERROR_INIT,
+ UCA_PF_CAMERA_ERROR_FG_GENERAL,
+ UCA_PF_CAMERA_ERROR_FG_ACQUISITION,
+ UCA_PF_CAMERA_ERROR_START_RECORDING,
+ UCA_PF_CAMERA_ERROR_STOP_RECORDING
+} UcaPfCameraError;
+
+typedef struct _UcaPfCamera UcaPfCamera;
+typedef struct _UcaPfCameraClass UcaPfCameraClass;
+typedef struct _UcaPfCameraPrivate UcaPfCameraPrivate;
+
+/**
+ * UcaPfCamera:
+ *
+ * Creates #UcaPfCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaPfCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaPfCamera {
+ /*< private >*/
+ UcaCamera parent;
+
+ UcaPfCameraPrivate *priv;
+};
+
+/**
+ * UcaPfCameraClass:
+ *
+ * #UcaPfCamera class
+ */
+struct _UcaPfCameraClass {
+ /*< private >*/
+ UcaCameraClass parent;
+};
+
+GType uca_pf_camera_get_type(void);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/pylon/CMakeLists.txt b/plugins/pylon/CMakeLists.txt
new file mode 100644
index 0000000..18823a4
--- /dev/null
+++ b/plugins/pylon/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8)
+project(ucapylon)
+
+find_package(Pylon)
+
+if (PYLON_FOUND)
+ set(UCA_CAMERA_NAME "pylon")
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../package-plugin.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/../../package-plugin-${UCA_CAMERA_NAME}.sh)
+
+ include_directories(${LIBPYLONCAM_INCLUDEDIR})
+
+ add_library(ucapylon SHARED
+ uca-pylon-camera.c)
+
+ target_link_libraries(ucapylon
+ ${UCA_DEPS}
+ ${LIBPYLONCAM_LIBRARIES})
+
+ install(TARGETS ucapylon
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca
+ COMPONENT ${UCA_CAMERA_NAME})
+endif()
diff --git a/plugins/pylon/uca-pylon-camera.c b/plugins/pylon/uca-pylon-camera.c
new file mode 100644
index 0000000..541b69b
--- /dev/null
+++ b/plugins/pylon/uca-pylon-camera.c
@@ -0,0 +1,391 @@
+/* Copyright (C) 2012 Volker Kaiser <volker.kaiser@softwareschneiderei>
+ (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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libpyloncam/pylon_camera.h>
+#include "uca-camera.h"
+#include "uca-pylon-camera.h"
+
+#define UCA_PYLON_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_PYLON_CAMERA, UcaPylonCameraPrivate))
+
+G_DEFINE_TYPE(UcaPylonCamera, uca_pylon_camera, UCA_TYPE_CAMERA)
+
+/**
+ * UcapylonCameraError:
+ * @UCA_PYLON_CAMERA_ERROR_LIBPYLON_INIT: Initializing libpylon failed
+ * @UCA_PYLON_CAMERA_ERROR_LIBPYLON_GENERAL: General libpylon error
+ * @UCA_PYLON_CAMERA_ERROR_UNSUPPORTED: Camera type is not supported
+ * @UCA_PYLON_CAMERA_ERROR_FG_INIT: Framegrabber initialization failed
+ * @UCA_PYLON_CAMERA_ERROR_FG_GENERAL: General framegrabber error
+ * @UCA_PYLON_CAMERA_ERROR_FG_ACQUISITION: Framegrabber acquisition error
+ */
+GQuark uca_pylon_camera_error_quark()
+{
+ return g_quark_from_static_string("uca-pylon-camera-error-quark");
+}
+
+enum {
+ PROP_ROI_WIDTH_DEFAULT = N_BASE_PROPERTIES,
+ PROP_ROI_HEIGHT_DEFAULT,
+ PROP_GAIN,
+ N_PROPERTIES
+};
+
+static gint base_overrideables[] = {
+ PROP_NAME,
+ PROP_SENSOR_WIDTH,
+ PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_BITDEPTH,
+ PROP_SENSOR_HORIZONTAL_BINNING,
+ PROP_SENSOR_HORIZONTAL_BINNINGS,
+ PROP_SENSOR_VERTICAL_BINNING,
+ PROP_SENSOR_VERTICAL_BINNINGS,
+ PROP_SENSOR_MAX_FRAME_RATE,
+ PROP_TRIGGER_MODE,
+ PROP_EXPOSURE_TIME,
+ PROP_ROI_X,
+ PROP_ROI_Y,
+ PROP_ROI_WIDTH,
+ PROP_ROI_HEIGHT,
+ PROP_ROI_WIDTH_MULTIPLIER,
+ PROP_ROI_HEIGHT_MULTIPLIER,
+ PROP_HAS_STREAMING,
+ PROP_HAS_CAMRAM_RECORDING,
+ 0
+};
+
+static GParamSpec *pylon_properties[N_PROPERTIES] = { NULL, };
+
+
+struct _UcaPylonCameraPrivate {
+ guint bit_depth;
+ gsize num_bytes;
+
+ guint width;
+ guint height;
+ guint16 roi_x, roi_y;
+ guint16 roi_width, roi_height;
+ GValueArray *binnings;
+};
+
+
+static void pylon_get_roi(GObject *object, GError** error)
+{
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(object);
+ pylon_camera_get_roi(&priv->roi_x, &priv->roi_y, &priv->roi_width, &priv->roi_height, error);
+}
+
+static void pylon_set_roi(GObject *object, GError** error)
+{
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(object);
+ pylon_camera_set_roi(priv->roi_x, priv->roi_y, priv->roi_width, priv->roi_height, error);
+}
+
+UcaPylonCamera *uca_pylon_camera_new(GError **error)
+{
+ UcaPylonCamera *camera = g_object_new(UCA_TYPE_PYLON_CAMERA, NULL);
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(camera);
+
+ pylon_camera_new("/usr/local/lib64", "141.52.111.110", error);
+
+ if (*error != NULL)
+ return NULL;
+
+ pylon_camera_get_sensor_size(&priv->width, &priv->height, error);
+
+ if (*error != NULL)
+ return NULL;
+
+ return camera;
+}
+
+static void uca_pylon_camera_start_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PYLON_CAMERA(camera));
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(camera);
+
+ priv->num_bytes = 2;
+ pylon_camera_start_acquision(error);
+
+}
+
+static void uca_pylon_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_PYLON_CAMERA(camera));
+ pylon_camera_stop_acquision(error);
+}
+
+static void uca_pylon_camera_grab(UcaCamera *camera, gpointer *data, GError **error)
+{
+ g_return_if_fail(UCA_IS_PYLON_CAMERA(camera));
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(camera);
+
+ if (*data == NULL) {
+ *data = g_malloc0(priv->width * priv->height * priv->num_bytes);
+ }
+ pylon_camera_grab(data, error);
+}
+
+static void uca_pylon_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(object);
+ GError* error = NULL;
+
+ switch (property_id) {
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ /* intentional fall-through*/
+ case PROP_SENSOR_VERTICAL_BINNING:
+ /* intentional fall-through*/
+ case PROP_TRIGGER_MODE:
+ break;
+
+ case PROP_ROI_X:
+ {
+ priv->roi_x = g_value_get_uint(value);
+ pylon_set_roi(object, &error);
+ }
+ break;
+
+ case PROP_ROI_Y:
+ {
+ priv->roi_y = g_value_get_uint(value);
+ pylon_set_roi(object, &error);
+ }
+ break;
+
+ case PROP_ROI_WIDTH:
+ {
+ priv->roi_width = g_value_get_uint(value);
+ pylon_set_roi(object, &error);
+ }
+ break;
+
+ case PROP_ROI_HEIGHT:
+ {
+ priv->roi_height = g_value_get_uint(value);
+ pylon_set_roi(object, &error);
+ }
+ break;
+
+ case PROP_EXPOSURE_TIME:
+ pylon_camera_set_exposure_time(g_value_get_double(value), &error);
+ break;
+
+ case PROP_GAIN:
+ pylon_camera_set_gain(g_value_get_int(value), &error);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ return;
+ }
+}
+
+static void uca_pylon_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(object);
+ GError* error = NULL;
+
+ switch (property_id) {
+ case PROP_SENSOR_WIDTH:
+ pylon_camera_get_sensor_size(&priv->width, &priv->height, &error);
+ g_value_set_uint(value, priv->width);
+ break;
+
+ case PROP_SENSOR_HEIGHT:
+ pylon_camera_get_sensor_size(&priv->width, &priv->height, &error);
+ g_value_set_uint(value, priv->height);
+ break;
+
+ case PROP_SENSOR_BITDEPTH:
+ pylon_camera_get_bit_depth(&priv->bit_depth, &error);
+ g_value_set_uint(value, priv->bit_depth);
+ break;
+
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+
+ case PROP_SENSOR_HORIZONTAL_BINNINGS:
+ g_value_set_boxed(value, priv->binnings);
+ break;
+
+ case PROP_SENSOR_VERTICAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+
+ case PROP_SENSOR_VERTICAL_BINNINGS:
+ g_value_set_boxed(value, priv->binnings);
+ break;
+
+ case PROP_SENSOR_MAX_FRAME_RATE:
+ g_value_set_float(value, 0.0);
+ break;
+
+ case PROP_TRIGGER_MODE:
+ g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO);
+ break;
+
+ case PROP_HAS_STREAMING:
+ g_value_set_boolean(value, FALSE);
+ break;
+
+ case PROP_HAS_CAMRAM_RECORDING:
+ g_value_set_boolean(value, FALSE);
+ break;
+
+ case PROP_ROI_X:
+ {
+ pylon_get_roi(object, &error);
+ g_value_set_uint(value, priv->roi_x);
+ }
+ break;
+
+ case PROP_ROI_Y:
+ {
+ pylon_get_roi(object, &error);
+ g_value_set_uint(value, priv->roi_y);
+ }
+ break;
+
+ case PROP_ROI_WIDTH:
+ {
+ pylon_get_roi(object, &error);
+ g_value_set_uint(value, priv->roi_width);
+ }
+ break;
+
+ case PROP_ROI_HEIGHT:
+ {
+ pylon_get_roi(object, &error);
+ g_value_set_uint(value, priv->roi_height);
+ }
+ break;
+
+ case PROP_ROI_WIDTH_DEFAULT:
+ pylon_camera_get_sensor_size(&priv->width, &priv->height, &error);
+ g_value_set_uint(value, priv->width);
+ break;
+
+ case PROP_ROI_HEIGHT_DEFAULT:
+ pylon_camera_get_sensor_size(&priv->width, &priv->height, &error);
+ g_value_set_uint(value, priv->height);
+ break;
+
+ case PROP_GAIN:
+ {
+ gint gain=0;
+ pylon_camera_get_gain(&gain, &error);
+ g_value_set_int(value, gain);
+ }
+ break;
+
+ case PROP_ROI_WIDTH_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+
+ case PROP_ROI_HEIGHT_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+
+ case PROP_EXPOSURE_TIME:
+ {
+ gdouble exp_time = 0.0;
+ pylon_camera_get_exposure_time(&exp_time, &error);
+ g_value_set_double(value, exp_time);
+ }
+ break;
+
+ case PROP_NAME:
+ g_value_set_string(value, "Pylon Camera");
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void uca_pylon_camera_finalize(GObject *object)
+{
+ UcaPylonCameraPrivate *priv = UCA_PYLON_CAMERA_GET_PRIVATE(object);
+ g_value_array_free(priv->binnings);
+
+ G_OBJECT_CLASS(uca_pylon_camera_parent_class)->finalize(object);
+}
+
+static void uca_pylon_camera_class_init(UcaPylonCameraClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property = uca_pylon_camera_set_property;
+ gobject_class->get_property = uca_pylon_camera_get_property;
+ gobject_class->finalize = uca_pylon_camera_finalize;
+
+ UcaCameraClass *camera_class = UCA_CAMERA_CLASS(klass);
+ camera_class->start_recording = uca_pylon_camera_start_recording;
+ camera_class->stop_recording = uca_pylon_camera_stop_recording;
+ camera_class->grab = uca_pylon_camera_grab;
+
+ for (guint i = 0; base_overrideables[i] != 0; i++)
+ g_object_class_override_property(gobject_class, base_overrideables[i], uca_camera_props[base_overrideables[i]]);
+
+ pylon_properties[PROP_NAME] =
+ g_param_spec_string("name",
+ "Name of the camera",
+ "Name of the camera",
+ "", G_PARAM_READABLE);
+
+ pylon_properties[PROP_ROI_WIDTH_DEFAULT] =
+ g_param_spec_uint("roi-width-default",
+ "ROI width default value",
+ "ROI width default value",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE);
+
+ pylon_properties[PROP_ROI_HEIGHT_DEFAULT] =
+ g_param_spec_uint("roi-height-default",
+ "ROI height default value",
+ "ROI height default value",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE);
+
+ pylon_properties[PROP_GAIN] =
+ g_param_spec_int("gain",
+ "gain",
+ "gain",
+ 0, G_MAXINT, 0,
+ G_PARAM_READWRITE);
+
+ for (guint id = N_BASE_PROPERTIES; id < N_PROPERTIES; id++)
+ g_object_class_install_property(gobject_class, id, pylon_properties[id]);
+
+ g_type_class_add_private(klass, sizeof(UcaPylonCameraPrivate));
+}
+
+static void uca_pylon_camera_init(UcaPylonCamera *self)
+{
+ self->priv = UCA_PYLON_CAMERA_GET_PRIVATE(self);
+
+ /* binnings */
+ GValue val = {0};
+ g_value_init(&val, G_TYPE_UINT);
+ g_value_set_uint(&val, 1);
+ self->priv->binnings = g_value_array_new(1);
+ g_value_array_append(self->priv->binnings, &val);
+}
diff --git a/plugins/pylon/uca-pylon-camera.h b/plugins/pylon/uca-pylon-camera.h
new file mode 100644
index 0000000..eebf63c
--- /dev/null
+++ b/plugins/pylon/uca-pylon-camera.h
@@ -0,0 +1,74 @@
+/* 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_PYLON_CAMERA_H
+#define __UCA_PYLON_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_PYLON_CAMERA (uca_pylon_camera_get_type())
+#define UCA_PYLON_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_PYLON_CAMERA, UcaPylonCamera))
+#define UCA_IS_PYLON_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_PYLON_CAMERA))
+#define UCA_PYLON_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_PYLON_CAMERA, UfoPylonCameraClass))
+#define UCA_IS_PYLON_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_PYLON_CAMERA))
+#define UCA_PYLON_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_PYLON_CAMERA, UcaPylonCameraClass))
+
+#define UCA_PYLON_CAMERA_ERROR uca_pylon_camera_error_quark()
+typedef enum {
+ UCA_PYLON_CAMERA_ERROR_LIBPYLON_INIT,
+ UCA_PYLON_CAMERA_ERROR_LIBPYLON_GENERAL,
+ UCA_PYLON_CAMERA_ERROR_UNSUPPORTED,
+} UcaPylonCameraError;
+
+typedef struct _UcaPylonCamera UcaPylonCamera;
+typedef struct _UcaPylonCameraClass UcaPylonCameraClass;
+typedef struct _UcaPylonCameraPrivate UcaPylonCameraPrivate;
+
+/**
+ * UcaPylonCamera:
+ *
+ * Creates #UcaPylonCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaPylonCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaPylonCamera {
+ /*< private >*/
+ UcaCamera parent;
+
+ UcaPylonCameraPrivate *priv;
+};
+
+/**
+ * UcaPylonCameraClass:
+ *
+ * #UcaPylonCamera class
+ */
+struct _UcaPylonCameraClass {
+ /*< private >*/
+ UcaCameraClass parent;
+};
+
+UcaPylonCamera *uca_pylon_camera_new(GError **error);
+
+GType uca_pylon_camera_get_type(void);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/ufo/CMakeLists.txt b/plugins/ufo/CMakeLists.txt
new file mode 100644
index 0000000..fe89668
--- /dev/null
+++ b/plugins/ufo/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8)
+project(ucaufo)
+
+find_package(IPE)
+
+if (IPE_FOUND)
+ set(UCA_CAMERA_NAME "ufo")
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../package-plugin.sh.in
+ ${CMAKE_CURRENT_BINARY_DIR}/../../package-plugin-${UCA_CAMERA_NAME}.sh)
+
+ include_directories(${IPE_INCLUDE_DIRS})
+
+ add_library(ucaufo SHARED
+ uca-ufo-camera.c)
+
+ target_link_libraries(ucaufo
+ ${UCA_DEPS}
+ ${IPE_LIBRARIES})
+
+ install(TARGETS ucaufo
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca
+ COMPONENT ${UCA_CAMERA_NAME})
+endif()
diff --git a/plugins/ufo/uca-ufo-camera.c b/plugins/ufo/uca-ufo-camera.c
new file mode 100644
index 0000000..7542fdf
--- /dev/null
+++ b/plugins/ufo/uca-ufo-camera.c
@@ -0,0 +1,497 @@
+/* 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 <gmodule.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pcilib.h>
+#include <errno.h>
+#include "uca-camera.h"
+#include "uca-ufo-camera.h"
+
+#define PCILIB_SET_ERROR(err, err_type) \
+ if (err != 0) { \
+ g_set_error(error, UCA_UFO_CAMERA_ERROR, \
+ err_type, \
+ "pcilib: %s", strerror(err)); \
+ return; \
+ }
+
+#define UCA_UFO_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_UFO_CAMERA, UcaUfoCameraPrivate))
+
+G_DEFINE_TYPE(UcaUfoCamera, uca_ufo_camera, UCA_TYPE_CAMERA)
+
+static const guint SENSOR_WIDTH = 2048;
+static const guint SENSOR_HEIGHT = 1088;
+static const gdouble EXPOSURE_TIME_SCALE = 2.69e6;
+
+/**
+ * UcaUfoCameraError:
+ * @UCA_UFO_CAMERA_ERROR_INIT: Initializing pcilib failed
+ * @UCA_UFO_CAMERA_ERROR_START_RECORDING: Starting failed
+ * @UCA_UFO_CAMERA_ERROR_STOP_RECORDING: Stopping failed
+ * @UCA_UFO_CAMERA_ERROR_TRIGGER: Triggering a frame failed
+ * @UCA_UFO_CAMERA_ERROR_NEXT_EVENT: No event happened
+ * @UCA_UFO_CAMERA_ERROR_NO_DATA: No data was transmitted
+ * @UCA_UFO_CAMERA_ERROR_MAYBE_CORRUPTED: Data is potentially corrupted
+ */
+GQuark uca_ufo_camera_error_quark()
+{
+ return g_quark_from_static_string("uca-ufo-camera-error-quark");
+}
+
+enum {
+ PROP_SENSOR_TEMPERATURE = N_BASE_PROPERTIES,
+ PROP_FPGA_TEMPERATURE,
+ PROP_UFO_START,
+ N_MAX_PROPERTIES = 512
+};
+
+static gint base_overrideables[] = {
+ PROP_NAME,
+ PROP_SENSOR_WIDTH,
+ PROP_SENSOR_HEIGHT,
+ PROP_SENSOR_HORIZONTAL_BINNING,
+ PROP_SENSOR_VERTICAL_BINNING,
+ PROP_SENSOR_MAX_FRAME_RATE,
+ PROP_SENSOR_BITDEPTH,
+ PROP_EXPOSURE_TIME,
+ PROP_ROI_X,
+ PROP_ROI_Y,
+ PROP_ROI_WIDTH,
+ PROP_ROI_HEIGHT,
+ PROP_ROI_WIDTH_MULTIPLIER,
+ PROP_ROI_HEIGHT_MULTIPLIER,
+ PROP_HAS_STREAMING,
+ PROP_HAS_CAMRAM_RECORDING,
+ PROP_TRIGGER_MODE,
+ 0,
+};
+
+typedef struct _RegisterInfo {
+ gchar *name;
+ guint cached_value;
+} RegisterInfo;
+
+static GParamSpec *ufo_properties[N_MAX_PROPERTIES] = { NULL, };
+
+static guint N_PROPERTIES;
+static GHashTable *ufo_property_table; /* maps from prop_id to RegisterInfo* */
+
+struct _UcaUfoCameraPrivate {
+ pcilib_t *handle;
+ pcilib_timeout_t timeout;
+ guint n_bits;
+ enum {
+ FPGA_48MHZ = 0,
+ FPGA_40MHZ
+ } frequency;
+};
+
+static void
+error_handler (const char *format, ...)
+{
+ va_list args;
+ gchar *message;
+
+ va_start (args, format);
+ message = g_strdup_vprintf (format, args);
+ g_warning ("%s", message);
+ va_end (args);
+}
+
+static guint
+read_register_value (pcilib_t *handle, const gchar *name)
+{
+ pcilib_register_value_t reg_value;
+
+ pcilib_read_register(handle, NULL, name, &reg_value);
+ return (guint) reg_value;
+}
+
+static int event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user)
+{
+ UcaCamera *camera = UCA_CAMERA(user);
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera);
+ size_t error = 0;
+
+ void *buffer = pcilib_get_data(priv->handle, event_id, PCILIB_EVENT_DATA, &error);
+
+ if (buffer == NULL) {
+ pcilib_trigger(priv->handle, PCILIB_EVENT0, 0, NULL);
+ return PCILIB_STREAMING_CONTINUE;
+ }
+
+ camera->grab_func(buffer, camera->user_data);
+ pcilib_return_data(priv->handle, event_id, PCILIB_EVENT_DATA, buffer);
+ pcilib_trigger(priv->handle, PCILIB_EVENT0, 0, NULL);
+
+ return PCILIB_STREAMING_CONTINUE;
+}
+
+G_MODULE_EXPORT UcaCamera *
+uca_camera_impl_new (GError **error)
+{
+ pcilib_model_t model = PCILIB_MODEL_DETECT;
+ pcilib_model_description_t *model_description;
+ pcilib_t *handle = pcilib_open("/dev/fpga0", model);
+ guint prop = PROP_UFO_START;
+ guint adc_resolution;
+
+ if (handle == NULL) {
+ g_set_error(error, UCA_UFO_CAMERA_ERROR, UCA_UFO_CAMERA_ERROR_INIT,
+ "Initializing pcilib failed");
+ return NULL;
+ }
+
+ pcilib_set_error_handler(&error_handler, &error_handler);
+
+ /* Generate properties from model description */
+ model_description = pcilib_get_model_description(handle);
+ ufo_property_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+
+ for (guint i = 0; model_description->registers[i].name != NULL; i++) {
+ GParamFlags flags = 0;
+ RegisterInfo *reg_info;
+ gchar *prop_name;
+ pcilib_register_description_t *reg;
+ pcilib_register_value_t value;
+
+ reg = &model_description->registers[i];
+
+ switch (reg->mode) {
+ case PCILIB_REGISTER_R:
+ flags = G_PARAM_READABLE;
+ break;
+ case PCILIB_REGISTER_W:
+ case PCILIB_REGISTER_W1C:
+ flags = G_PARAM_WRITABLE;
+ break;
+ case PCILIB_REGISTER_RW:
+ case PCILIB_REGISTER_RW1C:
+ flags = G_PARAM_READWRITE;
+ break;
+ }
+
+ pcilib_read_register (handle, NULL, reg->name, &value);
+ reg_info = g_new0 (RegisterInfo, 1);
+ reg_info->name = g_strdup (reg->name);
+ reg_info->cached_value = (guint32) value;
+
+ g_hash_table_insert (ufo_property_table, GINT_TO_POINTER (prop), reg_info);
+ prop_name = g_strdup_printf ("ufo-%s", reg->name);
+
+ ufo_properties[prop++] = g_param_spec_uint (
+ prop_name, reg->description, reg->description,
+ 0, G_MAXUINT, reg->defvalue, flags);
+
+ g_free (prop_name);
+ }
+
+ N_PROPERTIES = prop;
+
+ UcaUfoCamera *camera = g_object_new(UCA_TYPE_UFO_CAMERA, NULL);
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera);
+
+ priv->frequency = read_register_value (handle, "bit_mode");
+ adc_resolution = read_register_value (handle, "adc_resolution");
+
+ switch (adc_resolution) {
+ case 0:
+ priv->n_bits = 10;
+ break;
+ case 1:
+ priv->n_bits = 11;
+ break;
+ case 2:
+ priv->n_bits = 12;
+ break;
+ }
+
+ priv->handle = handle;
+
+ return UCA_CAMERA (camera);
+}
+
+static void uca_ufo_camera_start_recording(UcaCamera *camera, GError **error)
+{
+ UcaUfoCameraPrivate *priv;
+ gdouble exposure_time;
+ int err;
+
+ g_return_if_fail(UCA_IS_UFO_CAMERA(camera));
+
+ priv = UCA_UFO_CAMERA_GET_PRIVATE(camera);
+ err = pcilib_start(priv->handle, PCILIB_EVENT_DATA, PCILIB_EVENT_FLAGS_DEFAULT);
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_START_RECORDING);
+
+ gboolean transfer_async = FALSE;
+ g_object_get(G_OBJECT(camera),
+ "transfer-asynchronously", &transfer_async,
+ "exposure-time", &exposure_time,
+ NULL);
+
+ priv->timeout = ((pcilib_timeout_t) (exposure_time * 1000 + 50.0) * 1000);
+
+ if (transfer_async) {
+ pcilib_trigger(priv->handle, PCILIB_EVENT0, 0, NULL);
+ pcilib_stream(priv->handle, &event_callback, camera);
+ }
+}
+
+static void uca_ufo_camera_stop_recording(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_UFO_CAMERA(camera));
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera);
+ int err = pcilib_stop(priv->handle, PCILIB_EVENT_FLAGS_DEFAULT);
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_START_RECORDING);
+}
+
+static void uca_ufo_camera_start_readout(UcaCamera *camera, GError **error)
+{
+ g_return_if_fail(UCA_IS_UFO_CAMERA(camera));
+ g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_IMPLEMENTED,
+ "Ufo camera does not support recording to internal memory");
+}
+
+static void uca_ufo_camera_grab(UcaCamera *camera, gpointer *data, GError **error)
+{
+ g_return_if_fail(UCA_IS_UFO_CAMERA(camera));
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera);
+ pcilib_event_id_t event_id;
+ pcilib_event_info_t event_info;
+ size_t err;
+
+ const gsize size = SENSOR_WIDTH * SENSOR_HEIGHT * sizeof(guint16);
+
+ err = pcilib_trigger(priv->handle, PCILIB_EVENT0, 0, NULL);
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_TRIGGER);
+
+ err = pcilib_get_next_event(priv->handle, priv->timeout, &event_id, sizeof(pcilib_event_info_t), &event_info);
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_NEXT_EVENT);
+
+ if (*data == NULL)
+ *data = g_malloc0(SENSOR_WIDTH * SENSOR_HEIGHT * sizeof(guint16));
+
+ gpointer src = pcilib_get_data(priv->handle, event_id, PCILIB_EVENT_DATA, &err);
+
+ if (src == NULL)
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_NO_DATA);
+
+ /*
+ * Apparently, we checked that err equals total size in previous version.
+ * This is problematic because errno is positive and size could be equal
+ * even when an error condition is met, e.g. with a very small ROI. However,
+ * we don't know if src will always be NULL when an error occured.
+ */
+ /* assert(err == size); */
+
+ memcpy(*data, src, size);
+
+ /*
+ * Another problem here. What does this help us? At this point we have
+ * already overwritten the original buffer but can only know here if the
+ * data is corrupted.
+ */
+ err = pcilib_return_data(priv->handle, event_id, PCILIB_EVENT_DATA, data);
+ PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_MAYBE_CORRUPTED);
+}
+
+static void
+uca_ufo_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_EXPOSURE_TIME:
+ {
+ const guint frequency = priv->frequency == FPGA_40MHZ ? 40 : 48;
+ pcilib_register_value_t reg_value = (pcilib_register_value_t) 129 / frequency * 1000 * 1000 * g_value_get_double(value);
+ pcilib_write_register(priv->handle, NULL, "cmosis_exp_time", reg_value);
+ }
+ break;
+ case PROP_ROI_X:
+ case PROP_ROI_Y:
+ case PROP_ROI_WIDTH:
+ case PROP_ROI_HEIGHT:
+ g_debug("ROI feature not implemented yet");
+ break;
+
+ default:
+ {
+ RegisterInfo *reg_info = g_hash_table_lookup (ufo_property_table, GINT_TO_POINTER (property_id));
+
+ if (reg_info != NULL) {
+ pcilib_register_value_t reg_value;
+
+ reg_value = g_value_get_uint (value);
+ pcilib_write_register(priv->handle, NULL, reg_info->name, reg_value);
+ pcilib_read_register (priv->handle, NULL, reg_info->name, &reg_value);
+ reg_info->cached_value = (guint) reg_value;
+ }
+ else
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+ return;
+ }
+}
+
+
+static void
+uca_ufo_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(object);
+
+ switch (property_id) {
+ case PROP_SENSOR_WIDTH:
+ g_value_set_uint(value, SENSOR_WIDTH);
+ break;
+ case PROP_SENSOR_HEIGHT:
+ g_value_set_uint(value, SENSOR_HEIGHT);
+ break;
+ case PROP_SENSOR_BITDEPTH:
+ g_value_set_uint (value, priv->n_bits);
+ break;
+ case PROP_SENSOR_HORIZONTAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_SENSOR_VERTICAL_BINNING:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_SENSOR_MAX_FRAME_RATE:
+ g_value_set_float(value, 340.0);
+ break;
+ case PROP_SENSOR_TEMPERATURE:
+ {
+ const double a = priv->frequency == FPGA_48MHZ ? 0.3 : 0.25;
+ const double b = priv->frequency == FPGA_48MHZ ? 1000 : 1200;
+ guint32 temperature;
+
+ temperature = read_register_value (priv->handle, "sensor_temperature");
+ g_value_set_double (value, a * (temperature - b));
+ }
+ break;
+ case PROP_FPGA_TEMPERATURE:
+ {
+ const double a = 503.975 / 1024.0;
+ const double b = 273.15;
+ guint32 temperature;
+
+ temperature = read_register_value (priv->handle, "fpga_temperature");
+ g_value_set_double (value, a * temperature - b);
+ }
+ break;
+ case PROP_EXPOSURE_TIME:
+ {
+ const gdouble frequency = priv->frequency == FPGA_40MHZ ? 40.0 : 48.0;
+ g_value_set_double (value, read_register_value (priv->handle, "cmosis_exp_time") * 129 / frequency / 1000 / 1000 );
+ }
+ break;
+ case PROP_HAS_STREAMING:
+ g_value_set_boolean(value, TRUE);
+ break;
+ case PROP_HAS_CAMRAM_RECORDING:
+ g_value_set_boolean(value, FALSE);
+ break;
+ case PROP_ROI_X:
+ g_value_set_uint(value, 0);
+ break;
+ case PROP_ROI_Y:
+ g_value_set_uint(value, 0);
+ break;
+ case PROP_ROI_WIDTH:
+ g_value_set_uint(value, SENSOR_WIDTH);
+ break;
+ case PROP_ROI_HEIGHT:
+ g_value_set_uint(value, SENSOR_HEIGHT);
+ break;
+ case PROP_ROI_WIDTH_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_ROI_HEIGHT_MULTIPLIER:
+ g_value_set_uint(value, 1);
+ break;
+ case PROP_NAME:
+ g_value_set_string(value, "Ufo Camera w/ CMOSIS CMV2000");
+ break;
+ case PROP_TRIGGER_MODE:
+ break;
+ default:
+ {
+ RegisterInfo *reg_info = g_hash_table_lookup (ufo_property_table, GINT_TO_POINTER (property_id));
+
+ if (reg_info != NULL)
+ g_value_set_uint (value, reg_info->cached_value);
+ else
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+ break;
+ }
+}
+
+static void uca_ufo_camera_finalize(GObject *object)
+{
+ UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(object);
+ pcilib_close(priv->handle);
+ G_OBJECT_CLASS(uca_ufo_camera_parent_class)->finalize(object);
+}
+
+static void uca_ufo_camera_class_init(UcaUfoCameraClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->set_property = uca_ufo_camera_set_property;
+ gobject_class->get_property = uca_ufo_camera_get_property;
+ gobject_class->finalize = uca_ufo_camera_finalize;
+
+ UcaCameraClass *camera_class = UCA_CAMERA_CLASS(klass);
+ camera_class->start_recording = uca_ufo_camera_start_recording;
+ camera_class->stop_recording = uca_ufo_camera_stop_recording;
+ camera_class->start_readout = uca_ufo_camera_start_readout;
+ camera_class->grab = uca_ufo_camera_grab;
+
+ for (guint i = 0; base_overrideables[i] != 0; i++)
+ g_object_class_override_property(gobject_class, base_overrideables[i], uca_camera_props[base_overrideables[i]]);
+
+ ufo_properties[PROP_SENSOR_TEMPERATURE] =
+ g_param_spec_double("sensor-temperature",
+ "Temperature of the sensor",
+ "Temperature of the sensor in degree Celsius",
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE);
+
+ ufo_properties[PROP_FPGA_TEMPERATURE] =
+ g_param_spec_double("fpga-temperature",
+ "Temperature of the FPGA",
+ "Temperature of the FPGA in degree Celsius",
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE);
+
+ /*
+ * This automatic property installation includes the properties created
+ * dynamically in uca_ufo_camera_new().
+ */
+ for (guint id = N_BASE_PROPERTIES; id < N_PROPERTIES; id++)
+ g_object_class_install_property(gobject_class, id, ufo_properties[id]);
+
+ g_type_class_add_private(klass, sizeof(UcaUfoCameraPrivate));
+}
+
+static void uca_ufo_camera_init(UcaUfoCamera *self)
+{
+ self->priv = UCA_UFO_CAMERA_GET_PRIVATE(self);
+}
diff --git a/plugins/ufo/uca-ufo-camera.h b/plugins/ufo/uca-ufo-camera.h
new file mode 100644
index 0000000..7030389
--- /dev/null
+++ b/plugins/ufo/uca-ufo-camera.h
@@ -0,0 +1,76 @@
+/* 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_UFO_CAMERA_H
+#define __UCA_UFO_CAMERA_H
+
+#include <glib-object.h>
+#include "uca-camera.h"
+
+G_BEGIN_DECLS
+
+#define UCA_TYPE_UFO_CAMERA (uca_ufo_camera_get_type())
+#define UCA_UFO_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_UFO_CAMERA, UcaUfoCamera))
+#define UCA_IS_UFO_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_UFO_CAMERA))
+#define UCA_UFO_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UCA_TYPE_UFO_CAMERA, UcaUfoCameraClass))
+#define UCA_IS_UFO_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_UFO_CAMERA))
+#define UCA_UFO_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_UFO_CAMERA, UcaUfoCameraClass))
+
+#define UCA_UFO_CAMERA_ERROR uca_ufo_camera_error_quark()
+typedef enum {
+ UCA_UFO_CAMERA_ERROR_INIT,
+ UCA_UFO_CAMERA_ERROR_START_RECORDING,
+ UCA_UFO_CAMERA_ERROR_STOP_RECORDING,
+ UCA_UFO_CAMERA_ERROR_TRIGGER,
+ UCA_UFO_CAMERA_ERROR_NEXT_EVENT,
+ UCA_UFO_CAMERA_ERROR_NO_DATA,
+ UCA_UFO_CAMERA_ERROR_MAYBE_CORRUPTED
+} UcaUfoCameraError;
+
+typedef struct _UcaUfoCamera UcaUfoCamera;
+typedef struct _UcaUfoCameraClass UcaUfoCameraClass;
+typedef struct _UcaUfoCameraPrivate UcaUfoCameraPrivate;
+
+/**
+ * UcaUfoCamera:
+ *
+ * Creates #UcaUfoCamera instances by loading corresponding shared objects. The
+ * contents of the #UcaUfoCamera structure are private and should only be
+ * accessed via the provided API.
+ */
+struct _UcaUfoCamera {
+ /*< private >*/
+ UcaCamera parent;
+
+ UcaUfoCameraPrivate *priv;
+};
+
+/**
+ * UcaUfoCameraClass:
+ *
+ * #UcaUfoCamera class
+ */
+struct _UcaUfoCameraClass {
+ /*< private >*/
+ UcaCameraClass parent;
+};
+
+GType uca_ufo_camera_get_type(void);
+
+G_END_DECLS
+
+#endif