From bf641d06c522b86213b28640e85dc6e483a70cbd Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 31 Aug 2012 16:47:21 +0200 Subject: Extend section on new camera integration --- docs/manual.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/manual.md b/docs/manual.md index 69abae8..0373010 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -381,6 +381,31 @@ virtual methods. The simplest way is to take the `mock` camera and rename all occurences. Note, that if you class is going to be called `FooBar`, the upper case variant is `FOO_BAR` and the lower case variant is `foo_bar`. +In order to fully implement a camera, you need to override at least the +following virtual methods: + +* `start_recording`: Take suitable actions so that a subsequent call to + `grab` delivers an image or blocks until one is exposed. +* `stop_recording`: Stop recording so that subsequent calls to `grab` + fail. +* `grab`: Return an image from the camera or block until one is ready. + +## Asynchronous operation + +When the camera supports asynchronous acquisition and announces it with a true +boolean value for `"transfer-asynchronously"`, a mechanism must be setup up +during `start_recording` so that for each new frame the grab func callback is +called. + +## Cameras with internal memory + +Cameras such as the pco.dimax record into their own on-board memory rather than +streaming directly to the host PC. In this case, both `start_recording` and +`stop_recording` initiate and end acquisition to the on-board memory. To +initiate a data transfer, the host calls `start_readout` which must be suitably +implemented. The actual data transfer happens either with `grab` or +asynchronously. + [sub-classing]: http://developer.gnome.org/gobject/stable/howto-gobject.html -- cgit v1.2.3 From 539b6cebd615d71b377941e250117ebb99e49c27 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 14:20:57 +0200 Subject: Bump to development version 1.1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48592fd..ae371ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,8 @@ project(uca C) set(TARNAME "libuca") set(UCA_VERSION_MAJOR "1") -set(UCA_VERSION_MINOR "0") -set(UCA_VERSION_PATCH "0") +set(UCA_VERSION_MINOR "1") +set(UCA_VERSION_PATCH "0-dev") set(UCA_DESCRIPTION "Unified Camera Access") set(UCA_VERSION_STRING "${UCA_VERSION_MAJOR}.${UCA_VERSION_MINOR}.${UCA_VERSION_PATCH}") -- cgit v1.2.3 From 034204d3d8d1a32b1a20e50697c5f81db6fb20cf Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 31 Aug 2012 23:14:16 +0200 Subject: Initial plugin manager --- src/CMakeLists.txt | 12 ++- src/uca-camera.c | 199 ++++++++++++++++++------------------ src/uca-plugin-manager.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++ src/uca-plugin-manager.h | 65 ++++++++++++ test/CMakeLists.txt | 90 ++++++++-------- test/benchmark.c | 35 ++++--- test/test-mock.c | 9 ++ 7 files changed, 511 insertions(+), 159 deletions(-) create mode 100644 src/uca-plugin-manager.c create mode 100644 src/uca-plugin-manager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9508c5c..1b814aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8) # --- Set sources ------------------------------------------------------------- set(uca_SRCS uca-camera.c + uca-plugin-manager.c ) set(uca_HDRS @@ -10,6 +11,8 @@ set(uca_HDRS set(cameras) +set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") + # --- Find packages and libraries --------------------------------------------- set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) @@ -107,9 +110,12 @@ if (PYLON_FOUND) endif() if (HAVE_MOCK_CAMERA) - list(APPEND uca_SRCS cameras/uca-mock-camera.c) - list(APPEND uca_HDRS cameras/uca-mock-camera.h) - list(APPEND cameras "Mock") + add_library(ucamock SHARED cameras/uca-mock-camera.c) + #list(APPEND uca_SRCS cameras/uca-mock-camera.c) + ##list(APPEND uca_HDRS cameras/uca-mock-camera.h) + #list(APPEND cameras "Mock") + install(TARGETS ucamock + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) endif() # --- Generate enum file diff --git a/src/uca-camera.c b/src/uca-camera.c index 78adae3..59ab5c7 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -20,25 +20,25 @@ #include "uca-camera.h" #include "uca-enums.h" -#ifdef HAVE_PCO_CL -#include "cameras/uca-pco-camera.h" -#endif +/* #ifdef HAVE_PCO_CL */ +/* #include "cameras/uca-pco-camera.h" */ +/* #endif */ -#ifdef HAVE_PYLON_CAMERA -#include "cameras/uca-pylon-camera.h" -#endif +/* #ifdef HAVE_PYLON_CAMERA */ +/* #include "cameras/uca-pylon-camera.h" */ +/* #endif */ -#ifdef HAVE_MOCK_CAMERA -#include "cameras/uca-mock-camera.h" -#endif +/* #ifdef HAVE_MOCK_CAMERA */ +/* #include "cameras/uca-mock-camera.h" */ +/* #endif */ -#ifdef HAVE_UFO_CAMERA -#include "cameras/uca-ufo-camera.h" -#endif +/* #ifdef HAVE_UFO_CAMERA */ +/* #include "cameras/uca-ufo-camera.h" */ +/* #endif */ -#ifdef HAVE_PHOTON_FOCUS -#include "cameras/uca-pf-camera.h" -#endif +/* #ifdef HAVE_PHOTON_FOCUS */ +/* #include "cameras/uca-pf-camera.h" */ +/* #endif */ #define UCA_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_CAMERA, UcaCameraPrivate)) @@ -65,24 +65,24 @@ GQuark uca_camera_error_quark() return g_quark_from_static_string("uca-camera-error-quark"); } -static gchar *uca_camera_types[] = { -#ifdef HAVE_PCO_CL - "pco", -#endif -#ifdef HAVE_PYLON_CAMERA - "pylon", -#endif -#ifdef HAVE_MOCK_CAMERA - "mock", -#endif -#ifdef HAVE_UFO_CAMERA - "ufo", -#endif -#ifdef HAVE_PHOTON_FOCUS - "pf", -#endif - NULL -}; +/* static gchar *uca_camera_types[] = { */ +/* #ifdef HAVE_PCO_CL */ +/* "pco", */ +/* #endif */ +/* #ifdef HAVE_PYLON_CAMERA */ +/* "pylon", */ +/* #endif */ +/* #ifdef HAVE_MOCK_CAMERA */ +/* "mock", */ +/* #endif */ +/* #ifdef HAVE_UFO_CAMERA */ +/* "ufo", */ +/* #endif */ +/* #ifdef HAVE_PHOTON_FOCUS */ +/* "pf", */ +/* #endif */ +/* NULL */ +/* }; */ enum { LAST_SIGNAL @@ -126,7 +126,8 @@ struct _UcaCameraPrivate { gboolean transfer_async; }; -static void uca_camera_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +static void +uca_camera_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE(object); @@ -145,7 +146,8 @@ static void uca_camera_set_property(GObject *object, guint property_id, const GV } } -static void uca_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +static void +uca_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE(object); @@ -167,7 +169,8 @@ static void uca_camera_get_property(GObject *object, guint property_id, GValue * } } -static void uca_camera_class_init(UcaCameraClass *klass) +static void +uca_camera_class_init(UcaCameraClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); gobject_class->set_property = uca_camera_set_property; @@ -370,48 +373,48 @@ static void uca_camera_init(UcaCamera *camera) */ } -static UcaCamera *uca_camera_new_from_type(const gchar *type, GError **error) -{ -#ifdef HAVE_MOCK_CAMERA - if (!g_strcmp0(type, "mock")) - return UCA_CAMERA(uca_mock_camera_new(error)); -#endif - -#ifdef HAVE_PCO_CL - if (!g_strcmp0(type, "pco")) - return UCA_CAMERA(uca_pco_camera_new(error)); -#endif - -#ifdef HAVE_PYLON_CAMERA - if (!g_strcmp0(type, "pylon")) - return UCA_CAMERA(uca_pylon_camera_new(error)); -#endif - -#ifdef HAVE_UFO_CAMERA - if (!g_strcmp0(type, "ufo")) - return UCA_CAMERA(uca_ufo_camera_new(error)); -#endif - -#ifdef HAVE_PHOTON_FOCUS - if (!g_strcmp0(type, "pf")) - return UCA_CAMERA(uca_pf_camera_new(error)); -#endif - - return NULL; -} - -/** - * uca_camera_get_types: - * - * Enumerate all camera types that can be instantiated with uca_camera_new(). - * - * Returns: An array of strings with camera types. The list should be freed with - * g_strfreev(). - */ -gchar **uca_camera_get_types() -{ - return g_strdupv(uca_camera_types); -} +/* static UcaCamera *uca_camera_new_from_type(const gchar *type, GError **error) */ +/* { */ +/* #ifdef HAVE_MOCK_CAMERA */ +/* if (!g_strcmp0(type, "mock")) */ +/* return UCA_CAMERA(uca_mock_camera_new(error)); */ +/* #endif */ + +/* #ifdef HAVE_PCO_CL */ +/* if (!g_strcmp0(type, "pco")) */ +/* return UCA_CAMERA(uca_pco_camera_new(error)); */ +/* #endif */ + +/* #ifdef HAVE_PYLON_CAMERA */ +/* if (!g_strcmp0(type, "pylon")) */ +/* return UCA_CAMERA(uca_pylon_camera_new(error)); */ +/* #endif */ + +/* #ifdef HAVE_UFO_CAMERA */ +/* if (!g_strcmp0(type, "ufo")) */ +/* return UCA_CAMERA(uca_ufo_camera_new(error)); */ +/* #endif */ + +/* #ifdef HAVE_PHOTON_FOCUS */ +/* if (!g_strcmp0(type, "pf")) */ +/* return UCA_CAMERA(uca_pf_camera_new(error)); */ +/* #endif */ + +/* return NULL; */ +/* } */ + +/* /** */ +/* * uca_camera_get_types: */ +/* * */ +/* * Enumerate all camera types that can be instantiated with uca_camera_new(). */ +/* * */ +/* * Returns: An array of strings with camera types. The list should be freed with */ +/* * g_strfreev(). */ +/* *1/ */ +/* gchar **uca_camera_get_types() */ +/* { */ +/* return g_strdupv(uca_camera_types); */ +/* } */ /** * uca_camera_new: @@ -423,26 +426,26 @@ gchar **uca_camera_get_types() * * Returns: A new #UcaCamera of the correct type or %NULL if type was not found */ -UcaCamera *uca_camera_new(const gchar *type, GError **error) -{ - UcaCamera *camera = NULL; - GError *tmp_error = NULL; - - camera = uca_camera_new_from_type(type, &tmp_error); - - if (tmp_error != NULL) { - g_propagate_error(error, tmp_error); - return NULL; - } - - if ((tmp_error == NULL) && (camera == NULL)) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_FOUND, - "Camera type %s not found", type); - return NULL; - } - - return camera; -} +/* UcaCamera *uca_camera_new(const gchar *type, GError **error) */ +/* { */ +/* UcaCamera *camera = NULL; */ +/* GError *tmp_error = NULL; */ + +/* camera = uca_camera_new_from_type(type, &tmp_error); */ + +/* if (tmp_error != NULL) { */ +/* g_propagate_error(error, tmp_error); */ +/* return NULL; */ +/* } */ + +/* if ((tmp_error == NULL) && (camera == NULL)) { */ +/* g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_FOUND, */ +/* "Camera type %s not found", type); */ +/* return NULL; */ +/* } */ + +/* return camera; */ +/* } */ /** * uca_camera_start_recording: diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c new file mode 100644 index 0000000..7788678 --- /dev/null +++ b/src/uca-plugin-manager.c @@ -0,0 +1,260 @@ +/** + * SECTION:uca-plugin-manager + * @Short_description: Load an #UcaFilter from a shared object + * @Title: UcaPluginManager + * + * The plugin manager opens shared object modules searched for in locations + * specified with uca_plugin_manager_add_paths(). An #UcaFilter can be + * instantiated with uca_plugin_manager_get_filter() with a one-to-one mapping + * between filter name xyz and module name libfilterxyz.so. Any errors are + * reported as one of #UcaPluginManagerError codes. + */ +#include <gmodule.h> +#include "uca-plugin-manager.h" + +G_DEFINE_TYPE (UcaPluginManager, uca_plugin_manager, G_TYPE_OBJECT) + +#define UCA_PLUGIN_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_PLUGIN_MANAGER, UcaPluginManagerPrivate)) + +struct _UcaPluginManagerPrivate { + GList *search_paths; +}; + +/** + * UcaPluginManagerError: + * @UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND: The module could not be found + * @UCA_PLUGIN_MANAGER_ERROR_MODULE_OPEN: Module could not be opened + * @UCA_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND: Necessary entry symbol was not + * found + * + * Possible errors that uca_plugin_manager_get_filter() can return. + */ +GQuark +uca_plugin_manager_error_quark (void) +{ + return g_quark_from_static_string ("uca-plugin-manager-error-quark"); +} + +/** + * uca_plugin_manager_new: + * @config: (allow-none): A #UcaConfiguration object or %NULL. + * + * Create a plugin manager object to instantiate filter objects. When a config + * object is passed to the constructor, its search-path property is added to the + * internal search paths. + * + * Return value: A new plugin manager object. + */ +UcaPluginManager * +uca_plugin_manager_new () +{ + return UCA_PLUGIN_MANAGER (g_object_new (UCA_TYPE_PLUGIN_MANAGER, NULL)); +} + +void +uca_plugin_manager_add_path (UcaPluginManager *manager, + const gchar *path) +{ + g_return_if_fail (UCA_IS_PLUGIN_MANAGER (manager)); + + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + UcaPluginManagerPrivate *priv; + + priv = manager->priv; + priv->search_paths = g_list_append (priv->search_paths, + g_strdup (path)); + } +} + +static GList * +get_camera_names_from_directory (const gchar *path) +{ + static const gchar *pattern_string = "libuca([A-Za-z]+)"; + GRegex *pattern; + GDir *dir; + GList *result = NULL; + + pattern = g_regex_new (pattern_string, 0, 0, NULL); + dir = g_dir_open (path, 0, NULL); + + if (dir != NULL) { + GMatchInfo *match_info = NULL; + const gchar *name = g_dir_read_name (dir); + + while (name != NULL) { + g_regex_match (pattern, name, 0, &match_info); + + if (g_match_info_matches (match_info)) { + gchar *word = g_match_info_fetch (match_info, 1); + result = g_list_append (result, word); + } + + name = g_dir_read_name (dir); + } + } + + return result; +} + +GList * +uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) +{ + UcaPluginManagerPrivate *priv; + GList *camera_names; + + g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager), NULL); + + priv = manager->priv; + + for (GList *it = g_list_first (priv->search_paths); it != NULL; it = g_list_next (it)) { + camera_names = g_list_concat (camera_names, + get_camera_names_from_directory ((const gchar*) it->data)); + } + + return camera_names; +} + +UcaCamera * +uca_plugin_manager_new_camera (UcaPluginManager *manager, + const gchar *name, + GError **error) +{ + return NULL; +} + +/** + * uca_plugin_manager_get_filter: + * @manager: A #UcaPluginManager + * @name: Name of the plugin. + * @error: return location for a GError or %NULL + * + * Load a #UcaFilter module and return an instance. The shared object name must + * be * constructed as "libfilter@name.so". + * + * Returns: (transfer none) (allow-none): #UcaFilter or %NULL if module cannot be found + * + * Since: 0.2, the error parameter is available + */ +/* UcaFilter * */ +/* uca_plugin_manager_get_filter (UcaPluginManager *manager, const gchar *name, GError **error) */ +/* { */ +/* g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager) && (name != NULL), NULL); */ +/* UcaPluginManagerPrivate *priv = UCA_PLUGIN_MANAGER_GET_PRIVATE (manager); */ +/* UcaFilter *filter; */ +/* GetFilterFunc *func = NULL; */ +/* GModule *module = NULL; */ +/* gchar *module_name = NULL; */ +/* const gchar *entry_symbol_name = "uca_filter_plugin_new"; */ + +/* func = g_hash_table_lookup (priv->filter_funcs, name); */ + +/* if (func == NULL) { */ +/* module_name = g_strdup_printf ("libucafilter%s.so", name); */ +/* gchar *path = plugin_manager_get_path (priv, module_name); */ + +/* if (path == NULL) { */ +/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND, */ +/* "Module %s not found", module_name); */ +/* goto handle_error; */ +/* } */ + +/* module = g_module_open (path, G_MODULE_BIND_LAZY); */ +/* g_free (path); */ + +/* if (!module) { */ +/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_OPEN, */ +/* "Module %s could not be opened: %s", module_name, g_module_error ()); */ +/* goto handle_error; */ +/* } */ + +/* func = g_malloc0 (sizeof (GetFilterFunc)); */ + +/* if (!g_module_symbol (module, entry_symbol_name, (gpointer *) func)) { */ +/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND, */ +/* "%s is not exported by module %s: %s", entry_symbol_name, module_name, g_module_error ()); */ +/* g_free (func); */ + +/* if (!g_module_close (module)) */ +/* g_warning ("%s", g_module_error ()); */ + +/* goto handle_error; */ +/* } */ + +/* priv->modules = g_slist_append (priv->modules, module); */ +/* g_hash_table_insert (priv->filter_funcs, g_strdup (name), func); */ +/* g_free (module_name); */ +/* } */ + +/* filter = (*func) (); */ +/* uca_filter_set_plugin_name (filter, name); */ +/* g_message ("UcaPluginManager: Created %s-%p", name, (gpointer) filter); */ + +/* return filter; */ + +/* handle_error: */ +/* g_free (module_name); */ +/* return NULL; */ +/* } */ + +static void +uca_plugin_manager_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +uca_plugin_manager_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); + break; + } +} + +static void +uca_plugin_manager_dispose (GObject *object) +{ + G_OBJECT_CLASS (uca_plugin_manager_parent_class)->dispose (object); +} + +static void +uca_plugin_manager_finalize (GObject *object) +{ + UcaPluginManagerPrivate *priv = UCA_PLUGIN_MANAGER_GET_PRIVATE (object); + + g_list_foreach (priv->search_paths, (GFunc) g_free, NULL); + g_list_free (priv->search_paths); + + G_OBJECT_CLASS (uca_plugin_manager_parent_class)->finalize (object); +} + +static void +uca_plugin_manager_class_init (UcaPluginManagerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = uca_plugin_manager_get_property; + gobject_class->set_property = uca_plugin_manager_set_property; + gobject_class->dispose = uca_plugin_manager_dispose; + gobject_class->finalize = uca_plugin_manager_finalize; + + g_type_class_add_private (klass, sizeof (UcaPluginManagerPrivate)); +} + +static void +uca_plugin_manager_init (UcaPluginManager *manager) +{ + UcaPluginManagerPrivate *priv; + + manager->priv = priv = UCA_PLUGIN_MANAGER_GET_PRIVATE (manager); + priv->search_paths = NULL; + + uca_plugin_manager_add_path (manager, "/usr/lib/uca"); + uca_plugin_manager_add_path (manager, "/usr/lib64/uca"); + uca_plugin_manager_add_path (manager, "/usr/local/lib/uca"); + uca_plugin_manager_add_path (manager, "/usr/local/lib64/uca"); +} diff --git a/src/uca-plugin-manager.h b/src/uca-plugin-manager.h new file mode 100644 index 0000000..9291857 --- /dev/null +++ b/src/uca-plugin-manager.h @@ -0,0 +1,65 @@ +#ifndef __UCA_PLUGIN_MANAGER_H +#define __UCA_PLUGIN_MANAGER_H + +#include <glib-object.h> +#include "uca-camera.h" + +G_BEGIN_DECLS + +#define UCA_TYPE_PLUGIN_MANAGER (uca_plugin_manager_get_type()) +#define UCA_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UCA_TYPE_PLUGIN_MANAGER, UcaPluginManager)) +#define UCA_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UCA_TYPE_PLUGIN_MANAGER)) +#define UCA_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UCA_TYPE_PLUGIN_MANAGER, UcaPluginManagerClass)) +#define UCA_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_PLUGIN_MANAGER)) +#define UCA_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_PLUGIN_MANAGER, UcaPluginManagerClass)) + +#define UCA_PLUGIN_MANAGER_ERROR uca_plugin_manager_error_quark() +GQuark uca_plugin_manager_error_quark(void); + +typedef enum { + UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND, + UCA_PLUGIN_MANAGER_ERROR_MODULE_OPEN, + UCA_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND +} UcaPluginManagerError; + +typedef struct _UcaPluginManager UcaPluginManager; +typedef struct _UcaPluginManagerClass UcaPluginManagerClass; +typedef struct _UcaPluginManagerPrivate UcaPluginManagerPrivate; + +/** + * UcaPluginManager: + * + * Creates #UcaFilter instances by loading corresponding shared objects. The + * contents of the #UcaPluginManager structure are private and should only be + * accessed via the provided API. + */ +struct _UcaPluginManager { + /*< private >*/ + GObject parent_instance; + + UcaPluginManagerPrivate *priv; +}; + +/** + * UcaPluginManagerClass: + * + * #UcaPluginManager class + */ +struct _UcaPluginManagerClass { + /*< private >*/ + GObjectClass parent_class; +}; + +UcaPluginManager *uca_plugin_manager_new (void); +void uca_plugin_manager_add_path (UcaPluginManager *manager, + const gchar *path); +GList *uca_plugin_manager_get_available_cameras + (UcaPluginManager *manager); +UcaCamera *uca_plugin_manager_new_camera (UcaPluginManager *manager, + const gchar *name, + GError **error); +GType uca_plugin_manager_get_type (void); + +G_END_DECLS + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ce45d71..8fe702b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,51 +36,51 @@ if (HAVE_PYLON_CAMERA) link_directories(${PYLON_LIB_DIRS} ${LIBPYLONCAM_LIBDIR}) endif() -add_executable(grab grab.c) -add_executable(grab-async grab-async.c) +#add_executable(grab grab.c) +#add_executable(grab-async grab-async.c) add_executable(benchmark benchmark.c) target_link_libraries(benchmark uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) - -add_executable(grab_pylon grab_pylon.c) -target_link_libraries(grab_pylon uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) - -if (NOT DEFINED WITH_CONTROL_GUI) - set(WITH_CONTROL_GUI TRUE) -endif() - -if (GTK2_FOUND AND WITH_CONTROL_GUI) - include_directories(${GTK2_INCLUDE_DIRS}) - - add_executable(control - control.c - egg-property-cell-renderer.c - egg-property-tree-view.c) - - target_link_libraries(control uca - ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) - - install(TARGETS control - RUNTIME DESTINATION bin) - - install(FILES control.glade - DESTINATION share/libuca) -endif() - -if (HAVE_MOCK_CAMERA) - add_executable(test-mock test-mock.c) - - target_link_libraries(test-mock - uca - ${GLIB2_LIBRARIES} - ${GOBJECT2_LIBRARIES}) - - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl - ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) -endif() - -add_executable(test-all test-all.c) -target_link_libraries(test-all uca - ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +#target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +#target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) + +#add_executable(grab_pylon grab_pylon.c) +#target_link_libraries(grab_pylon uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +# +#if (NOT DEFINED WITH_CONTROL_GUI) +# set(WITH_CONTROL_GUI TRUE) +#endif() +# +#if (GTK2_FOUND AND WITH_CONTROL_GUI) +# include_directories(${GTK2_INCLUDE_DIRS}) +# +# add_executable(control +# control.c +# egg-property-cell-renderer.c +# egg-property-tree-view.c) +# +# target_link_libraries(control uca +# ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) +# +# install(TARGETS control +# RUNTIME DESTINATION bin) +# +# install(FILES control.glade +# DESTINATION share/libuca) +#endif() + +#if (HAVE_MOCK_CAMERA) +# add_executable(test-mock test-mock.c) +# +# target_link_libraries(test-mock +# uca +# ${GLIB2_LIBRARIES} +# ${GOBJECT2_LIBRARIES}) +# +# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl +# ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) +#endif() + +#add_executable(test-all test-all.c) +#target_link_libraries(test-all uca +# ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) diff --git a/test/benchmark.c b/test/benchmark.c index 0b4f6f8..1604cdb 100644 --- a/test/benchmark.c +++ b/test/benchmark.c @@ -20,6 +20,7 @@ #include <string.h> #include <stdlib.h> #include "uca-camera.h" +#include "uca-plugin-manager.h" typedef void (*GrabFrameFunc) (UcaCamera *camera, gpointer buffer, guint n_frames); @@ -37,20 +38,26 @@ sigint_handler(int signal) static void print_usage (void) { - gchar **types; - - g_print ("Usage: benchmark ("); - types = uca_camera_get_types (); + /* gchar **types; */ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark ["); + /* types = uca_camera_get_types (); */ + types = uca_plugin_manager_get_available_cameras (manager); + + if (g_list_length (types) == 0) { + g_print ("] -- no camera plugin found\n"); + return; + } - for (guint i = 0; types[i] != NULL; i++) { - if (types[i+1] == NULL) - g_print ("%s)", types[i]); - else - g_print ("%s | ", types[i]); + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + g_print ("`%s' ", name); } - g_print ("\n"); - g_strfreev (types); + g_print ("]\n"); } static void @@ -227,10 +234,12 @@ benchmark (UcaCamera *camera) int main (int argc, char *argv[]) { + UcaPluginManager *manager; GIOChannel *log_channel; GError *error = NULL; (void) signal (SIGINT, sigint_handler); + g_type_init(); if (argc < 2) { print_usage(); @@ -241,8 +250,8 @@ main (int argc, char *argv[]) g_assert_no_error (error); g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); - g_type_init(); - camera = uca_camera_new(argv[1], &error); + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); if (camera == NULL) { g_error ("Initialization: %s", error->message); diff --git a/test/test-mock.c b/test/test-mock.c index 7594a3a..625a3fe 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -1,6 +1,7 @@ #include <glib.h> #include "uca-camera.h" +#include "uca-plugin-manager.h" #include "cameras/uca-mock-camera.h" typedef struct { @@ -160,6 +161,14 @@ static void test_signal(Fixture *fixture, gconstpointer data) int main(int argc, char *argv[]) { g_type_init(); + + UcaPluginManager *manager = uca_plugin_manager_new (); + GList *list = uca_plugin_manager_get_available_cameras (manager); + + g_list_free (list); + + g_object_unref (manager); + g_test_init(&argc, &argv, NULL); g_test_bug_base("http://ufo.kit.edu/ufo/ticket"); -- cgit v1.2.3 From af00a17308fd17ea454021649a36f2f397a6da2b Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 15:59:57 +0200 Subject: Fix segfault --- src/uca-plugin-manager.c | 6 ++++-- test/benchmark.c | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index 7788678..bb27215 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -86,7 +86,9 @@ get_camera_names_from_directory (const gchar *path) if (g_match_info_matches (match_info)) { gchar *word = g_match_info_fetch (match_info, 1); - result = g_list_append (result, word); + + if (word != NULL) + result = g_list_append (result, word); } name = g_dir_read_name (dir); @@ -100,7 +102,7 @@ GList * uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) { UcaPluginManagerPrivate *priv; - GList *camera_names; + GList *camera_names = NULL; g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager), NULL); diff --git a/test/benchmark.c b/test/benchmark.c index 1604cdb..73b6805 100644 --- a/test/benchmark.c +++ b/test/benchmark.c @@ -38,16 +38,14 @@ sigint_handler(int signal) static void print_usage (void) { - /* gchar **types; */ GList *types; UcaPluginManager *manager; manager = uca_plugin_manager_new (); g_print ("Usage: benchmark ["); - /* types = uca_camera_get_types (); */ types = uca_plugin_manager_get_available_cameras (manager); - if (g_list_length (types) == 0) { + if (types == NULL) { g_print ("] -- no camera plugin found\n"); return; } -- cgit v1.2.3 From 90f0d4f6fa74111f38c9aedf31ecb740bc0ddf97 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 16:05:46 +0200 Subject: Add path from UCA_CAMERA_PATH environment variable --- src/uca-plugin-manager.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index bb27215..61e43f8 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -8,6 +8,9 @@ * instantiated with uca_plugin_manager_get_filter() with a one-to-one mapping * between filter name xyz and module name libfilterxyz.so. Any errors are * reported as one of #UcaPluginManagerError codes. + * + * By default, any path listed in the %UCA_CAMERA_PATH environment variable is + * added to the search path. */ #include <gmodule.h> #include "uca-plugin-manager.h" @@ -251,10 +254,16 @@ static void uca_plugin_manager_init (UcaPluginManager *manager) { UcaPluginManagerPrivate *priv; + const gchar *uca_camera_path; manager->priv = priv = UCA_PLUGIN_MANAGER_GET_PRIVATE (manager); priv->search_paths = NULL; + uca_camera_path = g_getenv ("UCA_CAMERA_PATH"); + + if (uca_camera_path != NULL) + uca_plugin_manager_add_path (manager, uca_camera_path); + uca_plugin_manager_add_path (manager, "/usr/lib/uca"); uca_plugin_manager_add_path (manager, "/usr/lib64/uca"); uca_plugin_manager_add_path (manager, "/usr/local/lib/uca"); -- cgit v1.2.3 From 6dd3229337aa1920d266fbd2c4001fb7c65f5cf1 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 18:04:32 +0200 Subject: Make most cameras plugins --- src/CMakeLists.txt | 104 ++++++++------- src/cameras/uca-mock-camera.c | 30 ++--- src/cameras/uca-mock-camera.h | 2 - src/cameras/uca-pco-camera.c | 304 +++++++++++++++++++++--------------------- src/cameras/uca-pco-camera.h | 2 - src/cameras/uca-pf-camera.c | 102 +++++++------- src/cameras/uca-pf-camera.h | 2 - src/cameras/uca-ufo-camera.c | 6 +- src/cameras/uca-ufo-camera.h | 2 - src/uca-camera.c | 113 ---------------- src/uca-plugin-manager.c | 217 +++++++++++++++++------------- test/CMakeLists.txt | 4 +- test/benchmark.c | 9 +- test/grab.c | 40 +++--- 14 files changed, 435 insertions(+), 502 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1b814aa..42f9dd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,10 +31,25 @@ find_package(PkgConfig) find_program(GLIB2_MKENUMS glib-mkenums REQUIRED) pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) +pkg_check_modules(GMODULE2 gmodule-2.0>=2.24 REQUIRED) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/cameras + ${GLIB2_INCLUDE_DIRS} + ${GOBJECT2_INCLUDE_DIRS}) + +# --- Configure step +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) set(uca_LIBS - ${GLIB2_LIBRARIES} - ${GOBJECT2_LIBRARIES}) + ${GLIB2_LIBRARIES} + ${GOBJECT2_LIBRARIES} + ${GMODULE2_LIBRARIES}) + +set(uca_enum_hdrs uca-camera.h) # --- Build options ----------------------------------------------------------- option(HAVE_MOCK_CAMERA "Camera: Dummy" ON) @@ -45,18 +60,20 @@ if (PF_FOUND) option(HAVE_PHOTON_FOCUS "Camera: Photon Focus MV2-D1280-640-CL-8" ON) if (HAVE_PHOTON_FOCUS AND CLSERME4_FOUND AND FGLIB5_FOUND) - list(APPEND uca_SRCS cameras/uca-pf-camera.c) - list(APPEND uca_HDRS cameras/uca-pf-camera.h) - list(APPEND cameras "Pf") - - set(uca_LIBS ${uca_LIBS} - ${CLSERME4_LIBRARY} - ${FGLIB5_LIBRARY} - ${PF_LIBRARIES}) + list(APPEND uca_enum_hdrs cameras/uca-pf-camera.h) - include_directories(${PF_INCLUDE_DIRS} + include_directories( + ${PF_INCLUDE_DIRS} ${CLSERME4_INCLUDE_DIR} ${FGLIB5_INCLUDE_DIR}) + + add_library(ucapf SHARED cameras/uca-pf-camera.c) + + target_link_libraries(ucapf + ${uca_LIBS} + ${CLSERME4_LIBRARY} + ${FGLIB5_LIBRARY} + ${PF_LIBRARIES}) endif() endif() @@ -64,19 +81,23 @@ if (PCO_FOUND AND CLSERME4_FOUND AND FGLIB5_FOUND) option(HAVE_PCO_CL "Camera: CameraLink-based pco" ON) if (HAVE_PCO_CL) - list(APPEND uca_SRCS cameras/uca-pco-camera.c) - list(APPEND uca_HDRS cameras/uca-pco-camera.h) - list(APPEND cameras "Pco") - - set(uca_LIBS ${uca_LIBS} - ${PCO_LIBRARIES} - ${CLSERME4_LIBRARY} - ${FGLIB5_LIBRARY}) + list(APPEND uca_enum_hdrs cameras/uca-pco-camera.h) include_directories( ${PCO_INCLUDE_DIRS} ${CLSERME4_INCLUDE_DIR} ${FGLIB5_INCLUDE_DIR}) + + add_library(ucapco SHARED cameras/uca-pco-camera.c) + + target_link_libraries(ucapco + ${uca_LIBS} + ${PCO_LIBRARIES} + ${CLSERME4_LIBRARY} + ${FGLIB5_LIBRARY}) + + install(TARGETS ucapco + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) endif() endif() @@ -84,13 +105,18 @@ if (IPE_FOUND) option(HAVE_UFO_CAMERA "Camera: Custom based on Xilinx FPGA" ON) if (HAVE_UFO_CAMERA) - list(APPEND uca_SRCS cameras/uca-ufo-camera.c) - list(APPEND uca_HDRS cameras/uca-ufo-camera.h) - list(APPEND cameras "Ufo") - - set(uca_LIBS ${uca_LIBS} ${IPE_LIBRARIES}) + list(APPEND uca_enum_hdrs cameras/uca-ufo-camera.h) include_directories(${IPE_INCLUDE_DIRS}) + + add_library(ucaufo SHARED cameras/uca-ufo-camera.c) + target_link_libraries(ucaufo + ${uca_LIBS} + ${IPE_LIBRARIES} + ) + + install(TARGETS ucaufo + LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) endif() endif() @@ -111,9 +137,6 @@ endif() if (HAVE_MOCK_CAMERA) add_library(ucamock SHARED cameras/uca-mock-camera.c) - #list(APPEND uca_SRCS cameras/uca-mock-camera.c) - ##list(APPEND uca_HDRS cameras/uca-mock-camera.h) - #list(APPEND cameras "Mock") install(TARGETS ucamock LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) endif() @@ -124,9 +147,9 @@ add_custom_command( COMMAND ${GLIB2_MKENUMS} ARGS --template uca-enums.h.template - ${uca_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h + ${uca_enum_hdrs} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${uca_HDRS} + DEPENDS ${uca_enum_hdrs} ${CMAKE_CURRENT_SOURCE_DIR}/uca-enums.h.template) add_custom_command( @@ -134,29 +157,18 @@ add_custom_command( COMMAND ${GLIB2_MKENUMS} ARGS --template uca-enums.c.template - ${uca_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.c + ${uca_enum_hdrs} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${uca_HDRS} + DEPENDS ${uca_enum_hdrs} ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h ${CMAKE_CURRENT_SOURCE_DIR}/uca-enums.c.template ) -# --- Configure step -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cameras - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT2_INCLUDE_DIRS}) - # --- Build target ------------------------------------------------------------ add_definitions("-std=c99 -Wall") -add_library(uca SHARED - ${uca_SRCS} +add_library(uca SHARED + ${uca_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.c) set_target_properties(uca PROPERTIES @@ -177,7 +189,7 @@ if(GTK_DOC_FOUND) set(docs_out "${docs_dir}/reference") file(MAKE_DIRECTORY ${docs_out}) - set(reference_files + set(reference_files "${docs_out}/index.html" "${docs_out}/api-index-full.html" "${docs_out}/ch01.html" @@ -261,7 +273,7 @@ set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") install(TARGETS uca LIBRARY DESTINATION ${LIB_INSTALL_DIR}) -install(FILES ${uca_HDRS} +install(FILES ${uca_HDRS} DESTINATION include/uca) # --- install pkg-config file diff --git a/src/cameras/uca-mock-camera.c b/src/cameras/uca-mock-camera.c index 59c5ae8..7cd4689 100644 --- a/src/cameras/uca-mock-camera.c +++ b/src/cameras/uca-mock-camera.c @@ -15,6 +15,7 @@ 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" @@ -156,20 +157,6 @@ static void print_current_frame(UcaMockCameraPrivate *priv, gchar *buffer) } } -/** - * uca_mock_camera_new: - * @error: Location for error - * - * Create a new #UcaMockCamera object. - * - * Returns: A newly created #UcaMockCamera object - */ -UcaMockCamera *uca_mock_camera_new(GError **error) -{ - UcaMockCamera *camera = g_object_new(UCA_TYPE_MOCK_CAMERA, NULL); - return camera; -} - static gpointer mock_grab_func(gpointer data) { UcaMockCamera *mock_camera = UCA_MOCK_CAMERA(data); @@ -208,7 +195,7 @@ static void uca_mock_camera_start_recording(UcaCamera *camera, GError **error) if (transfer_async) { GError *tmp_error = NULL; priv->thread_running = TRUE; - priv->grab_thread = g_thread_create(mock_grab_func, camera, TRUE, &tmp_error); + priv->grab_thread = g_thread_create(mock_grab_func, camera, TRUE, &tmp_error); if (tmp_error != NULL) { priv->thread_running = FALSE; @@ -232,7 +219,7 @@ static void uca_mock_camera_stop_recording(UcaCamera *camera, GError **error) NULL); if (transfer_async) { - priv->thread_running = FALSE; + priv->thread_running = FALSE; g_thread_join(priv->grab_thread); } } @@ -358,7 +345,7 @@ static void uca_mock_camera_finalize(GObject *object) UcaMockCameraPrivate *priv = UCA_MOCK_CAMERA_GET_PRIVATE(object); if (priv->thread_running) { - priv->thread_running = FALSE; + priv->thread_running = FALSE; g_thread_join(priv->grab_thread); } @@ -383,7 +370,7 @@ static void uca_mock_camera_class_init(UcaMockCameraClass *klass) 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] = + mock_properties[PROP_FRAMERATE] = g_param_spec_float("frame-rate", "Frame rate", "Number of frames per second that are taken", @@ -413,3 +400,10 @@ static void uca_mock_camera_init(UcaMockCamera *self) 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/src/cameras/uca-mock-camera.h b/src/cameras/uca-mock-camera.h index 92030f8..9ee9190 100644 --- a/src/cameras/uca-mock-camera.h +++ b/src/cameras/uca-mock-camera.h @@ -58,8 +58,6 @@ struct _UcaMockCameraClass { UcaCameraClass parent; }; -UcaMockCamera *uca_mock_camera_new(GError **error); - GType uca_mock_camera_get_type(void); G_END_DECLS diff --git a/src/cameras/uca-pco-camera.c b/src/cameras/uca-pco-camera.c index a56392f..8bf2936 100644 --- a/src/cameras/uca-pco-camera.c +++ b/src/cameras/uca-pco-camera.c @@ -15,6 +15,7 @@ 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> @@ -50,7 +51,7 @@ "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) @@ -186,7 +187,7 @@ struct _UcaPcoCameraPrivate { guint current_image; }; -static pco_cl_map_entry pco_cl_map[] = { +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 }, @@ -200,7 +201,7 @@ static pco_cl_map_entry *get_pco_cl_map_entry(int camera_type) while (entry->camera_type != 0) { if (entry->camera_type == camera_type) return entry; - entry++; + entry++; } return NULL; @@ -212,8 +213,8 @@ static guint fill_binnings(UcaPcoCameraPrivate *priv) uint16_t *vertical = NULL; guint num_horizontal, num_vertical; - guint err = pco_get_possible_binnings(priv->pco, - &horizontal, &num_horizontal, + guint err = pco_get_possible_binnings(priv->pco, + &horizontal, &num_horizontal, &vertical, &num_vertical); GValue val = {0}; @@ -246,7 +247,7 @@ static void fill_pixelrates(UcaPcoCameraPrivate *priv, guint32 rates[4], gint nu 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_set_uint(&val, (guint) rates[i]); g_value_array_append(priv->pixelrates, &val); } } @@ -315,93 +316,6 @@ static gdouble get_suitable_timebase(gdouble time) return TIMEBASE_INVALID; } -UcaPcoCamera *uca_pco_camera_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 camera; -} - static int fg_callback(frameindex_t frame, struct fg_apc_data *apc) { UcaCamera *camera = UCA_CAMERA(apc); @@ -506,7 +420,7 @@ static void uca_pco_camera_start_recording(UcaCamera *camera, GError **error) Fg_FreeMemEx(priv->fg, priv->fg_mem); const guint num_buffers = 2; - priv->fg_mem = Fg_AllocMemEx(priv->fg, + 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) { @@ -557,9 +471,9 @@ 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. + * edge. */ guint err = pco_get_active_segment(priv->pco, &priv->active_segment); @@ -582,7 +496,7 @@ static void uca_pco_camera_trigger(UcaCamera *camera, GError **error) if (!success) g_set_error(error, UCA_PCO_CAMERA_ERROR, UCA_PCO_CAMERA_ERROR_LIBPCO_GENERAL, - "Could not trigger frame acquisition"); + "Could not trigger frame acquisition"); } static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) @@ -611,7 +525,7 @@ static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **erro 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); @@ -620,7 +534,7 @@ static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **erro 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); + *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); @@ -635,7 +549,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons switch (property_id) { case PROP_SENSOR_EXTENDED: { - guint16 format = g_value_get_boolean (value) ? SENSORFORMAT_EXTENDED : SENSORFORMAT_STANDARD; + guint16 format = g_value_get_boolean (value) ? SENSORFORMAT_EXTENDED : SENSORFORMAT_STANDARD; pco_set_sensor_format(priv->pco, format); } break; @@ -651,7 +565,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons 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 @@ -662,7 +576,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons 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 @@ -681,7 +595,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons case PROP_EXPOSURE_TIME: { const gdouble time = g_value_get_double(value); - + if (priv->exposure_timebase == TIMEBASE_INVALID) read_timebase(priv); @@ -692,7 +606,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons guint16 suitable_timebase = get_suitable_timebase(time); if (suitable_timebase == TIMEBASE_INVALID) { - g_warning("Cannot set such a small exposure time"); + g_warning("Cannot set such a small exposure time"); } else { if (suitable_timebase != priv->exposure_timebase) { @@ -712,7 +626,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons case PROP_DELAY_TIME: { const gdouble time = g_value_get_double(value); - + if (priv->delay_timebase == TIMEBASE_INVALID) read_timebase(priv); @@ -733,7 +647,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons g_warning("Cannot set zero delay time"); } else - g_warning("Cannot set such a small exposure time"); + g_warning("Cannot set such a small exposure time"); } else { if (suitable_timebase != priv->delay_timebase) { @@ -752,7 +666,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons case PROP_SENSOR_ADCS: { - const guint num_adcs = g_value_get_uint(value); + 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"); } @@ -765,7 +679,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons 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; + pixel_rate = desired_pixel_rate; break; } } @@ -792,7 +706,7 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons case PROP_COOLING_POINT: { - int16_t temperature = (int16_t) g_value_get_int(value); + int16_t temperature = (int16_t) g_value_get_int(value); pco_set_cooling_temperature(priv->pco, temperature); } break; @@ -856,11 +770,11 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons 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 */ - }; + 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; @@ -878,25 +792,25 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal switch (property_id) { case PROP_SENSOR_EXTENDED: { - guint16 format; + guint16 format; pco_get_sensor_format(priv->pco, &format); g_value_set_boolean(value, format == SENSORFORMAT_EXTENDED); } break; - case PROP_SENSOR_WIDTH: + case PROP_SENSOR_WIDTH: g_value_set_uint(value, priv->width); break; - case PROP_SENSOR_HEIGHT: + case PROP_SENSOR_HEIGHT: g_value_set_uint(value, priv->height); break; - case PROP_SENSOR_WIDTH_EXTENDED: + 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: + case PROP_SENSOR_HEIGHT_EXTENDED: g_value_set_uint(value, priv->height_ex < priv->height ? priv->height : priv->height_ex); break; @@ -926,7 +840,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_SENSOR_TEMPERATURE: { - gint32 ccd, camera, power; + gint32 ccd, camera, power; pco_get_temperature(priv->pco, &ccd, &camera, &power); g_value_set_double(value, ccd / 10.0); } @@ -938,7 +852,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal * Up to now, the ADC mode corresponds directly to the number of * ADCs in use. */ - pco_adc_mode mode; + 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); @@ -958,7 +872,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_SENSOR_PIXELRATE: { - guint32 pixelrate; + guint32 pixelrate; pco_get_pixelrate(priv->pco, &pixelrate); g_value_set_uint(value, pixelrate); } @@ -1048,7 +962,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_TRIGGER_MODE: { - guint16 mode; + guint16 mode; pco_get_trigger_mode(priv->pco, &mode); switch (mode) { @@ -1091,7 +1005,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal g_value_set_uint(value, priv->roi_vertical_steps); break; - case PROP_NAME: + case PROP_NAME: { gchar *name = NULL; pco_get_name(priv->pco, &name); @@ -1102,7 +1016,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_COOLING_POINT: { - int16_t temperature; + 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); @@ -1140,7 +1054,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_TIMESTAMP_MODE: { - guint16 mode; + guint16 mode; pco_get_timestamp_mode(priv->pco, &mode); switch (mode) { @@ -1151,7 +1065,7 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal g_value_set_flags(value, UCA_PCO_CAMERA_TIMESTAMP_BINARY); break; case TIMESTAMP_MODE_BINARYANDASCII: - g_value_set_flags(value, + g_value_set_flags(value, UCA_PCO_CAMERA_TIMESTAMP_BINARY | UCA_PCO_CAMERA_TIMESTAMP_ASCII); break; case TIMESTAMP_MODE_ASCII: @@ -1220,20 +1134,20 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) * #UcaPcoCamera:sensor-height-extended to query the resolution of the * larger area. */ - pco_properties[PROP_SENSOR_EXTENDED] = + 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] = + 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] = + pco_properties[PROP_SENSOR_HEIGHT_EXTENDED] = g_param_spec_uint("sensor-height-extended", "Height of extended sensor", "Height of the extended sensor in pixels", @@ -1248,21 +1162,21 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) * #UcaPcoCamera:sensor-pixelrates property. Any other value will be * rejected by the camera. */ - pco_properties[PROP_SENSOR_PIXELRATE] = + 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] = + 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] = + pco_properties[PROP_NAME] = g_param_spec_string("name", "Name of the camera", "Name of the camera", @@ -1275,38 +1189,38 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READABLE); - pco_properties[PROP_HAS_DOUBLE_IMAGE_MODE] = + 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] = + 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] = + 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", + 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", + 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", @@ -1314,7 +1228,7 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE); - pco_properties[PROP_NOISE_FILTER] = + pco_properties[PROP_NOISE_FILTER] = g_param_spec_boolean("noise-filter", "Noise filter", "Noise filter", @@ -1327,42 +1241,42 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) * the camera and just don't know the cooling range. We override these * values in #uca_pco_camera_new(). */ - pco_properties[PROP_COOLING_POINT] = + 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] = + 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] = + 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] = + 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] = + + pco_properties[PROP_SENSOR_ADCS] = g_param_spec_uint("sensor-adcs", "Number of ADCs to use", "Number of ADCs to use", - 1, 2, 1, + 1, 2, 1, G_PARAM_READWRITE); - pco_properties[PROP_SENSOR_MAX_ADCS] = + 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, + 1, G_MAXUINT, 1, G_PARAM_READABLE); pco_properties[PROP_TIMESTAMP_MODE] = @@ -1394,3 +1308,91 @@ static void uca_pco_camera_init(UcaPcoCamera *self) 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/src/cameras/uca-pco-camera.h b/src/cameras/uca-pco-camera.h index fdb709a..73ae44e 100644 --- a/src/cameras/uca-pco-camera.h +++ b/src/cameras/uca-pco-camera.h @@ -84,8 +84,6 @@ struct _UcaPcoCameraClass { UcaCameraClass parent; }; -UcaPcoCamera *uca_pco_camera_new(GError **error); - GType uca_pco_camera_get_type(void); G_END_DECLS diff --git a/src/cameras/uca-pf-camera.c b/src/cameras/uca-pf-camera.c index 5bc8c6b..35b5edd 100644 --- a/src/cameras/uca-pf-camera.c +++ b/src/cameras/uca-pf-camera.c @@ -15,6 +15,7 @@ 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> @@ -99,52 +100,6 @@ struct _UcaPfCameraPrivate { dma_mem *fg_mem; }; -UcaPfCamera *uca_pf_camera_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 camera; -} - /* * We just embed our private structure here. */ @@ -226,7 +181,7 @@ static void uca_pf_camera_grab(UcaCamera *camera, gpointer *data, GError **error 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); @@ -252,10 +207,10 @@ static void uca_pf_camera_set_property(GObject *object, guint property_id, const static void uca_pf_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { - case PROP_SENSOR_WIDTH: + case PROP_SENSOR_WIDTH: g_value_set_uint(value, 1280); break; - case PROP_SENSOR_HEIGHT: + case PROP_SENSOR_HEIGHT: g_value_set_uint(value, 1024); break; case PROP_SENSOR_BITDEPTH: @@ -298,7 +253,7 @@ static void uca_pf_camera_get_property(GObject *object, guint property_id, GValu case PROP_ROI_HEIGHT_MULTIPLIER: g_value_set_uint(value, 1); break; - case PROP_NAME: + case PROP_NAME: g_value_set_string(value, "Photon Focus MV2-D1280-640-CL"); break; default: @@ -347,3 +302,50 @@ static void uca_pf_camera_init(UcaPfCamera *self) 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/src/cameras/uca-pf-camera.h b/src/cameras/uca-pf-camera.h index 7e3fe2c..3a309aa 100644 --- a/src/cameras/uca-pf-camera.h +++ b/src/cameras/uca-pf-camera.h @@ -67,8 +67,6 @@ struct _UcaPfCameraClass { UcaCameraClass parent; }; -UcaPfCamera *uca_pf_camera_new(GError **error); - GType uca_pf_camera_get_type(void); G_END_DECLS diff --git a/src/cameras/uca-ufo-camera.c b/src/cameras/uca-ufo-camera.c index 5f59f4a..7542fdf 100644 --- a/src/cameras/uca-ufo-camera.c +++ b/src/cameras/uca-ufo-camera.c @@ -15,6 +15,7 @@ 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> @@ -143,7 +144,8 @@ static int event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, return PCILIB_STREAMING_CONTINUE; } -UcaUfoCamera *uca_ufo_camera_new(GError **error) +G_MODULE_EXPORT UcaCamera * +uca_camera_impl_new (GError **error) { pcilib_model_t model = PCILIB_MODEL_DETECT; pcilib_model_description_t *model_description; @@ -223,7 +225,7 @@ UcaUfoCamera *uca_ufo_camera_new(GError **error) priv->handle = handle; - return camera; + return UCA_CAMERA (camera); } static void uca_ufo_camera_start_recording(UcaCamera *camera, GError **error) diff --git a/src/cameras/uca-ufo-camera.h b/src/cameras/uca-ufo-camera.h index 0b52ffb..7030389 100644 --- a/src/cameras/uca-ufo-camera.h +++ b/src/cameras/uca-ufo-camera.h @@ -69,8 +69,6 @@ struct _UcaUfoCameraClass { UcaCameraClass parent; }; -UcaUfoCamera *uca_ufo_camera_new(GError **error); - GType uca_ufo_camera_get_type(void); G_END_DECLS diff --git a/src/uca-camera.c b/src/uca-camera.c index 59ab5c7..e34bf62 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -20,26 +20,6 @@ #include "uca-camera.h" #include "uca-enums.h" -/* #ifdef HAVE_PCO_CL */ -/* #include "cameras/uca-pco-camera.h" */ -/* #endif */ - -/* #ifdef HAVE_PYLON_CAMERA */ -/* #include "cameras/uca-pylon-camera.h" */ -/* #endif */ - -/* #ifdef HAVE_MOCK_CAMERA */ -/* #include "cameras/uca-mock-camera.h" */ -/* #endif */ - -/* #ifdef HAVE_UFO_CAMERA */ -/* #include "cameras/uca-ufo-camera.h" */ -/* #endif */ - -/* #ifdef HAVE_PHOTON_FOCUS */ -/* #include "cameras/uca-pf-camera.h" */ -/* #endif */ - #define UCA_CAMERA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UCA_TYPE_CAMERA, UcaCameraPrivate)) G_DEFINE_TYPE(UcaCamera, uca_camera, G_TYPE_OBJECT) @@ -65,25 +45,6 @@ GQuark uca_camera_error_quark() return g_quark_from_static_string("uca-camera-error-quark"); } -/* static gchar *uca_camera_types[] = { */ -/* #ifdef HAVE_PCO_CL */ -/* "pco", */ -/* #endif */ -/* #ifdef HAVE_PYLON_CAMERA */ -/* "pylon", */ -/* #endif */ -/* #ifdef HAVE_MOCK_CAMERA */ -/* "mock", */ -/* #endif */ -/* #ifdef HAVE_UFO_CAMERA */ -/* "ufo", */ -/* #endif */ -/* #ifdef HAVE_PHOTON_FOCUS */ -/* "pf", */ -/* #endif */ -/* NULL */ -/* }; */ - enum { LAST_SIGNAL }; @@ -373,80 +334,6 @@ static void uca_camera_init(UcaCamera *camera) */ } -/* static UcaCamera *uca_camera_new_from_type(const gchar *type, GError **error) */ -/* { */ -/* #ifdef HAVE_MOCK_CAMERA */ -/* if (!g_strcmp0(type, "mock")) */ -/* return UCA_CAMERA(uca_mock_camera_new(error)); */ -/* #endif */ - -/* #ifdef HAVE_PCO_CL */ -/* if (!g_strcmp0(type, "pco")) */ -/* return UCA_CAMERA(uca_pco_camera_new(error)); */ -/* #endif */ - -/* #ifdef HAVE_PYLON_CAMERA */ -/* if (!g_strcmp0(type, "pylon")) */ -/* return UCA_CAMERA(uca_pylon_camera_new(error)); */ -/* #endif */ - -/* #ifdef HAVE_UFO_CAMERA */ -/* if (!g_strcmp0(type, "ufo")) */ -/* return UCA_CAMERA(uca_ufo_camera_new(error)); */ -/* #endif */ - -/* #ifdef HAVE_PHOTON_FOCUS */ -/* if (!g_strcmp0(type, "pf")) */ -/* return UCA_CAMERA(uca_pf_camera_new(error)); */ -/* #endif */ - -/* return NULL; */ -/* } */ - -/* /** */ -/* * uca_camera_get_types: */ -/* * */ -/* * Enumerate all camera types that can be instantiated with uca_camera_new(). */ -/* * */ -/* * Returns: An array of strings with camera types. The list should be freed with */ -/* * g_strfreev(). */ -/* *1/ */ -/* gchar **uca_camera_get_types() */ -/* { */ -/* return g_strdupv(uca_camera_types); */ -/* } */ - -/** - * uca_camera_new: - * @type: Type name of the camera - * @error: Location to store an error or %NULL - * - * Factory method for instantiating cameras by names listed in - * uca_camera_get_types(). - * - * Returns: A new #UcaCamera of the correct type or %NULL if type was not found - */ -/* UcaCamera *uca_camera_new(const gchar *type, GError **error) */ -/* { */ -/* UcaCamera *camera = NULL; */ -/* GError *tmp_error = NULL; */ - -/* camera = uca_camera_new_from_type(type, &tmp_error); */ - -/* if (tmp_error != NULL) { */ -/* g_propagate_error(error, tmp_error); */ -/* return NULL; */ -/* } */ - -/* if ((tmp_error == NULL) && (camera == NULL)) { */ -/* g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_FOUND, */ -/* "Camera type %s not found", type); */ -/* return NULL; */ -/* } */ - -/* return camera; */ -/* } */ - /** * uca_camera_start_recording: * @camera: A #UcaCamera object diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index 61e43f8..c044a4a 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -23,6 +23,10 @@ struct _UcaPluginManagerPrivate { GList *search_paths; }; +static const gchar *MODULE_PATTERN = "libuca([A-Za-z]+)"; + +typedef UcaCamera * (*GetCameraFunc) (GError **error); + /** * UcaPluginManagerError: * @UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND: The module could not be found @@ -70,30 +74,24 @@ uca_plugin_manager_add_path (UcaPluginManager *manager, } static GList * -get_camera_names_from_directory (const gchar *path) +get_camera_module_paths (const gchar *path) { - static const gchar *pattern_string = "libuca([A-Za-z]+)"; - GRegex *pattern; + GRegex *pattern; GDir *dir; GList *result = NULL; - - pattern = g_regex_new (pattern_string, 0, 0, NULL); + + pattern = g_regex_new (MODULE_PATTERN, 0, 0, NULL); dir = g_dir_open (path, 0, NULL); if (dir != NULL) { GMatchInfo *match_info = NULL; - const gchar *name = g_dir_read_name (dir); + const gchar *name = g_dir_read_name (dir); while (name != NULL) { - g_regex_match (pattern, name, 0, &match_info); - - if (g_match_info_matches (match_info)) { - gchar *word = g_match_info_fetch (match_info, 1); - - if (word != NULL) - result = g_list_append (result, word); - } + if (g_regex_match (pattern, name, 0, &match_info)) + result = g_list_append (result, g_build_filename (path, name, NULL)); + g_match_info_free (match_info); name = g_dir_read_name (dir); } } @@ -101,105 +99,138 @@ get_camera_names_from_directory (const gchar *path) return result; } +static GList * +scan_search_paths (GList *search_paths) +{ + GList *camera_paths = NULL; + + for (GList *it = g_list_first (search_paths); it != NULL; it = g_list_next (it)) { + camera_paths = g_list_concat (camera_paths, + get_camera_module_paths ((const gchar*) it->data)); + } + + return camera_paths; +} + +static void +transform_camera_module_path_to_name (gchar *path, GList **result) +{ + GRegex *pattern; + GMatchInfo *match_info; + + pattern = g_regex_new (MODULE_PATTERN, 0, 0, NULL); + g_regex_match (pattern, path, 0, &match_info); + + *result = g_list_append (*result, g_match_info_fetch (match_info, 1)); + g_match_info_free (match_info); +} + +static void +g_list_free_full (GList *list) +{ + g_list_foreach (list, (GFunc) g_free, NULL); + g_list_free (list); +} + GList * uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) { UcaPluginManagerPrivate *priv; + GList *camera_paths; GList *camera_names = NULL; g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager), NULL); priv = manager->priv; + camera_paths = scan_search_paths (priv->search_paths); - for (GList *it = g_list_first (priv->search_paths); it != NULL; it = g_list_next (it)) { - camera_names = g_list_concat (camera_names, - get_camera_names_from_directory ((const gchar*) it->data)); - } + g_list_foreach (camera_paths, (GFunc) transform_camera_module_path_to_name, &camera_names); + g_list_free_full (camera_paths); return camera_names; } +static gchar * +find_camera_module_path (GList *search_paths, const gchar *name) +{ + gchar *result = NULL; + GList *paths; + + paths = scan_search_paths (search_paths); + + for (GList *it = g_list_first (paths); it != NULL; it = g_list_next (it)) { + gchar *path = (gchar *) it->data; + gchar *basename = g_path_get_basename ((gchar *) path); + + if (g_strrstr (basename, name)) { + result = g_strdup (path); + g_free (basename); + break; + } + + g_free (basename); + } + + g_list_free_full (paths); + return result; +} + UcaCamera * uca_plugin_manager_new_camera (UcaPluginManager *manager, const gchar *name, GError **error) { - return NULL; -} + UcaPluginManagerPrivate *priv; + UcaCamera *camera; + GModule *module; + GetCameraFunc *func; + gchar *module_path; + GError *tmp_error = NULL; -/** - * uca_plugin_manager_get_filter: - * @manager: A #UcaPluginManager - * @name: Name of the plugin. - * @error: return location for a GError or %NULL - * - * Load a #UcaFilter module and return an instance. The shared object name must - * be * constructed as "libfilter@name.so". - * - * Returns: (transfer none) (allow-none): #UcaFilter or %NULL if module cannot be found - * - * Since: 0.2, the error parameter is available - */ -/* UcaFilter * */ -/* uca_plugin_manager_get_filter (UcaPluginManager *manager, const gchar *name, GError **error) */ -/* { */ -/* g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager) && (name != NULL), NULL); */ -/* UcaPluginManagerPrivate *priv = UCA_PLUGIN_MANAGER_GET_PRIVATE (manager); */ -/* UcaFilter *filter; */ -/* GetFilterFunc *func = NULL; */ -/* GModule *module = NULL; */ -/* gchar *module_name = NULL; */ -/* const gchar *entry_symbol_name = "uca_filter_plugin_new"; */ - -/* func = g_hash_table_lookup (priv->filter_funcs, name); */ - -/* if (func == NULL) { */ -/* module_name = g_strdup_printf ("libucafilter%s.so", name); */ -/* gchar *path = plugin_manager_get_path (priv, module_name); */ - -/* if (path == NULL) { */ -/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND, */ -/* "Module %s not found", module_name); */ -/* goto handle_error; */ -/* } */ - -/* module = g_module_open (path, G_MODULE_BIND_LAZY); */ -/* g_free (path); */ - -/* if (!module) { */ -/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_OPEN, */ -/* "Module %s could not be opened: %s", module_name, g_module_error ()); */ -/* goto handle_error; */ -/* } */ - -/* func = g_malloc0 (sizeof (GetFilterFunc)); */ - -/* if (!g_module_symbol (module, entry_symbol_name, (gpointer *) func)) { */ -/* g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND, */ -/* "%s is not exported by module %s: %s", entry_symbol_name, module_name, g_module_error ()); */ -/* g_free (func); */ - -/* if (!g_module_close (module)) */ -/* g_warning ("%s", g_module_error ()); */ - -/* goto handle_error; */ -/* } */ - -/* priv->modules = g_slist_append (priv->modules, module); */ -/* g_hash_table_insert (priv->filter_funcs, g_strdup (name), func); */ -/* g_free (module_name); */ -/* } */ - -/* filter = (*func) (); */ -/* uca_filter_set_plugin_name (filter, name); */ -/* g_message ("UcaPluginManager: Created %s-%p", name, (gpointer) filter); */ - -/* return filter; */ - -/* handle_error: */ -/* g_free (module_name); */ -/* return NULL; */ -/* } */ + const gchar *symbol_name = "uca_camera_impl_new"; + + g_return_val_if_fail (UCA_IS_PLUGIN_MANAGER (manager) && (name != NULL), NULL); + + priv = manager->priv; + module_path = find_camera_module_path (priv->search_paths, name); + + if (module_path == NULL) { + g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND, + "Camera module `%s' not found", name); + return NULL; + } + + module = g_module_open (module_path, G_MODULE_BIND_LAZY); + g_free (module_path); + + if (!module) { + g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_OPEN, + "Camera module `%s' could not be opened: %s", name, g_module_error ()); + return NULL; + } + + func = g_malloc0 (sizeof (GetCameraFunc)); + + if (!g_module_symbol (module, symbol_name, (gpointer *) func)) { + g_set_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_SYMBOL_NOT_FOUND, + "%s", g_module_error ()); + g_free (func); + + if (!g_module_close (module)) + g_warning ("%s", g_module_error ()); + + return NULL; + } + + camera = (*func) (&tmp_error); + + if (tmp_error != NULL) { + g_propagate_error (error, tmp_error); + return NULL; + } + + return camera; +} static void uca_plugin_manager_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8fe702b..37ea6bf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,12 +36,12 @@ if (HAVE_PYLON_CAMERA) link_directories(${PYLON_LIB_DIRS} ${LIBPYLONCAM_LIBDIR}) endif() -#add_executable(grab grab.c) +add_executable(grab grab.c) #add_executable(grab-async grab-async.c) add_executable(benchmark benchmark.c) target_link_libraries(benchmark uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -#target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) #target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) #add_executable(grab_pylon grab_pylon.c) diff --git a/test/benchmark.c b/test/benchmark.c index 73b6805..ef99fd1 100644 --- a/test/benchmark.c +++ b/test/benchmark.c @@ -42,7 +42,7 @@ print_usage (void) UcaPluginManager *manager; manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark ["); + g_print ("Usage: benchmark [ "); types = uca_plugin_manager_get_available_cameras (manager); if (types == NULL) { @@ -52,10 +52,11 @@ print_usage (void) for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { gchar *name = (gchar *) it->data; - g_print ("`%s' ", name); + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); } - - g_print ("]\n"); } static void diff --git a/test/grab.c b/test/grab.c index 41e6d88..e507d69 100644 --- a/test/grab.c +++ b/test/grab.c @@ -19,6 +19,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include "uca-plugin-manager.h" #include "uca-camera.h" static UcaCamera *camera = NULL; @@ -31,26 +32,33 @@ static void sigint_handler(int signal) exit(signal); } -static void print_usage(void) +static void +print_usage (void) { - gchar **types; - - g_print("Usage: grab ("); - types = uca_camera_get_types(); - - for (guint i = 0; types[i] != NULL; i++) { - if (types[i+1] == NULL) - g_print("%s)", types[i]); - else - g_print("%s | ", types[i]); + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; } - g_print("\n"); - g_strfreev(types); + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } } int main(int argc, char *argv[]) { + UcaPluginManager *manager; GError *error = NULL; (void) signal(SIGINT, sigint_handler); @@ -59,13 +67,15 @@ int main(int argc, char *argv[]) guint bits; gchar *name; + g_type_init(); + if (argc < 2) { print_usage(); return 1; } - g_type_init(); - camera = uca_camera_new(argv[1], &error); + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); -- cgit v1.2.3 From 7b32cb1f541a4606bfed3cdfe470d69a9ccbde5a Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 18:07:14 +0200 Subject: Install plugin manager header file --- src/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42f9dd8..e186975 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,8 @@ set(uca_SRCS ) set(uca_HDRS - uca-camera.h) + uca-camera.h + uca-plugin-manager.h) set(cameras) -- cgit v1.2.3 From 7e4637741be0cdb0fd3e53bb779df649cee59374 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 19 Sep 2012 18:25:22 +0200 Subject: Update documentation --- docs/manual.md | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/docs/manual.md b/docs/manual.md index 69abae8..584da8f 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -107,6 +107,7 @@ necessary header files: ~~~ {.c} #include <glib-object.h> +#include <uca-plugin-manager.h> #include <uca-camera.h> ~~~ @@ -116,6 +117,7 @@ Then you need to setup the type system: int main (int argc, char *argv[]) { + UcaPluginManager *manager; UcaCamera *camera; GError *error = NULL; /* this _must_ be set to NULL */ @@ -124,10 +126,12 @@ main (int argc, char *argv[]) Now you can instantiate new camera _objects_. Each camera is identified by a human-readable string, in this case we want to access any pco camera that is -supported by [libpco][]: +supported by [libpco][]. To instantiate a camera we have to create a plugin +manager first: ~~~ {.c} - camera = uca_camera_new ("pco", &error); + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, "pco", &error); ~~~ Errors are indicated with a returned value `NULL` and `error` set to a value @@ -252,38 +256,19 @@ communicate with the camera. Now we will go into more detail. We have already seen how to instantiate a camera object from a name. If you have more than one camera connected to a machine, you will most likely want the user decide which to use. To do so, you can enumerate all camera strings with -`uca_camera_get_types`: +`uca_plugin_manager_get_available_cameras`: ~~~ {.c} - gchar **types; + GList *types; - types = uca_camera_get_types (); + types = uca_camera_get_available_cameras (manager); - for (guint i = 0; types[i] != NULL; i++) - g_print ("%s\n", types[i]); + for (GList *it = g_list_first; it != NULL; it = g_list_next (it)) + g_print ("%s\n", (gchar *) it->data); - /* free the string array */ - g_strfreev (types); -~~~ - -If you _know_ which camera you want to use you can instantiate the sub-classed -camera object directly. In this case we create a pco-based camera: - -~~~ {.c} -#include <glib-object.h> -#include <uca/uca-camera-pco.h> - -int -main (int argc, char *argv[]) -{ - UcaPcoCamera *camera; - GError *error = NULL; - - g_type_init (); - camera = uca_pco_camera_new (&error); - g_object_unref (camera); - return 0; -} + /* free the strings and the list */ + g_list_foreach (types, (GFunc) g_free, NULL); + g_list_free (types); ~~~ [last section]: #first-look-at-the-api -- cgit v1.2.3 From 74885f26875f73f92b402119d28c24bd7735ff3b Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 20 Sep 2012 08:50:15 +0200 Subject: Add notice about the plugin manager --- NEWS | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/NEWS b/NEWS index 4f3c174..e7c7243 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,23 @@ +Changes in libuca 1.1 +===================== + +Plugin System +------------- + +A new plugin manager is used to instantiate camera objects from a shared +library. Instead of calling `uca_camera_new`, a plugin manager is created that +looks in pre- and user-defined directories for DSOs that match +`libuca[A-Za-z].so` and used to instantiate: + + UcaPluginManager *manager; + UcaCamera *camera; + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, "foo", &error); + +The plugin manager adds a dependency on GModule (pkg-config package +`gmodule-2.0`) that is part of GLib. + Changes in libuca 1.0 aka 0.6 ============================= -- cgit v1.2.3 From 94459e5838c8923a0820135c4915976958dde2ed Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 20 Sep 2012 18:32:08 +0200 Subject: Add docstrings --- src/uca-plugin-manager.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index c044a4a..fdfb59f 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -4,13 +4,16 @@ * @Title: UcaPluginManager * * The plugin manager opens shared object modules searched for in locations - * specified with uca_plugin_manager_add_paths(). An #UcaFilter can be - * instantiated with uca_plugin_manager_get_filter() with a one-to-one mapping - * between filter name xyz and module name libfilterxyz.so. Any errors are - * reported as one of #UcaPluginManagerError codes. + * specified with uca_plugin_manager_add_path(). A #UcaCamera can be + * instantiated with uca_plugin_manager_new_camera() with a one-to-one mapping + * between filter name xyz and module name libucaxyz.so. Any errors are reported + * as one of #UcaPluginManagerError codes. To get a list of available camera + * names call uca_plugin_manager_get_available_cameras(). * * By default, any path listed in the %UCA_CAMERA_PATH environment variable is * added to the search path. + * + * @Since: 1.1 */ #include <gmodule.h> #include "uca-plugin-manager.h" @@ -58,6 +61,13 @@ uca_plugin_manager_new () return UCA_PLUGIN_MANAGER (g_object_new (UCA_TYPE_PLUGIN_MANAGER, NULL)); } +/** + * uca_plugin_manager_add_path: + * @manager: A #UcaPluginManager + * @path: Path to look for camera modules + * + * Add a search path to the plugin manager. + */ void uca_plugin_manager_add_path (UcaPluginManager *manager, const gchar *path) @@ -132,6 +142,15 @@ g_list_free_full (GList *list) g_list_free (list); } +/** + * uca_plugin_manager_get_available_cameras: + * + * @manager: A #UcaPluginManager + * + * Return: A list with strings of available camera names. You have to free the + * individual strings with g_list_foreach(list, (GFunc) g_free, NULL) and the + * list itself with g_list_free. + */ GList * uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) { @@ -175,6 +194,12 @@ find_camera_module_path (GList *search_paths, const gchar *name) return result; } +/** + * uca_plugin_manager_new_camera: + * @manager: A #UcaPluginManager + * @name: Name of the camera module, that maps to libuca<name>.so + * @error: Location for a #GError + */ UcaCamera * uca_plugin_manager_new_camera (UcaPluginManager *manager, const gchar *name, -- cgit v1.2.3 From 6a9b9b7817d1ed3354eace900f5e63abd4c46a78 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 11:11:56 +0200 Subject: Update to a more readable style --- docs/style.css | 95 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/docs/style.css b/docs/style.css index a9fc9ca..646a097 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,35 +1,34 @@ - /* --- Reset ------------------------------------------------------ */ body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, -p, blockquote, th, td { - margin: 0; +p, blockquote, th, td { + margin: 0; padding: 0; } table { - border-collapse: collapse; + border-collapse: collapse; border-spacing: 0; } fieldset, img { - border: 0; - } - address, caption, cite, dfn, th, var { + border: 0; +} +address, caption, cite, dfn, th, var { font-style: normal; - font-weight: normal; - } - caption, th { + font-weight: normal; +} +caption, th { text-align: left; } h1, h2, h3, h4, h5, h6 { - font-size: 100%; + font-size: 100%; font-weight: normal; } q:before, q:after { - content: ''; - } - abbr, acronym { + content: ''; +} +abbr, acronym { border: 0; } @@ -52,10 +51,6 @@ p { margin-bottom: 24px; } -/* p > code { */ -/* font-size: 0.8em; */ -/* } */ - h1, h2, h3, h4, h5, h6 { margin-bottom: 24px; font-family: "Droid Sans", sans-serif; @@ -65,6 +60,9 @@ h1, h2, h3, h4, h5, h6 { h1 { font-size: 1.5em; line-height: 1em; + margin-top: 2em; + padding-bottom: 0.5em; + border-bottom: 2px dotted #bbb; } h2 { @@ -87,11 +85,29 @@ h5, h6 { line-height: 1.5em; } -h1 > a, h2 > a, h3 > a, h4 > a, h5 > a, h6 > a { - color: black; +h1 > a { + color: #555; + text-decoration: none; +} + +a { + color: #8e3557; text-decoration: none; } +a:hover { + color: #88a33e; +} + +h1:hover :after, +h2:hover :after, +h3:hover :after, +h4:hover :after, +h5:hover :after, +h6:hover :after { + content: " \2191"; +} + pre { margin-bottom: 24px; line-height: 1.2em; @@ -103,19 +119,58 @@ code { } ul, ol { + list-style-position: inside; + padding-left: 1em; + text-indent: -1em; + margin-left: 0; margin-bottom: 24px; } +li + li { + margin-top: 0.1em; +} + ul ul, ol ol { margin: 0 0 0 24px; } +table { + width: 100%; + margin-bottom: 24px; +} + +th { + color: #555; + font-family: 'Droid Sans', sans-serif; + font-weight: bold; + border-bottom: 1px dotted #bbb; +} + +td, th { + padding: 2px; +} + +dl { + margin-bottom: 24px; +} + +dt { + font-style: italic; +} + +dd { + margin-top: 12px; + padding-left: 1em; +} + .title { font-size: xx-large; + color: #555; } .author { font-size: 1.25em; font-weight: normal; + color: #555; } -- cgit v1.2.3 From 2c770ee3fe040186602aeadd62a5d256724e1105 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 11:46:46 +0200 Subject: Rename g_list_free_full to list_free_full This got really implemented with GLib 2.28, so the names clash. --- src/uca-plugin-manager.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index fdfb59f..5678e83 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -136,7 +136,7 @@ transform_camera_module_path_to_name (gchar *path, GList **result) } static void -g_list_free_full (GList *list) +list_free_full (GList *list) { g_list_foreach (list, (GFunc) g_free, NULL); g_list_free (list); @@ -164,7 +164,7 @@ uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) camera_paths = scan_search_paths (priv->search_paths); g_list_foreach (camera_paths, (GFunc) transform_camera_module_path_to_name, &camera_names); - g_list_free_full (camera_paths); + list_free_full (camera_paths); return camera_names; } @@ -190,7 +190,7 @@ find_camera_module_path (GList *search_paths, const gchar *name) g_free (basename); } - g_list_free_full (paths); + list_free_full (paths); return result; } -- cgit v1.2.3 From 10af0e5911e06d041874a3da7adafa3f21319def Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 11:47:42 +0200 Subject: Port control GUI to use the plugin manager --- test/CMakeLists.txt | 34 ++++---- test/control.c | 234 ++++++++++++++++++++++++++++------------------------ 2 files changed, 141 insertions(+), 127 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 37ea6bf..651c805 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -51,23 +51,23 @@ target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) # set(WITH_CONTROL_GUI TRUE) #endif() # -#if (GTK2_FOUND AND WITH_CONTROL_GUI) -# include_directories(${GTK2_INCLUDE_DIRS}) -# -# add_executable(control -# control.c -# egg-property-cell-renderer.c -# egg-property-tree-view.c) -# -# target_link_libraries(control uca -# ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) -# -# install(TARGETS control -# RUNTIME DESTINATION bin) -# -# install(FILES control.glade -# DESTINATION share/libuca) -#endif() +if (GTK2_FOUND) + include_directories(${GTK2_INCLUDE_DIRS}) + + add_executable(control + control.c + egg-property-cell-renderer.c + egg-property-tree-view.c) + + target_link_libraries(control uca + ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) + + install(TARGETS control + RUNTIME DESTINATION bin) + + install(FILES control.glade + DESTINATION share/libuca) +endif() #if (HAVE_MOCK_CAMERA) # add_executable(test-mock test-mock.c) diff --git a/test/control.c b/test/control.c index eaa88e3..5a7b702 100644 --- a/test/control.c +++ b/test/control.c @@ -26,6 +26,7 @@ #include "config.h" #include "uca-camera.h" +#include "uca-plugin-manager.h" #include "egg-property-tree-view.h" @@ -48,20 +49,17 @@ typedef struct { int pixel_size; } ThreadData; -typedef struct { - ThreadData *thread_data; - GtkTreeStore *tree_store; -} ValueCellData; - enum { COLUMN_NAME = 0, COLUMN_VALUE, COLUMN_EDITABLE, NUM_COLUMNS }; + +static UcaPluginManager *plugin_manager; - -static void convert_8bit_to_rgb(guchar *output, guchar *input, int width, int height) +static void +convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) { for (int i = 0, j = 0; i < width*height; i++) { output[j++] = input[i]; @@ -70,7 +68,8 @@ static void convert_8bit_to_rgb(guchar *output, guchar *input, int width, int he } } -static void convert_16bit_to_rgb(guchar *output, guchar *input, int width, int height) +static void +convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) { guint16 *in = (guint16 *) input; guint16 min = G_MAXUINT16, max = 0; @@ -96,54 +95,58 @@ static void convert_16bit_to_rgb(guchar *output, guchar *input, int width, int h } } -static void *grab_thread(void *args) +static void * +grab_thread (void *args) { ThreadData *data = (ThreadData *) args; gchar filename[FILENAME_MAX] = {0,}; gint counter = 0; while (data->running) { - uca_camera_grab(data->camera, (gpointer) &data->buffer, NULL); + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { - snprintf(filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); - FILE *fp = fopen(filename, "wb"); - fwrite(data->buffer, data->width*data->height, data->pixel_size, fp); - fclose(fp); + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + FILE *fp = fopen (filename, "wb"); + fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); + fclose (fp); } /* FIXME: We should actually check if this is really a new frame and * just do nothing if it is an already displayed one. */ if (data->pixel_size == 1) - convert_8bit_to_rgb(data->pixels, data->buffer, data->width, data->height); + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); else if (data->pixel_size == 2) { - convert_16bit_to_rgb(data->pixels, data->buffer, data->width, data->height); + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); } - gdk_threads_enter(); - gdk_flush(); - gtk_image_clear(GTK_IMAGE(data->image)); - gtk_image_set_from_pixbuf(GTK_IMAGE(data->image), data->pixbuf); - gtk_widget_queue_draw_area(data->image, 0, 0, data->width, data->height); - gdk_threads_leave(); + gdk_threads_enter (); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gdk_threads_leave (); } return NULL; } -gboolean on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) +gboolean +on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; } -void on_destroy(GtkWidget *widget, gpointer data) +void +on_destroy (GtkWidget *widget, gpointer data) { ThreadData *td = (ThreadData *) data; td->running = FALSE; - g_object_unref(td->camera); - gtk_main_quit(); + g_object_unref (td->camera); + gtk_main_quit (); } -static void on_toolbutton_run_clicked(GtkWidget *widget, gpointer args) +static void +on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; @@ -153,184 +156,195 @@ static void on_toolbutton_run_clicked(GtkWidget *widget, gpointer args) GError *error = NULL; data->running = TRUE; - uca_camera_start_recording(data->camera, &error); + uca_camera_start_recording (data->camera, &error); if (error != NULL) { - g_printerr("Failed to start recording: %s\n", error->message); + g_printerr ("Failed to start recording: %s\n", error->message); return; } - if (!g_thread_create(grab_thread, data, FALSE, &error)) { - g_printerr("Failed to create thread: %s\n", error->message); + if (!g_thread_create (grab_thread, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); return; } } -static void on_toolbutton_stop_clicked(GtkWidget *widget, gpointer args) +static void +on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; data->running = FALSE; data->store = FALSE; GError *error = NULL; - uca_camera_stop_recording(data->camera, &error); + uca_camera_stop_recording (data->camera, &error); if (error != NULL) - g_printerr("Failed to stop: %s\n", error->message); + g_printerr ("Failed to stop: %s\n", error->message); } -static void on_toolbutton_record_clicked(GtkWidget *widget, gpointer args) +static void +on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; - data->timestamp = (int) time(0); + data->timestamp = (int) time (0); data->store = TRUE; GError *error = NULL; - gtk_statusbar_push(data->statusbar, data->statusbar_context_id, "Recording..."); + gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); if (data->running != TRUE) { data->running = TRUE; - uca_camera_start_recording(data->camera, &error); + uca_camera_start_recording (data->camera, &error); - if (!g_thread_create(grab_thread, data, FALSE, &error)) - g_printerr("Failed to create thread: %s\n", error->message); + if (!g_thread_create (grab_thread, data, FALSE, &error)) + g_printerr ("Failed to create thread: %s\n", error->message); } } -static void create_main_window(GtkBuilder *builder, const gchar* camera_name) +static void +create_main_window (GtkBuilder *builder, const gchar* camera_name) { static ThreadData td; GError *error = NULL; - UcaCamera *camera = uca_camera_new(camera_name, &error); + UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); if ((camera == NULL) || (error != NULL)) { - g_error("%s\n", error->message); - gtk_main_quit(); + g_error ("%s\n", error->message); + gtk_main_quit (); } guint bits_per_sample; - g_object_get(camera, + g_object_get (camera, "roi-width", &td.width, "roi-height", &td.height, "sensor-bitdepth", &bits_per_sample, NULL); - GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); - GtkWidget *image = GTK_WIDGET(gtk_builder_get_object(builder, "image")); + GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); gtk_container_add (scrolled_property_window, property_tree_view); gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); - GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); - gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf); + GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); td.pixel_size = bits_per_sample > 8 ? 2 : 1; td.image = image; td.pixbuf = pixbuf; - td.buffer = (guchar *) g_malloc(td.pixel_size * td.width * td.height); - td.pixels = gdk_pixbuf_get_pixels(pixbuf); + td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.running = FALSE; - td.statusbar = GTK_STATUSBAR(gtk_builder_get_object(builder, "statusbar")); - td.statusbar_context_id = gtk_statusbar_get_context_id(td.statusbar, "Recording Information"); + td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); + td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); td.store = FALSE; td.camera = camera; - td.property_model = GTK_TREE_MODEL(gtk_builder_get_object(builder, "camera-properties")); - - g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), &td); - g_signal_connect(gtk_builder_get_object(builder, "toolbutton_run"), - "clicked", G_CALLBACK(on_toolbutton_run_clicked), &td); - g_signal_connect(gtk_builder_get_object(builder, "toolbutton_stop"), - "clicked", G_CALLBACK(on_toolbutton_stop_clicked), &td); - g_signal_connect(gtk_builder_get_object(builder, "toolbutton_record"), - "clicked", G_CALLBACK(on_toolbutton_record_clicked), &td); - - gtk_widget_show(image); - gtk_widget_show(window); + td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); + + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), + "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), + "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), + "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); + + gtk_widget_show (image); + gtk_widget_show (window); } -static void on_button_proceed_clicked(GtkWidget *widget, gpointer data) +static void +on_button_proceed_clicked (GtkWidget *widget, gpointer data) { - GtkBuilder *builder = GTK_BUILDER(data); - GtkWidget *choice_window = GTK_WIDGET(gtk_builder_get_object(builder, "choice-window")); - GtkTreeView *treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview-cameras")); - GtkListStore *list_store = GTK_LIST_STORE(gtk_builder_get_object(builder, "camera-types")); + GtkBuilder *builder = GTK_BUILDER (data); + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - GList *selected_rows = gtk_tree_selection_get_selected_rows(selection, NULL); + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); GtkTreeIter iter; - gtk_widget_destroy(choice_window); - gboolean valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store), &iter, selected_rows->data); + gtk_widget_destroy (choice_window); + gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), &iter, selected_rows->data); if (valid) { gchar *data; - gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter, 0, &data, -1); - create_main_window(builder, data); - g_free(data); + gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 0, &data, -1); + create_main_window (builder, data); + g_free (data); } - g_list_foreach(selected_rows, (GFunc) gtk_tree_path_free, NULL); - g_list_free(selected_rows); + g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (selected_rows); } -static void on_treeview_keypress(GtkWidget *widget, GdkEventKey *event, gpointer data) +static void +on_treeview_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event->keyval == GDK_KEY_Return) - gtk_widget_grab_focus(GTK_WIDGET(data)); + gtk_widget_grab_focus (GTK_WIDGET (data)); } -static void create_choice_window(GtkBuilder *builder) +static void +create_choice_window (GtkBuilder *builder) { - gchar **camera_types = uca_camera_get_types(); + GList *camera_types = uca_plugin_manager_get_available_cameras (plugin_manager); - GtkWidget *choice_window = GTK_WIDGET(gtk_builder_get_object(builder, "choice-window")); - GtkTreeView *treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview-cameras")); - GtkListStore *list_store = GTK_LIST_STORE(gtk_builder_get_object(builder, "camera-types")); - GtkButton *proceed_button = GTK_BUTTON(gtk_builder_get_object(builder, "button-proceed")); + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); GtkTreeIter iter; - for (guint i = 0; camera_types[i] != NULL; i++) { - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, 0, camera_types[i], -1); + for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, 0, g_strdup ((gchar *) it->data), -1); } - gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list_store), &iter); + gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); if (valid) { - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - gtk_tree_selection_unselect_all(selection); - gtk_tree_selection_select_path(selection, gtk_tree_model_get_path(GTK_TREE_MODEL(list_store), &iter)); + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter)); } - g_strfreev(camera_types); - g_signal_connect(proceed_button, "clicked", G_CALLBACK(on_button_proceed_clicked), builder); - g_signal_connect(treeview, "key-press-event", G_CALLBACK(on_treeview_keypress), proceed_button); - gtk_widget_show_all(GTK_WIDGET(choice_window)); + g_signal_connect (proceed_button, "clicked", G_CALLBACK (on_button_proceed_clicked), builder); + g_signal_connect (treeview, "key-press-event", G_CALLBACK (on_treeview_keypress), proceed_button); + gtk_widget_show_all (GTK_WIDGET (choice_window)); + + g_list_foreach (camera_types, (GFunc) g_free, NULL); + g_list_free (camera_types); } -int main(int argc, char *argv[]) +int +main (int argc, char *argv[]) { GError *error = NULL; - g_thread_init(NULL); - gdk_threads_init(); - gtk_init(&argc, &argv); + g_thread_init (NULL); + gdk_threads_init (); + gtk_init (&argc, &argv); - GtkBuilder *builder = gtk_builder_new(); + GtkBuilder *builder = gtk_builder_new (); - if (!gtk_builder_add_from_file(builder, CONTROL_GLADE_PATH, &error)) { - g_print("Error: %s\n", error->message); + if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { + g_print ("Error: %s\n", error->message); return 1; } - create_choice_window(builder); - gtk_builder_connect_signals(builder, NULL); + plugin_manager = uca_plugin_manager_new (); + create_choice_window (builder); + gtk_builder_connect_signals (builder, NULL); - gdk_threads_enter(); - gtk_main(); - gdk_threads_leave(); + gdk_threads_enter (); + gtk_main (); + gdk_threads_leave (); + g_object_unref (plugin_manager); return 0; } -- cgit v1.2.3 From ec0e31d89baf7cb6c2fb30ead081655886478609 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 11:59:06 +0200 Subject: Port the unit tests to the plugin manager --- test/CMakeLists.txt | 26 ++++---- test/test-mock.c | 182 +++++++++++++++++++++++++++------------------------- 2 files changed, 107 insertions(+), 101 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 651c805..ee5b407 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,10 +47,6 @@ target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) #add_executable(grab_pylon grab_pylon.c) #target_link_libraries(grab_pylon uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) # -#if (NOT DEFINED WITH_CONTROL_GUI) -# set(WITH_CONTROL_GUI TRUE) -#endif() -# if (GTK2_FOUND) include_directories(${GTK2_INCLUDE_DIRS}) @@ -69,17 +65,17 @@ if (GTK2_FOUND) DESTINATION share/libuca) endif() -#if (HAVE_MOCK_CAMERA) -# add_executable(test-mock test-mock.c) -# -# target_link_libraries(test-mock -# uca -# ${GLIB2_LIBRARIES} -# ${GOBJECT2_LIBRARIES}) -# -# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl -# ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) -#endif() +if (HAVE_MOCK_CAMERA) + add_executable(test-mock test-mock.c) + + target_link_libraries(test-mock + uca + ${GLIB2_LIBRARIES} + ${GOBJECT2_LIBRARIES}) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl + ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) +endif() #add_executable(test-all test-all.c) #target_link_libraries(test-all uca diff --git a/test/test-mock.c b/test/test-mock.c index 625a3fe..ca16c59 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -2,184 +2,194 @@ #include <glib.h> #include "uca-camera.h" #include "uca-plugin-manager.h" -#include "cameras/uca-mock-camera.h" typedef struct { - UcaMockCamera *camera; + UcaPluginManager *manager; + UcaCamera *camera; } Fixture; -static void fixture_setup(Fixture *fixture, gconstpointer data) +static void +fixture_setup (Fixture *fixture, gconstpointer data) { GError *error = NULL; - fixture->camera = uca_mock_camera_new(&error); - g_assert(error == NULL); - g_assert(fixture->camera); + + fixture->manager = uca_plugin_manager_new (); + uca_plugin_manager_add_path (fixture->manager, "./src"); + + fixture->camera = uca_plugin_manager_new_camera (fixture->manager, "mock", &error); + g_assert (error == NULL); + g_assert (fixture->camera); } -static void fixture_teardown(Fixture *fixture, gconstpointer data) +static void +fixture_teardown (Fixture *fixture, gconstpointer data) { - g_object_unref(fixture->camera); + g_object_unref (fixture->camera); + g_object_unref (fixture->manager); } -static void on_property_change(gpointer instance, GParamSpec *pspec, gpointer user_data) +static void +on_property_change (gpointer instance, GParamSpec *pspec, gpointer user_data) { gboolean *success = (gboolean *) user_data; *success = TRUE; } -static void test_factory() +static void +test_factory (Fixture *fixture, gconstpointer data) { GError *error = NULL; - UcaCamera *camera = uca_camera_new("fox994m3a0yxmy", &error); - g_assert_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_FOUND); - g_assert(camera == NULL); + UcaCamera *camera = uca_plugin_manager_new_camera (fixture->manager, "fox994m3a0yxmy", &error); + g_assert_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND); + g_assert (camera == NULL); } -static void test_recording(Fixture *fixture, gconstpointer data) +static void +test_recording (Fixture *fixture, gconstpointer data) { GError *error = NULL; - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); - uca_camera_stop_recording(camera, &error); - g_assert_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING); - g_error_free(error); + uca_camera_stop_recording (camera, &error); + g_assert_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING); + g_error_free (error); error = NULL; - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); + uca_camera_start_recording (camera, &error); + g_assert_no_error (error); + uca_camera_stop_recording (camera, &error); + g_assert_no_error (error); } -static void test_recording_signal(Fixture *fixture, gconstpointer data) +static void +test_recording_signal (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); gboolean success = FALSE; - g_signal_connect(G_OBJECT(camera), "notify::is-recording", + g_signal_connect (G_OBJECT (camera), "notify::is-recording", (GCallback) on_property_change, &success); - uca_camera_start_recording(camera, NULL); - g_assert(success == TRUE); + uca_camera_start_recording (camera, NULL); + g_assert (success == TRUE); success = FALSE; - uca_camera_stop_recording(camera, NULL); - g_assert(success == TRUE); + uca_camera_stop_recording (camera, NULL); + g_assert (success == TRUE); } -static void grab_func(gpointer data, gpointer user_data) +static void +grab_func (gpointer data, gpointer user_data) { guint *count = (guint *) user_data; *count += 1; } -static void test_recording_async(Fixture *fixture, gconstpointer data) +static void +test_recording_async (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); guint count = 0; - uca_camera_set_grab_func(camera, grab_func, &count); + uca_camera_set_grab_func (camera, grab_func, &count); - g_object_set(G_OBJECT(camera), + g_object_set (G_OBJECT (camera), "frame-rate", 10.0, "transfer-asynchronously", TRUE, NULL); GError *error = NULL; - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); + uca_camera_start_recording (camera, &error); + g_assert_no_error (error); /* * We sleep for an 1/8 of a second at 10 frames per second, thus we should * record 2 frames. */ - g_usleep(G_USEC_PER_SEC / 8); + g_usleep (G_USEC_PER_SEC / 8); - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); - g_assert_cmpint(count, ==, 2); + uca_camera_stop_recording (camera, &error); + g_assert_no_error (error); + g_assert_cmpint (count, ==, 2); } -static void test_recording_property(Fixture *fixture, gconstpointer data) +static void +test_recording_property (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); gboolean is_recording = FALSE; - uca_camera_start_recording(camera, NULL); - g_object_get(G_OBJECT(camera), + uca_camera_start_recording (camera, NULL); + g_object_get (G_OBJECT (camera), "is-recording", &is_recording, NULL); - g_assert(is_recording == TRUE); + g_assert (is_recording == TRUE); - uca_camera_stop_recording(camera, NULL); - g_object_get(G_OBJECT(camera), + uca_camera_stop_recording (camera, NULL); + g_object_get (G_OBJECT (camera), "is-recording", &is_recording, NULL); - g_assert(is_recording == FALSE); + g_assert (is_recording == FALSE); } -static void test_base_properties(Fixture *fixture, gconstpointer data) +static void +test_base_properties (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); guint n_properties = 0; - GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(camera), &n_properties); + GParamSpec **properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (camera), &n_properties); GValue val = {0}; for (guint i = 0; i < n_properties; i++) { - g_value_init(&val, properties[i]->value_type); - g_object_get_property(G_OBJECT(camera), properties[i]->name, &val); - g_value_unset(&val); + g_value_init (&val, properties[i]->value_type); + g_object_get_property (G_OBJECT (camera), properties[i]->name, &val); + g_value_unset (&val); } - g_free(properties); + g_free (properties); } -static void test_binnings_properties(Fixture *fixture, gconstpointer data) +static void +test_binnings_properties (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); GValueArray *array = NULL; - g_object_get(G_OBJECT(camera), + g_object_get (G_OBJECT (camera), "sensor-horizontal-binnings", &array, NULL); - GValue *value = g_value_array_get_nth(array, 0); - g_assert(value != NULL); - g_assert(g_value_get_uint(value) == 1); + GValue *value = g_value_array_get_nth (array, 0); + g_assert (value != NULL); + g_assert (g_value_get_uint (value) == 1); } -static void test_signal(Fixture *fixture, gconstpointer data) +static void +test_signal (Fixture *fixture, gconstpointer data) { - UcaCamera *camera = UCA_CAMERA(fixture->camera); + UcaCamera *camera = UCA_CAMERA (fixture->camera); gboolean success = FALSE; - g_signal_connect(camera, "notify::frame-rate", (GCallback) on_property_change, &success); - g_object_set(G_OBJECT(camera), + g_signal_connect (camera, "notify::frame-rate", (GCallback) on_property_change, &success); + g_object_set (G_OBJECT (camera), "frame-rate", 30.0, NULL); - g_assert(success == TRUE); + g_assert (success == TRUE); } -int main(int argc, char *argv[]) +int main (int argc, char *argv[]) { - g_type_init(); - - UcaPluginManager *manager = uca_plugin_manager_new (); - GList *list = uca_plugin_manager_get_available_cameras (manager); - - g_list_free (list); - - g_object_unref (manager); + g_type_init (); - g_test_init(&argc, &argv, NULL); - g_test_bug_base("http://ufo.kit.edu/ufo/ticket"); + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("http://ufo.kit.edu/ufo/ticket"); - g_test_add_func("/factory", test_factory); - g_test_add("/recording", Fixture, NULL, fixture_setup, test_recording, fixture_teardown); - g_test_add("/recording/signal", Fixture, NULL, fixture_setup, test_recording_signal, fixture_teardown); - g_test_add("/recording/asynchronous", Fixture, NULL, fixture_setup, test_recording_async, fixture_teardown); - g_test_add("/properties/base", Fixture, NULL, fixture_setup, test_base_properties, fixture_teardown); - g_test_add("/properties/recording", Fixture, NULL, fixture_setup, test_recording_property, fixture_teardown); - g_test_add("/properties/binnings", Fixture, NULL, fixture_setup, test_binnings_properties, fixture_teardown); - g_test_add("/signal", Fixture, NULL, fixture_setup, test_signal, fixture_teardown); + g_test_add ("/factory", Fixture, NULL, fixture_setup, test_factory, fixture_teardown); + g_test_add ("/recording", Fixture, NULL, fixture_setup, test_recording, fixture_teardown); + g_test_add ("/recording/signal", Fixture, NULL, fixture_setup, test_recording_signal, fixture_teardown); + g_test_add ("/recording/asynchronous", Fixture, NULL, fixture_setup, test_recording_async, fixture_teardown); + g_test_add ("/properties/base", Fixture, NULL, fixture_setup, test_base_properties, fixture_teardown); + g_test_add ("/properties/recording", Fixture, NULL, fixture_setup, test_recording_property, fixture_teardown); + g_test_add ("/properties/binnings", Fixture, NULL, fixture_setup, test_binnings_properties, fixture_teardown); + g_test_add ("/signal", Fixture, NULL, fixture_setup, test_signal, fixture_teardown); - return g_test_run(); + return g_test_run (); } -- cgit v1.2.3 From 7132f5b74e74597fea4e358381e9e102bba7c8ed Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 12:07:31 +0200 Subject: Remove obsolete test tools --- test/enum.c | 88 -------------------------------------------------- test/grab_pylon.c | 96 ------------------------------------------------------- test/run.py | 31 ------------------ 3 files changed, 215 deletions(-) delete mode 100644 test/enum.c delete mode 100644 test/grab_pylon.c delete mode 100755 test/run.py diff --git a/test/enum.c b/test/enum.c deleted file mode 100644 index 75ca596..0000000 --- a/test/enum.c +++ /dev/null @@ -1,88 +0,0 @@ -/* 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 <stdio.h> -#include "uca.h" - -int count_dots(const char *s) -{ - int res = 0; - while (*(s++) != '\0') - if (*s == '.') - res++; - return res; -} - -void print_level(int depth) -{ - for (int i = 0; i < depth; i++) - printf("| "); - printf("|-- "); -} - -int main(int argc, char *argv[]) -{ - uca *u = uca_init(NULL); - if (u == NULL) { - printf("Couldn't find a camera\n"); - return 1; - } - - /* take first camera */ - uca_camera *cam = u->cameras; - - const size_t num_bytes = 256; - char string_value[num_bytes]; - uint32_t uint32_value; - uint8_t uint8_value; - - while (cam != NULL) { - for (int i = 0; i < UCA_PROP_LAST; i++) { - uca_property *prop = uca_get_full_property(i); - print_level(count_dots(prop->name)); - printf("%s = ", prop->name); - switch (prop->type) { - case uca_string: - if (uca_cam_get_property(cam, i, string_value, num_bytes) == UCA_NO_ERROR) { - printf("%s ", string_value); - } - else - printf("n/a"); - break; - case uca_uint32t: - if (uca_cam_get_property(cam, i, &uint32_value, 0) == UCA_NO_ERROR) { - printf("%u %s", uint32_value, uca_unit_map[prop->unit]); - } - else - printf("n/a"); - break; - case uca_uint8t: - if (uca_cam_get_property(cam, i, &uint8_value, 0) == UCA_NO_ERROR) { - printf("%u %s", uint8_value, uca_unit_map[prop->unit]); - } - else - printf("n/a"); - break; - } - printf("\n"); - } - cam = cam->next; - } - - uca_destroy(u); - return 0; -} diff --git a/test/grab_pylon.c b/test/grab_pylon.c deleted file mode 100644 index 2f9b5a0..0000000 --- a/test/grab_pylon.c +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 <glib-object.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include "uca-camera.h" - -#define handle_error(errno) {if ((errno) != UCA_NO_ERROR) printf("error at <%s:%i>\n", \ - __FILE__, __LINE__);} - -static UcaCamera *camera = NULL; - -void sigint_handler(int signal) -{ - printf("Closing down libuca\n"); - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - exit(signal); -} - -int main(int argc, char *argv[]) -{ - GError *error = NULL; - (void) signal(SIGINT, sigint_handler); - - g_type_init(); - camera = uca_camera_new("pylon", &error); - - if (camera == NULL) { - g_print("Couldn't initialize camera\n"); - return 1; - } - - guint width, height, bits; - g_object_get(G_OBJECT(camera), - "sensor-width", &width, - "sensor-height", &height, - "sensor-bitdepth", &bits, - NULL); - - const int pixel_size = bits == 8 ? 1 : 2; - g_print("allocate buffer %u, %u, %d\n", width, height, pixel_size); - gpointer buffer = g_malloc0(width * height * pixel_size); - - gchar filename[FILENAME_MAX]; - - for (int i = 0; i < 2; i++) { - gint counter = 0; - g_print("Start recording\n"); - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - - while (counter < 10) { - g_print(" grab frame ... "); - uca_camera_grab(camera, &buffer, &error); - if (error != NULL) { - g_print("\nError: %s\n", error->message); - goto cleanup; - } - g_print("done\n"); - - snprintf(filename, FILENAME_MAX, "frame-%08i.raw", counter++); - FILE *fp = fopen(filename, "wb"); - fwrite(buffer, width*height, pixel_size, fp); - fclose(fp); - //g_usleep(2 * G_USEC_PER_SEC); - } - - g_print("Stop recording\n"); - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); - } - -cleanup: - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - g_free(buffer); - - return error != NULL ? 1 : 0; -} diff --git a/test/run.py b/test/run.py deleted file mode 100755 index 7982617..0000000 --- a/test/run.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python - -import Tkinter -import threading -import subprocess - -class App(object): - def __init__(self, parent): - self.parent = parent - self.canvas = Tkinter.Canvas(root, width=300, height=300) - self.canvas.pack() - self.rect = self.canvas.create_rectangle(0, 0, 300, 300, fill='yellow') - self.run_button = Tkinter.Button(parent, text='Start grabbing', command=self.run_click) - self.run_button.pack() - - def run_grab(self): - proc = subprocess.Popen(['./grab']) - proc.wait() - self.canvas.itemconfig(self.rect, fill='red') - self.run_button.config(state=Tkinter.NORMAL, text='Close', command=self.parent.destroy) - - def run_click(self): - self.canvas.itemconfig(self.rect, fill='green') - self.run_button.config(state=Tkinter.DISABLED) - thread = threading.Thread(None, self.run_grab) - thread.start() - -if __name__ == '__main__': - root = Tkinter.Tk() - app = App(root) - root.mainloop() -- cgit v1.2.3 From 9f262857d13a3e0d7ee214b33b90359c51227718 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 12:11:55 +0200 Subject: Port grab-async to new plugin manager --- test/CMakeLists.txt | 10 ++-------- test/grab-async.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ee5b407..e4e60dc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,10 +10,7 @@ pkg_check_modules(GTHREAD2 gthread-2.0) pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) -#include_directories(${CMAKE_SOURCE_DIR}/src) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.glade ${CMAKE_CURRENT_BINARY_DIR}) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run.py ${CMAKE_CURRENT_BINARY_DIR}) # --- Build targets ----------------------------------------------------------- include_directories( @@ -37,16 +34,13 @@ if (HAVE_PYLON_CAMERA) endif() add_executable(grab grab.c) -#add_executable(grab-async grab-async.c) +add_executable(grab-async grab-async.c) add_executable(benchmark benchmark.c) target_link_libraries(benchmark uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -#target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -#add_executable(grab_pylon grab_pylon.c) -#target_link_libraries(grab_pylon uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -# if (GTK2_FOUND) include_directories(${GTK2_INCLUDE_DIRS}) diff --git a/test/grab-async.c b/test/grab-async.c index e1ec114..6132829 100644 --- a/test/grab-async.c +++ b/test/grab-async.c @@ -19,6 +19,7 @@ #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include "uca-plugin-manager.h" #include "uca-camera.h" static UcaCamera *camera = NULL; @@ -29,7 +30,8 @@ typedef struct { guint counter; } CallbackData; -static void sigint_handler(int signal) +static void +sigint_handler(int signal) { printf("Closing down libuca\n"); uca_camera_stop_recording(camera, NULL); @@ -37,7 +39,8 @@ static void sigint_handler(int signal) exit(signal); } -static void grab_callback(gpointer data, gpointer user_data) +static void +grab_callback(gpointer data, gpointer user_data) { CallbackData *cbd = (CallbackData *) user_data; gchar *filename = g_strdup_printf("frame-%04i.raw", cbd->counter++); @@ -49,16 +52,49 @@ static void grab_callback(gpointer data, gpointer user_data) g_free(filename); } -int main(int argc, char *argv[]) +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +int +main(int argc, char *argv[]) { CallbackData cbd; guint sensor_width, sensor_height; gchar *name; + UcaPluginManager *manager; GError *error = NULL; (void) signal(SIGINT, sigint_handler); g_type_init(); - camera = uca_camera_new("pco", &error); + + if (argc < 2) { + print_usage(); + return 1; + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); -- cgit v1.2.3 From f2c4098e756b237aa0654f71a0f437086d5e667e Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 14:54:05 +0200 Subject: Port perf overhead tool --- test/CMakeLists.txt | 2 + test/perf-overhead.c | 122 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 42 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e4e60dc..0f46c32 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,10 +36,12 @@ endif() add_executable(grab grab.c) add_executable(grab-async grab-async.c) add_executable(benchmark benchmark.c) +add_executable(perf perf-overhead.c) target_link_libraries(benchmark uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) +target_link_libraries(perf uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) if (GTK2_FOUND) include_directories(${GTK2_INCLUDE_DIRS}) diff --git a/test/perf-overhead.c b/test/perf-overhead.c index 20ca6c3..f8bdcbd 100644 --- a/test/perf-overhead.c +++ b/test/perf-overhead.c @@ -20,6 +20,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "uca-plugin-manager.h" #include "uca-camera.h" #define handle_error(errno) {if ((errno) != UCA_NO_ERROR) printf("error at <%s:%i>\n", \ @@ -33,19 +34,45 @@ typedef struct { static UcaCamera *camera = NULL; -static void sigint_handler(int signal) +static void +sigint_handler (int signal) { - printf("Closing down libuca\n"); - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - exit(signal); + printf ("Closing down libuca\n"); + uca_camera_stop_recording (camera, NULL); + g_object_unref (camera); + exit (signal); } -static void test_synchronous_operation(UcaCamera *camera) +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static void +test_synchronous_operation (UcaCamera *camera) { GError *error = NULL; guint width, height, bits; - g_object_get(G_OBJECT(camera), + g_object_get (G_OBJECT (camera), "sensor-width", &width, "sensor-height", &height, "sensor-bitdepth", &bits, @@ -56,41 +83,43 @@ static void test_synchronous_operation(UcaCamera *camera) const guint n_trials = 10000; gpointer buffer = g_malloc0(size); - uca_camera_start_recording(camera, &error); - GTimer *timer = g_timer_new(); + uca_camera_start_recording (camera, &error); + GTimer *timer = g_timer_new (); for (guint n = 0; n < n_trials; n++) - uca_camera_grab(camera, &buffer, &error); + uca_camera_grab (camera, &buffer, &error); - gdouble total_time = g_timer_elapsed(timer, NULL); - g_timer_stop(timer); + gdouble total_time = g_timer_elapsed (timer, NULL); + g_timer_stop (timer); - g_print("Synchronous data transfer\n"); - g_print(" Bandwidth: %3.2f MB/s\n", size * n_trials / 1024. / 1024. / total_time); - g_print(" Throughput: %3.2f frames/s\n", n_trials / total_time); + g_print ("Synchronous data transfer\n"); + g_print (" Bandwidth: %3.2f MB/s\n", size * n_trials / 1024. / 1024. / total_time); + g_print (" Throughput: %3.2f frames/s\n", n_trials / total_time); - uca_camera_stop_recording(camera, &error); - g_free(buffer); - g_timer_destroy(timer); + uca_camera_stop_recording (camera, &error); + g_free (buffer); + g_timer_destroy (timer); } -static void grab_func(gpointer data, gpointer user_data) +static void +grab_func (gpointer data, gpointer user_data) { static GStaticMutex mutex = G_STATIC_MUTEX_INIT; thread_data *d = (thread_data *) user_data; - g_memmove(d->destination, data, d->size); - g_static_mutex_lock(&mutex); + g_memmove (d->destination, data, d->size); + g_static_mutex_lock (&mutex); d->counter++; - g_static_mutex_unlock(&mutex); + g_static_mutex_unlock (&mutex); } -static void test_asynchronous_operation(UcaCamera *camera) +static void +test_asynchronous_operation (UcaCamera *camera) { GError *error = NULL; guint width, height, bits; - g_object_get(G_OBJECT(camera), + g_object_get (G_OBJECT (camera), "sensor-width", &width, "sensor-height", &height, "sensor-bitdepth", &bits, @@ -104,40 +133,49 @@ static void test_asynchronous_operation(UcaCamera *camera) .destination = g_malloc0(width * height * pixel_size) }; - g_object_set(G_OBJECT(camera), + g_object_set (G_OBJECT (camera), "transfer-asynchronously", TRUE, NULL); - uca_camera_set_grab_func(camera, &grab_func, &d); - uca_camera_start_recording(camera, &error); - g_usleep(G_USEC_PER_SEC); - uca_camera_stop_recording(camera, &error); + uca_camera_set_grab_func (camera, &grab_func, &d); + uca_camera_start_recording (camera, &error); + g_usleep (G_USEC_PER_SEC); + uca_camera_stop_recording (camera, &error); - g_print("Asynchronous data transfer\n"); - g_print(" Bandwidth: %3.2f MB/s\n", d.size * d.counter / 1024. / 1024.); - g_print(" Throughput: %i frames/s\n", d.counter); + g_print ("Asynchronous data transfer\n"); + g_print (" Bandwidth: %3.2f MB/s\n", d.size * d.counter / 1024. / 1024.); + g_print (" Throughput: %i frames/s\n", d.counter); - g_free(d.destination); + g_free (d.destination); } -int main(int argc, char *argv[]) +int +main (int argc, char *argv[]) { + UcaPluginManager *manager; GError *error = NULL; - (void) signal(SIGINT, sigint_handler); + (void) signal (SIGINT, sigint_handler); + + g_type_init (); + if (argc < 2) { + print_usage (); + return 1; + } - g_type_init(); - camera = uca_camera_new("mock", &error); + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); if (camera == NULL) { - g_print("Couldn't initialize camera\n"); + g_print ("Error during initialization: %s\n", error->message); return 1; } - test_synchronous_operation(camera); - g_print("\n"); - test_asynchronous_operation(camera); + test_synchronous_operation (camera); + g_print ("\n"); + test_asynchronous_operation (camera); - g_object_unref(camera); + g_object_unref (camera); + g_object_unref (manager); return error != NULL ? 1 : 0; } -- cgit v1.2.3 From e5ff011119ac42e48f3f3521b789a18bdfdfb51e Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 21 Sep 2012 19:24:36 +0200 Subject: Add documentation generator and mock docs --- CMakeLists.txt | 1 + docs/manual.md | 6 ++ docs/mock.html | 70 ++++++++++++++++++++++++ docs/style.css | 4 ++ tools/CMakeLists.txt | 24 ++++++++ tools/gen-doc.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 256 insertions(+) create mode 100644 docs/mock.html create mode 100644 tools/CMakeLists.txt create mode 100644 tools/gen-doc.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ae371ff..bc65dc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,3 +29,4 @@ SET(UCA_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(src) add_subdirectory(test) +add_subdirectory(tools) diff --git a/docs/manual.md b/docs/manual.md index 5600d3f..cff6f18 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -245,6 +245,12 @@ The following cameras are supported: * Pylon * UFO Camera developed at KIT/IPE. +## Property documentation + +* [mock][mock-doc] + +[mock-doc]: mock.html + # More API diff --git a/docs/mock.html b/docs/mock.html new file mode 100644 index 0000000..0d38fc8 --- /dev/null +++ b/docs/mock.html @@ -0,0 +1,70 @@ +<html><head><link rel="stylesheet" href="style.css" type="text/css" /><link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Serif:400,400italic|Inconsolata' rel='stylesheet' type='text/css'><title>mock — properties</title></head><body><div id="header"><h1 class="title">Property documentation of mock</h1><h2>Properties</h2><ul id="toc"><li><code><a href=#name>"name"</a></code></li><li><code><a href=#sensor-width>"sensor-width"</a></code></li><li><code><a href=#sensor-height>"sensor-height"</a></code></li><li><code><a href=#sensor-bitdepth>"sensor-bitdepth"</a></code></li><li><code><a href=#sensor-horizontal-binning>"sensor-horizontal-binning"</a></code></li><li><code><a href=#sensor-horizontal-binnings>"sensor-horizontal-binnings"</a></code></li><li><code><a href=#sensor-vertical-binning>"sensor-vertical-binning"</a></code></li><li><code><a href=#sensor-vertical-binnings>"sensor-vertical-binnings"</a></code></li><li><code><a href=#sensor-max-frame-rate>"sensor-max-frame-rate"</a></code></li><li><code><a href=#trigger-mode>"trigger-mode"</a></code></li><li><code><a href=#exposure-time>"exposure-time"</a></code></li><li><code><a href=#roi-x0>"roi-x0"</a></code></li><li><code><a href=#roi-y0>"roi-y0"</a></code></li><li><code><a href=#roi-width>"roi-width"</a></code></li><li><code><a href=#roi-height>"roi-height"</a></code></li><li><code><a href=#roi-width-multiplier>"roi-width-multiplier"</a></code></li><li><code><a href=#roi-height-multiplier>"roi-height-multiplier"</a></code></li><li><code><a href=#has-streaming>"has-streaming"</a></code></li><li><code><a href=#has-camram-recording>"has-camram-recording"</a></code></li><li><code><a href=#transfer-asynchronously>"transfer-asynchronously"</a></code></li><li><code><a href=#is-recording>"is-recording"</a></code></li><li><code><a href=#is-readout>"is-readout"</a></code></li><li><code><a href=#frame-rate>"frame-rate"</a></code></li></ul><h2>Details</h2><dl><dt id="name"><a href="#toc">name</a></dt> +<dd><pre><code class="prop-type">"name" : gchararray : Read-only</code></pre> +<p>Name of the camera</p> +</dd><dt id="sensor-width"><a href="#toc">sensor-width</a></dt> +<dd><pre><code class="prop-type">"sensor-width" : guint : Read-only</code></pre> +<p>Width of the sensor in pixels</p> +</dd><dt id="sensor-height"><a href="#toc">sensor-height</a></dt> +<dd><pre><code class="prop-type">"sensor-height" : guint : Read-only</code></pre> +<p>Height of the sensor in pixels</p> +</dd><dt id="sensor-bitdepth"><a href="#toc">sensor-bitdepth</a></dt> +<dd><pre><code class="prop-type">"sensor-bitdepth" : guint : Read-only</code></pre> +<p>Number of bits per pixel</p> +</dd><dt id="sensor-horizontal-binning"><a href="#toc">sensor-horizontal-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in horizontal direction</p> +</dd><dt id="sensor-horizontal-binnings"><a href="#toc">sensor-horizontal-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in horizontal direction</p> +</dd><dt id="sensor-vertical-binning"><a href="#toc">sensor-vertical-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in vertical direction</p> +</dd><dt id="sensor-vertical-binnings"><a href="#toc">sensor-vertical-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in vertical direction</p> +</dd><dt id="sensor-max-frame-rate"><a href="#toc">sensor-max-frame-rate</a></dt> +<dd><pre><code class="prop-type">"sensor-max-frame-rate" : gfloat : Read-only</code></pre> +<p>Maximum frame rate at full frame resolution</p> +</dd><dt id="trigger-mode"><a href="#toc">trigger-mode</a></dt> +<dd><pre><code class="prop-type">"trigger-mode" : UcaCameraTrigger : Read / Write</code></pre> +<p>Trigger mode</p> +</dd><dt id="exposure-time"><a href="#toc">exposure-time</a></dt> +<dd><pre><code class="prop-type">"exposure-time" : gdouble : Read / Write</code></pre> +<p>Exposure time in seconds</p> +</dd><dt id="roi-x0"><a href="#toc">roi-x0</a></dt> +<dd><pre><code class="prop-type">"roi-x0" : guint : Read / Write</code></pre> +<p>Horizontal coordinate</p> +</dd><dt id="roi-y0"><a href="#toc">roi-y0</a></dt> +<dd><pre><code class="prop-type">"roi-y0" : guint : Read / Write</code></pre> +<p>Vertical coordinate</p> +</dd><dt id="roi-width"><a href="#toc">roi-width</a></dt> +<dd><pre><code class="prop-type">"roi-width" : guint : Read / Write</code></pre> +<p>Width of the region of interest</p> +</dd><dt id="roi-height"><a href="#toc">roi-height</a></dt> +<dd><pre><code class="prop-type">"roi-height" : guint : Read / Write</code></pre> +<p>Height of the region of interest</p> +</dd><dt id="roi-width-multiplier"><a href="#toc">roi-width-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-width-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of horizontal ROI</p> +</dd><dt id="roi-height-multiplier"><a href="#toc">roi-height-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-height-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of vertical ROI</p> +</dd><dt id="has-streaming"><a href="#toc">has-streaming</a></dt> +<dd><pre><code class="prop-type">"has-streaming" : gboolean : Read-only</code></pre> +<p>Is the camera able to stream the data</p> +</dd><dt id="has-camram-recording"><a href="#toc">has-camram-recording</a></dt> +<dd><pre><code class="prop-type">"has-camram-recording" : gboolean : Read-only</code></pre> +<p>Is the camera able to record the data in-camera</p> +</dd><dt id="transfer-asynchronously"><a href="#toc">transfer-asynchronously</a></dt> +<dd><pre><code class="prop-type">"transfer-asynchronously" : gboolean : Read / Write</code></pre> +<p>Specify whether data should be transfered asynchronously using a specified callback</p> +</dd><dt id="is-recording"><a href="#toc">is-recording</a></dt> +<dd><pre><code class="prop-type">"is-recording" : gboolean : Read-only</code></pre> +<p>Is the camera currently recording</p> +</dd><dt id="is-readout"><a href="#toc">is-readout</a></dt> +<dd><pre><code class="prop-type">"is-readout" : gboolean : Read-only</code></pre> +<p>Is camera in readout mode</p> +</dd><dt id="frame-rate"><a href="#toc">frame-rate</a></dt> +<dd><pre><code class="prop-type">"frame-rate" : gfloat : Read / Write</code></pre> +<p>Number of frames per second that are taken</p> +</dd></dl></body></html> diff --git a/docs/style.css b/docs/style.css index 646a097..beccf45 100644 --- a/docs/style.css +++ b/docs/style.css @@ -126,6 +126,10 @@ ul, ol { margin-bottom: 24px; } +ul#toc { + list-style-type: none; +} + li + li { margin-top: 0.1em; } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..957fdbf --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions("--std=c99 -Wall") + +# --- Find packages and libraries --------------------------------------------- +find_package(PkgConfig) + +pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) +pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) + +# --- Build targets ----------------------------------------------------------- +include_directories( + ${GLIB2_INCLUDE_DIRS} + ${GOBJECT2_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR}/../src/ + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ) + +add_executable(gen-doc gen-doc.c) + +target_link_libraries(gen-doc uca + ${GLIB2_LIBRARIES} + ${GOBJECT2_LIBRARIES} + ) diff --git a/tools/gen-doc.c b/tools/gen-doc.c new file mode 100644 index 0000000..d9b6b41 --- /dev/null +++ b/tools/gen-doc.c @@ -0,0 +1,151 @@ +/* Copyright (C) 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 <glib-object.h> +#include "uca-plugin-manager.h" +#include "uca-camera.h" + + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: gen-doc [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static const gchar * +get_flags_description (GParamSpec *pspec) +{ + static const gchar *descriptions[] = { + "", + "Read-only", + "Write-only", + "Read / Write", + "" + }; + + if (pspec->flags >= 3) + return descriptions[3]; + + return descriptions[pspec->flags]; +} + +static void +print_property_toc (GParamSpec **pspecs, guint n_props) +{ + g_print ("<h2>Properties</h2><ul id=\"toc\">"); + + for (guint i = 0; i < n_props; i++) { + GParamSpec *pspec = pspecs[i]; + const gchar *name = g_param_spec_get_name (pspec); + + g_print ("<li><code><a href=#%s>\"%s\"</a></code></li>", name, name); + } + + g_print ("</ul>"); +} + +static void +print_property_descriptions (GParamSpec **pspecs, guint n_props) +{ + g_print ("<h2>Details</h2><dl>"); + + for (guint i = 0; i < n_props; i++) { + GParamSpec *pspec = pspecs[i]; + const gchar *name = g_param_spec_get_name (pspec); + + g_print ("<dt id=\"%s\"><a href=\"#toc\">%s</a></dt>\n", name, name); + g_print ("<dd>"); + g_print ("<pre><code class=\"prop-type\">\"%s\" : %s : %s</code></pre>\n", + name, + g_type_name (pspec->value_type), + get_flags_description (pspec)); + g_print ("<p>%s</p>\n", g_param_spec_get_blurb (pspec)); + g_print ("</dd>"); + } + + g_print ("</dl>"); +} + +static void +print_properties (UcaCamera *camera) +{ + GObjectClass *oclass; + GParamSpec **pspecs; + guint n_props; + + oclass = G_OBJECT_GET_CLASS (camera); + pspecs = g_object_class_list_properties (oclass, &n_props); + + print_property_toc (pspecs, n_props); + print_property_descriptions (pspecs, n_props); + + g_free (pspecs); +} + +static const gchar *html_header = "<html><head>\ +<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\" />\ +<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Serif:400,400italic|Inconsolata' rel='stylesheet' type='text/css'>\ +<title>%s — properties</title></head><body>"; +static const gchar *html_footer = "</body></html>"; + +int main(int argc, char *argv[]) +{ + UcaPluginManager *manager; + UcaCamera *camera; + GError *error = NULL; + + g_type_init(); + + if (argc < 2) { + print_usage(); + return 1; + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + + if (camera == NULL) { + g_print("Error during initialization: %s\n", error->message); + return 1; + } + + g_print (html_header, argv[1]); + g_print ("<div id=\"header\"><h1 class=\"title\">Property documentation of %s</h1>", argv[1]); + print_properties (camera); + g_print ("%s\n", html_footer); + + g_object_unref (camera); + g_object_unref (manager); +} -- cgit v1.2.3 From 468641280f9bd6771b5a565b526f40f7fb8e8fad Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 25 Sep 2012 10:58:43 +0200 Subject: Fix #139: Lock API functions --- src/uca-camera.c | 184 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 73 deletions(-) diff --git a/src/uca-camera.c b/src/uca-camera.c index e34bf62..f973355 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -303,7 +303,8 @@ uca_camera_class_init(UcaCameraClass *klass) g_type_class_add_private(klass, sizeof(UcaCameraPrivate)); } -static void uca_camera_init(UcaCamera *camera) +static void +uca_camera_init(UcaCamera *camera) { camera->grab_func = NULL; @@ -343,38 +344,47 @@ static void uca_camera_init(UcaCamera *camera) * #UcaCameraGrabFunc callback is set, frames are automatically transfered to * the client program, otherwise you must use uca_camera_grab(). */ -void uca_camera_start_recording(UcaCamera *camera, GError **error) +void +uca_camera_start_recording (UcaCamera *camera, GError **error) { - g_return_if_fail(UCA_IS_CAMERA(camera)); + UcaCameraClass *klass; + GError *tmp_error = NULL; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (UCA_IS_CAMERA (camera)); - UcaCameraClass *klass = UCA_CAMERA_GET_CLASS(camera); + klass = UCA_CAMERA_GET_CLASS (camera); - g_return_if_fail(klass != NULL); - g_return_if_fail(klass->start_recording != NULL); + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->start_recording != NULL); + + g_static_mutex_lock (&mutex); if (camera->priv->is_recording) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, "Camera is already recording"); - return; + goto start_recording_unlock; } if (camera->priv->transfer_async && (camera->grab_func == NULL)) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NO_GRAB_FUNC, + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NO_GRAB_FUNC, "No grab callback function set"); - return; + goto start_recording_unlock; } - GError *tmp_error = NULL; (*klass->start_recording)(camera, &tmp_error); if (tmp_error == NULL) { camera->priv->is_readout = FALSE; camera->priv->is_recording = TRUE; /* TODO: we should depend on GLib 2.26 and use g_object_notify_by_pspec */ - g_object_notify(G_OBJECT(camera), "is-recording"); + g_object_notify (G_OBJECT (camera), "is-recording"); } else - g_propagate_error(error, tmp_error); + g_propagate_error (error, tmp_error); + +start_recording_unlock: + g_static_mutex_unlock (&mutex); } /** @@ -384,32 +394,41 @@ void uca_camera_start_recording(UcaCamera *camera, GError **error) * * Stop recording. */ -void uca_camera_stop_recording(UcaCamera *camera, GError **error) +void +uca_camera_stop_recording (UcaCamera *camera, GError **error) { - g_return_if_fail(UCA_IS_CAMERA(camera)); + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - UcaCameraClass *klass = UCA_CAMERA_GET_CLASS(camera); + g_return_if_fail (UCA_IS_CAMERA (camera)); - g_return_if_fail(klass != NULL); - g_return_if_fail(klass->stop_recording != NULL); + klass = UCA_CAMERA_GET_CLASS (camera); - if (!camera->priv->is_recording) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, - "Camera is not recording"); - return; - } + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->stop_recording != NULL); - GError *tmp_error = NULL; - (*klass->stop_recording)(camera, &tmp_error); + g_static_mutex_lock (&mutex); - if (tmp_error == NULL) { - camera->priv->is_readout = FALSE; - camera->priv->is_recording = FALSE; - /* TODO: we should depend on GLib 2.26 and use g_object_notify_by_pspec */ - g_object_notify(G_OBJECT(camera), "is-recording"); + if (!camera->priv->is_recording) { + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, + "Camera is not recording"); } - else - g_propagate_error(error, tmp_error); + else { + GError *tmp_error = NULL; + + (*klass->stop_recording)(camera, &tmp_error); + + if (tmp_error == NULL) { + camera->priv->is_readout = FALSE; + camera->priv->is_recording = FALSE; + /* TODO: we should depend on GLib 2.26 and use g_object_notify_by_pspec */ + g_object_notify (G_OBJECT (camera), "is-recording"); + } + else + g_propagate_error (error, tmp_error); + } + + g_static_mutex_unlock (&mutex); } /** @@ -422,31 +441,40 @@ void uca_camera_stop_recording(UcaCamera *camera, GError **error) * uca_camera_stop_recording(). Frames have to be picked up with * ufo_camera_grab(). */ -void uca_camera_start_readout(UcaCamera *camera, GError **error) +void +uca_camera_start_readout (UcaCamera *camera, GError **error) { - g_return_if_fail(UCA_IS_CAMERA(camera)); + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - UcaCameraClass *klass = UCA_CAMERA_GET_CLASS(camera); + g_return_if_fail (UCA_IS_CAMERA(camera)); - g_return_if_fail(klass != NULL); - g_return_if_fail(klass->start_readout != NULL); + klass = UCA_CAMERA_GET_CLASS(camera); - if (camera->priv->is_recording) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, - "Camera is still recording"); - return; - } + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->start_readout != NULL); - GError *tmp_error = NULL; - (*klass->start_readout)(camera, &tmp_error); + g_static_mutex_lock (&mutex); - if (tmp_error == NULL) { - camera->priv->is_readout = TRUE; - /* TODO: we should depend on GLib 2.26 and use g_object_notify_by_pspec */ - g_object_notify(G_OBJECT(camera), "is-readout"); + if (camera->priv->is_recording) { + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, + "Camera is still recording"); } - else - g_propagate_error(error, tmp_error); + else { + GError *tmp_error = NULL; + + (*klass->start_readout) (camera, &tmp_error); + + if (tmp_error == NULL) { + camera->priv->is_readout = TRUE; + /* TODO: we should depend on GLib 2.26 and use g_object_notify_by_pspec */ + g_object_notify (G_OBJECT (camera), "is-readout"); + } + else + g_propagate_error (error, tmp_error); + } + + g_static_mutex_unlock (&mutex); } /** @@ -473,22 +501,27 @@ void uca_camera_set_grab_func(UcaCamera *camera, UcaCameraGrabFunc func, gpointe * You must have called uca_camera_start_recording() before, otherwise you will * get a #UCA_CAMERA_ERROR_NOT_RECORDING error. */ -void uca_camera_trigger(UcaCamera *camera, GError **error) +void +uca_camera_trigger (UcaCamera *camera, GError **error) { - g_return_if_fail(UCA_IS_CAMERA(camera)); + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - UcaCameraClass *klass = UCA_CAMERA_GET_CLASS(camera); + g_return_if_fail (UCA_IS_CAMERA (camera)); - g_return_if_fail(klass != NULL); - g_return_if_fail(klass->trigger != NULL); + klass = UCA_CAMERA_GET_CLASS (camera); - if (!camera->priv->is_recording) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, - "Camera is not recording"); - return; - } + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->trigger != NULL); + + g_static_mutex_lock (&mutex); + + if (!camera->priv->is_recording) + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, "Camera is not recording"); + else + (*klass->trigger) (camera, error); - (*klass->trigger)(camera, error); + g_static_mutex_unlock (&mutex); } /** @@ -505,22 +538,27 @@ void uca_camera_trigger(UcaCamera *camera, GError **error) * You must have called uca_camera_start_recording() before, otherwise you will * get a #UCA_CAMERA_ERROR_NOT_RECORDING error. */ -void uca_camera_grab(UcaCamera *camera, gpointer *data, GError **error) +void +uca_camera_grab (UcaCamera *camera, gpointer *data, GError **error) { - g_return_if_fail(UCA_IS_CAMERA(camera)); + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - UcaCameraClass *klass = UCA_CAMERA_GET_CLASS(camera); + g_return_if_fail (UCA_IS_CAMERA(camera)); - g_return_if_fail(klass != NULL); - g_return_if_fail(klass->grab != NULL); - g_return_if_fail(data != NULL); + klass = UCA_CAMERA_GET_CLASS (camera); - if (!camera->priv->is_recording && !camera->priv->is_readout) { - g_set_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, - "Camera is neither recording nor in readout mode"); - return; - } + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->grab != NULL); + g_return_if_fail (data != NULL); + + g_static_mutex_lock (&mutex); + + if (!camera->priv->is_recording && !camera->priv->is_readout) + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING, "Camera is neither recording nor in readout mode"); + else + (*klass->grab) (camera, data, error); - (*klass->grab)(camera, data, error); + g_static_mutex_unlock (&mutex); } -- cgit v1.2.3 From 3a45434834999e1ac7c7a99cdaa644d939b859b0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 25 Sep 2012 18:18:23 +0200 Subject: Move tools from test/ to tools/ directory --- test/CMakeLists.txt | 57 +--- test/benchmark.c | 267 --------------- test/control.c | 350 ------------------- test/control.glade | 302 ----------------- test/egg-property-cell-renderer.c | 594 --------------------------------- test/egg-property-cell-renderer.h | 55 --- test/egg-property-tree-view.c | 114 ------- test/egg-property-tree-view.h | 54 --- test/grab-async.c | 138 -------- test/grab.c | 160 --------- test/perf-overhead.c | 181 ---------- test/test-all.c | 214 ------------ tools/CMakeLists.txt | 20 +- tools/benchmark.c | 267 +++++++++++++++ tools/grab-async.c | 138 ++++++++ tools/grab.c | 160 +++++++++ tools/gui/control.c | 350 +++++++++++++++++++ tools/gui/control.glade | 302 +++++++++++++++++ tools/gui/egg-property-cell-renderer.c | 594 +++++++++++++++++++++++++++++++++ tools/gui/egg-property-cell-renderer.h | 55 +++ tools/gui/egg-property-tree-view.c | 113 +++++++ tools/gui/egg-property-tree-view.h | 54 +++ tools/perf-overhead.c | 181 ++++++++++ 23 files changed, 2233 insertions(+), 2487 deletions(-) delete mode 100644 test/benchmark.c delete mode 100644 test/control.c delete mode 100644 test/control.glade delete mode 100644 test/egg-property-cell-renderer.c delete mode 100644 test/egg-property-cell-renderer.h delete mode 100644 test/egg-property-tree-view.c delete mode 100644 test/egg-property-tree-view.h delete mode 100644 test/grab-async.c delete mode 100644 test/grab.c delete mode 100644 test/perf-overhead.c delete mode 100644 test/test-all.c create mode 100644 tools/benchmark.c create mode 100644 tools/grab-async.c create mode 100644 tools/grab.c create mode 100644 tools/gui/control.c create mode 100644 tools/gui/control.glade create mode 100644 tools/gui/egg-property-cell-renderer.c create mode 100644 tools/gui/egg-property-cell-renderer.h create mode 100644 tools/gui/egg-property-tree-view.c create mode 100644 tools/gui/egg-property-tree-view.h create mode 100644 tools/perf-overhead.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0f46c32..b579d1b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,12 +5,10 @@ add_definitions("--std=c99 -Wall") # --- Find packages and libraries --------------------------------------------- find_package(PkgConfig) -pkg_check_modules(GTK2 gtk+-2.0>=2.22) -pkg_check_modules(GTHREAD2 gthread-2.0) pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.glade ${CMAKE_CURRENT_BINARY_DIR}) +set(libs uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) # --- Build targets ----------------------------------------------------------- include_directories( @@ -20,59 +18,10 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../src ) -if (HAVE_PYLON_CAMERA) - set(GENICAM_ROOT $ENV{PYLON_ROOT}/genicam) - # check for 32/64 bit - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(PYLON_LIB_DIRS $ENV{PYLON_ROOT}/lib64 $ENV{PYLON_ROOT}/bin ${GENICAM_ROOT}/bin/Linux64_x64 - ${GENICAM_ROOT}/bin/Linux64_x64/GenApi/Generic) - else() - set(PYLON_LIB_DIRS $ENV{PYLON_ROOT}/lib64 $ENV{PYLON_ROOT}/bin ${GENICAM_ROOT}/bin/Linux32_i86 - ${GENICAM_ROOT}/bin/Linux32_i86/GenApi/Generic) - endif() - link_directories(${PYLON_LIB_DIRS} ${LIBPYLONCAM_LIBDIR}) -endif() - -add_executable(grab grab.c) -add_executable(grab-async grab-async.c) -add_executable(benchmark benchmark.c) -add_executable(perf perf-overhead.c) - -target_link_libraries(benchmark uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -target_link_libraries(grab uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) -target_link_libraries(perf uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) - -if (GTK2_FOUND) - include_directories(${GTK2_INCLUDE_DIRS}) - - add_executable(control - control.c - egg-property-cell-renderer.c - egg-property-tree-view.c) - - target_link_libraries(control uca - ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) - - install(TARGETS control - RUNTIME DESTINATION bin) - - install(FILES control.glade - DESTINATION share/libuca) -endif() - if (HAVE_MOCK_CAMERA) add_executable(test-mock test-mock.c) - - target_link_libraries(test-mock - uca - ${GLIB2_LIBRARIES} - ${GOBJECT2_LIBRARIES}) + target_link_libraries(test-mock ${libs}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl - ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) + ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) endif() - -#add_executable(test-all test-all.c) -#target_link_libraries(test-all uca -# ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) diff --git a/test/benchmark.c b/test/benchmark.c deleted file mode 100644 index ef99fd1..0000000 --- a/test/benchmark.c +++ /dev/null @@ -1,267 +0,0 @@ -/* 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 <glib-object.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> -#include "uca-camera.h" -#include "uca-plugin-manager.h" - -typedef void (*GrabFrameFunc) (UcaCamera *camera, gpointer buffer, guint n_frames); - -static UcaCamera *camera = NULL; - -static void -sigint_handler(int signal) -{ - g_print ("Closing down libuca\n"); - uca_camera_stop_recording (camera, NULL); - g_object_unref (camera); - exit (signal); -} - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -static void -log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user) -{ - gsize n_written; - GError *error = NULL; - GIOChannel *channel = user; - -#if GLIB_CHECK_VERSION(2, 26, 0) - GTimeZone *tz; - GDateTime *date_time; - gchar *new_message; - - tz = g_time_zone_new_local (); - date_time = g_date_time_new_now (tz); - - new_message = g_strdup_printf ("[%s] %s\n", - g_date_time_format (date_time, "%FT%H:%M:%S%z"), message); - - g_time_zone_unref (tz); - g_date_time_unref (date_time); - - g_io_channel_write_chars (channel, new_message, strlen (new_message), &n_written, &error); - g_assert_no_error (error); - g_free (new_message); -#else - g_io_channel_write_chars (channel, message, strlen (message), &n_written, &error); - g_assert_no_error (error); -#endif - - g_io_channel_flush (channel, &error); - g_assert_no_error (error); -} - -static void -grab_frames_sync (UcaCamera *camera, gpointer buffer, guint n_frames) -{ - GError *error = NULL; - - uca_camera_start_recording (camera, &error); - - for (guint i = 0; i < n_frames; i++) { - uca_camera_grab(camera, &buffer, &error); - - if (error != NULL) { - g_warning ("Error grabbing frame %02i/%i: `%s'", i, n_frames, error->message); - g_error_free (error); - error = NULL; - } - } - - uca_camera_stop_recording (camera, &error); -} - -static void -grab_callback (gpointer data, gpointer user_data) -{ - guint *n_acquired_frames = user_data; - *n_acquired_frames += 1; -} - -static void -grab_frames_async (UcaCamera *camera, gpointer buffer, guint n_frames) -{ - GError *error = NULL; - guint n_acquired_frames = 0; - - uca_camera_set_grab_func (camera, grab_callback, &n_acquired_frames); - uca_camera_start_recording (camera, &error); - - /* - * Behold! Spinlooping is probably a bad idea but nowadays single core - * machines are relatively rare. - */ - while (n_acquired_frames < n_frames) - ; - - uca_camera_stop_recording (camera, &error); - -} - -static void -benchmark_method (UcaCamera *camera, gpointer buffer, GrabFrameFunc func, guint n_runs, guint n_frames, guint n_bytes) -{ - GTimer *timer; - gdouble fps; - gdouble bandwidth; - gdouble total_time = 0.0; - GError *error = NULL; - - g_print ("%-10i%-10i", n_frames, n_runs); - timer = g_timer_new (); - g_assert_no_error (error); - - for (guint run = 0; run < n_runs; run++) { - g_message ("Start run %i of %i", run, n_runs); - g_timer_start (timer); - - func (camera, buffer, n_frames); - - g_timer_stop (timer); - total_time += g_timer_elapsed (timer, NULL); - } - - g_assert_no_error (error); - - fps = n_runs * n_frames / total_time; - bandwidth = n_bytes * fps / 1024 / 1024; - g_print ("%-16.2f%-16.2f\n", fps, bandwidth); - - g_timer_destroy (timer); -} - -static void -benchmark (UcaCamera *camera) -{ - const guint n_runs = 3; - const guint n_frames = 100; - - guint sensor_width; - guint sensor_height; - guint roi_width; - guint roi_height; - guint bits; - guint n_bytes_per_pixel; - guint n_bytes; - gdouble exposure = 0.00001; - gpointer buffer; - - g_object_set (G_OBJECT (camera), - "exposure-time", exposure, - NULL); - - g_object_get (G_OBJECT (camera), - "sensor-width", &sensor_width, - "sensor-height", &sensor_height, - "sensor-bitdepth", &bits, - "roi-width", &roi_width, - "roi-height", &roi_height, - "exposure-time", &exposure, - NULL); - - g_print ("# --- General information ---\n"); - g_print ("# Sensor size: %ix%i\n", sensor_width, sensor_height); - g_print ("# ROI size: %ix%i\n", roi_width, roi_height); - g_print ("# Exposure time: %fs\n", exposure); - - /* Synchronous frame acquisition */ - g_print ("# %-10s%-10s%-10s%-16s%-16s\n", "type", "n_frames", "n_runs", "frames/s", "MiB/s"); - g_print (" %-10s", "sync"); - - g_message ("Start synchronous benchmark"); - - n_bytes_per_pixel = bits > 8 ? 2 : 1; - n_bytes = roi_width * roi_height * n_bytes_per_pixel; - buffer = g_malloc0(n_bytes); - - benchmark_method (camera, buffer, grab_frames_sync, n_runs, n_frames, n_bytes); - - /* Asynchronous frame acquisition */ - g_object_set (G_OBJECT(camera), - "transfer-asynchronously", TRUE, - NULL); - - g_message ("Start asynchronous benchmark"); - g_print (" %-10s", "async"); - - benchmark_method (camera, buffer, grab_frames_async, n_runs, n_frames, n_bytes); - - g_free (buffer); -} - -int -main (int argc, char *argv[]) -{ - UcaPluginManager *manager; - GIOChannel *log_channel; - GError *error = NULL; - - (void) signal (SIGINT, sigint_handler); - g_type_init(); - - if (argc < 2) { - print_usage(); - return 1; - } - - log_channel = g_io_channel_new_file ("error.log", "a+", &error); - g_assert_no_error (error); - g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); - - if (camera == NULL) { - g_error ("Initialization: %s", error->message); - return 1; - } - - benchmark (camera); - - g_object_unref (camera); - g_io_channel_shutdown (log_channel, TRUE, &error); - g_assert_no_error (error); - - return 0; -} diff --git a/test/control.c b/test/control.c deleted file mode 100644 index 5a7b702..0000000 --- a/test/control.c +++ /dev/null @@ -1,350 +0,0 @@ -/* 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 <glib/gprintf.h> -#include <gtk/gtk.h> -#include <gdk/gdk.h> -#include <gdk/gdkkeysyms.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <errno.h> - -#include "config.h" -#include "uca-camera.h" -#include "uca-plugin-manager.h" -#include "egg-property-tree-view.h" - - -typedef struct { - gboolean running; - gboolean store; - - guchar *buffer, *pixels; - GdkPixbuf *pixbuf; - GtkWidget *image; - GtkTreeModel *property_model; - UcaCamera *camera; - - GtkStatusbar *statusbar; - guint statusbar_context_id; - - int timestamp; - int width; - int height; - int pixel_size; -} ThreadData; - -enum { - COLUMN_NAME = 0, - COLUMN_VALUE, - COLUMN_EDITABLE, - NUM_COLUMNS -}; - -static UcaPluginManager *plugin_manager; - -static void -convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) -{ - for (int i = 0, j = 0; i < width*height; i++) { - output[j++] = input[i]; - output[j++] = input[i]; - output[j++] = input[i]; - } -} - -static void -convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) -{ - guint16 *in = (guint16 *) input; - guint16 min = G_MAXUINT16, max = 0; - gfloat spread = 0.0f; - - for (int i = 0; i < width * height; i++) { - guint16 v = in[i]; - if (v < min) - min = v; - if (v > max) - max = v; - } - - spread = (gfloat) max - min; - - if (spread > 0.0f) { - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } - } -} - -static void * -grab_thread (void *args) -{ - ThreadData *data = (ThreadData *) args; - gchar filename[FILENAME_MAX] = {0,}; - gint counter = 0; - - while (data->running) { - uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); - - if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); - FILE *fp = fopen (filename, "wb"); - fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); - fclose (fp); - } - - /* FIXME: We should actually check if this is really a new frame and - * just do nothing if it is an already displayed one. */ - if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - else if (data->pixel_size == 2) { - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - } - - gdk_threads_enter (); - gdk_flush (); - gtk_image_clear (GTK_IMAGE (data->image)); - gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); - gdk_threads_leave (); - } - return NULL; -} - -gboolean -on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - return FALSE; -} - -void -on_destroy (GtkWidget *widget, gpointer data) -{ - ThreadData *td = (ThreadData *) data; - td->running = FALSE; - g_object_unref (td->camera); - gtk_main_quit (); -} - -static void -on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) -{ - ThreadData *data = (ThreadData *) args; - - if (data->running) - return; - - GError *error = NULL; - data->running = TRUE; - - uca_camera_start_recording (data->camera, &error); - - if (error != NULL) { - g_printerr ("Failed to start recording: %s\n", error->message); - return; - } - - if (!g_thread_create (grab_thread, data, FALSE, &error)) { - g_printerr ("Failed to create thread: %s\n", error->message); - return; - } -} - -static void -on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) -{ - ThreadData *data = (ThreadData *) args; - data->running = FALSE; - data->store = FALSE; - GError *error = NULL; - uca_camera_stop_recording (data->camera, &error); - - if (error != NULL) - g_printerr ("Failed to stop: %s\n", error->message); -} - -static void -on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) -{ - ThreadData *data = (ThreadData *) args; - data->timestamp = (int) time (0); - data->store = TRUE; - GError *error = NULL; - - gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); - - if (data->running != TRUE) { - data->running = TRUE; - uca_camera_start_recording (data->camera, &error); - - if (!g_thread_create (grab_thread, data, FALSE, &error)) - g_printerr ("Failed to create thread: %s\n", error->message); - } -} - -static void -create_main_window (GtkBuilder *builder, const gchar* camera_name) -{ - static ThreadData td; - - GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); - - if ((camera == NULL) || (error != NULL)) { - g_error ("%s\n", error->message); - gtk_main_quit (); - } - - guint bits_per_sample; - g_object_get (camera, - "roi-width", &td.width, - "roi-height", &td.height, - "sensor-bitdepth", &bits_per_sample, - NULL); - - GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - - gtk_container_add (scrolled_property_window, property_tree_view); - gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); - - GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); - gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); - - td.pixel_size = bits_per_sample > 8 ? 2 : 1; - td.image = image; - td.pixbuf = pixbuf; - td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); - td.pixels = gdk_pixbuf_get_pixels (pixbuf); - td.running = FALSE; - td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); - td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); - td.store = FALSE; - td.camera = camera; - td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); - - g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), - "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), - "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), - "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); - - gtk_widget_show (image); - gtk_widget_show (window); -} - -static void -on_button_proceed_clicked (GtkWidget *widget, gpointer data) -{ - GtkBuilder *builder = GTK_BUILDER (data); - GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); - GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); - GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); - - GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); - GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); - GtkTreeIter iter; - - gtk_widget_destroy (choice_window); - gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), &iter, selected_rows->data); - - if (valid) { - gchar *data; - gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 0, &data, -1); - create_main_window (builder, data); - g_free (data); - } - - g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); - g_list_free (selected_rows); -} - -static void -on_treeview_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - if (event->keyval == GDK_KEY_Return) - gtk_widget_grab_focus (GTK_WIDGET (data)); -} - -static void -create_choice_window (GtkBuilder *builder) -{ - GList *camera_types = uca_plugin_manager_get_available_cameras (plugin_manager); - - GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); - GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); - GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); - GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); - GtkTreeIter iter; - - for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { - gtk_list_store_append (list_store, &iter); - gtk_list_store_set (list_store, &iter, 0, g_strdup ((gchar *) it->data), -1); - } - - gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); - - if (valid) { - GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); - gtk_tree_selection_unselect_all (selection); - gtk_tree_selection_select_path (selection, gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter)); - } - - g_signal_connect (proceed_button, "clicked", G_CALLBACK (on_button_proceed_clicked), builder); - g_signal_connect (treeview, "key-press-event", G_CALLBACK (on_treeview_keypress), proceed_button); - gtk_widget_show_all (GTK_WIDGET (choice_window)); - - g_list_foreach (camera_types, (GFunc) g_free, NULL); - g_list_free (camera_types); -} - -int -main (int argc, char *argv[]) -{ - GError *error = NULL; - - g_thread_init (NULL); - gdk_threads_init (); - gtk_init (&argc, &argv); - - GtkBuilder *builder = gtk_builder_new (); - - if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { - g_print ("Error: %s\n", error->message); - return 1; - } - - plugin_manager = uca_plugin_manager_new (); - create_choice_window (builder); - gtk_builder_connect_signals (builder, NULL); - - gdk_threads_enter (); - gtk_main (); - gdk_threads_leave (); - - g_object_unref (plugin_manager); - return 0; -} diff --git a/test/control.glade b/test/control.glade deleted file mode 100644 index d7ba2fc..0000000 --- a/test/control.glade +++ /dev/null @@ -1,302 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <requires lib="gtk+" version="2.20"/> - <!-- interface-naming-policy project-wide --> - <object class="GtkListStore" id="camera-types"> - <columns> - <!-- column-name name --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkListStore" id="camera-properties"> - <columns> - <!-- column-name PropertyName --> - <column type="gchararray"/> - <!-- column-name PropertyValue --> - <column type="gchararray"/> - <!-- column-name writeable --> - <column type="gboolean"/> - </columns> - </object> - <object class="GtkWindow" id="window"> - <property name="title" translatable="yes">Camera Control</property> - <property name="default_width">1024</property> - <property name="default_height">768</property> - <signal name="delete_event" handler="on_delete_event"/> - <child> - <object class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <child> - <object class="GtkMenuBar" id="menubar1"> - <property name="visible">True</property> - <child> - <object class="GtkMenuItem" id="menuitem1"> - <property name="visible">True</property> - <property name="label" translatable="yes">_File</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu_file"> - <property name="visible">True</property> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem1"> - <property name="label">gtk-new</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem2"> - <property name="label">gtk-open</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem3"> - <property name="label">gtk-save</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem4"> - <property name="label">gtk-save-as</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkSeparatorMenuItem" id="separatormenuitem1"> - <property name="visible">True</property> - </object> - </child> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem_quit"> - <property name="label">gtk-quit</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - <signal name="activate" handler="gtk_main_quit"/> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem4"> - <property name="visible">True</property> - <property name="label" translatable="yes">_Help</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu_help"> - <property name="visible">True</property> - <child> - <object class="GtkImageMenuItem" id="imagemenuitem_about"> - <property name="label">gtk-about</property> - <property name="visible">True</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="toolbar"> - <property name="visible">True</property> - <child> - <object class="GtkToolButton" id="toolbutton_run"> - <property name="visible">True</property> - <property name="label" translatable="yes">Run</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-media-play</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbutton_record"> - <property name="visible">True</property> - <property name="label" translatable="yes">Record</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-media-record</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbutton_stop"> - <property name="visible">True</property> - <property name="label" translatable="yes">Stop</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-media-stop</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkHPaned" id="hpaned1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">6</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="width_request">300</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <child> - <object class="GtkViewport" id="viewport1"> - <property name="visible">True</property> - <property name="resize_mode">queue</property> - <child> - <object class="GtkImage" id="image"> - <property name="visible">True</property> - <property name="stock">gtk-missing-image</property> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="resize">True</property> - <property name="shrink">False</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow2"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="resize">True</property> - <property name="shrink">True</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkStatusbar" id="statusbar"> - <property name="visible">True</property> - <property name="spacing">2</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">3</property> - </packing> - </child> - </object> - </child> - </object> - <object class="GtkAdjustment" id="adjustment_scale"> - <property name="value">65535</property> - <property name="lower">1</property> - <property name="upper">65535</property> - <property name="step_increment">1</property> - <property name="page_increment">10</property> - </object> - <object class="GtkWindow" id="choice-window"> - <property name="border_width">6</property> - <child> - <object class="GtkVBox" id="vbox3"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkTreeView" id="treeview-cameras"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="model">camera-types</property> - <child> - <object class="GtkTreeViewColumn" id="treeviewcolumn1"> - <property name="title">Choose camera</property> - <child> - <object class="GtkCellRendererText" id="cellrenderertext1"/> - <attributes> - <attribute name="text">0</attribute> - </attributes> - </child> - </object> - </child> - </object> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHButtonBox" id="hbuttonbox1"> - <property name="visible">True</property> - <property name="spacing">6</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="button-cancel"> - <property name="label">gtk-quit</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - <signal name="clicked" handler="gtk_main_quit"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button-proceed"> - <property name="label">gtk-ok</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="padding">6</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> -</interface> diff --git a/test/egg-property-cell-renderer.c b/test/egg-property-cell-renderer.c deleted file mode 100644 index 9df5cc3..0000000 --- a/test/egg-property-cell-renderer.c +++ /dev/null @@ -1,594 +0,0 @@ -/* 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 <stdlib.h> -#include "egg-property-cell-renderer.h" - -G_DEFINE_TYPE (EggPropertyCellRenderer, egg_property_cell_renderer, GTK_TYPE_CELL_RENDERER) - -#define EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererPrivate)) - - -struct _EggPropertyCellRendererPrivate -{ - GObject *object; - GtkListStore *list_store; - GtkCellRenderer *renderer; - GtkCellRenderer *text_renderer; - GtkCellRenderer *spin_renderer; - GtkCellRenderer *toggle_renderer; - GtkCellRenderer *combo_renderer; - GHashTable *combo_models; -}; - -enum -{ - PROP_0, - PROP_PROP_NAME, - N_PROPERTIES -}; - -enum -{ - COMBO_COLUMN_VALUE_NAME, - COMBO_COLUMN_VALUE, - N_COMBO_COLUMNS -}; - -static GParamSpec *egg_property_cell_renderer_properties[N_PROPERTIES] = { NULL, }; - -GtkCellRenderer * -egg_property_cell_renderer_new (GObject *object, - GtkListStore *list_store) -{ - EggPropertyCellRenderer *renderer; - - renderer = EGG_PROPERTY_CELL_RENDERER (g_object_new (EGG_TYPE_PROPERTY_CELL_RENDERER, NULL)); - renderer->priv->object = object; - renderer->priv->list_store = list_store; - return GTK_CELL_RENDERER (renderer); -} - -static GParamSpec * -get_pspec_from_object (GObject *object, const gchar *prop_name) -{ - GObjectClass *oclass = G_OBJECT_GET_CLASS (object); - return g_object_class_find_property (oclass, prop_name); -} - -static void -get_string_double_repr (GObject *object, const gchar *prop_name, gchar **text, gdouble *number) -{ - GParamSpec *pspec; - GValue from = { 0 }; - GValue to_string = { 0 }; - GValue to_double = { 0 }; - - pspec = get_pspec_from_object (object, prop_name); - g_value_init (&from, pspec->value_type); - g_value_init (&to_string, G_TYPE_STRING); - g_value_init (&to_double, G_TYPE_DOUBLE); - g_object_get_property (object, prop_name, &from); - - if (g_value_transform (&from, &to_string)) - *text = g_strdup (g_value_get_string (&to_string)); - else - g_warning ("Could not convert from %s gchar*\n", g_type_name (pspec->value_type)); - - if (g_value_transform (&from, &to_double)) - *number = g_value_get_double (&to_double); - else - g_warning ("Could not convert from %s to gdouble\n", g_type_name (pspec->value_type)); -} - -static void -clear_adjustment (GObject *object) -{ - GtkAdjustment *adjustment; - - g_object_get (object, - "adjustment", &adjustment, - NULL); - - if (adjustment) - g_object_unref (adjustment); - - g_object_set (object, - "adjustment", NULL, - NULL); -} - -static void -egg_property_cell_renderer_set_renderer (EggPropertyCellRenderer *renderer, - const gchar *prop_name) -{ - EggPropertyCellRendererPrivate *priv; - GParamSpec *pspec; - gchar *text = NULL; - gdouble number; - - priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer); - pspec = get_pspec_from_object (priv->object, prop_name); - - /* - * Set this renderers mode, so that any actions can be forwarded to our - * child renderers. - */ - switch (pspec->value_type) { - /* toggle renderers */ - case G_TYPE_BOOLEAN: - priv->renderer = priv->toggle_renderer; - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); - break; - - /* spin renderers */ - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: - priv->renderer = priv->spin_renderer; - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); - g_object_set (priv->renderer, "digits", 5, NULL); - break; - - case G_TYPE_INT: - case G_TYPE_UINT: - case G_TYPE_LONG: - case G_TYPE_ULONG: - case G_TYPE_INT64: - case G_TYPE_UINT64: - priv->renderer = priv->spin_renderer; - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); - g_object_set (priv->renderer, "digits", 0, NULL); - break; - - /* text renderers */ - case G_TYPE_POINTER: - case G_TYPE_STRING: - priv->renderer = priv->text_renderer; - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); - break; - - /* combo renderers */ - default: - if (G_TYPE_IS_ENUM (pspec->value_type)) { - priv->renderer = priv->combo_renderer; - g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); - } - break; - } - - /* - * Set the content from the objects property. - */ - switch (pspec->value_type) { - case G_TYPE_BOOLEAN: - { - gboolean val; - - g_object_get (priv->object, prop_name, &val, NULL); - g_object_set (priv->renderer, - "active", val, - "activatable", pspec->flags & G_PARAM_WRITABLE ? TRUE : FALSE, - NULL); - break; - } - - case G_TYPE_INT: - case G_TYPE_UINT: - case G_TYPE_LONG: - case G_TYPE_ULONG: - case G_TYPE_INT64: - case G_TYPE_UINT64: - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: - get_string_double_repr (priv->object, prop_name, &text, &number); - break; - - case G_TYPE_STRING: - g_object_get (priv->object, prop_name, &text, NULL); - break; - - case G_TYPE_POINTER: - { - gpointer val; - - g_object_get (priv->object, prop_name, &val, NULL); - text = g_strdup_printf ("0x%x", GPOINTER_TO_INT (val)); - } - break; - - default: - if (G_TYPE_IS_ENUM (pspec->value_type)) { - GParamSpecEnum *pspec_enum; - GEnumClass *enum_class; - GtkTreeModel *combo_model; - GtkTreeIter iter; - gint value; - - g_object_get (priv->object, prop_name, &value, NULL); - - pspec_enum = G_PARAM_SPEC_ENUM (pspec); - enum_class = pspec_enum->enum_class; - combo_model = g_hash_table_lookup (priv->combo_models, prop_name); - - if (combo_model == NULL) { - combo_model = GTK_TREE_MODEL (gtk_list_store_new (N_COMBO_COLUMNS, G_TYPE_STRING, G_TYPE_INT)); - g_hash_table_insert (priv->combo_models, g_strdup (prop_name), combo_model); - - for (guint i = 0; i < enum_class->n_values; i++) { - gtk_list_store_append (GTK_LIST_STORE (combo_model), &iter); - gtk_list_store_set (GTK_LIST_STORE (combo_model), &iter, - COMBO_COLUMN_VALUE_NAME, enum_class->values[i].value_name, - COMBO_COLUMN_VALUE, enum_class->values[i].value, - -1); - } - } - - - for (guint i = 0; i < enum_class->n_values; i++) { - if (enum_class->values[i].value == value) - text = g_strdup (enum_class->values[i].value_name); - } - - g_object_set (priv->renderer, - "model", combo_model, - "text-column", 0, - NULL); - } - break; - } - - if (pspec->flags & G_PARAM_WRITABLE) { - if (GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer)) - g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); - else - g_object_set (priv->renderer, "foreground", "#000000", NULL); - - if (GTK_IS_CELL_RENDERER_TEXT (priv->renderer)) { - g_object_set (priv->renderer, - "editable", TRUE, - "mode", GTK_CELL_RENDERER_MODE_EDITABLE, - NULL); - } - - if (GTK_IS_CELL_RENDERER_SPIN (priv->renderer)) { - GtkObject *adjustment = NULL; - -#define gtk_typed_adjustment_new(type, pspec, val, step_inc, page_inc) \ - gtk_adjustment_new (val, ((type *) pspec)->minimum, ((type *) pspec)->maximum, step_inc, page_inc, 0) - - switch (pspec->value_type) { - case G_TYPE_INT: - adjustment = gtk_typed_adjustment_new (GParamSpecInt, pspec, number, 1, 10); - break; - case G_TYPE_UINT: - adjustment = gtk_typed_adjustment_new (GParamSpecUInt, pspec, number, 1, 10); - break; - case G_TYPE_LONG: - adjustment = gtk_typed_adjustment_new (GParamSpecLong, pspec, number, 1, 10); - break; - case G_TYPE_ULONG: - adjustment = gtk_typed_adjustment_new (GParamSpecULong, pspec, number, 1, 10); - break; - case G_TYPE_INT64: - adjustment = gtk_typed_adjustment_new (GParamSpecInt64, pspec, number, 1, 10); - break; - case G_TYPE_UINT64: - adjustment = gtk_typed_adjustment_new (GParamSpecUInt64, pspec, number, 1, 10); - break; - case G_TYPE_FLOAT: - adjustment = gtk_typed_adjustment_new (GParamSpecFloat, pspec, number, 0.05, 10); - break; - case G_TYPE_DOUBLE: - adjustment = gtk_typed_adjustment_new (GParamSpecDouble, pspec, number, 0.05, 10); - break; - } - - clear_adjustment (G_OBJECT (priv->renderer)); - g_object_set (priv->renderer, "adjustment", adjustment, NULL); - } - } - else { - g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); - - if (!GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer)) - g_object_set (priv->renderer, "foreground", "#aaaaaa", NULL); - } - - if (text != NULL) { - g_object_set (priv->renderer, "text", text, NULL); - g_free (text); - } -} - -static gchar * -get_prop_name_from_tree_model (GtkTreeModel *model, const gchar *path) -{ - GtkTreeIter iter; - gchar *prop_name = NULL; - - /* TODO: don't assume column 0 to contain the prop name */ - if (gtk_tree_model_get_iter_from_string (model, &iter, path)) - gtk_tree_model_get (model, &iter, 0, &prop_name, -1); - - return prop_name; -} - -static void -egg_property_cell_renderer_toggle_cb (GtkCellRendererToggle *renderer, - gchar *path, - gpointer user_data) -{ - EggPropertyCellRendererPrivate *priv; - gchar *prop_name; - - priv = (EggPropertyCellRendererPrivate *) user_data; - prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); - - if (prop_name != NULL) { - gboolean activated; - - g_object_get (priv->object, prop_name, &activated, NULL); - g_object_set (priv->object, prop_name, !activated, NULL); - g_free (prop_name); - } -} - -static void -egg_property_cell_renderer_text_edited_cb (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - gpointer user_data) -{ - EggPropertyCellRendererPrivate *priv; - gchar *prop_name; - - priv = (EggPropertyCellRendererPrivate *) user_data; - prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); - - if (prop_name != NULL) { - g_object_set (priv->object, prop_name, new_text, NULL); - g_free (prop_name); - } -} - -static void -egg_property_cell_renderer_spin_edited_cb (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - gpointer user_data) -{ - EggPropertyCellRendererPrivate *priv; - gchar *prop_name; - - priv = (EggPropertyCellRendererPrivate *) user_data; - prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); - - if (prop_name != NULL) { - GParamSpec *pspec; - GValue from = { 0 }; - GValue to = { 0 }; - - pspec = get_pspec_from_object (priv->object, prop_name); - - g_value_init (&from, G_TYPE_DOUBLE); - g_value_init (&to, pspec->value_type); - g_value_set_double (&from, strtod (new_text, NULL)); - - if (g_value_transform (&from, &to)) - g_object_set_property (priv->object, prop_name, &to); - else - g_warning ("Could not transform %s to %s\n", - g_value_get_string (&from), g_type_name (pspec->value_type)); - - g_free (prop_name); - } -} - -static void -egg_property_cell_renderer_changed_cb (GtkCellRendererCombo *combo, - gchar *path, - GtkTreeIter *new_iter, - gpointer user_data) -{ - EggPropertyCellRendererPrivate *priv; - gchar *prop_name; - - priv = (EggPropertyCellRendererPrivate *) user_data; - prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); - - if (prop_name != NULL) { - GtkTreeModel *combo_model; - gchar *value_name; - gint value; - - combo_model = g_hash_table_lookup (priv->combo_models, prop_name); - - gtk_tree_model_get (combo_model, new_iter, - COMBO_COLUMN_VALUE_NAME, &value_name, - COMBO_COLUMN_VALUE, &value, - -1); - - g_object_set (priv->object, prop_name, value, NULL); - g_free (value_name); - g_free (prop_name); - } -} - -static void -egg_property_cell_renderer_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - - EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); - gtk_cell_renderer_get_size (priv->renderer, widget, cell_area, x_offset, y_offset, width, height); -} - -static void -egg_property_cell_renderer_render (GtkCellRenderer *cell, - GdkDrawable *window, - GtkWidget *widget, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GdkRectangle *expose_area, - GtkCellRendererState flags) -{ - EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); - gtk_cell_renderer_render (priv->renderer, window, widget, background_area, cell_area, expose_area, flags); -} - -static gboolean -egg_property_cell_renderer_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); - return gtk_cell_renderer_activate (priv->renderer, event, widget, path, background_area, cell_area, flags); -} - -static GtkCellEditable * -egg_property_cell_renderer_start_editing (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); - return gtk_cell_renderer_start_editing (priv->renderer, event, widget, path, background_area, cell_area, flags); -} - -static void -egg_property_cell_renderer_dispose (GObject *object) -{ - EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object); - g_hash_table_destroy (renderer->priv->combo_models); -} - -static void -egg_property_cell_renderer_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object)); - EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object); - - switch (property_id) { - case PROP_PROP_NAME: - egg_property_cell_renderer_set_renderer (renderer, g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - return; - } -} - -static void -egg_property_cell_renderer_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object)); - - switch (property_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - return; - } -} - -static void -egg_property_cell_renderer_class_init (EggPropertyCellRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkCellRendererClass *cellrenderer_class = GTK_CELL_RENDERER_CLASS (klass); - - gobject_class->set_property = egg_property_cell_renderer_set_property; - gobject_class->get_property = egg_property_cell_renderer_get_property; - gobject_class->dispose = egg_property_cell_renderer_dispose; - - cellrenderer_class->render = egg_property_cell_renderer_render; - cellrenderer_class->get_size = egg_property_cell_renderer_get_size; - cellrenderer_class->activate = egg_property_cell_renderer_activate; - cellrenderer_class->start_editing = egg_property_cell_renderer_start_editing; - - egg_property_cell_renderer_properties[PROP_PROP_NAME] = - g_param_spec_string("prop-name", - "Property name", "Property name", "", - G_PARAM_READWRITE); - - g_object_class_install_property(gobject_class, PROP_PROP_NAME, egg_property_cell_renderer_properties[PROP_PROP_NAME]); - - g_type_class_add_private (klass, sizeof (EggPropertyCellRendererPrivate)); -} - -static void -egg_property_cell_renderer_init (EggPropertyCellRenderer *renderer) -{ - EggPropertyCellRendererPrivate *priv; - - renderer->priv = priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer); - - priv->text_renderer = gtk_cell_renderer_text_new (); - priv->spin_renderer = gtk_cell_renderer_spin_new (); - priv->toggle_renderer = gtk_cell_renderer_toggle_new (); - priv->combo_renderer = gtk_cell_renderer_combo_new (); - priv->renderer = priv->text_renderer; - priv->combo_models = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - - g_object_set (priv->text_renderer, - "editable", TRUE, - NULL); - - g_object_set (priv->spin_renderer, - "editable", TRUE, - NULL); - - g_object_set (priv->toggle_renderer, - "xalign", 0.0f, - "activatable", TRUE, - "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, - NULL); - - g_object_set (priv->combo_renderer, - "has-entry", FALSE, - NULL); - - g_signal_connect (priv->spin_renderer, "edited", - G_CALLBACK (egg_property_cell_renderer_spin_edited_cb), priv); - - g_signal_connect (priv->text_renderer, "edited", - G_CALLBACK (egg_property_cell_renderer_text_edited_cb), NULL); - - g_signal_connect (priv->toggle_renderer, "toggled", - G_CALLBACK (egg_property_cell_renderer_toggle_cb), priv); - - g_signal_connect (priv->combo_renderer, "changed", - G_CALLBACK (egg_property_cell_renderer_changed_cb), priv); -} diff --git a/test/egg-property-cell-renderer.h b/test/egg-property-cell-renderer.h deleted file mode 100644 index d4dbe02..0000000 --- a/test/egg-property-cell-renderer.h +++ /dev/null @@ -1,55 +0,0 @@ -/* 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 EGG_PROPERTY_CELL_RENDERER_H -#define EGG_PROPERTY_CELL_RENDERER_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define EGG_TYPE_PROPERTY_CELL_RENDERER (egg_property_cell_renderer_get_type()) -#define EGG_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRenderer)) -#define EGG_IS_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER)) -#define EGG_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass)) -#define EGG_IS_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_CELL_RENDERER)) -#define EGG_PROPERTY_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass)) - -typedef struct _EggPropertyCellRenderer EggPropertyCellRenderer; -typedef struct _EggPropertyCellRendererClass EggPropertyCellRendererClass; -typedef struct _EggPropertyCellRendererPrivate EggPropertyCellRendererPrivate; - -struct _EggPropertyCellRenderer -{ - GtkCellRenderer parent_instance; - - /*< private >*/ - EggPropertyCellRendererPrivate *priv; -}; - -struct _EggPropertyCellRendererClass -{ - GtkCellRendererClass parent_class; -}; - -GType egg_property_cell_renderer_get_type (void); -GtkCellRenderer* egg_property_cell_renderer_new (GObject *object, - GtkListStore *list_store); - -G_END_DECLS - -#endif diff --git a/test/egg-property-tree-view.c b/test/egg-property-tree-view.c deleted file mode 100644 index f4ed2fb..0000000 --- a/test/egg-property-tree-view.c +++ /dev/null @@ -1,114 +0,0 @@ -/* 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 "egg-property-tree-view.h" -#include "egg-property-cell-renderer.h" - -G_DEFINE_TYPE (EggPropertyTreeView, egg_property_tree_view, GTK_TYPE_TREE_VIEW) - -#define EGG_PROPERTY_TREE_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewPrivate)) - -struct _EggPropertyTreeViewPrivate -{ - GtkListStore *list_store; -}; - -enum -{ - COLUMN_PROP_NAME, - COLUMN_PROP_ROW, - COLUMN_PROP_ADJUSTMENT, - N_COLUMNS -}; - -static void -egg_property_tree_view_populate_model_with_properties (GtkListStore *model, GObject *object) -{ - GParamSpec **pspecs; - GObjectClass *oclass; - guint n_properties; - GtkTreeIter iter; - - oclass = G_OBJECT_GET_CLASS (object); - pspecs = g_object_class_list_properties (oclass, &n_properties); - - for (guint i = 0; i < n_properties; i++) { - if (pspecs[i]->flags & G_PARAM_READABLE) { - GtkObject *adjustment; - - adjustment = gtk_adjustment_new (5, 0, 1000, 1, 10, 0); - - gtk_list_store_append (model, &iter); - gtk_list_store_set (model, &iter, - COLUMN_PROP_NAME, pspecs[i]->name, - COLUMN_PROP_ROW, FALSE, - COLUMN_PROP_ADJUSTMENT, adjustment, - -1); - } - } - - g_free (pspecs); -} - -GtkWidget * -egg_property_tree_view_new (GObject *object) -{ - EggPropertyTreeView *property_tree_view; - GtkTreeView *tree_view; - GtkTreeViewColumn *prop_column, *value_column; - GtkCellRenderer *prop_renderer, *value_renderer; - GtkListStore *list_store; - - property_tree_view = EGG_PROPERTY_TREE_VIEW (g_object_new (EGG_TYPE_PROPERTY_TREE_VIEW, NULL)); - list_store = property_tree_view->priv->list_store; - tree_view = GTK_TREE_VIEW (property_tree_view); - - egg_property_tree_view_populate_model_with_properties (list_store, object); - gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store)); - - prop_renderer = gtk_cell_renderer_text_new (); - prop_column = gtk_tree_view_column_new_with_attributes ("Property", prop_renderer, - "text", COLUMN_PROP_NAME, - NULL); - - value_renderer = egg_property_cell_renderer_new (object, list_store); - value_column = gtk_tree_view_column_new_with_attributes ("Value", value_renderer, - "prop-name", COLUMN_PROP_NAME, - NULL); - - gtk_tree_view_append_column (tree_view, prop_column); - gtk_tree_view_append_column (tree_view, value_column); - - return GTK_WIDGET (tree_view); -} - -static void -egg_property_tree_view_class_init (EggPropertyTreeViewClass *klass) -{ - g_type_class_add_private (klass, sizeof (EggPropertyTreeViewPrivate)); -} - -static void -egg_property_tree_view_init (EggPropertyTreeView *tree_view) -{ - EggPropertyTreeViewPrivate *priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view); - - tree_view->priv = priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view); - priv->list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, GTK_TYPE_ADJUSTMENT); -} - diff --git a/test/egg-property-tree-view.h b/test/egg-property-tree-view.h deleted file mode 100644 index e8fd0fe..0000000 --- a/test/egg-property-tree-view.h +++ /dev/null @@ -1,54 +0,0 @@ -/* 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 EGG_PROPERTY_TREE_VIEW_H -#define EGG_PROPERTY_TREE_VIEW_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define EGG_TYPE_PROPERTY_TREE_VIEW (egg_property_tree_view_get_type()) -#define EGG_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeView)) -#define EGG_IS_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_TREE_VIEW)) -#define EGG_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass)) -#define EGG_IS_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_TREE_VIEW)) -#define EGG_PROPERTY_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass)) - -typedef struct _EggPropertyTreeView EggPropertyTreeView; -typedef struct _EggPropertyTreeViewClass EggPropertyTreeViewClass; -typedef struct _EggPropertyTreeViewPrivate EggPropertyTreeViewPrivate; - -struct _EggPropertyTreeView -{ - GtkTreeView parent_instance; - - /*< private >*/ - EggPropertyTreeViewPrivate *priv; -}; - -struct _EggPropertyTreeViewClass -{ - GtkTreeViewClass parent_class; -}; - -GType egg_property_tree_view_get_type (void) G_GNUC_CONST; -GtkWidget* egg_property_tree_view_new (GObject *object); - -G_END_DECLS - -#endif diff --git a/test/grab-async.c b/test/grab-async.c deleted file mode 100644 index 6132829..0000000 --- a/test/grab-async.c +++ /dev/null @@ -1,138 +0,0 @@ -/* 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 <glib-object.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include "uca-plugin-manager.h" -#include "uca-camera.h" - -static UcaCamera *camera = NULL; - -typedef struct { - guint roi_width; - guint roi_height; - guint counter; -} CallbackData; - -static void -sigint_handler(int signal) -{ - printf("Closing down libuca\n"); - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - exit(signal); -} - -static void -grab_callback(gpointer data, gpointer user_data) -{ - CallbackData *cbd = (CallbackData *) user_data; - gchar *filename = g_strdup_printf("frame-%04i.raw", cbd->counter++); - FILE *fp = fopen(filename, "wb"); - - fwrite(data, sizeof(guint16), cbd->roi_width * cbd->roi_height, fp); - g_print("."); - fclose(fp); - g_free(filename); -} - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -int -main(int argc, char *argv[]) -{ - CallbackData cbd; - guint sensor_width, sensor_height; - gchar *name; - UcaPluginManager *manager; - GError *error = NULL; - (void) signal(SIGINT, sigint_handler); - - g_type_init(); - - if (argc < 2) { - print_usage(); - return 1; - } - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); - - if (camera == NULL) { - g_print("Error during initialization: %s\n", error->message); - return 1; - } - - g_object_get(G_OBJECT(camera), - "name", &name, - "sensor-width", &sensor_width, - "sensor-height", &sensor_height, - NULL); - - g_object_set(G_OBJECT(camera), - "roi-x0", 0, - "roi-y0", 0, - "roi-width", sensor_width, - "roi-height", sensor_height, - "transfer-asynchronously", TRUE, - NULL); - - g_object_get(G_OBJECT(camera), - "roi-width", &cbd.roi_width, - "roi-height", &cbd.roi_height, - NULL); - - g_print("Camera: %s\n", name); - g_free(name); - - g_print("Start asynchronous recording\n"); - cbd.counter = 0; - uca_camera_set_grab_func(camera, grab_callback, &cbd); - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - g_usleep(2 * G_USEC_PER_SEC); - - g_print(" done\n"); - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - - return error != NULL ? 1 : 0; -} diff --git a/test/grab.c b/test/grab.c deleted file mode 100644 index e507d69..0000000 --- a/test/grab.c +++ /dev/null @@ -1,160 +0,0 @@ -/* 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 <glib-object.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include "uca-plugin-manager.h" -#include "uca-camera.h" - -static UcaCamera *camera = NULL; - -static void sigint_handler(int signal) -{ - printf("Closing down libuca\n"); - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - exit(signal); -} - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -int main(int argc, char *argv[]) -{ - UcaPluginManager *manager; - GError *error = NULL; - (void) signal(SIGINT, sigint_handler); - - guint sensor_width, sensor_height; - guint roi_width, roi_height, roi_x, roi_y, roi_width_multiplier, roi_height_multiplier; - guint bits; - gchar *name; - - g_type_init(); - - if (argc < 2) { - print_usage(); - return 1; - } - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); - - if (camera == NULL) { - g_print("Error during initialization: %s\n", error->message); - return 1; - } - - g_object_get(G_OBJECT(camera), - "sensor-width", &sensor_width, - "sensor-height", &sensor_height, - "name", &name, - NULL); - - g_object_set(G_OBJECT(camera), - "exposure-time", 0.001, - "roi-x0", 0, - "roi-y0", 0, - "roi-width", 1000, - "roi-height", sensor_height, - NULL); - - g_object_get(G_OBJECT(camera), - "roi-width", &roi_width, - "roi-height", &roi_height, - "roi-width-multiplier", &roi_width_multiplier, - "roi-height-multiplier", &roi_height_multiplier, - "roi-x0", &roi_x, - "roi-y0", &roi_y, - "sensor-bitdepth", &bits, - NULL); - - g_print("Camera: %s\n", name); - g_free(name); - - g_print("Sensor: %ix%i px\n", sensor_width, sensor_height); - g_print("ROI: %ix%i @ (%i, %i), steps: %i, %i\n", - roi_width, roi_height, roi_x, roi_y, roi_width_multiplier, roi_height_multiplier); - - const int pixel_size = bits == 8 ? 1 : 2; - gpointer buffer = g_malloc0(roi_width * roi_height * pixel_size); - gchar filename[FILENAME_MAX]; - GTimer *timer = g_timer_new(); - - for (int i = 0; i < 1; i++) { - gint counter = 0; - g_print("Start recording\n"); - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - - while (counter < 5) { - g_print(" grab frame ... "); - g_timer_start(timer); - uca_camera_grab(camera, &buffer, &error); - - if (error != NULL) { - g_print("\nError: %s\n", error->message); - goto cleanup; - } - - g_timer_stop(timer); - g_print("done (took %3.5fs)\n", g_timer_elapsed(timer, NULL)); - - snprintf(filename, FILENAME_MAX, "frame-%08i.raw", counter++); - FILE *fp = fopen(filename, "wb"); - fwrite(buffer, roi_width * roi_height, pixel_size, fp); - fclose(fp); - g_usleep(2 * G_USEC_PER_SEC); - } - - g_print("Stop recording\n"); - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); - } - - g_timer_destroy(timer); - -cleanup: - uca_camera_stop_recording(camera, NULL); - g_object_unref(camera); - g_free(buffer); - - return error != NULL ? 1 : 0; -} diff --git a/test/perf-overhead.c b/test/perf-overhead.c deleted file mode 100644 index f8bdcbd..0000000 --- a/test/perf-overhead.c +++ /dev/null @@ -1,181 +0,0 @@ -/* 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 <glib-object.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "uca-plugin-manager.h" -#include "uca-camera.h" - -#define handle_error(errno) {if ((errno) != UCA_NO_ERROR) printf("error at <%s:%i>\n", \ - __FILE__, __LINE__);} - -typedef struct { - guint counter; - gsize size; - gpointer destination; -} thread_data; - -static UcaCamera *camera = NULL; - -static void -sigint_handler (int signal) -{ - printf ("Closing down libuca\n"); - uca_camera_stop_recording (camera, NULL); - g_object_unref (camera); - exit (signal); -} - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -static void -test_synchronous_operation (UcaCamera *camera) -{ - GError *error = NULL; - guint width, height, bits; - g_object_get (G_OBJECT (camera), - "sensor-width", &width, - "sensor-height", &height, - "sensor-bitdepth", &bits, - NULL); - - const int pixel_size = bits == 8 ? 1 : 2; - const gsize size = width * height * pixel_size; - const guint n_trials = 10000; - gpointer buffer = g_malloc0(size); - - uca_camera_start_recording (camera, &error); - GTimer *timer = g_timer_new (); - - for (guint n = 0; n < n_trials; n++) - uca_camera_grab (camera, &buffer, &error); - - gdouble total_time = g_timer_elapsed (timer, NULL); - g_timer_stop (timer); - - g_print ("Synchronous data transfer\n"); - g_print (" Bandwidth: %3.2f MB/s\n", size * n_trials / 1024. / 1024. / total_time); - g_print (" Throughput: %3.2f frames/s\n", n_trials / total_time); - - uca_camera_stop_recording (camera, &error); - g_free (buffer); - g_timer_destroy (timer); -} - -static void -grab_func (gpointer data, gpointer user_data) -{ - static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - - thread_data *d = (thread_data *) user_data; - g_memmove (d->destination, data, d->size); - g_static_mutex_lock (&mutex); - d->counter++; - g_static_mutex_unlock (&mutex); -} - -static void -test_asynchronous_operation (UcaCamera *camera) -{ - GError *error = NULL; - guint width, height, bits; - - g_object_get (G_OBJECT (camera), - "sensor-width", &width, - "sensor-height", &height, - "sensor-bitdepth", &bits, - NULL); - - const guint pixel_size = bits == 8 ? 1 : 2; - - thread_data d = { - .counter = 0, - .size = width * height * pixel_size, - .destination = g_malloc0(width * height * pixel_size) - }; - - g_object_set (G_OBJECT (camera), - "transfer-asynchronously", TRUE, - NULL); - - uca_camera_set_grab_func (camera, &grab_func, &d); - uca_camera_start_recording (camera, &error); - g_usleep (G_USEC_PER_SEC); - uca_camera_stop_recording (camera, &error); - - g_print ("Asynchronous data transfer\n"); - g_print (" Bandwidth: %3.2f MB/s\n", d.size * d.counter / 1024. / 1024.); - g_print (" Throughput: %i frames/s\n", d.counter); - - g_free (d.destination); -} - -int -main (int argc, char *argv[]) -{ - UcaPluginManager *manager; - GError *error = NULL; - (void) signal (SIGINT, sigint_handler); - - g_type_init (); - if (argc < 2) { - print_usage (); - return 1; - } - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); - - if (camera == NULL) { - g_print ("Error during initialization: %s\n", error->message); - return 1; - } - - test_synchronous_operation (camera); - g_print ("\n"); - test_asynchronous_operation (camera); - - g_object_unref (camera); - g_object_unref (manager); - - return error != NULL ? 1 : 0; -} diff --git a/test/test-all.c b/test/test-all.c deleted file mode 100644 index 9526d4f..0000000 --- a/test/test-all.c +++ /dev/null @@ -1,214 +0,0 @@ - -#include <glib.h> -#include "uca-camera.h" -#include "cameras/uca-mock-camera.h" - -typedef struct { - UcaCamera *camera; -} Fixture; - -typedef void (*UcaFixtureFunc) (Fixture *fixture, gconstpointer data); - -static void fixture_setup(Fixture *fixture, gconstpointer data) -{ - const gchar *type = (gchar *) data; - GError *error = NULL; - fixture->camera = uca_camera_new(type, &error); - g_assert_no_error(error); - g_assert(fixture->camera); -} - -static void fixture_teardown(Fixture *fixture, gconstpointer data) -{ - g_object_unref(fixture->camera); -} - -static void on_property_change(gpointer instance, GParamSpec *pspec, gpointer user_data) -{ - gboolean *success = (gboolean *) user_data; - *success = TRUE; -} - -static void test_factory() -{ - GError *error = NULL; - UcaCamera *camera = uca_camera_new("fox994m3a0yxmy", &error); - g_assert_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_FOUND); - g_assert(camera == NULL); -} - -static void test_recording(Fixture *fixture, gconstpointer data) -{ - GError *error = NULL; - UcaCamera *camera = UCA_CAMERA(fixture->camera); - - uca_camera_stop_recording(camera, &error); - g_assert_error(error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_NOT_RECORDING); - g_error_free(error); - - error = NULL; - gboolean success = FALSE; - g_signal_connect(G_OBJECT(camera), "notify::is-recording", - (GCallback) on_property_change, &success); - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - g_assert(success == TRUE); - - success = FALSE; - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); - g_assert(success == TRUE); -} - -static void grab_func(gpointer data, gpointer user_data) -{ - gboolean *success = (gboolean *) user_data; - *success = TRUE; -} - -static void test_recording_async(Fixture *fixture, gconstpointer data) -{ - UcaCamera *camera = UCA_CAMERA(fixture->camera); - - gboolean success = FALSE; - uca_camera_set_grab_func(camera, grab_func, &success); - - gfloat max_frame_rate = 1.0f; - g_object_get(G_OBJECT(camera), - "sensor-max-frame-rate", &max_frame_rate, - NULL); - g_assert(max_frame_rate != 0.0f); - - g_object_set(G_OBJECT(camera), - "transfer-asynchronously", TRUE, - NULL); - - GError *error = NULL; - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - - const gulong sleep_time = G_USEC_PER_SEC / ((gulong) (max_frame_rate / 2.0f)); - g_usleep(sleep_time); - - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); - g_assert(success == TRUE); -} - -static void test_recording_grab(Fixture *fixture, gconstpointer data) -{ - UcaCamera *camera = UCA_CAMERA(fixture->camera); - GError *error = NULL; - gpointer frame = NULL; - - uca_camera_start_recording(camera, &error); - g_assert_no_error(error); - - uca_camera_grab(camera, &frame, &error); - g_assert_no_error(error); - g_assert(frame != NULL); - - uca_camera_stop_recording(camera, &error); - g_assert_no_error(error); -} - -static void test_recording_property(Fixture *fixture, gconstpointer data) -{ - UcaCamera *camera = UCA_CAMERA(fixture->camera); - - gboolean is_recording = FALSE; - uca_camera_start_recording(camera, NULL); - g_object_get(G_OBJECT(camera), - "is-recording", &is_recording, - NULL); - g_assert(is_recording == TRUE); - - uca_camera_stop_recording(camera, NULL); - g_object_get(G_OBJECT(camera), - "is-recording", &is_recording, - NULL); - g_assert(is_recording == FALSE); -} - -static void test_base_properties(Fixture *fixture, gconstpointer data) -{ - UcaCamera *camera = UCA_CAMERA(fixture->camera); - guint n_properties = 0; - GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(camera), &n_properties); - GValue val = {0}; - - for (guint i = 0; i < n_properties; i++) { - g_value_init(&val, properties[i]->value_type); - g_object_get_property(G_OBJECT(camera), properties[i]->name, &val); - g_value_unset(&val); - } - - g_free(properties); -} - -static void test_binnings_properties(Fixture *fixture, gconstpointer data) -{ - UcaCamera *camera = UCA_CAMERA(fixture->camera); - - GValueArray *array = NULL; - g_object_get(G_OBJECT(camera), - "sensor-horizontal-binnings", &array, - NULL); - - GValue *value = g_value_array_get_nth(array, 0); - g_assert(value != NULL); - g_assert(g_value_get_uint(value) == 1); -} - - -int main(int argc, char *argv[]) -{ - g_type_init(); - g_test_init(&argc, &argv, NULL); - g_test_bug_base("http://ufo.kit.edu/ufo/ticket"); - - g_test_add_func("/factory", test_factory); - - gchar **types = NULL; - types = argc > 1 ? argv + 1 : uca_camera_get_types(); - - /* - * paths and test_funcs MUST correspond! - */ - static const gchar *paths[] = { - "/recording", - "/recording/grab", - "/recording/asynchronous", - "/properties/base", - "/properties/recording", - "/properties/binnings", - NULL - }; - - static UcaFixtureFunc test_funcs[] = { - test_recording, - test_recording_grab, - test_recording_async, - test_base_properties, - test_recording_property, - test_binnings_properties, - }; - - for (guint i = 0; i < g_strv_length(types); i++) { - guint j = 0; - - while (paths[j] != NULL) { - gchar *new_path = g_strdup_printf("/%s%s", types[i], paths[j]); - g_test_add(new_path, Fixture, types[i], fixture_setup, test_funcs[j], fixture_teardown); - g_free(new_path); - j++; - } - } - - gint result = g_test_run(); - - if (argc == 1) - g_strfreev(types); - - return result; -} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 957fdbf..0e4d28e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -16,9 +16,21 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../src ) +set(libs uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) + add_executable(gen-doc gen-doc.c) +target_link_libraries(gen-doc ${libs}) -target_link_libraries(gen-doc uca - ${GLIB2_LIBRARIES} - ${GOBJECT2_LIBRARIES} - ) +add_executable(grab grab.c) +target_link_libraries(grab ${libs}) + +add_executable(grab-async grab-async.c) +target_link_libraries(grab-async ${libs}) + +add_executable(benchmark benchmark.c) +target_link_libraries(benchmark ${libs}) + +add_executable(perf perf-overhead.c) +target_link_libraries(perf ${libs}) + +add_subdirectory(gui) diff --git a/tools/benchmark.c b/tools/benchmark.c new file mode 100644 index 0000000..ef99fd1 --- /dev/null +++ b/tools/benchmark.c @@ -0,0 +1,267 @@ +/* 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 <glib-object.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include "uca-camera.h" +#include "uca-plugin-manager.h" + +typedef void (*GrabFrameFunc) (UcaCamera *camera, gpointer buffer, guint n_frames); + +static UcaCamera *camera = NULL; + +static void +sigint_handler(int signal) +{ + g_print ("Closing down libuca\n"); + uca_camera_stop_recording (camera, NULL); + g_object_unref (camera); + exit (signal); +} + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static void +log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user) +{ + gsize n_written; + GError *error = NULL; + GIOChannel *channel = user; + +#if GLIB_CHECK_VERSION(2, 26, 0) + GTimeZone *tz; + GDateTime *date_time; + gchar *new_message; + + tz = g_time_zone_new_local (); + date_time = g_date_time_new_now (tz); + + new_message = g_strdup_printf ("[%s] %s\n", + g_date_time_format (date_time, "%FT%H:%M:%S%z"), message); + + g_time_zone_unref (tz); + g_date_time_unref (date_time); + + g_io_channel_write_chars (channel, new_message, strlen (new_message), &n_written, &error); + g_assert_no_error (error); + g_free (new_message); +#else + g_io_channel_write_chars (channel, message, strlen (message), &n_written, &error); + g_assert_no_error (error); +#endif + + g_io_channel_flush (channel, &error); + g_assert_no_error (error); +} + +static void +grab_frames_sync (UcaCamera *camera, gpointer buffer, guint n_frames) +{ + GError *error = NULL; + + uca_camera_start_recording (camera, &error); + + for (guint i = 0; i < n_frames; i++) { + uca_camera_grab(camera, &buffer, &error); + + if (error != NULL) { + g_warning ("Error grabbing frame %02i/%i: `%s'", i, n_frames, error->message); + g_error_free (error); + error = NULL; + } + } + + uca_camera_stop_recording (camera, &error); +} + +static void +grab_callback (gpointer data, gpointer user_data) +{ + guint *n_acquired_frames = user_data; + *n_acquired_frames += 1; +} + +static void +grab_frames_async (UcaCamera *camera, gpointer buffer, guint n_frames) +{ + GError *error = NULL; + guint n_acquired_frames = 0; + + uca_camera_set_grab_func (camera, grab_callback, &n_acquired_frames); + uca_camera_start_recording (camera, &error); + + /* + * Behold! Spinlooping is probably a bad idea but nowadays single core + * machines are relatively rare. + */ + while (n_acquired_frames < n_frames) + ; + + uca_camera_stop_recording (camera, &error); + +} + +static void +benchmark_method (UcaCamera *camera, gpointer buffer, GrabFrameFunc func, guint n_runs, guint n_frames, guint n_bytes) +{ + GTimer *timer; + gdouble fps; + gdouble bandwidth; + gdouble total_time = 0.0; + GError *error = NULL; + + g_print ("%-10i%-10i", n_frames, n_runs); + timer = g_timer_new (); + g_assert_no_error (error); + + for (guint run = 0; run < n_runs; run++) { + g_message ("Start run %i of %i", run, n_runs); + g_timer_start (timer); + + func (camera, buffer, n_frames); + + g_timer_stop (timer); + total_time += g_timer_elapsed (timer, NULL); + } + + g_assert_no_error (error); + + fps = n_runs * n_frames / total_time; + bandwidth = n_bytes * fps / 1024 / 1024; + g_print ("%-16.2f%-16.2f\n", fps, bandwidth); + + g_timer_destroy (timer); +} + +static void +benchmark (UcaCamera *camera) +{ + const guint n_runs = 3; + const guint n_frames = 100; + + guint sensor_width; + guint sensor_height; + guint roi_width; + guint roi_height; + guint bits; + guint n_bytes_per_pixel; + guint n_bytes; + gdouble exposure = 0.00001; + gpointer buffer; + + g_object_set (G_OBJECT (camera), + "exposure-time", exposure, + NULL); + + g_object_get (G_OBJECT (camera), + "sensor-width", &sensor_width, + "sensor-height", &sensor_height, + "sensor-bitdepth", &bits, + "roi-width", &roi_width, + "roi-height", &roi_height, + "exposure-time", &exposure, + NULL); + + g_print ("# --- General information ---\n"); + g_print ("# Sensor size: %ix%i\n", sensor_width, sensor_height); + g_print ("# ROI size: %ix%i\n", roi_width, roi_height); + g_print ("# Exposure time: %fs\n", exposure); + + /* Synchronous frame acquisition */ + g_print ("# %-10s%-10s%-10s%-16s%-16s\n", "type", "n_frames", "n_runs", "frames/s", "MiB/s"); + g_print (" %-10s", "sync"); + + g_message ("Start synchronous benchmark"); + + n_bytes_per_pixel = bits > 8 ? 2 : 1; + n_bytes = roi_width * roi_height * n_bytes_per_pixel; + buffer = g_malloc0(n_bytes); + + benchmark_method (camera, buffer, grab_frames_sync, n_runs, n_frames, n_bytes); + + /* Asynchronous frame acquisition */ + g_object_set (G_OBJECT(camera), + "transfer-asynchronously", TRUE, + NULL); + + g_message ("Start asynchronous benchmark"); + g_print (" %-10s", "async"); + + benchmark_method (camera, buffer, grab_frames_async, n_runs, n_frames, n_bytes); + + g_free (buffer); +} + +int +main (int argc, char *argv[]) +{ + UcaPluginManager *manager; + GIOChannel *log_channel; + GError *error = NULL; + + (void) signal (SIGINT, sigint_handler); + g_type_init(); + + if (argc < 2) { + print_usage(); + return 1; + } + + log_channel = g_io_channel_new_file ("error.log", "a+", &error); + g_assert_no_error (error); + g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + + if (camera == NULL) { + g_error ("Initialization: %s", error->message); + return 1; + } + + benchmark (camera); + + g_object_unref (camera); + g_io_channel_shutdown (log_channel, TRUE, &error); + g_assert_no_error (error); + + return 0; +} diff --git a/tools/grab-async.c b/tools/grab-async.c new file mode 100644 index 0000000..6132829 --- /dev/null +++ b/tools/grab-async.c @@ -0,0 +1,138 @@ +/* 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 <glib-object.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include "uca-plugin-manager.h" +#include "uca-camera.h" + +static UcaCamera *camera = NULL; + +typedef struct { + guint roi_width; + guint roi_height; + guint counter; +} CallbackData; + +static void +sigint_handler(int signal) +{ + printf("Closing down libuca\n"); + uca_camera_stop_recording(camera, NULL); + g_object_unref(camera); + exit(signal); +} + +static void +grab_callback(gpointer data, gpointer user_data) +{ + CallbackData *cbd = (CallbackData *) user_data; + gchar *filename = g_strdup_printf("frame-%04i.raw", cbd->counter++); + FILE *fp = fopen(filename, "wb"); + + fwrite(data, sizeof(guint16), cbd->roi_width * cbd->roi_height, fp); + g_print("."); + fclose(fp); + g_free(filename); +} + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +int +main(int argc, char *argv[]) +{ + CallbackData cbd; + guint sensor_width, sensor_height; + gchar *name; + UcaPluginManager *manager; + GError *error = NULL; + (void) signal(SIGINT, sigint_handler); + + g_type_init(); + + if (argc < 2) { + print_usage(); + return 1; + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + + if (camera == NULL) { + g_print("Error during initialization: %s\n", error->message); + return 1; + } + + g_object_get(G_OBJECT(camera), + "name", &name, + "sensor-width", &sensor_width, + "sensor-height", &sensor_height, + NULL); + + g_object_set(G_OBJECT(camera), + "roi-x0", 0, + "roi-y0", 0, + "roi-width", sensor_width, + "roi-height", sensor_height, + "transfer-asynchronously", TRUE, + NULL); + + g_object_get(G_OBJECT(camera), + "roi-width", &cbd.roi_width, + "roi-height", &cbd.roi_height, + NULL); + + g_print("Camera: %s\n", name); + g_free(name); + + g_print("Start asynchronous recording\n"); + cbd.counter = 0; + uca_camera_set_grab_func(camera, grab_callback, &cbd); + uca_camera_start_recording(camera, &error); + g_assert_no_error(error); + g_usleep(2 * G_USEC_PER_SEC); + + g_print(" done\n"); + uca_camera_stop_recording(camera, NULL); + g_object_unref(camera); + + return error != NULL ? 1 : 0; +} diff --git a/tools/grab.c b/tools/grab.c new file mode 100644 index 0000000..1f5c917 --- /dev/null +++ b/tools/grab.c @@ -0,0 +1,160 @@ +/* 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 <glib-object.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include "uca-plugin-manager.h" +#include "uca-camera.h" + +static UcaCamera *camera = NULL; + +static void sigint_handler(int signal) +{ + printf("Closing down libuca\n"); + uca_camera_stop_recording(camera, NULL); + g_object_unref(camera); + exit(signal); +} + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +int main(int argc, char *argv[]) +{ + UcaPluginManager *manager; + GError *error = NULL; + (void) signal(SIGINT, sigint_handler); + + guint sensor_width, sensor_height; + guint roi_width, roi_height, roi_x, roi_y, roi_width_multiplier, roi_height_multiplier; + guint bits; + gchar *name; + + g_type_init(); + + if (argc < 2) { + print_usage(); + return 1; + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + + if (camera == NULL) { + g_print("Error during initialization: %s\n", error->message); + return 1; + } + + g_object_get(G_OBJECT(camera), + "sensor-width", &sensor_width, + "sensor-height", &sensor_height, + "name", &name, + NULL); + + g_object_set(G_OBJECT(camera), + "exposure-time", 0.001, + "roi-x0", 0, + "roi-y0", 0, + "roi-width", 1000, + "roi-height", sensor_height, + NULL); + + g_object_get(G_OBJECT(camera), + "roi-width", &roi_width, + "roi-height", &roi_height, + "roi-width-multiplier", &roi_width_multiplier, + "roi-height-multiplier", &roi_height_multiplier, + "roi-x0", &roi_x, + "roi-y0", &roi_y, + "sensor-bitdepth", &bits, + NULL); + + g_print("Camera: %s\n", name); + g_free(name); + + g_print("Sensor: %ix%i px\n", sensor_width, sensor_height); + g_print("ROI: %ix%i @ (%i, %i), steps: %i, %i\n", + roi_width, roi_height, roi_x, roi_y, roi_width_multiplier, roi_height_multiplier); + + const int pixel_size = bits == 8 ? 1 : 2; + gpointer buffer = g_malloc0(roi_width * roi_height * pixel_size); + gchar filename[FILENAME_MAX]; + GTimer *timer = g_timer_new(); + + for (int i = 0; i < 1; i++) { + gint counter = 0; + g_print("Start recording\n"); + uca_camera_start_recording(camera, &error); + g_assert_no_error(error); + + while (counter < 5) { + g_print(" grab frame ... "); + g_timer_start(timer); + uca_camera_grab(camera, &buffer, &error); + + if (error != NULL) { + g_print("\nError: %s\n", error->message); + goto cleanup; + } + + g_timer_stop(timer); + g_print("done (took %3.5fs)\n", g_timer_elapsed(timer, NULL)); + + snprintf(filename, FILENAME_MAX, "frame-%08i.raw", counter++); + FILE *fp = fopen(filename, "wb"); + fwrite(buffer, roi_width * roi_height, pixel_size, fp); + fclose(fp); + g_usleep(2 * G_USEC_PER_SEC); + } + + g_print("Stop recording\n"); + uca_camera_stop_recording(camera, &error); + g_assert_no_error(error); + } + + g_timer_destroy(timer); + +cleanup: + uca_camera_stop_recording(camera, NULL); + g_object_unref(camera); + g_free(buffer); + + return error != NULL ? 1 : 0; +} diff --git a/tools/gui/control.c b/tools/gui/control.c new file mode 100644 index 0000000..75b3cde --- /dev/null +++ b/tools/gui/control.c @@ -0,0 +1,350 @@ +/* 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 <glib/gprintf.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <gdk/gdkkeysyms.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> + +#include "config.h" +#include "uca-camera.h" +#include "uca-plugin-manager.h" +#include "egg-property-tree-view.h" + + +typedef struct { + gboolean running; + gboolean store; + + guchar *buffer, *pixels; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkTreeModel *property_model; + UcaCamera *camera; + + GtkStatusbar *statusbar; + guint statusbar_context_id; + + int timestamp; + int width; + int height; + int pixel_size; +} ThreadData; + +enum { + COLUMN_NAME = 0, + COLUMN_VALUE, + COLUMN_EDITABLE, + NUM_COLUMNS +}; + +static UcaPluginManager *plugin_manager; + +static void +convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + for (int i = 0, j = 0; i < width*height; i++) { + output[j++] = input[i]; + output[j++] = input[i]; + output[j++] = input[i]; + } +} + +static void +convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + guint16 *in = (guint16 *) input; + guint16 min = G_MAXUINT16, max = 0; + gfloat spread = 0.0f; + + for (int i = 0; i < width * height; i++) { + guint16 v = in[i]; + if (v < min) + min = v; + if (v > max) + max = v; + } + + spread = (gfloat) max - min; + + if (spread > 0.0f) { + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } + } +} + +static void * +grab_thread (void *args) +{ + ThreadData *data = (ThreadData *) args; + gchar filename[FILENAME_MAX] = {0,}; + gint counter = 0; + + while (data->running) { + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); + + if (data->store) { + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + FILE *fp = fopen (filename, "wb"); + fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); + fclose (fp); + } + + /* FIXME: We should actually check if this is really a new frame and + * just do nothing if it is an already displayed one. */ + if (data->pixel_size == 1) + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + else if (data->pixel_size == 2) { + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + } + + gdk_threads_enter (); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gdk_threads_leave (); + } + return NULL; +} + +gboolean +on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +void +on_destroy (GtkWidget *widget, gpointer data) +{ + ThreadData *td = (ThreadData *) data; + td->running = FALSE; + g_object_unref (td->camera); + gtk_main_quit (); +} + +static void +on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + + if (data->running) + return; + + GError *error = NULL; + data->running = TRUE; + + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + return; + } + + if (!g_thread_create (grab_thread, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + return; + } +} + +static void +on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->running = FALSE; + data->store = FALSE; + GError *error = NULL; + uca_camera_stop_recording (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop: %s\n", error->message); +} + +static void +on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->timestamp = (int) time (0); + data->store = TRUE; + GError *error = NULL; + + gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); + + if (data->running != TRUE) { + data->running = TRUE; + uca_camera_start_recording (data->camera, &error); + + if (!g_thread_create (grab_thread, data, FALSE, &error)) + g_printerr ("Failed to create thread: %s\n", error->message); + } +} + +static void +create_main_window (GtkBuilder *builder, const gchar* camera_name) +{ + static ThreadData td; + + GError *error = NULL; + UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); + + if ((camera == NULL) || (error != NULL)) { + g_error ("%s\n", error->message); + gtk_main_quit (); + } + + guint bits_per_sample; + g_object_get (camera, + "roi-width", &td.width, + "roi-height", &td.height, + "sensor-bitdepth", &bits_per_sample, + NULL); + + GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); + + gtk_container_add (scrolled_property_window, property_tree_view); + gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); + + GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + + td.pixel_size = bits_per_sample > 8 ? 2 : 1; + td.image = image; + td.pixbuf = pixbuf; + td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.pixels = gdk_pixbuf_get_pixels (pixbuf); + td.running = FALSE; + td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); + td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); + td.store = FALSE; + td.camera = camera; + td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); + + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), + "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), + "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), + "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); + + gtk_widget_show (image); + gtk_widget_show (window); +} + +static void +on_button_proceed_clicked (GtkWidget *widget, gpointer data) +{ + GtkBuilder *builder = GTK_BUILDER (data); + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); + GtkTreeIter iter; + + gtk_widget_destroy (choice_window); + gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), &iter, selected_rows->data); + + if (valid) { + gchar *data; + gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 0, &data, -1); + create_main_window (builder, data); + g_free (data); + } + + g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (selected_rows); +} + +static void +on_treeview_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + if (event->keyval == GDK_KEY_Return) + gtk_widget_grab_focus (GTK_WIDGET (data)); +} + +static void +create_choice_window (GtkBuilder *builder) +{ + GList *camera_types = uca_plugin_manager_get_available_cameras (plugin_manager); + + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); + GtkTreeIter iter; + + for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, 0, g_strdup ((gchar *) it->data), -1); + } + + gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); + + if (valid) { + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter)); + } + + g_signal_connect (proceed_button, "clicked", G_CALLBACK (on_button_proceed_clicked), builder); + g_signal_connect (treeview, "key-press-event", G_CALLBACK (on_treeview_keypress), proceed_button); + gtk_widget_show_all (GTK_WIDGET (choice_window)); + + g_list_foreach (camera_types, (GFunc) g_free, NULL); + g_list_free (camera_types); +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + + g_thread_init (NULL); + gdk_threads_init (); + gtk_init (&argc, &argv); + + GtkBuilder *builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { + g_print ("Error: %s\n", error->message); + return 1; + } + + plugin_manager = uca_plugin_manager_new (); + create_choice_window (builder); + gtk_builder_connect_signals (builder, NULL); + + gdk_threads_enter (); + gtk_main (); + gdk_threads_leave (); + + g_object_unref (plugin_manager); + return 0; +} diff --git a/tools/gui/control.glade b/tools/gui/control.glade new file mode 100644 index 0000000..d7ba2fc --- /dev/null +++ b/tools/gui/control.glade @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <requires lib="gtk+" version="2.20"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkListStore" id="camera-types"> + <columns> + <!-- column-name name --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkListStore" id="camera-properties"> + <columns> + <!-- column-name PropertyName --> + <column type="gchararray"/> + <!-- column-name PropertyValue --> + <column type="gchararray"/> + <!-- column-name writeable --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkWindow" id="window"> + <property name="title" translatable="yes">Camera Control</property> + <property name="default_width">1024</property> + <property name="default_height">768</property> + <signal name="delete_event" handler="on_delete_event"/> + <child> + <object class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <child> + <object class="GtkMenuBar" id="menubar1"> + <property name="visible">True</property> + <child> + <object class="GtkMenuItem" id="menuitem1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_file"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem1"> + <property name="label">gtk-new</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem2"> + <property name="label">gtk-open</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem3"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem4"> + <property name="label">gtk-save-as</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="separatormenuitem1"> + <property name="visible">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_quit"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="gtk_main_quit"/> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem4"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_help"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_about"> + <property name="label">gtk-about</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <child> + <object class="GtkToolButton" id="toolbutton_run"> + <property name="visible">True</property> + <property name="label" translatable="yes">Run</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-play</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="toolbutton_record"> + <property name="visible">True</property> + <property name="label" translatable="yes">Record</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-record</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="toolbutton_stop"> + <property name="visible">True</property> + <property name="label" translatable="yes">Stop</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-stop</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHPaned" id="hpaned1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">6</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="width_request">300</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="resize_mode">queue</property> + <child> + <object class="GtkImage" id="image"> + <property name="visible">True</property> + <property name="stock">gtk-missing-image</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkStatusbar" id="statusbar"> + <property name="visible">True</property> + <property name="spacing">2</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkAdjustment" id="adjustment_scale"> + <property name="value">65535</property> + <property name="lower">1</property> + <property name="upper">65535</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkWindow" id="choice-window"> + <property name="border_width">6</property> + <child> + <object class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <object class="GtkTreeView" id="treeview-cameras"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">camera-types</property> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <property name="title">Choose camera</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="spacing">6</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="button-cancel"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="gtk_main_quit"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button-proceed"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/tools/gui/egg-property-cell-renderer.c b/tools/gui/egg-property-cell-renderer.c new file mode 100644 index 0000000..9df5cc3 --- /dev/null +++ b/tools/gui/egg-property-cell-renderer.c @@ -0,0 +1,594 @@ +/* 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 <stdlib.h> +#include "egg-property-cell-renderer.h" + +G_DEFINE_TYPE (EggPropertyCellRenderer, egg_property_cell_renderer, GTK_TYPE_CELL_RENDERER) + +#define EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererPrivate)) + + +struct _EggPropertyCellRendererPrivate +{ + GObject *object; + GtkListStore *list_store; + GtkCellRenderer *renderer; + GtkCellRenderer *text_renderer; + GtkCellRenderer *spin_renderer; + GtkCellRenderer *toggle_renderer; + GtkCellRenderer *combo_renderer; + GHashTable *combo_models; +}; + +enum +{ + PROP_0, + PROP_PROP_NAME, + N_PROPERTIES +}; + +enum +{ + COMBO_COLUMN_VALUE_NAME, + COMBO_COLUMN_VALUE, + N_COMBO_COLUMNS +}; + +static GParamSpec *egg_property_cell_renderer_properties[N_PROPERTIES] = { NULL, }; + +GtkCellRenderer * +egg_property_cell_renderer_new (GObject *object, + GtkListStore *list_store) +{ + EggPropertyCellRenderer *renderer; + + renderer = EGG_PROPERTY_CELL_RENDERER (g_object_new (EGG_TYPE_PROPERTY_CELL_RENDERER, NULL)); + renderer->priv->object = object; + renderer->priv->list_store = list_store; + return GTK_CELL_RENDERER (renderer); +} + +static GParamSpec * +get_pspec_from_object (GObject *object, const gchar *prop_name) +{ + GObjectClass *oclass = G_OBJECT_GET_CLASS (object); + return g_object_class_find_property (oclass, prop_name); +} + +static void +get_string_double_repr (GObject *object, const gchar *prop_name, gchar **text, gdouble *number) +{ + GParamSpec *pspec; + GValue from = { 0 }; + GValue to_string = { 0 }; + GValue to_double = { 0 }; + + pspec = get_pspec_from_object (object, prop_name); + g_value_init (&from, pspec->value_type); + g_value_init (&to_string, G_TYPE_STRING); + g_value_init (&to_double, G_TYPE_DOUBLE); + g_object_get_property (object, prop_name, &from); + + if (g_value_transform (&from, &to_string)) + *text = g_strdup (g_value_get_string (&to_string)); + else + g_warning ("Could not convert from %s gchar*\n", g_type_name (pspec->value_type)); + + if (g_value_transform (&from, &to_double)) + *number = g_value_get_double (&to_double); + else + g_warning ("Could not convert from %s to gdouble\n", g_type_name (pspec->value_type)); +} + +static void +clear_adjustment (GObject *object) +{ + GtkAdjustment *adjustment; + + g_object_get (object, + "adjustment", &adjustment, + NULL); + + if (adjustment) + g_object_unref (adjustment); + + g_object_set (object, + "adjustment", NULL, + NULL); +} + +static void +egg_property_cell_renderer_set_renderer (EggPropertyCellRenderer *renderer, + const gchar *prop_name) +{ + EggPropertyCellRendererPrivate *priv; + GParamSpec *pspec; + gchar *text = NULL; + gdouble number; + + priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer); + pspec = get_pspec_from_object (priv->object, prop_name); + + /* + * Set this renderers mode, so that any actions can be forwarded to our + * child renderers. + */ + switch (pspec->value_type) { + /* toggle renderers */ + case G_TYPE_BOOLEAN: + priv->renderer = priv->toggle_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); + break; + + /* spin renderers */ + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + priv->renderer = priv->spin_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); + g_object_set (priv->renderer, "digits", 5, NULL); + break; + + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_INT64: + case G_TYPE_UINT64: + priv->renderer = priv->spin_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); + g_object_set (priv->renderer, "digits", 0, NULL); + break; + + /* text renderers */ + case G_TYPE_POINTER: + case G_TYPE_STRING: + priv->renderer = priv->text_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); + break; + + /* combo renderers */ + default: + if (G_TYPE_IS_ENUM (pspec->value_type)) { + priv->renderer = priv->combo_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); + } + break; + } + + /* + * Set the content from the objects property. + */ + switch (pspec->value_type) { + case G_TYPE_BOOLEAN: + { + gboolean val; + + g_object_get (priv->object, prop_name, &val, NULL); + g_object_set (priv->renderer, + "active", val, + "activatable", pspec->flags & G_PARAM_WRITABLE ? TRUE : FALSE, + NULL); + break; + } + + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_INT64: + case G_TYPE_UINT64: + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + get_string_double_repr (priv->object, prop_name, &text, &number); + break; + + case G_TYPE_STRING: + g_object_get (priv->object, prop_name, &text, NULL); + break; + + case G_TYPE_POINTER: + { + gpointer val; + + g_object_get (priv->object, prop_name, &val, NULL); + text = g_strdup_printf ("0x%x", GPOINTER_TO_INT (val)); + } + break; + + default: + if (G_TYPE_IS_ENUM (pspec->value_type)) { + GParamSpecEnum *pspec_enum; + GEnumClass *enum_class; + GtkTreeModel *combo_model; + GtkTreeIter iter; + gint value; + + g_object_get (priv->object, prop_name, &value, NULL); + + pspec_enum = G_PARAM_SPEC_ENUM (pspec); + enum_class = pspec_enum->enum_class; + combo_model = g_hash_table_lookup (priv->combo_models, prop_name); + + if (combo_model == NULL) { + combo_model = GTK_TREE_MODEL (gtk_list_store_new (N_COMBO_COLUMNS, G_TYPE_STRING, G_TYPE_INT)); + g_hash_table_insert (priv->combo_models, g_strdup (prop_name), combo_model); + + for (guint i = 0; i < enum_class->n_values; i++) { + gtk_list_store_append (GTK_LIST_STORE (combo_model), &iter); + gtk_list_store_set (GTK_LIST_STORE (combo_model), &iter, + COMBO_COLUMN_VALUE_NAME, enum_class->values[i].value_name, + COMBO_COLUMN_VALUE, enum_class->values[i].value, + -1); + } + } + + + for (guint i = 0; i < enum_class->n_values; i++) { + if (enum_class->values[i].value == value) + text = g_strdup (enum_class->values[i].value_name); + } + + g_object_set (priv->renderer, + "model", combo_model, + "text-column", 0, + NULL); + } + break; + } + + if (pspec->flags & G_PARAM_WRITABLE) { + if (GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer)) + g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); + else + g_object_set (priv->renderer, "foreground", "#000000", NULL); + + if (GTK_IS_CELL_RENDERER_TEXT (priv->renderer)) { + g_object_set (priv->renderer, + "editable", TRUE, + "mode", GTK_CELL_RENDERER_MODE_EDITABLE, + NULL); + } + + if (GTK_IS_CELL_RENDERER_SPIN (priv->renderer)) { + GtkObject *adjustment = NULL; + +#define gtk_typed_adjustment_new(type, pspec, val, step_inc, page_inc) \ + gtk_adjustment_new (val, ((type *) pspec)->minimum, ((type *) pspec)->maximum, step_inc, page_inc, 0) + + switch (pspec->value_type) { + case G_TYPE_INT: + adjustment = gtk_typed_adjustment_new (GParamSpecInt, pspec, number, 1, 10); + break; + case G_TYPE_UINT: + adjustment = gtk_typed_adjustment_new (GParamSpecUInt, pspec, number, 1, 10); + break; + case G_TYPE_LONG: + adjustment = gtk_typed_adjustment_new (GParamSpecLong, pspec, number, 1, 10); + break; + case G_TYPE_ULONG: + adjustment = gtk_typed_adjustment_new (GParamSpecULong, pspec, number, 1, 10); + break; + case G_TYPE_INT64: + adjustment = gtk_typed_adjustment_new (GParamSpecInt64, pspec, number, 1, 10); + break; + case G_TYPE_UINT64: + adjustment = gtk_typed_adjustment_new (GParamSpecUInt64, pspec, number, 1, 10); + break; + case G_TYPE_FLOAT: + adjustment = gtk_typed_adjustment_new (GParamSpecFloat, pspec, number, 0.05, 10); + break; + case G_TYPE_DOUBLE: + adjustment = gtk_typed_adjustment_new (GParamSpecDouble, pspec, number, 0.05, 10); + break; + } + + clear_adjustment (G_OBJECT (priv->renderer)); + g_object_set (priv->renderer, "adjustment", adjustment, NULL); + } + } + else { + g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); + + if (!GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer)) + g_object_set (priv->renderer, "foreground", "#aaaaaa", NULL); + } + + if (text != NULL) { + g_object_set (priv->renderer, "text", text, NULL); + g_free (text); + } +} + +static gchar * +get_prop_name_from_tree_model (GtkTreeModel *model, const gchar *path) +{ + GtkTreeIter iter; + gchar *prop_name = NULL; + + /* TODO: don't assume column 0 to contain the prop name */ + if (gtk_tree_model_get_iter_from_string (model, &iter, path)) + gtk_tree_model_get (model, &iter, 0, &prop_name, -1); + + return prop_name; +} + +static void +egg_property_cell_renderer_toggle_cb (GtkCellRendererToggle *renderer, + gchar *path, + gpointer user_data) +{ + EggPropertyCellRendererPrivate *priv; + gchar *prop_name; + + priv = (EggPropertyCellRendererPrivate *) user_data; + prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); + + if (prop_name != NULL) { + gboolean activated; + + g_object_get (priv->object, prop_name, &activated, NULL); + g_object_set (priv->object, prop_name, !activated, NULL); + g_free (prop_name); + } +} + +static void +egg_property_cell_renderer_text_edited_cb (GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + gpointer user_data) +{ + EggPropertyCellRendererPrivate *priv; + gchar *prop_name; + + priv = (EggPropertyCellRendererPrivate *) user_data; + prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); + + if (prop_name != NULL) { + g_object_set (priv->object, prop_name, new_text, NULL); + g_free (prop_name); + } +} + +static void +egg_property_cell_renderer_spin_edited_cb (GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + gpointer user_data) +{ + EggPropertyCellRendererPrivate *priv; + gchar *prop_name; + + priv = (EggPropertyCellRendererPrivate *) user_data; + prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); + + if (prop_name != NULL) { + GParamSpec *pspec; + GValue from = { 0 }; + GValue to = { 0 }; + + pspec = get_pspec_from_object (priv->object, prop_name); + + g_value_init (&from, G_TYPE_DOUBLE); + g_value_init (&to, pspec->value_type); + g_value_set_double (&from, strtod (new_text, NULL)); + + if (g_value_transform (&from, &to)) + g_object_set_property (priv->object, prop_name, &to); + else + g_warning ("Could not transform %s to %s\n", + g_value_get_string (&from), g_type_name (pspec->value_type)); + + g_free (prop_name); + } +} + +static void +egg_property_cell_renderer_changed_cb (GtkCellRendererCombo *combo, + gchar *path, + GtkTreeIter *new_iter, + gpointer user_data) +{ + EggPropertyCellRendererPrivate *priv; + gchar *prop_name; + + priv = (EggPropertyCellRendererPrivate *) user_data; + prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path); + + if (prop_name != NULL) { + GtkTreeModel *combo_model; + gchar *value_name; + gint value; + + combo_model = g_hash_table_lookup (priv->combo_models, prop_name); + + gtk_tree_model_get (combo_model, new_iter, + COMBO_COLUMN_VALUE_NAME, &value_name, + COMBO_COLUMN_VALUE, &value, + -1); + + g_object_set (priv->object, prop_name, value, NULL); + g_free (value_name); + g_free (prop_name); + } +} + +static void +egg_property_cell_renderer_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + + EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); + gtk_cell_renderer_get_size (priv->renderer, widget, cell_area, x_offset, y_offset, width, height); +} + +static void +egg_property_cell_renderer_render (GtkCellRenderer *cell, + GdkDrawable *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags) +{ + EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); + gtk_cell_renderer_render (priv->renderer, window, widget, background_area, cell_area, expose_area, flags); +} + +static gboolean +egg_property_cell_renderer_activate (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); + return gtk_cell_renderer_activate (priv->renderer, event, widget, path, background_area, cell_area, flags); +} + +static GtkCellEditable * +egg_property_cell_renderer_start_editing (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell); + return gtk_cell_renderer_start_editing (priv->renderer, event, widget, path, background_area, cell_area, flags); +} + +static void +egg_property_cell_renderer_dispose (GObject *object) +{ + EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object); + g_hash_table_destroy (renderer->priv->combo_models); +} + +static void +egg_property_cell_renderer_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object)); + EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object); + + switch (property_id) { + case PROP_PROP_NAME: + egg_property_cell_renderer_set_renderer (renderer, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_property_cell_renderer_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object)); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_property_cell_renderer_class_init (EggPropertyCellRendererClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkCellRendererClass *cellrenderer_class = GTK_CELL_RENDERER_CLASS (klass); + + gobject_class->set_property = egg_property_cell_renderer_set_property; + gobject_class->get_property = egg_property_cell_renderer_get_property; + gobject_class->dispose = egg_property_cell_renderer_dispose; + + cellrenderer_class->render = egg_property_cell_renderer_render; + cellrenderer_class->get_size = egg_property_cell_renderer_get_size; + cellrenderer_class->activate = egg_property_cell_renderer_activate; + cellrenderer_class->start_editing = egg_property_cell_renderer_start_editing; + + egg_property_cell_renderer_properties[PROP_PROP_NAME] = + g_param_spec_string("prop-name", + "Property name", "Property name", "", + G_PARAM_READWRITE); + + g_object_class_install_property(gobject_class, PROP_PROP_NAME, egg_property_cell_renderer_properties[PROP_PROP_NAME]); + + g_type_class_add_private (klass, sizeof (EggPropertyCellRendererPrivate)); +} + +static void +egg_property_cell_renderer_init (EggPropertyCellRenderer *renderer) +{ + EggPropertyCellRendererPrivate *priv; + + renderer->priv = priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer); + + priv->text_renderer = gtk_cell_renderer_text_new (); + priv->spin_renderer = gtk_cell_renderer_spin_new (); + priv->toggle_renderer = gtk_cell_renderer_toggle_new (); + priv->combo_renderer = gtk_cell_renderer_combo_new (); + priv->renderer = priv->text_renderer; + priv->combo_models = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + g_object_set (priv->text_renderer, + "editable", TRUE, + NULL); + + g_object_set (priv->spin_renderer, + "editable", TRUE, + NULL); + + g_object_set (priv->toggle_renderer, + "xalign", 0.0f, + "activatable", TRUE, + "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, + NULL); + + g_object_set (priv->combo_renderer, + "has-entry", FALSE, + NULL); + + g_signal_connect (priv->spin_renderer, "edited", + G_CALLBACK (egg_property_cell_renderer_spin_edited_cb), priv); + + g_signal_connect (priv->text_renderer, "edited", + G_CALLBACK (egg_property_cell_renderer_text_edited_cb), NULL); + + g_signal_connect (priv->toggle_renderer, "toggled", + G_CALLBACK (egg_property_cell_renderer_toggle_cb), priv); + + g_signal_connect (priv->combo_renderer, "changed", + G_CALLBACK (egg_property_cell_renderer_changed_cb), priv); +} diff --git a/tools/gui/egg-property-cell-renderer.h b/tools/gui/egg-property-cell-renderer.h new file mode 100644 index 0000000..d4dbe02 --- /dev/null +++ b/tools/gui/egg-property-cell-renderer.h @@ -0,0 +1,55 @@ +/* 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 EGG_PROPERTY_CELL_RENDERER_H +#define EGG_PROPERTY_CELL_RENDERER_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_PROPERTY_CELL_RENDERER (egg_property_cell_renderer_get_type()) +#define EGG_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRenderer)) +#define EGG_IS_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER)) +#define EGG_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass)) +#define EGG_IS_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_CELL_RENDERER)) +#define EGG_PROPERTY_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass)) + +typedef struct _EggPropertyCellRenderer EggPropertyCellRenderer; +typedef struct _EggPropertyCellRendererClass EggPropertyCellRendererClass; +typedef struct _EggPropertyCellRendererPrivate EggPropertyCellRendererPrivate; + +struct _EggPropertyCellRenderer +{ + GtkCellRenderer parent_instance; + + /*< private >*/ + EggPropertyCellRendererPrivate *priv; +}; + +struct _EggPropertyCellRendererClass +{ + GtkCellRendererClass parent_class; +}; + +GType egg_property_cell_renderer_get_type (void); +GtkCellRenderer* egg_property_cell_renderer_new (GObject *object, + GtkListStore *list_store); + +G_END_DECLS + +#endif diff --git a/tools/gui/egg-property-tree-view.c b/tools/gui/egg-property-tree-view.c new file mode 100644 index 0000000..52d1e10 --- /dev/null +++ b/tools/gui/egg-property-tree-view.c @@ -0,0 +1,113 @@ +/* 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 "egg-property-tree-view.h" +#include "egg-property-cell-renderer.h" + +G_DEFINE_TYPE (EggPropertyTreeView, egg_property_tree_view, GTK_TYPE_TREE_VIEW) + +#define EGG_PROPERTY_TREE_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewPrivate)) + +struct _EggPropertyTreeViewPrivate +{ + GtkListStore *list_store; +}; + +enum +{ + COLUMN_PROP_NAME, + COLUMN_PROP_ROW, + COLUMN_PROP_ADJUSTMENT, + N_COLUMNS +}; + +static void +egg_property_tree_view_populate_model_with_properties (GtkListStore *model, GObject *object) +{ + GParamSpec **pspecs; + GObjectClass *oclass; + guint n_properties; + GtkTreeIter iter; + + oclass = G_OBJECT_GET_CLASS (object); + pspecs = g_object_class_list_properties (oclass, &n_properties); + + for (guint i = 0; i < n_properties; i++) { + if (pspecs[i]->flags & G_PARAM_READABLE) { + GtkObject *adjustment; + + adjustment = gtk_adjustment_new (5, 0, 1000, 1, 10, 0); + + gtk_list_store_append (model, &iter); + gtk_list_store_set (model, &iter, + COLUMN_PROP_NAME, pspecs[i]->name, + COLUMN_PROP_ROW, FALSE, + COLUMN_PROP_ADJUSTMENT, adjustment, + -1); + } + } + + g_free (pspecs); +} + +GtkWidget * +egg_property_tree_view_new (GObject *object) +{ + EggPropertyTreeView *property_tree_view; + GtkTreeView *tree_view; + GtkTreeViewColumn *prop_column, *value_column; + GtkCellRenderer *prop_renderer, *value_renderer; + GtkListStore *list_store; + + property_tree_view = EGG_PROPERTY_TREE_VIEW (g_object_new (EGG_TYPE_PROPERTY_TREE_VIEW, NULL)); + list_store = property_tree_view->priv->list_store; + tree_view = GTK_TREE_VIEW (property_tree_view); + + egg_property_tree_view_populate_model_with_properties (list_store, object); + gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store)); + + prop_renderer = gtk_cell_renderer_text_new (); + prop_column = gtk_tree_view_column_new_with_attributes ("Property", prop_renderer, + "text", COLUMN_PROP_NAME, + NULL); + + value_renderer = egg_property_cell_renderer_new (object, list_store); + value_column = gtk_tree_view_column_new_with_attributes ("Value", value_renderer, + "prop-name", COLUMN_PROP_NAME, + NULL); + + gtk_tree_view_append_column (tree_view, prop_column); + gtk_tree_view_append_column (tree_view, value_column); + + return GTK_WIDGET (tree_view); +} + +static void +egg_property_tree_view_class_init (EggPropertyTreeViewClass *klass) +{ + g_type_class_add_private (klass, sizeof (EggPropertyTreeViewPrivate)); +} + +static void +egg_property_tree_view_init (EggPropertyTreeView *tree_view) +{ + EggPropertyTreeViewPrivate *priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view); + + tree_view->priv = priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view); + priv->list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, GTK_TYPE_ADJUSTMENT); +} diff --git a/tools/gui/egg-property-tree-view.h b/tools/gui/egg-property-tree-view.h new file mode 100644 index 0000000..e8fd0fe --- /dev/null +++ b/tools/gui/egg-property-tree-view.h @@ -0,0 +1,54 @@ +/* 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 EGG_PROPERTY_TREE_VIEW_H +#define EGG_PROPERTY_TREE_VIEW_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_PROPERTY_TREE_VIEW (egg_property_tree_view_get_type()) +#define EGG_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeView)) +#define EGG_IS_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_TREE_VIEW)) +#define EGG_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass)) +#define EGG_IS_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_TREE_VIEW)) +#define EGG_PROPERTY_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass)) + +typedef struct _EggPropertyTreeView EggPropertyTreeView; +typedef struct _EggPropertyTreeViewClass EggPropertyTreeViewClass; +typedef struct _EggPropertyTreeViewPrivate EggPropertyTreeViewPrivate; + +struct _EggPropertyTreeView +{ + GtkTreeView parent_instance; + + /*< private >*/ + EggPropertyTreeViewPrivate *priv; +}; + +struct _EggPropertyTreeViewClass +{ + GtkTreeViewClass parent_class; +}; + +GType egg_property_tree_view_get_type (void) G_GNUC_CONST; +GtkWidget* egg_property_tree_view_new (GObject *object); + +G_END_DECLS + +#endif diff --git a/tools/perf-overhead.c b/tools/perf-overhead.c new file mode 100644 index 0000000..f8bdcbd --- /dev/null +++ b/tools/perf-overhead.c @@ -0,0 +1,181 @@ +/* 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 <glib-object.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "uca-plugin-manager.h" +#include "uca-camera.h" + +#define handle_error(errno) {if ((errno) != UCA_NO_ERROR) printf("error at <%s:%i>\n", \ + __FILE__, __LINE__);} + +typedef struct { + guint counter; + gsize size; + gpointer destination; +} thread_data; + +static UcaCamera *camera = NULL; + +static void +sigint_handler (int signal) +{ + printf ("Closing down libuca\n"); + uca_camera_stop_recording (camera, NULL); + g_object_unref (camera); + exit (signal); +} + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static void +test_synchronous_operation (UcaCamera *camera) +{ + GError *error = NULL; + guint width, height, bits; + g_object_get (G_OBJECT (camera), + "sensor-width", &width, + "sensor-height", &height, + "sensor-bitdepth", &bits, + NULL); + + const int pixel_size = bits == 8 ? 1 : 2; + const gsize size = width * height * pixel_size; + const guint n_trials = 10000; + gpointer buffer = g_malloc0(size); + + uca_camera_start_recording (camera, &error); + GTimer *timer = g_timer_new (); + + for (guint n = 0; n < n_trials; n++) + uca_camera_grab (camera, &buffer, &error); + + gdouble total_time = g_timer_elapsed (timer, NULL); + g_timer_stop (timer); + + g_print ("Synchronous data transfer\n"); + g_print (" Bandwidth: %3.2f MB/s\n", size * n_trials / 1024. / 1024. / total_time); + g_print (" Throughput: %3.2f frames/s\n", n_trials / total_time); + + uca_camera_stop_recording (camera, &error); + g_free (buffer); + g_timer_destroy (timer); +} + +static void +grab_func (gpointer data, gpointer user_data) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + thread_data *d = (thread_data *) user_data; + g_memmove (d->destination, data, d->size); + g_static_mutex_lock (&mutex); + d->counter++; + g_static_mutex_unlock (&mutex); +} + +static void +test_asynchronous_operation (UcaCamera *camera) +{ + GError *error = NULL; + guint width, height, bits; + + g_object_get (G_OBJECT (camera), + "sensor-width", &width, + "sensor-height", &height, + "sensor-bitdepth", &bits, + NULL); + + const guint pixel_size = bits == 8 ? 1 : 2; + + thread_data d = { + .counter = 0, + .size = width * height * pixel_size, + .destination = g_malloc0(width * height * pixel_size) + }; + + g_object_set (G_OBJECT (camera), + "transfer-asynchronously", TRUE, + NULL); + + uca_camera_set_grab_func (camera, &grab_func, &d); + uca_camera_start_recording (camera, &error); + g_usleep (G_USEC_PER_SEC); + uca_camera_stop_recording (camera, &error); + + g_print ("Asynchronous data transfer\n"); + g_print (" Bandwidth: %3.2f MB/s\n", d.size * d.counter / 1024. / 1024.); + g_print (" Throughput: %i frames/s\n", d.counter); + + g_free (d.destination); +} + +int +main (int argc, char *argv[]) +{ + UcaPluginManager *manager; + GError *error = NULL; + (void) signal (SIGINT, sigint_handler); + + g_type_init (); + if (argc < 2) { + print_usage (); + return 1; + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + + if (camera == NULL) { + g_print ("Error during initialization: %s\n", error->message); + return 1; + } + + test_synchronous_operation (camera); + g_print ("\n"); + test_asynchronous_operation (camera); + + g_object_unref (camera); + g_object_unref (manager); + + return error != NULL ? 1 : 0; +} -- cgit v1.2.3 From f92e2316665c75ed44f1c662cf7aa62fcbf6d419 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 25 Sep 2012 18:18:53 +0200 Subject: Add CMakeLists.txt for control GUI --- tools/gui/CMakeLists.txt | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tools/gui/CMakeLists.txt diff --git a/tools/gui/CMakeLists.txt b/tools/gui/CMakeLists.txt new file mode 100644 index 0000000..39afe98 --- /dev/null +++ b/tools/gui/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions("--std=c99 -Wall") + +# --- Find packages and libraries --------------------------------------------- +find_package(PkgConfig) + +pkg_check_modules(GTK2 gtk+-2.0>=2.22) +pkg_check_modules(GTHREAD2 gthread-2.0) +pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) +pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.glade ${CMAKE_CURRENT_BINARY_DIR}) + +# --- Build targets ----------------------------------------------------------- +include_directories( + ${GLIB2_INCLUDE_DIRS} + ${GOBJECT2_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR}/../../src/ + ${CMAKE_CURRENT_SOURCE_DIR}/../../src + ) + +if (GTK2_FOUND) + include_directories(${GTK2_INCLUDE_DIRS}) + + add_executable(control + control.c + egg-property-cell-renderer.c + egg-property-tree-view.c) + + target_link_libraries(control uca + ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) + + install(TARGETS control + RUNTIME DESTINATION bin) + + install(FILES control.glade + DESTINATION share/libuca) +endif() -- cgit v1.2.3 From b60398963a2072115675f732e7d38d99205e8c9a Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 26 Sep 2012 14:26:29 +0200 Subject: Add change log to manual --- docs/Makefile | 4 ++-- docs/manual.md | 3 +++ docs/update-changelog | 22 ++++++++++++++++++++++ docs/z-changes-1.0.md | 5 +++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100755 docs/update-changelog create mode 100644 docs/z-changes-1.0.md diff --git a/docs/Makefile b/docs/Makefile index 53dc6fd..83c1d01 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -11,10 +11,10 @@ clean: rm -f manual.pdf manual.html manual.pdf: manual.md - $(PANDOC) $(OPTS) manual.md -o manual.pdf + $(PANDOC) $(OPTS) manual.md z-changes-*.md -o manual.pdf manual.html: manual.md style.css - $(PANDOC) $(OPTS) manual.md -H webfonts.html -c style.css -o manual.html + $(PANDOC) $(OPTS) manual.md z-changes-*.md -H webfonts.html -c style.css -o manual.html ifeq ($(PANDOC),) $(warning Pandoc not found!) diff --git a/docs/manual.md b/docs/manual.md index cff6f18..19eacca 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -442,3 +442,6 @@ grabbing time: # The GObject Tango device [TODO: Get more information from Volker Kaiser and/or Mihael Koep] + + +# Changes diff --git a/docs/update-changelog b/docs/update-changelog new file mode 100755 index 0000000..57fe7a6 --- /dev/null +++ b/docs/update-changelog @@ -0,0 +1,22 @@ +#!/bin/bash + +FROM=$1 +TO=$2 +OUTPUT=$3 + +echo "## Changes from $FROM to $TO +" >> tmp +git log --pretty=format:'* [%h](http://ufo.kit.edu/repos/libuca.git/commit/?id=%h): %s' $FROM..$TO >> tmp + +echo " +" >> tmp + +if [ -f "$OUTPUT" ] +then + cat tmp $OUTPUT > tmp_md + rm $OUTPUT + mv tmp_md $OUTPUT + rm tmp +else + mv tmp $OUTPUT +fi diff --git a/docs/z-changes-1.0.md b/docs/z-changes-1.0.md new file mode 100644 index 0000000..4628b37 --- /dev/null +++ b/docs/z-changes-1.0.md @@ -0,0 +1,5 @@ +## Changes from v1.0 to v1.0.1 + +* [5d99f27](http://ufo.kit.edu/repos/libuca.git/commit/?id=5d99f27): Bump version to prepare for SO fix +* [178298f](http://ufo.kit.edu/repos/libuca.git/commit/?id=178298f): Set SO version to major not minor version + -- cgit v1.2.3 From 0bc642a31600bbfaac15779b8d932a409283ae3f Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 26 Sep 2012 14:51:14 +0200 Subject: Generalized log generation --- docs/Makefile | 8 ++++++-- docs/gen-changelog | 20 ++++++++++++++++++++ docs/manual.md | 2 +- docs/update-changelog | 22 ---------------------- docs/z-changes-1.0.md | 5 ----- 5 files changed, 27 insertions(+), 30 deletions(-) create mode 100755 docs/gen-changelog delete mode 100755 docs/update-changelog delete mode 100644 docs/z-changes-1.0.md diff --git a/docs/Makefile b/docs/Makefile index 83c1d01..ff7113d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -10,11 +10,15 @@ html: manual.html clean: rm -f manual.pdf manual.html -manual.pdf: manual.md +manual.pdf: manual.md gen-changelog + ./gen-changelog $(PANDOC) $(OPTS) manual.md z-changes-*.md -o manual.pdf + rm z-changes-*.md -manual.html: manual.md style.css +manual.html: manual.md style.css gen-changelog + ./gen-changelog $(PANDOC) $(OPTS) manual.md z-changes-*.md -H webfonts.html -c style.css -o manual.html + rm z-changes-*.md ifeq ($(PANDOC),) $(warning Pandoc not found!) diff --git a/docs/gen-changelog b/docs/gen-changelog new file mode 100755 index 0000000..51650f1 --- /dev/null +++ b/docs/gen-changelog @@ -0,0 +1,20 @@ +#!/bin/bash + +FROM=$1 +TO=$2 +OUTPUT=$3 +series=('v1.0' 'v1.0.1') + +logname="z-changes-${series[0]}.md" + +echo "## Changes for stable branch ${series[0]} +" >> $logname + +for ((i = 1; i < ${#series[@]}; i++)) do + curr=${series[i]} + prev=${series[i-1]} + + echo "### Changes from $prev to $curr +" >> $logname + git log --pretty=format:'* [%h](http://ufo.kit.edu/repos/libuca.git/commit/?id=%h): %s' $prev..$curr >> $logname +done diff --git a/docs/manual.md b/docs/manual.md index 19eacca..91935cc 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -444,4 +444,4 @@ grabbing time: [TODO: Get more information from Volker Kaiser and/or Mihael Koep] -# Changes +# ChangeLog diff --git a/docs/update-changelog b/docs/update-changelog deleted file mode 100755 index 57fe7a6..0000000 --- a/docs/update-changelog +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -FROM=$1 -TO=$2 -OUTPUT=$3 - -echo "## Changes from $FROM to $TO -" >> tmp -git log --pretty=format:'* [%h](http://ufo.kit.edu/repos/libuca.git/commit/?id=%h): %s' $FROM..$TO >> tmp - -echo " -" >> tmp - -if [ -f "$OUTPUT" ] -then - cat tmp $OUTPUT > tmp_md - rm $OUTPUT - mv tmp_md $OUTPUT - rm tmp -else - mv tmp $OUTPUT -fi diff --git a/docs/z-changes-1.0.md b/docs/z-changes-1.0.md deleted file mode 100644 index 4628b37..0000000 --- a/docs/z-changes-1.0.md +++ /dev/null @@ -1,5 +0,0 @@ -## Changes from v1.0 to v1.0.1 - -* [5d99f27](http://ufo.kit.edu/repos/libuca.git/commit/?id=5d99f27): Bump version to prepare for SO fix -* [178298f](http://ufo.kit.edu/repos/libuca.git/commit/?id=178298f): Set SO version to major not minor version - -- cgit v1.2.3 From 99b737ae9f3f1d35a4696594821fa3bc39e8aa87 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 28 Sep 2012 18:16:56 +0200 Subject: 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. --- CMakeLists.txt | 46 +- package.sh.in | 7 + plugins/CMakeLists.txt | 5 + plugins/mock/CMakeLists.txt | 18 + plugins/mock/uca-mock-camera.c | 409 +++++++++++ plugins/mock/uca-mock-camera.h | 65 ++ plugins/package-plugin.sh.in | 1 + plugins/pco/CMakeLists.txt | 30 + plugins/pco/uca-pco-camera.c | 1398 ++++++++++++++++++++++++++++++++++++++ plugins/pco/uca-pco-camera.h | 91 +++ plugins/pf/CMakeLists.txt | 30 + plugins/pf/uca-pf-camera.c | 351 ++++++++++ plugins/pf/uca-pf-camera.h | 74 ++ plugins/pylon/CMakeLists.txt | 24 + plugins/pylon/uca-pylon-camera.c | 391 +++++++++++ plugins/pylon/uca-pylon-camera.h | 74 ++ plugins/ufo/CMakeLists.txt | 24 + plugins/ufo/uca-ufo-camera.c | 497 ++++++++++++++ plugins/ufo/uca-ufo-camera.h | 76 +++ src/CMakeLists.txt | 202 ++---- src/cameras/uca-mock-camera.c | 409 ----------- src/cameras/uca-mock-camera.h | 65 -- src/cameras/uca-pco-camera.c | 1398 -------------------------------------- src/cameras/uca-pco-camera.h | 91 --- src/cameras/uca-pf-camera.c | 351 ---------- src/cameras/uca-pf-camera.h | 74 -- src/cameras/uca-pylon-camera.c | 391 ----------- src/cameras/uca-pylon-camera.h | 74 -- src/cameras/uca-ufo-camera.c | 497 -------------- src/cameras/uca-ufo-camera.h | 76 --- 30 files changed, 3646 insertions(+), 3593 deletions(-) create mode 100644 package.sh.in create mode 100644 plugins/CMakeLists.txt create mode 100644 plugins/mock/CMakeLists.txt create mode 100644 plugins/mock/uca-mock-camera.c create mode 100644 plugins/mock/uca-mock-camera.h create mode 100644 plugins/package-plugin.sh.in create mode 100644 plugins/pco/CMakeLists.txt create mode 100644 plugins/pco/uca-pco-camera.c create mode 100644 plugins/pco/uca-pco-camera.h create mode 100644 plugins/pf/CMakeLists.txt create mode 100644 plugins/pf/uca-pf-camera.c create mode 100644 plugins/pf/uca-pf-camera.h create mode 100644 plugins/pylon/CMakeLists.txt create mode 100644 plugins/pylon/uca-pylon-camera.c create mode 100644 plugins/pylon/uca-pylon-camera.h create mode 100644 plugins/ufo/CMakeLists.txt create mode 100644 plugins/ufo/uca-ufo-camera.c create mode 100644 plugins/ufo/uca-ufo-camera.h delete mode 100644 src/cameras/uca-mock-camera.c delete mode 100644 src/cameras/uca-mock-camera.h delete mode 100644 src/cameras/uca-pco-camera.c delete mode 100644 src/cameras/uca-pco-camera.h delete mode 100644 src/cameras/uca-pf-camera.c delete mode 100644 src/cameras/uca-pf-camera.h delete mode 100644 src/cameras/uca-pylon-camera.c delete mode 100644 src/cameras/uca-pylon-camera.h delete mode 100644 src/cameras/uca-ufo-camera.c delete mode 100644 src/cameras/uca-ufo-camera.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bc65dc1..b6ac69f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,9 @@ cmake_minimum_required(VERSION 2.8) -project(uca C) set(TARNAME "libuca") set(UCA_VERSION_MAJOR "1") set(UCA_VERSION_MINOR "1") -set(UCA_VERSION_PATCH "0-dev") +set(UCA_VERSION_PATCH "0dev") set(UCA_DESCRIPTION "Unified Camera Access") set(UCA_VERSION_STRING "${UCA_VERSION_MAJOR}.${UCA_VERSION_MINOR}.${UCA_VERSION_PATCH}") @@ -16,7 +15,7 @@ set(PACKAGE_TARNAME "${TARNAME}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "http://ufo.kit.edu/ufo/newticket") -set(CPACK_GENERATOR "DEB;RPM;") +set(CPACK_GENERATOR "RPM") set(CPACK_PACKAGE_RELEASE 3) set(CPACK_DEBIAN_PACKAGE_NAME "libuca") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Matthias Vogelgesang <matthias.vogelgesang@kit.edu>") @@ -25,8 +24,47 @@ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY ${UCA_DESCRIPTION}) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") -SET(UCA_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(UCA_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") + +set(UCA_ENUM_HDRS + ${CMAKE_CURRENT_SOURCE_DIR}/src/uca-camera.h + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/pco/uca-pco-camera.h) + +# --- Common configuration --------------------------------------------------- + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/package.sh) + + +# --- Common flags ------------------------------------------------------------ + +add_definitions("-std=c99 -Wall") + + +# --- Common libraries -------------------------------------------------------- + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +find_package(PkgConfig) +find_program(GLIB2_MKENUMS glib-mkenums REQUIRED) +pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) +pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) +pkg_check_modules(GMODULE2 gmodule-2.0>=2.24 REQUIRED) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${GLIB2_INCLUDE_DIRS} + ${GOBJECT2_INCLUDE_DIRS}) + +set(UCA_DEPS + ${GLIB2_LIBRARIES} + ${GOBJECT2_LIBRARIES} + ${GMODULE2_LIBRARIES}) add_subdirectory(src) +add_subdirectory(plugins) add_subdirectory(test) add_subdirectory(tools) diff --git a/package.sh.in b/package.sh.in new file mode 100644 index 0000000..7c15b78 --- /dev/null +++ b/package.sh.in @@ -0,0 +1,7 @@ +cpack -D CPACK_INSTALL_CMAKE_PROJECTS="${CMAKE_CURRENT_BINARY_DIR}/;Project;libraries;/" +cpack -D CPACK_INSTALL_CMAKE_PROJECTS="${CMAKE_CURRENT_BINARY_DIR}/;Project;headers;/" -D CPACK_PACKAGE_FILE_NAME="libuca-${UCA_VERSION_MAJOR}.${UCA_VERSION_MINOR}.${UCA_VERSION_PATCH}-devel" + +# Build packages for all available cameras +for shell_script in `find -name 'package-plugin-*.sh'`; do + sh $shell_script +done 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, ®_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, ®_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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a681f67..4bf5820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 2.8) +project(uca C) # --- Set sources ------------------------------------------------------------- set(uca_SRCS @@ -10,147 +11,15 @@ set(uca_HDRS uca-camera.h uca-plugin-manager.h) -set(cameras) - -set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") - -# --- Find packages and libraries --------------------------------------------- -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) - -# --- Find camera interfaces -find_package(PCO) -find_package(PF) -find_package(IPE) -find_package(Pylon) - -# --- Find frame grabber interfaces -find_package(FgLib5) -find_package(ClSerMe4) - -# --- Miscellanous packages -find_package(PkgConfig) -find_program(GLIB2_MKENUMS glib-mkenums REQUIRED) -pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) -pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) -pkg_check_modules(GMODULE2 gmodule-2.0>=2.24 REQUIRED) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cameras - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT2_INCLUDE_DIRS}) - -# --- Configure step -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -set(uca_LIBS - ${GLIB2_LIBRARIES} - ${GOBJECT2_LIBRARIES} - ${GMODULE2_LIBRARIES}) - -set(uca_enum_hdrs uca-camera.h) - -# --- Build options ----------------------------------------------------------- -option(HAVE_MOCK_CAMERA "Camera: Dummy" ON) - - -# --- Add sources if camera/framegrabber access sources are available --------- -if (PF_FOUND) - option(HAVE_PHOTON_FOCUS "Camera: Photon Focus MV2-D1280-640-CL-8" ON) - - if (HAVE_PHOTON_FOCUS AND CLSERME4_FOUND AND FGLIB5_FOUND) - list(APPEND uca_enum_hdrs cameras/uca-pf-camera.h) - - include_directories( - ${PF_INCLUDE_DIRS} - ${CLSERME4_INCLUDE_DIR} - ${FGLIB5_INCLUDE_DIR}) - - add_library(ucapf SHARED cameras/uca-pf-camera.c) - - target_link_libraries(ucapf - ${uca_LIBS} - ${CLSERME4_LIBRARY} - ${FGLIB5_LIBRARY} - ${PF_LIBRARIES}) - endif() -endif() - -if (PCO_FOUND AND CLSERME4_FOUND AND FGLIB5_FOUND) - option(HAVE_PCO_CL "Camera: CameraLink-based pco" ON) - - if (HAVE_PCO_CL) - list(APPEND uca_enum_hdrs cameras/uca-pco-camera.h) - - include_directories( - ${PCO_INCLUDE_DIRS} - ${CLSERME4_INCLUDE_DIR} - ${FGLIB5_INCLUDE_DIR}) - - add_library(ucapco SHARED cameras/uca-pco-camera.c) - - target_link_libraries(ucapco - ${uca_LIBS} - ${PCO_LIBRARIES} - ${CLSERME4_LIBRARY} - ${FGLIB5_LIBRARY}) - - install(TARGETS ucapco - LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) - endif() -endif() - -if (IPE_FOUND) - option(HAVE_UFO_CAMERA "Camera: Custom based on Xilinx FPGA" ON) - - if (HAVE_UFO_CAMERA) - list(APPEND uca_enum_hdrs cameras/uca-ufo-camera.h) - - include_directories(${IPE_INCLUDE_DIRS}) - - add_library(ucaufo SHARED cameras/uca-ufo-camera.c) - target_link_libraries(ucaufo - ${uca_LIBS} - ${IPE_LIBRARIES} - ) - - install(TARGETS ucaufo - LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) - endif() -endif() - -if (PYLON_FOUND) - option(HAVE_PYLON_CAMERA "Camera: Pylon based (Basler)" ON) - - if (HAVE_PYLON_CAMERA) - list(APPEND uca_SRCS cameras/uca-pylon-camera.c) - list(APPEND uca_HDRS cameras/uca-pylon-camera.h) - list(APPEND cameras "Pylon") - set(uca_LIBS ${uca_LIBS} ${LIBPYLONCAM_LIBRARIES}) - - include_directories(${LIBPYLONCAM_INCLUDEDIR}) - link_directories(${LIBPYLONCAM_LIBDIR}) - endif() - -endif() - -if (HAVE_MOCK_CAMERA) - add_library(ucamock SHARED cameras/uca-mock-camera.c) - install(TARGETS ucamock - LIBRARY DESTINATION ${LIB_INSTALL_DIR}/uca) -endif() - # --- Generate enum file add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h COMMAND ${GLIB2_MKENUMS} ARGS --template uca-enums.h.template - ${uca_enum_hdrs} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h + ${UCA_ENUM_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${uca_enum_hdrs} + DEPENDS ${UCA_ENUM_HDRS} ${CMAKE_CURRENT_SOURCE_DIR}/uca-enums.h.template) add_custom_command( @@ -158,15 +27,34 @@ add_custom_command( COMMAND ${GLIB2_MKENUMS} ARGS --template uca-enums.c.template - ${uca_enum_hdrs} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.c + ${UCA_ENUM_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${uca_enum_hdrs} + DEPENDS ${UCA_ENUM_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/uca-enums.h ${CMAKE_CURRENT_SOURCE_DIR}/uca-enums.c.template ) + +# --- Configure --------------------------------------------------------------- + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +set(prefix ${CMAKE_INSTALL_PREFIX}) +if (CI_INSTALL_PREFIX) + set(prefix ${CI_INSTALL_PREFIX}) +endif() + +set(exec_prefix "\${prefix}") +set(libdir ${prefix}/${LIB_INSTALL_DIR}) +set(includedir "\${prefix}/include") +set(VERSION ${UCA_VERSION_STRING}) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uca.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/uca.pc" @ONLY IMMEDIATE) + + # --- Build target ------------------------------------------------------------ -add_definitions("-std=c99 -Wall") add_library(uca SHARED ${uca_SRCS} @@ -176,8 +64,8 @@ set_target_properties(uca PROPERTIES VERSION ${UCA_ABI_VERSION} SOVERSION ${UCA_VERSION_MAJOR}) -target_link_libraries(uca - ${uca_LIBS}) +target_link_libraries(uca ${UCA_DEPS}) + # --- Build documentation ----------------------------------------------------- pkg_check_modules(GTK_DOC gtk-doc) @@ -269,37 +157,26 @@ endif() # --- Install target ---------------------------------------------------------- -set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}") install(TARGETS uca - LIBRARY DESTINATION ${LIB_INSTALL_DIR}) - -install(FILES ${uca_HDRS} - DESTINATION include/uca) - -# --- install pkg-config file -set(prefix ${CMAKE_INSTALL_PREFIX}) -if (CI_INSTALL_PREFIX) - set(prefix ${CI_INSTALL_PREFIX}) -endif() + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + COMPONENT libraries) -set(exec_prefix "\${prefix}") -set(libdir ${prefix}/${LIB_INSTALL_DIR}) -set(includedir "\${prefix}/include") -set(VERSION ${UCA_VERSION_STRING}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uca.pc + DESTINATION lib/pkgconfig + COMPONENT libraries) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uca.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/uca.pc" @ONLY IMMEDIATE) +install(FILES ${uca_HDRS} + DESTINATION include/uca + COMPONENT headers) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uca.pc DESTINATION lib/pkgconfig) +# --- Generate package description -------------------------------------------- set(CPACK_PACKAGE_DESCRIPTION "Unified Camera Access library") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Abstract interface for different camera classes and frame grabber devices") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GObject-based library for accessing scientific cameras") set(CPACK_PACKAGE_NAME "libuca") -# --- Distro specific -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1)") - # this doesn't work when building RPMs on Jenkins set(CPACK_SET_DESTDIR ON) @@ -310,13 +187,12 @@ set(CPACK_PACKAGE_VERSION_MINOR ${UCA_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${UCA_VERSION_PATCH}) set(VERSION ${UCA_VERSION_STRING}) -set(CPACK_GENERATOR "DEB;RPM;") +set(CPACK_GENERATOR "RPM;") + set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES ".git" "tags" ".bzr" ".swp") set(CPACK_SOURCE_PACKAGE_FILE_NAME "libuca-${UCA_VERSION_STRING}" CACHE INTERNAL "tarball basename") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${UCA_VERSION_STRING}-${CMAKE_SYSTEM_PROCESSOR}") -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../libuca.spec.in" - "${CMAKE_CURRENT_BINARY_DIR}/../libuca.spec" @ONLY IMMEDIATE) include(CPack) diff --git a/src/cameras/uca-mock-camera.c b/src/cameras/uca-mock-camera.c deleted file mode 100644 index 7cd4689..0000000 --- a/src/cameras/uca-mock-camera.c +++ /dev/null @@ -1,409 +0,0 @@ -/* 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/src/cameras/uca-mock-camera.h b/src/cameras/uca-mock-camera.h deleted file mode 100644 index 9ee9190..0000000 --- a/src/cameras/uca-mock-camera.h +++ /dev/null @@ -1,65 +0,0 @@ -/* 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/src/cameras/uca-pco-camera.c b/src/cameras/uca-pco-camera.c deleted file mode 100644 index 8bf2936..0000000 --- a/src/cameras/uca-pco-camera.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* 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/src/cameras/uca-pco-camera.h b/src/cameras/uca-pco-camera.h deleted file mode 100644 index 73ae44e..0000000 --- a/src/cameras/uca-pco-camera.h +++ /dev/null @@ -1,91 +0,0 @@ -/* 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/src/cameras/uca-pf-camera.c b/src/cameras/uca-pf-camera.c deleted file mode 100644 index 35b5edd..0000000 --- a/src/cameras/uca-pf-camera.c +++ /dev/null @@ -1,351 +0,0 @@ -/* 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/src/cameras/uca-pf-camera.h b/src/cameras/uca-pf-camera.h deleted file mode 100644 index 3a309aa..0000000 --- a/src/cameras/uca-pf-camera.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 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/src/cameras/uca-pylon-camera.c b/src/cameras/uca-pylon-camera.c deleted file mode 100644 index 541b69b..0000000 --- a/src/cameras/uca-pylon-camera.c +++ /dev/null @@ -1,391 +0,0 @@ -/* 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/src/cameras/uca-pylon-camera.h b/src/cameras/uca-pylon-camera.h deleted file mode 100644 index eebf63c..0000000 --- a/src/cameras/uca-pylon-camera.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 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/src/cameras/uca-ufo-camera.c b/src/cameras/uca-ufo-camera.c deleted file mode 100644 index 7542fdf..0000000 --- a/src/cameras/uca-ufo-camera.c +++ /dev/null @@ -1,497 +0,0 @@ -/* 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, ®_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, ®_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/src/cameras/uca-ufo-camera.h b/src/cameras/uca-ufo-camera.h deleted file mode 100644 index 7030389..0000000 --- a/src/cameras/uca-ufo-camera.h +++ /dev/null @@ -1,76 +0,0 @@ -/* 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 -- cgit v1.2.3 From b781c67a6bb80823c629dbc2824672c338f029cb Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 28 Sep 2012 18:24:49 +0200 Subject: Fix mock unit test --- test/CMakeLists.txt | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b579d1b..f98def0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,27 +1,8 @@ cmake_minimum_required(VERSION 2.8) -add_definitions("--std=c99 -Wall") +add_executable(test-mock test-mock.c) -# --- Find packages and libraries --------------------------------------------- -find_package(PkgConfig) +target_link_libraries(test-mock uca ${UCA_DEPS}) -pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) -pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) - -set(libs uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) - -# --- Build targets ----------------------------------------------------------- -include_directories( - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT2_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR}/../src/ - ${CMAKE_CURRENT_SOURCE_DIR}/../src - ) - -if (HAVE_MOCK_CAMERA) - add_executable(test-mock test-mock.c) - target_link_libraries(test-mock ${libs}) - - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl - ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) -endif() +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl + ${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl) -- cgit v1.2.3 From b8d34c22c479bd5def2744eae3a9380d3ff843c2 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@kit.edu> Date: Mon, 1 Oct 2012 09:08:52 +0200 Subject: Define plugins as C projects Otherwise CMake complains about non-existent C++ compilers, which are not needed here anyway. --- CMakeLists.txt | 1 + plugins/mock/CMakeLists.txt | 2 +- plugins/pco/CMakeLists.txt | 2 +- plugins/pf/CMakeLists.txt | 2 +- plugins/pylon/CMakeLists.txt | 3 +-- plugins/ufo/CMakeLists.txt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6ac69f..bb53b40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 2.8) +project(uca C) set(TARNAME "libuca") set(UCA_VERSION_MAJOR "1") diff --git a/plugins/mock/CMakeLists.txt b/plugins/mock/CMakeLists.txt index 75d8635..d5b6771 100644 --- a/plugins/mock/CMakeLists.txt +++ b/plugins/mock/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project(ucamock) +project(ucamock C) set(UCA_CAMERA_NAME "mock") diff --git a/plugins/pco/CMakeLists.txt b/plugins/pco/CMakeLists.txt index 7c016b9..a526f4d 100644 --- a/plugins/pco/CMakeLists.txt +++ b/plugins/pco/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project(ucapco) +project(ucapco C) find_package(PCO) find_package(FgLib5) diff --git a/plugins/pf/CMakeLists.txt b/plugins/pf/CMakeLists.txt index f392603..ef11f8f 100644 --- a/plugins/pf/CMakeLists.txt +++ b/plugins/pf/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project(ucapf) +project(ucapf C) find_package(PF) find_package(FgLib5) diff --git a/plugins/pylon/CMakeLists.txt b/plugins/pylon/CMakeLists.txt index 18823a4..9a3c15c 100644 --- a/plugins/pylon/CMakeLists.txt +++ b/plugins/pylon/CMakeLists.txt @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 2.8) -project(ucapylon) +project(ucapylon C) -find_package(Pylon) if (PYLON_FOUND) set(UCA_CAMERA_NAME "pylon") diff --git a/plugins/ufo/CMakeLists.txt b/plugins/ufo/CMakeLists.txt index fe89668..c7fd21b 100644 --- a/plugins/ufo/CMakeLists.txt +++ b/plugins/ufo/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project(ucaufo) +project(ucaufo C) find_package(IPE) -- cgit v1.2.3 From 5ed330a163073f4aab98995520eebbc15dff83f3 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 1 Oct 2012 10:04:10 +0200 Subject: Fix #114: look for SISO rt in /opt/siso --- cmake/FindClSerMe4.cmake | 2 ++ cmake/FindFgLib5.cmake | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cmake/FindClSerMe4.cmake b/cmake/FindClSerMe4.cmake index 2251c9a..803b620 100644 --- a/cmake/FindClSerMe4.cmake +++ b/cmake/FindClSerMe4.cmake @@ -13,6 +13,7 @@ FIND_PATH(CLSERME4_INCLUDE_DIR clser.h ${SISODIR4}/include ${SISODIRME4}/include ${CMAKE_INSTALL_PREFIX}/include + "/opt/siso/include" ) INCLUDE(SisoLibDir) @@ -26,6 +27,7 @@ FIND_LIBRARY(CLSERME4_LIBRARY NAMES clserme4 clsersisome4 $ENV{CLSERME4} ${LIB_DIRS} ${CMAKE_INSTALL_PREFIX}/lib + "/opt/siso/lib" ) IF(CLSERME4_INCLUDE_DIR AND CLSERME4_LIBRARY) diff --git a/cmake/FindFgLib5.cmake b/cmake/FindFgLib5.cmake index cba0002..3f6a0c1 100644 --- a/cmake/FindFgLib5.cmake +++ b/cmake/FindFgLib5.cmake @@ -10,6 +10,7 @@ FIND_PATH(FGLIB5_INCLUDE_DIR fgrab_define.h "${CMAKE_INSTALL_PREFIX}/include" "${SISODIR5}/include" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Silicon Software GmbH\\Runtime5;Info]/include" + "/opt/siso/include" ) INCLUDE(SisoLibDir) @@ -23,6 +24,7 @@ FIND_LIBRARY(FGLIB5_LIBRARY NAMES fglib5 ${LIB_DIRS} "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Silicon Software GmbH\\Runtime5;Info]/lib/${COMPILER_LIB_DIR}" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Silicon Software GmbH\\Runtime5;Info]/lib" + "/opt/siso/lib" ) IF(FGLIB5_INCLUDE_DIR AND FGLIB5_LIBRARY) -- cgit v1.2.3 From 4e78a33ab00c8437d341a4cb83919e2a67e54493 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 8 Oct 2012 10:04:18 +0200 Subject: Generate documentation for the base camera object --- docs/base.html | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/manual.md | 2 ++ tools/gen-doc.c | 18 ++++++++++------ 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 docs/base.html diff --git a/docs/base.html b/docs/base.html new file mode 100644 index 0000000..e86807f --- /dev/null +++ b/docs/base.html @@ -0,0 +1,67 @@ +<html><head><link rel="stylesheet" href="style.css" type="text/css" /><link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Serif:400,400italic|Inconsolata' rel='stylesheet' type='text/css'><title>Basic camera — properties</title></head><body><div id="header"><h1 class="title">Property documentation of Basic camera</h1><h2>Properties</h2><ul id="toc"><li><code><a href=#name>"name"</a></code></li><li><code><a href=#sensor-width>"sensor-width"</a></code></li><li><code><a href=#sensor-height>"sensor-height"</a></code></li><li><code><a href=#sensor-bitdepth>"sensor-bitdepth"</a></code></li><li><code><a href=#sensor-horizontal-binning>"sensor-horizontal-binning"</a></code></li><li><code><a href=#sensor-horizontal-binnings>"sensor-horizontal-binnings"</a></code></li><li><code><a href=#sensor-vertical-binning>"sensor-vertical-binning"</a></code></li><li><code><a href=#sensor-vertical-binnings>"sensor-vertical-binnings"</a></code></li><li><code><a href=#sensor-max-frame-rate>"sensor-max-frame-rate"</a></code></li><li><code><a href=#trigger-mode>"trigger-mode"</a></code></li><li><code><a href=#exposure-time>"exposure-time"</a></code></li><li><code><a href=#roi-x0>"roi-x0"</a></code></li><li><code><a href=#roi-y0>"roi-y0"</a></code></li><li><code><a href=#roi-width>"roi-width"</a></code></li><li><code><a href=#roi-height>"roi-height"</a></code></li><li><code><a href=#roi-width-multiplier>"roi-width-multiplier"</a></code></li><li><code><a href=#roi-height-multiplier>"roi-height-multiplier"</a></code></li><li><code><a href=#has-streaming>"has-streaming"</a></code></li><li><code><a href=#has-camram-recording>"has-camram-recording"</a></code></li><li><code><a href=#transfer-asynchronously>"transfer-asynchronously"</a></code></li><li><code><a href=#is-recording>"is-recording"</a></code></li><li><code><a href=#is-readout>"is-readout"</a></code></li></ul><h2>Details</h2><dl><dt id="name"><a href="#toc">name</a></dt> +<dd><pre><code class="prop-type">"name" : gchararray : Read-only</code></pre> +<p>Name of the camera</p> +</dd><dt id="sensor-width"><a href="#toc">sensor-width</a></dt> +<dd><pre><code class="prop-type">"sensor-width" : guint : Read-only</code></pre> +<p>Width of the sensor in pixels</p> +</dd><dt id="sensor-height"><a href="#toc">sensor-height</a></dt> +<dd><pre><code class="prop-type">"sensor-height" : guint : Read-only</code></pre> +<p>Height of the sensor in pixels</p> +</dd><dt id="sensor-bitdepth"><a href="#toc">sensor-bitdepth</a></dt> +<dd><pre><code class="prop-type">"sensor-bitdepth" : guint : Read-only</code></pre> +<p>Number of bits per pixel</p> +</dd><dt id="sensor-horizontal-binning"><a href="#toc">sensor-horizontal-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in horizontal direction</p> +</dd><dt id="sensor-horizontal-binnings"><a href="#toc">sensor-horizontal-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in horizontal direction</p> +</dd><dt id="sensor-vertical-binning"><a href="#toc">sensor-vertical-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in vertical direction</p> +</dd><dt id="sensor-vertical-binnings"><a href="#toc">sensor-vertical-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in vertical direction</p> +</dd><dt id="sensor-max-frame-rate"><a href="#toc">sensor-max-frame-rate</a></dt> +<dd><pre><code class="prop-type">"sensor-max-frame-rate" : gfloat : Read-only</code></pre> +<p>Maximum frame rate at full frame resolution</p> +</dd><dt id="trigger-mode"><a href="#toc">trigger-mode</a></dt> +<dd><pre><code class="prop-type">"trigger-mode" : UcaCameraTrigger : Read / Write</code></pre> +<p>Trigger mode</p> +</dd><dt id="exposure-time"><a href="#toc">exposure-time</a></dt> +<dd><pre><code class="prop-type">"exposure-time" : gdouble : Read / Write</code></pre> +<p>Exposure time in seconds</p> +</dd><dt id="roi-x0"><a href="#toc">roi-x0</a></dt> +<dd><pre><code class="prop-type">"roi-x0" : guint : Read / Write</code></pre> +<p>Horizontal coordinate</p> +</dd><dt id="roi-y0"><a href="#toc">roi-y0</a></dt> +<dd><pre><code class="prop-type">"roi-y0" : guint : Read / Write</code></pre> +<p>Vertical coordinate</p> +</dd><dt id="roi-width"><a href="#toc">roi-width</a></dt> +<dd><pre><code class="prop-type">"roi-width" : guint : Read / Write</code></pre> +<p>Width of the region of interest</p> +</dd><dt id="roi-height"><a href="#toc">roi-height</a></dt> +<dd><pre><code class="prop-type">"roi-height" : guint : Read / Write</code></pre> +<p>Height of the region of interest</p> +</dd><dt id="roi-width-multiplier"><a href="#toc">roi-width-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-width-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of horizontal ROI</p> +</dd><dt id="roi-height-multiplier"><a href="#toc">roi-height-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-height-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of vertical ROI</p> +</dd><dt id="has-streaming"><a href="#toc">has-streaming</a></dt> +<dd><pre><code class="prop-type">"has-streaming" : gboolean : Read-only</code></pre> +<p>Is the camera able to stream the data</p> +</dd><dt id="has-camram-recording"><a href="#toc">has-camram-recording</a></dt> +<dd><pre><code class="prop-type">"has-camram-recording" : gboolean : Read-only</code></pre> +<p>Is the camera able to record the data in-camera</p> +</dd><dt id="transfer-asynchronously"><a href="#toc">transfer-asynchronously</a></dt> +<dd><pre><code class="prop-type">"transfer-asynchronously" : gboolean : Read / Write</code></pre> +<p>Specify whether data should be transfered asynchronously using a specified callback</p> +</dd><dt id="is-recording"><a href="#toc">is-recording</a></dt> +<dd><pre><code class="prop-type">"is-recording" : gboolean : Read-only</code></pre> +<p>Is the camera currently recording</p> +</dd><dt id="is-readout"><a href="#toc">is-readout</a></dt> +<dd><pre><code class="prop-type">"is-readout" : gboolean : Read-only</code></pre> +<p>Is camera in readout mode</p> +</dd></dl></body></html> diff --git a/docs/manual.md b/docs/manual.md index 91935cc..0fe4cca 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -247,8 +247,10 @@ The following cameras are supported: ## Property documentation +* [Basic camera properties][base-doc] * [mock][mock-doc] +[base-doc]: base.html [mock-doc]: mock.html diff --git a/tools/gen-doc.c b/tools/gen-doc.c index d9b6b41..86d6ff9 100644 --- a/tools/gen-doc.c +++ b/tools/gen-doc.c @@ -124,25 +124,29 @@ int main(int argc, char *argv[]) { UcaPluginManager *manager; UcaCamera *camera; + gchar *name; GError *error = NULL; g_type_init(); + manager = uca_plugin_manager_new (); if (argc < 2) { - print_usage(); - return 1; + name = g_strdup ("Basic camera"); + camera = g_object_new (UCA_TYPE_CAMERA, NULL); + } + else { + name = argv[1]; + camera = uca_plugin_manager_new_camera (manager, name, &error); } - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); + print_usage(); return 1; } - g_print (html_header, argv[1]); - g_print ("<div id=\"header\"><h1 class=\"title\">Property documentation of %s</h1>", argv[1]); + g_print (html_header, name); + g_print ("<div id=\"header\"><h1 class=\"title\">Property documentation of %s</h1>", name); print_properties (camera); g_print ("%s\n", html_footer); -- cgit v1.2.3 From d58bbe683873d043f50c8261f4588d7941e9cb8c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 8 Oct 2012 10:43:42 +0200 Subject: Remove uca_camera_get_types from public API This functionality was moved to the plugin manager and could not be used anyway. --- src/uca-camera.h | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/uca-camera.h b/src/uca-camera.h index 8924fa8..bd89bc6 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -110,24 +110,31 @@ struct _UcaCameraClass { GObjectClass parent; void (*start_recording) (UcaCamera *camera, GError **error); - void (*stop_recording) (UcaCamera *camera, GError **error); - void (*start_readout) (UcaCamera *camera, GError **error); - void (*trigger) (UcaCamera *camera, GError **error); - void (*grab) (UcaCamera *camera, gpointer *data, GError **error); + void (*stop_recording) (UcaCamera *camera, GError **error); + void (*start_readout) (UcaCamera *camera, GError **error); + void (*trigger) (UcaCamera *camera, GError **error); + void (*grab) (UcaCamera *camera, gpointer *data, GError **error); void (*recording_started) (UcaCamera *camera); void (*recording_stopped) (UcaCamera *camera); }; -gchar **uca_camera_get_types(); -UcaCamera *uca_camera_new(const gchar *type, GError **error); - -void uca_camera_start_recording(UcaCamera *camera, GError **error); -void uca_camera_stop_recording(UcaCamera *camera, GError **error); -void uca_camera_start_readout(UcaCamera *camera, GError **error); -void uca_camera_trigger(UcaCamera *camera, GError **error); -void uca_camera_grab(UcaCamera *camera, gpointer *data, GError **error); -void uca_camera_set_grab_func(UcaCamera *camera, UcaCameraGrabFunc func, gpointer user_data); +UcaCamera * uca_camera_new (const gchar *type, + GError **error); +void uca_camera_start_recording (UcaCamera *camera, + GError **error); +void uca_camera_stop_recording (UcaCamera *camera, + GError **error); +void uca_camera_start_readout (UcaCamera *camera, + GError **error); +void uca_camera_trigger (UcaCamera *camera, + GError **error); +void uca_camera_grab (UcaCamera *camera, + gpointer *data, + GError **error); +void uca_camera_set_grab_func (UcaCamera *camera, + UcaCameraGrabFunc func, + gpointer user_data); GType uca_camera_get_type(void); -- cgit v1.2.3 From b3dbedeec78a55802565a3824ab52188e8b9bd4d Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 8 Oct 2012 14:38:16 +0200 Subject: Generate introspection files Unfortunately, the gir tools recognize anything with $PREFIX_new_$SUFFIX as some kind of constructor. This means that we have to rename uca_plugin_manager_new_camera() to uca_plugin_manager_get_camera(). --- CMakeLists.txt | 1 + NEWS | 2 +- src/CMakeLists.txt | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ src/uca-plugin-manager.c | 13 +++++------ src/uca-plugin-manager.h | 2 +- test/test-mock.c | 4 ++-- tools/benchmark.c | 2 +- tools/gen-doc.c | 2 +- tools/grab-async.c | 2 +- tools/grab.c | 2 +- tools/gui/control.c | 2 +- tools/perf-overhead.c | 2 +- 12 files changed, 74 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb53b40..bef3712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(UCA_ENUM_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/src/uca-camera.h ${CMAKE_CURRENT_SOURCE_DIR}/plugins/pco/uca-pco-camera.h) + # --- Common configuration --------------------------------------------------- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package.sh.in diff --git a/NEWS b/NEWS index e7c7243..624242b 100644 --- a/NEWS +++ b/NEWS @@ -13,7 +13,7 @@ looks in pre- and user-defined directories for DSOs that match UcaCamera *camera; manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, "foo", &error); + camera = uca_plugin_manager_get_camera (manager, "foo", &error); The plugin manager adds a dependency on GModule (pkg-config package `gmodule-2.0`) that is part of GLib. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bf5820..dd2f464 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,6 +37,9 @@ add_custom_command( # --- Configure --------------------------------------------------------------- +find_program(INTROSPECTION_SCANNER "g-ir-scanner") +find_program(INTROSPECTION_COMPILER "g-ir-compiler") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) @@ -67,7 +70,51 @@ set_target_properties(uca PROPERTIES target_link_libraries(uca ${UCA_DEPS}) +# --- Build introspection files ----------------------------------------------- + +if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER) + option(WITH_GIR "Build introspection files" ON) + + if (WITH_GIR) + set(GIR_PREFIX "Uca-${UCA_ABI_VERSION}") + set(GIR_XML "${GIR_PREFIX}.gir") + set(GIR_TYPELIB "${GIR_PREFIX}.typelib") + set(_gir_input) + + foreach(_src ${uca_SRCS} ${uca_HDRS}) + list(APPEND _gir_input "${CMAKE_CURRENT_SOURCE_DIR}/${_src}") + endforeach() + + add_custom_command(OUTPUT ${GIR_XML} + COMMAND ${INTROSPECTION_SCANNER} + --namespace=Uca + --nsversion=${UCA_ABI_VERSION} + --library=uca + --no-libtool + --include=GObject-2.0 + --include=GModule-2.0 + --output ${GIR_XML} + --warn-all + ${_gir_input} + DEPENDS ${uca_SRCS} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + add_custom_command(OUTPUT ${GIR_TYPELIB} + COMMAND ${INTROSPECTION_COMPILER} + -o ${GIR_TYPELIB} + ${GIR_XML} + DEPENDS ${GIR_XML} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + add_custom_target(gir ALL DEPENDS ${GIR_XML} ${GIR_TYPELIB}) + add_dependencies(gir uca) + + endif() +endif() + + # --- Build documentation ----------------------------------------------------- + pkg_check_modules(GTK_DOC gtk-doc) if(GTK_DOC_FOUND) @@ -170,6 +217,16 @@ install(FILES ${uca_HDRS} DESTINATION include/uca COMPONENT headers) +if(WITH_GIR) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_XML} + DESTINATION share/gir-1.0 + COMPONENT libraries) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB} + DESTINATION ${LIB_INSTALL_DIR}/girepository-1.0 + COMPONENT libraries) +endif() + # --- Generate package description -------------------------------------------- diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index 5678e83..cb7e518 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -49,9 +49,7 @@ uca_plugin_manager_error_quark (void) * uca_plugin_manager_new: * @config: (allow-none): A #UcaConfiguration object or %NULL. * - * Create a plugin manager object to instantiate filter objects. When a config - * object is passed to the constructor, its search-path property is added to the - * internal search paths. + * Create a plugin manager object to instantiate camera objects. * * Return value: A new plugin manager object. */ @@ -147,9 +145,10 @@ list_free_full (GList *list) * * @manager: A #UcaPluginManager * - * Return: A list with strings of available camera names. You have to free the - * individual strings with g_list_foreach(list, (GFunc) g_free, NULL) and the - * list itself with g_list_free. + * Returns: (element-type utf8) (transfer full): A list with strings of + * available camera names. You have to free the individual strings with + * g_list_foreach(list, (GFunc) g_free, NULL) and the list itself with + * g_list_free. */ GList * uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) @@ -201,7 +200,7 @@ find_camera_module_path (GList *search_paths, const gchar *name) * @error: Location for a #GError */ UcaCamera * -uca_plugin_manager_new_camera (UcaPluginManager *manager, +uca_plugin_manager_get_camera (UcaPluginManager *manager, const gchar *name, GError **error) { diff --git a/src/uca-plugin-manager.h b/src/uca-plugin-manager.h index 9291857..6c3ab4e 100644 --- a/src/uca-plugin-manager.h +++ b/src/uca-plugin-manager.h @@ -55,7 +55,7 @@ void uca_plugin_manager_add_path (UcaPluginManager *manager const gchar *path); GList *uca_plugin_manager_get_available_cameras (UcaPluginManager *manager); -UcaCamera *uca_plugin_manager_new_camera (UcaPluginManager *manager, +UcaCamera *uca_plugin_manager_get_camera (UcaPluginManager *manager, const gchar *name, GError **error); GType uca_plugin_manager_get_type (void); diff --git a/test/test-mock.c b/test/test-mock.c index ca16c59..711364d 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -16,7 +16,7 @@ fixture_setup (Fixture *fixture, gconstpointer data) fixture->manager = uca_plugin_manager_new (); uca_plugin_manager_add_path (fixture->manager, "./src"); - fixture->camera = uca_plugin_manager_new_camera (fixture->manager, "mock", &error); + fixture->camera = uca_plugin_manager_get_camera (fixture->manager, "mock", &error); g_assert (error == NULL); g_assert (fixture->camera); } @@ -39,7 +39,7 @@ static void test_factory (Fixture *fixture, gconstpointer data) { GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_new_camera (fixture->manager, "fox994m3a0yxmy", &error); + UcaCamera *camera = uca_plugin_manager_get_camera (fixture->manager, "fox994m3a0yxmy", &error); g_assert_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND); g_assert (camera == NULL); } diff --git a/tools/benchmark.c b/tools/benchmark.c index ef99fd1..bff8b50 100644 --- a/tools/benchmark.c +++ b/tools/benchmark.c @@ -250,7 +250,7 @@ main (int argc, char *argv[]) g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_error ("Initialization: %s", error->message); diff --git a/tools/gen-doc.c b/tools/gen-doc.c index 86d6ff9..f555a5f 100644 --- a/tools/gen-doc.c +++ b/tools/gen-doc.c @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) } else { name = argv[1]; - camera = uca_plugin_manager_new_camera (manager, name, &error); + camera = uca_plugin_manager_get_camera (manager, name, &error); } if (camera == NULL) { diff --git a/tools/grab-async.c b/tools/grab-async.c index 6132829..2c4bf04 100644 --- a/tools/grab-async.c +++ b/tools/grab-async.c @@ -94,7 +94,7 @@ main(int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); diff --git a/tools/grab.c b/tools/grab.c index 1f5c917..1518997 100644 --- a/tools/grab.c +++ b/tools/grab.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); diff --git a/tools/gui/control.c b/tools/gui/control.c index 75b3cde..178c809 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -207,7 +207,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) static ThreadData td; GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); + UcaCamera *camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); if ((camera == NULL) || (error != NULL)) { g_error ("%s\n", error->message); diff --git a/tools/perf-overhead.c b/tools/perf-overhead.c index f8bdcbd..6735e6f 100644 --- a/tools/perf-overhead.c +++ b/tools/perf-overhead.c @@ -163,7 +163,7 @@ main (int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print ("Error during initialization: %s\n", error->message); -- cgit v1.2.3 From 1568fc37538a70bb0309df98f2b8e7b6d0daa265 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 8 Oct 2012 15:05:28 +0200 Subject: Introspection has to be in the NEWS --- NEWS | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 624242b..f0a4c30 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,12 @@ looks in pre- and user-defined directories for DSOs that match The plugin manager adds a dependency on GModule (pkg-config package `gmodule-2.0`) that is part of GLib. +Minor changes +------------- + +- It is now possible to generate GObject introspection meta data to bind libuca + to all languages that support GObject introspection. + Changes in libuca 1.0 aka 0.6 ============================= @@ -34,7 +40,6 @@ instead of trying to initialize each camera first and having the user decide what to use, the user must now determine the used camera at compile time or use the factory pattern to delegate this to run-time. - Tango Wrapper ------------- -- cgit v1.2.3 From 1716926f5c36a89cb00c900160629110657638b1 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 8 Oct 2012 16:05:19 +0200 Subject: Add packages and bindings sections --- docs/manual.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/docs/manual.md b/docs/manual.md index 0fe4cca..5162ddf 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -12,7 +12,18 @@ Before installing `libuca` itself, you should install any drivers and SDKs needed to access the cameras you want to access through `libuca`. Now you have two options: install pre-built packages or build from source. -## Building from source +### Installing packages + +Packages for the core library and all plugins are currently provided for +openSUSE. To install them run `zypper`: + + sudo zypper in libuca-x.y.z-x86_64.rpm + sudo zypper in uca-plugin-*.rpm + +To install development files such as headers, you have to install the +`libuca-x.y.z-devel.rpm` package. + +### Building from source Building the library and installing from source is simple and straightforward. Make sure you have @@ -38,7 +49,8 @@ repository][repo], you also need Git: [repo]: http://ufo.kit.edu/repos/libuca.git/ -### Fetching the sources + +#### Fetching the sources Untar the distribution @@ -54,7 +66,7 @@ and create a new, empty build directory inside: mkdir build -### Configuring and building +#### Configuring and building Now you need to create the Makefile with CMake. Go into the build directory and point CMake to the `libuca` top-level directory: @@ -86,7 +98,7 @@ latter that 64 should be appended to any library paths. This is necessary on Linux distributions that expect 64-bit libraries in `/usr[/local]/lib64`. -### Building this manual +#### Building this manual Make sure you have [Pandoc][] installed. With Debian/Ubuntu this can be achieved with @@ -367,6 +379,37 @@ setup_async (UcaCamera *camera) } ~~~ + +# Bindings + +Since version 1.1, libuca generates GObject introspection meta data if +`g-ir-scanner` and `g-ir-compiler` can be found. When the XML description +`Uca-x.y.gir` and the typelib `Uca-x.y.typelib` are installed, GI-aware +languages can access libuca and create and modify cameras, for example in +Python: + +~~~ {.python} +from gi.repository import Uca + +pm = Uca.PluginManager() + +# List all cameras +print(pm.get_available_cameras()) + +# Load a camera +cam = pm.get_camera('pco') + +# You can read and write properties in two ways +cam.set_properties(exposure_time=0.05) +cam.props.roi_width = 1024 +~~~ + +Note, that the naming of classes and properties depends on the GI implementation +of the target language. For example with Python, the namespace prefix `uca_` +becomes the module name `Uca` and dashes separating property names become +underscores. + + # Integrating new cameras A new camera is integrated by [sub-classing][] `UcaCamera` and implement all -- cgit v1.2.3 From 21bce1b4a01ff6735325457297aa9bd8fcdebe8f Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 14:12:18 +0200 Subject: Load correct framegrabber plugin --- plugins/pco/uca-pco-camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 8bf2936..352c5f0 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -190,7 +190,7 @@ struct _UcaPcoCameraPrivate { 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 }, + { CAMERATYPE_PCO_DIMAX_STD, "libDualAreaGray16.so", FG_CL_SINGLETAP_8_BIT, FG_GRAY16, 1279.0f, TRUE }, { 0, NULL, 0, 0, 0.0f, FALSE } }; -- cgit v1.2.3 From 805129cf7452e37c6d1042a87fadd297098fac9c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 14:35:06 +0200 Subject: Fix #149: Make timestamp mode an enum --- plugins/pco/uca-pco-camera.c | 40 +++++++++++++++++----------------------- plugins/pco/uca-pco-camera.h | 7 ++++--- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 352c5f0..ccccf82 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -77,6 +77,7 @@ G_DEFINE_TYPE(UcaPcoCamera, uca_pco_camera, UCA_TYPE_CAMERA) * @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 + * @UCA_PCO_CAMERA_TIMESTAMP_BOTH: Embed both types of timestamps */ /** @@ -769,13 +770,14 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons 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 */ + guint16 table[] = { + TIMESTAMP_MODE_OFF, + TIMESTAMP_MODE_BINARY, + TIMESTAMP_MODE_BINARYANDASCII, + TIMESTAMP_MODE_ASCII, }; - pco_set_timestamp_mode(priv->pco, modes[g_value_get_flags(value)]); + + pco_set_timestamp_mode(priv->pco, table[g_value_get_flags(value)]); } break; @@ -1055,23 +1057,15 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal case PROP_TIMESTAMP_MODE: { guint16 mode; - pco_get_timestamp_mode(priv->pco, &mode); + UcaPcoCameraTimestamp table[] = { + UCA_PCO_CAMERA_TIMESTAMP_NONE, + UCA_PCO_CAMERA_TIMESTAMP_BINARY, + UCA_PCO_CAMERA_TIMESTAMP_BOTH, + UCA_PCO_CAMERA_TIMESTAMP_ASCII + }; - 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; - } + pco_get_timestamp_mode(priv->pco, &mode); + g_value_set_enum (value, table[mode]); } break; @@ -1280,7 +1274,7 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) G_PARAM_READABLE); pco_properties[PROP_TIMESTAMP_MODE] = - g_param_spec_flags("timestamp-mode", + g_param_spec_enum("timestamp-mode", "Timestamp mode", "Timestamp mode", UCA_TYPE_PCO_CAMERA_TIMESTAMP, UCA_PCO_CAMERA_TIMESTAMP_NONE, diff --git a/plugins/pco/uca-pco-camera.h b/plugins/pco/uca-pco-camera.h index 73ae44e..d134fb1 100644 --- a/plugins/pco/uca-pco-camera.h +++ b/plugins/pco/uca-pco-camera.h @@ -55,9 +55,10 @@ typedef enum { } UcaPcoCameraAcquireMode; typedef enum { - UCA_PCO_CAMERA_TIMESTAMP_NONE = 0, - UCA_PCO_CAMERA_TIMESTAMP_BINARY = 1 << 0, - UCA_PCO_CAMERA_TIMESTAMP_ASCII = 1 << 1 + UCA_PCO_CAMERA_TIMESTAMP_NONE, + UCA_PCO_CAMERA_TIMESTAMP_BINARY, + UCA_PCO_CAMERA_TIMESTAMP_ASCII, + UCA_PCO_CAMERA_TIMESTAMP_BOTH } UcaPcoCameraTimestamp; /** -- cgit v1.2.3 From 4a27a2e95aa1a2312ad17404d7ab236b2fa6f1b7 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 15:43:10 +0200 Subject: Fix #150: Add "frames-per-second" property Right now, there is only information for the DIMAX camera about the actual inherent system delay. For all other cameras fps = 1. / t_exp. --- plugins/pco/uca-pco-camera.c | 111 +++++++++++++++++++++++++++++++++++-------- src/uca-camera.c | 26 ++++++++++ src/uca-camera.h | 1 + test/test-mock.c | 21 ++++++++ 4 files changed, 139 insertions(+), 20 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index ccccf82..893a480 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -129,6 +129,7 @@ static gint base_overrideables[] = { PROP_SENSOR_VERTICAL_BINNINGS, PROP_SENSOR_MAX_FRAME_RATE, PROP_EXPOSURE_TIME, + PROP_FRAMES_PER_SECOND, PROP_TRIGGER_MODE, PROP_ROI_X, PROP_ROI_Y, @@ -208,7 +209,8 @@ static pco_cl_map_entry *get_pco_cl_map_entry(int camera_type) return NULL; } -static guint fill_binnings(UcaPcoCameraPrivate *priv) +static guint +fill_binnings(UcaPcoCameraPrivate *priv) { uint16_t *horizontal = NULL; uint16_t *vertical = NULL; @@ -241,7 +243,8 @@ static guint fill_binnings(UcaPcoCameraPrivate *priv) return err; } -static void fill_pixelrates(UcaPcoCameraPrivate *priv, guint32 rates[4], gint num_rates) +static void +fill_pixelrates(UcaPcoCameraPrivate *priv, guint32 rates[4], gint num_rates) { GValue val = {0}; g_value_init(&val, G_TYPE_UINT); @@ -253,7 +256,8 @@ static void fill_pixelrates(UcaPcoCameraPrivate *priv, guint32 rates[4], gint nu } } -static guint override_temperature_range(UcaPcoCameraPrivate *priv) +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); @@ -270,7 +274,8 @@ static guint override_temperature_range(UcaPcoCameraPrivate *priv) return err; } -static void property_override_default_guint_value (GObjectClass *oclass, const gchar *property_name, guint new_default) +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)); @@ -280,13 +285,15 @@ static void property_override_default_guint_value (GObjectClass *oclass, const g g_warning ("pspec for %s not found\n", property_name); } -static void override_maximum_adcs(UcaPcoCameraPrivate *priv) +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) +static gdouble +convert_timebase(guint16 timebase) { switch (timebase) { case TIMEBASE_NS: @@ -301,12 +308,14 @@ static gdouble convert_timebase(guint16 timebase) return 1e-3; } -static void read_timebase(UcaPcoCameraPrivate *priv) +static void +read_timebase(UcaPcoCameraPrivate *priv) { pco_get_timebase(priv->pco, &priv->delay_timebase, &priv->exposure_timebase); } -static gdouble get_suitable_timebase(gdouble time) +static gdouble +get_suitable_timebase(gdouble time) { if (time * 1e3 >= 1.0) return TIMEBASE_MS; @@ -317,7 +326,24 @@ static gdouble get_suitable_timebase(gdouble time) return TIMEBASE_INVALID; } -static int fg_callback(frameindex_t frame, struct fg_apc_data *apc) +static gdouble +get_internal_delay (UcaPcoCamera *camera) +{ + if (camera->priv->camera_description->camera_type == CAMERATYPE_PCO_DIMAX_STD) { + gdouble sensor_rate; + g_object_get (camera, "sensor-rate", &sensor_rate, NULL); + + if (sensor_rate == 55000000.0) + return 0.000079; + else if (sensor_rate == 62500000.0) + return 0.000069; + } + + return 0.0; +} + +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); @@ -333,7 +359,8 @@ static int fg_callback(frameindex_t frame, struct fg_apc_data *apc) return 0; } -static gboolean setup_fg_callback(UcaCamera *camera) +static gboolean +setup_fg_callback(UcaCamera *camera) { UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera); struct FgApcControl ctrl; @@ -353,7 +380,8 @@ static gboolean setup_fg_callback(UcaCamera *camera) 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) +static void +uca_pco_camera_start_recording(UcaCamera *camera, GError **error) { g_return_if_fail(UCA_IS_PCO_CAMERA(camera)); guint err = PCO_NOERROR; @@ -451,7 +479,8 @@ static void uca_pco_camera_start_recording(UcaCamera *camera, GError **error) FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_ACQUISITION); } -static void uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) +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); @@ -467,7 +496,8 @@ static void uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) g_warning(" Unable to unblock all\n"); } -static void uca_pco_camera_start_readout(UcaCamera *camera, GError **error) +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); @@ -486,7 +516,8 @@ static void uca_pco_camera_start_readout(UcaCamera *camera, GError **error) priv->current_image = 1; } -static void uca_pco_camera_trigger(UcaCamera *camera, GError **error) +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); @@ -500,7 +531,8 @@ static void uca_pco_camera_trigger(UcaCamera *camera, GError **error) "Could not trigger frame acquisition"); } -static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) +static void +uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) { static const gint MAX_TIMEOUT = G_MAXINT; @@ -543,7 +575,8 @@ static void uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **erro 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) +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); @@ -624,6 +657,29 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons } break; + case PROP_FRAMES_PER_SECOND: + { + gdouble n_frames_per_second; + gdouble exposure_time; + gdouble delay; + + /* + * We want to expose n frames in one second, each frame takes + * exposure time + delay time. Thus we have + * + * 1s = n * (t_exp + t_delay) <=> t_exp = 1s/n - t_delay. + */ + delay = get_internal_delay (UCA_PCO_CAMERA (object)); + n_frames_per_second = g_value_get_double (value); + exposure_time = 1.0 / n_frames_per_second - delay; + + if (exposure_time <= 0.0) + g_warning ("Too many frames per second requested."); + else + g_object_set (object, "exposure-time", exposure_time, NULL); + } + break; + case PROP_DELAY_TIME: { const gdouble time = g_value_get_double(value); @@ -787,7 +843,8 @@ static void uca_pco_camera_set_property(GObject *object, guint property_id, cons } } -static void uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +static void +uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object); @@ -892,6 +949,17 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal } break; + case PROP_FRAMES_PER_SECOND: + { + gdouble exposure_time; + gdouble delay; + + delay = get_internal_delay (UCA_PCO_CAMERA (object)); + g_object_get (object, "exposure-time", &exposure_time, NULL); + g_value_set_double (value, 1.0 / (exposure_time + delay)); + } + break; + case PROP_DELAY_TIME: { uint32_t delay_time; @@ -1075,7 +1143,8 @@ static void uca_pco_camera_get_property(GObject *object, guint property_id, GVal } } -static void uca_pco_camera_finalize(GObject *object) +static void +uca_pco_camera_finalize(GObject *object) { UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object); @@ -1103,7 +1172,8 @@ static void uca_pco_camera_finalize(GObject *object) G_OBJECT_CLASS(uca_pco_camera_parent_class)->finalize(object); } -static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) +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; @@ -1286,7 +1356,8 @@ static void uca_pco_camera_class_init(UcaPcoCameraClass *klass) g_type_class_add_private(klass, sizeof(UcaPcoCameraPrivate)); } -static void uca_pco_camera_init(UcaPcoCamera *self) +static void +uca_pco_camera_init(UcaPcoCamera *self) { self->priv = UCA_PCO_CAMERA_GET_PRIVATE(self); self->priv->fg = NULL; diff --git a/src/uca-camera.c b/src/uca-camera.c index f973355..14da820 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -66,6 +66,7 @@ const gchar *uca_camera_props[N_BASE_PROPERTIES] = { "sensor-max-frame-rate", "trigger-mode", "exposure-time", + "frames-per-second", "roi-x0", "roi-y0", "roi-width", @@ -102,6 +103,15 @@ uca_camera_set_property (GObject *object, guint property_id, const GValue *value priv->transfer_async = g_value_get_boolean(value); break; + case PROP_FRAMES_PER_SECOND: + { + gdouble frames_per_second; + + frames_per_second = g_value_get_double (value); + g_object_set (object, "exposure-time", 1. / frames_per_second, NULL); + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -125,6 +135,15 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara g_value_set_boolean(value, priv->transfer_async); break; + case PROP_FRAMES_PER_SECOND: + { + gdouble exposure_time; + + g_object_get (object, "exposure-time", &exposure_time, NULL); + g_value_set_double (value, 1. / exposure_time); + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -267,6 +286,13 @@ uca_camera_class_init(UcaCameraClass *klass) 0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE); + camera_properties[PROP_FRAMES_PER_SECOND] = + g_param_spec_double(uca_camera_props[PROP_FRAMES_PER_SECOND], + "Frames per second", + "Frames per second", + 0.0, G_MAXDOUBLE, 1.0, + G_PARAM_READWRITE); + camera_properties[PROP_HAS_STREAMING] = g_param_spec_boolean(uca_camera_props[PROP_HAS_STREAMING], "Streaming capability", diff --git a/src/uca-camera.h b/src/uca-camera.h index bd89bc6..7d81dac 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -63,6 +63,7 @@ enum { PROP_SENSOR_MAX_FRAME_RATE, PROP_TRIGGER_MODE, PROP_EXPOSURE_TIME, + PROP_FRAMES_PER_SECOND, PROP_ROI_X, PROP_ROI_Y, PROP_ROI_WIDTH, diff --git a/test/test-mock.c b/test/test-mock.c index 711364d..17af329 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -148,6 +148,26 @@ test_base_properties (Fixture *fixture, gconstpointer data) g_free (properties); } +static void +test_fps_property (Fixture *fixture, gconstpointer data) +{ + gdouble frames_per_second; + gdouble exposure_time = 0.5; + + g_object_set (G_OBJECT (fixture->camera), + "exposure-time", exposure_time, + NULL); + g_object_get (G_OBJECT (fixture->camera), + "frames-per-second", &frames_per_second, + NULL); + + /* + * The mock camera does not override the "frames-per-second" property, so we + * check the implementation from the base camera. + */ + g_assert_cmpfloat (frames_per_second, ==, 1.0 / exposure_time); +} + static void test_binnings_properties (Fixture *fixture, gconstpointer data) { @@ -189,6 +209,7 @@ int main (int argc, char *argv[]) g_test_add ("/properties/base", Fixture, NULL, fixture_setup, test_base_properties, fixture_teardown); g_test_add ("/properties/recording", Fixture, NULL, fixture_setup, test_recording_property, fixture_teardown); g_test_add ("/properties/binnings", Fixture, NULL, fixture_setup, test_binnings_properties, fixture_teardown); + g_test_add ("/properties/frames-per-second", Fixture, NULL, fixture_setup, test_fps_property, fixture_teardown); g_test_add ("/signal", Fixture, NULL, fixture_setup, test_signal, fixture_teardown); return g_test_run (); -- cgit v1.2.3 From 0d329da1679e1a3a8639131560ad101d94aace9b Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 15:51:41 +0200 Subject: Set sane default exposure time --- plugins/mock/uca-mock-camera.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 7cd4689..7ab1d4a 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -393,6 +393,7 @@ static void uca_mock_camera_init(UcaMockCamera *self) self->priv->frame_rate = self->priv->max_frame_rate = 100000.0f; self->priv->grab_thread = NULL; self->priv->current_frame = 0; + self->priv->exposure_time = 0.05; self->priv->binnings = g_value_array_new(1); GValue val = {0}; -- cgit v1.2.3 From b72daf9dbba95a208a4fb84e5b1c629d64a72c00 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 16:05:20 +0200 Subject: Fix #151: Rename trigger enum value --- plugins/pco/uca-pco-camera.c | 4 ++-- src/CMakeLists.txt | 13 +------------ src/uca-camera.c | 10 +++++++++- src/uca-camera.h | 2 +- src/uca-docs.xml.in | 4 ++-- src/uca-plugin-manager.c | 21 ++++++++++++++++++--- src/uca.types.in | 2 +- 7 files changed, 34 insertions(+), 22 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 893a480..5415867 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -807,7 +807,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va case UCA_CAMERA_TRIGGER_AUTO: pco_set_trigger_mode(priv->pco, TRIGGER_MODE_AUTOTRIGGER); break; - case UCA_CAMERA_TRIGGER_INTERNAL: + case UCA_CAMERA_TRIGGER_SOFTWARE: pco_set_trigger_mode(priv->pco, TRIGGER_MODE_SOFTWARETRIGGER); break; case UCA_CAMERA_TRIGGER_EXTERNAL: @@ -1040,7 +1040,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO); break; case TRIGGER_MODE_SOFTWARETRIGGER: - g_value_set_enum(value, UCA_CAMERA_TRIGGER_INTERNAL); + g_value_set_enum(value, UCA_CAMERA_TRIGGER_SOFTWARE); break; case TRIGGER_MODE_EXTERNALTRIGGER: g_value_set_enum(value, UCA_CAMERA_TRIGGER_EXTERNAL); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd2f464..160c52b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,6 +130,7 @@ if(GTK_DOC_FOUND) "${docs_out}/api-index-full.html" "${docs_out}/ch01.html" "${docs_out}/UcaCamera.html" + "${docs_out}/UcaPluginManager.html" "${docs_out}/style.css" "${docs_out}/uca.devhelp2" "${docs_out}/home.png" @@ -137,18 +138,6 @@ if(GTK_DOC_FOUND) "${docs_out}/right.png" "${docs_out}/up.png") - # Put in uca-docs.xml and uca.types all cameras that are built - set(_xml_doc_input) - set(_types_input) - foreach (_cam ${cameras}) - # add camera to the installed documentation - list(APPEND reference_files "${docs_out}/Uca${_cam}Camera.html") - - string(TOLOWER ${_cam} _cam) - set(_xml_doc_input "${_xml_doc_input}\n<xi:include href=\"xml/uca-${_cam}-camera.xml\"/>") - set(_types_input "${_types_input}\nuca_${_cam}_camera_get_type") - endforeach() - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uca-docs.xml.in ${docs_out}/uca-docs.xml) diff --git a/src/uca-camera.c b/src/uca-camera.c index 14da820..6d92e6a 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -15,6 +15,14 @@ with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */ +/** + * SECTION:uca-camera + * @Short_description: Base class representing a camera + * @Title: UcaCamera + * + * UcaCamera is the base camera from which a real hardware camera derives from. + */ + #include <glib.h> #include "config.h" #include "uca-camera.h" @@ -28,7 +36,7 @@ G_DEFINE_TYPE(UcaCamera, uca_camera, G_TYPE_OBJECT) * UcaCameraTrigger: * @UCA_CAMERA_TRIGGER_AUTO: Trigger automatically * @UCA_CAMERA_TRIGGER_EXTERNAL: Trigger from an external source - * @UCA_CAMERA_TRIGGER_INTERNAL: Trigger internally from software using + * @UCA_CAMERA_TRIGGER_SOFTWARE: Trigger from software using * #uca_camera_trigger */ diff --git a/src/uca-camera.h b/src/uca-camera.h index 7d81dac..8bc48bc 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -42,7 +42,7 @@ typedef enum { typedef enum { UCA_CAMERA_TRIGGER_AUTO, - UCA_CAMERA_TRIGGER_INTERNAL, + UCA_CAMERA_TRIGGER_SOFTWARE, UCA_CAMERA_TRIGGER_EXTERNAL } UcaCameraTrigger; diff --git a/src/uca-docs.xml.in b/src/uca-docs.xml.in index 43a830d..093fd36 100644 --- a/src/uca-docs.xml.in +++ b/src/uca-docs.xml.in @@ -16,8 +16,8 @@ <chapter> <title>Unified Camera Access</title> - <xi:include href="xml/uca-camera.xml"/> - ${_xml_doc_input} + <xi:include href="xml/uca-camera.xml"/> + <xi:include href="xml/uca-plugin-manager.xml"/> </chapter> <index id="api-index-full"> diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index cb7e518..373ccb2 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -1,3 +1,20 @@ +/* Copyright (C) 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 */ + /** * SECTION:uca-plugin-manager * @Short_description: Load an #UcaFilter from a shared object @@ -47,7 +64,6 @@ uca_plugin_manager_error_quark (void) /** * uca_plugin_manager_new: - * @config: (allow-none): A #UcaConfiguration object or %NULL. * * Create a plugin manager object to instantiate camera objects. * @@ -142,10 +158,9 @@ list_free_full (GList *list) /** * uca_plugin_manager_get_available_cameras: - * * @manager: A #UcaPluginManager * - * Returns: (element-type utf8) (transfer full): A list with strings of + * Return value: (element-type utf8) (transfer full): A list with strings of * available camera names. You have to free the individual strings with * g_list_foreach(list, (GFunc) g_free, NULL) and the list itself with * g_list_free. diff --git a/src/uca.types.in b/src/uca.types.in index a9ce408..7526948 100644 --- a/src/uca.types.in +++ b/src/uca.types.in @@ -1,2 +1,2 @@ uca_camera_get_type -${_types_input} +uca_plugin_manager_get_type -- cgit v1.2.3 From 5b0a76d69d631838a08a2678388b55c8dacd6d74 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 09:28:45 +0200 Subject: More elegant error reporting when libpco fails --- plugins/pco/uca-pco-camera.c | 100 ++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 5415867..e20d683 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -380,6 +380,16 @@ setup_fg_callback(UcaCamera *camera) return Fg_registerApcHandler(priv->fg, priv->fg_port, &ctrl, FG_APC_CONTROL_BASIC) == FG_OK; } +static void +check_pco_property_error (guint err, guint property_id) +{ + if (err != PCO_NOERROR) { + g_warning ("Call to libpco failed with error code %x for property `%s'", + err, + pco_properties[property_id]->name); + } +} + static void uca_pco_camera_start_recording(UcaCamera *camera, GError **error) { @@ -579,12 +589,13 @@ 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); + guint err = PCO_NOERROR; 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); + err = pco_set_sensor_format(priv->pco, format); } break; @@ -645,14 +656,13 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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"); + err = pco_set_timebase(priv->pco, priv->delay_timebase, suitable_timebase); + break; } 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"); + err = pco_set_exposure_time(priv->pco, timesteps); } } break; @@ -700,8 +710,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va * 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"); + err = pco_set_delay_time(priv->pco, 0); } else g_warning("Cannot set such a small exposure time"); @@ -709,14 +718,12 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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"); + err = pco_set_timebase(priv->pco, suitable_timebase, priv->exposure_timebase); } 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"); + err = pco_set_delay_time(priv->pco, timesteps); } } break; @@ -724,8 +731,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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"); + err = pco_set_adc_mode(priv->pco, num_adcs); } break; @@ -742,8 +748,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va } if (pixel_rate != 0) { - if (pco_set_pixelrate(priv->pco, pixel_rate) != PCO_NOERROR) - g_warning("Cannot set pixel rate"); + err = pco_set_pixelrate(priv->pco, pixel_rate); } else g_warning("%i Hz is not possible. Please check the \"sensor-pixelrates\" property", desired_pixel_rate); @@ -754,17 +759,17 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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)); + err = 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)); + err = 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); + err = pco_set_cooling_temperature(priv->pco, temperature); } break; @@ -774,9 +779,9 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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); + err = 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); + err = pco_set_record_mode(priv->pco, RECORDER_SUBMODE_RINGBUFFER); else g_warning("Unknown record mode"); } @@ -785,7 +790,6 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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); @@ -793,9 +797,6 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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; @@ -805,13 +806,13 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va switch (trigger_mode) { case UCA_CAMERA_TRIGGER_AUTO: - pco_set_trigger_mode(priv->pco, TRIGGER_MODE_AUTOTRIGGER); + err = pco_set_trigger_mode(priv->pco, TRIGGER_MODE_AUTOTRIGGER); break; case UCA_CAMERA_TRIGGER_SOFTWARE: - pco_set_trigger_mode(priv->pco, TRIGGER_MODE_SOFTWARETRIGGER); + err = pco_set_trigger_mode(priv->pco, TRIGGER_MODE_SOFTWARETRIGGER); break; case UCA_CAMERA_TRIGGER_EXTERNAL: - pco_set_trigger_mode(priv->pco, TRIGGER_MODE_EXTERNALTRIGGER); + err = pco_set_trigger_mode(priv->pco, TRIGGER_MODE_EXTERNALTRIGGER); break; } } @@ -820,7 +821,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va 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); + err = pco_set_noise_filter_mode(priv->pco, filter_mode); } break; @@ -833,7 +834,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va TIMESTAMP_MODE_ASCII, }; - pco_set_timestamp_mode(priv->pco, table[g_value_get_flags(value)]); + err = pco_set_timestamp_mode(priv->pco, table[g_value_get_flags(value)]); } break; @@ -841,18 +842,21 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); return; } + + check_pco_property_error (err, property_id); } static void uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(object); + guint err = PCO_NOERROR; switch (property_id) { case PROP_SENSOR_EXTENDED: { guint16 format; - pco_get_sensor_format(priv->pco, &format); + err = pco_get_sensor_format(priv->pco, &format); g_value_set_boolean(value, format == SENSORFORMAT_EXTENDED); } break; @@ -900,7 +904,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_SENSOR_TEMPERATURE: { gint32 ccd, camera, power; - pco_get_temperature(priv->pco, &ccd, &camera, &power); + err = pco_get_temperature(priv->pco, &ccd, &camera, &power); g_value_set_double(value, ccd / 10.0); } break; @@ -912,8 +916,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G * 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"); + err = pco_get_adc_mode(priv->pco, &mode); g_value_set_uint(value, mode); } break; @@ -932,7 +935,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_SENSOR_PIXELRATE: { guint32 pixelrate; - pco_get_pixelrate(priv->pco, &pixelrate); + err = pco_get_pixelrate(priv->pco, &pixelrate); g_value_set_uint(value, pixelrate); } break; @@ -940,7 +943,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_EXPOSURE_TIME: { uint32_t exposure_time; - pco_get_exposure_time(priv->pco, &exposure_time); + err = pco_get_exposure_time(priv->pco, &exposure_time); if (priv->exposure_timebase == TIMEBASE_INVALID) read_timebase(priv); @@ -963,7 +966,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_DELAY_TIME: { uint32_t delay_time; - pco_get_delay_time(priv->pco, &delay_time); + err = pco_get_delay_time(priv->pco, &delay_time); if (priv->delay_timebase == TIMEBASE_INVALID) read_timebase(priv); @@ -981,7 +984,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G g_warning("Double image mode is not available on this pco model"); else { bool on; - pco_get_double_image_mode(priv->pco, &on); + err = pco_get_double_image_mode(priv->pco, &on); g_value_set_boolean(value, on); } break; @@ -989,7 +992,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_OFFSET_MODE: { bool on; - pco_get_offset_mode(priv->pco, &on); + err = pco_get_offset_mode(priv->pco, &on); g_value_set_boolean(value, on); } break; @@ -1005,7 +1008,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_RECORD_MODE: { guint16 mode; - pco_get_record_mode(priv->pco, &mode); + err = pco_get_record_mode(priv->pco, &mode); if (mode == RECORDER_SUBMODE_SEQUENCE) g_value_set_enum(value, UCA_PCO_CAMERA_RECORD_MODE_SEQUENCE); @@ -1019,7 +1022,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_ACQUIRE_MODE: { guint16 mode; - pco_get_acquire_mode(priv->pco, &mode); + err = pco_get_acquire_mode(priv->pco, &mode); if (mode == ACQUIRE_MODE_AUTO) g_value_set_enum(value, UCA_PCO_CAMERA_ACQUIRE_MODE_AUTO); @@ -1033,7 +1036,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_TRIGGER_MODE: { guint16 mode; - pco_get_trigger_mode(priv->pco, &mode); + err = pco_get_trigger_mode(priv->pco, &mode); switch (mode) { case TRIGGER_MODE_AUTOTRIGGER: @@ -1078,8 +1081,8 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_NAME: { gchar *name = NULL; - pco_get_name(priv->pco, &name); - g_value_set_string(value, name); + err = pco_get_name (priv->pco, &name); + g_value_set_string (value, name); g_free(name); } break; @@ -1087,8 +1090,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_COOLING_POINT: { int16_t temperature; - if (pco_get_cooling_temperature(priv->pco, &temperature) != PCO_NOERROR) - g_warning("Cannot read cooling temperature\n"); + err = pco_get_cooling_temperature(priv->pco, &temperature); g_value_set_int(value, temperature); } break; @@ -1117,7 +1119,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_NOISE_FILTER: { guint16 mode; - pco_get_noise_filter_mode(priv->pco, &mode); + err = pco_get_noise_filter_mode(priv->pco, &mode); g_value_set_boolean(value, mode != NOISE_FILTER_MODE_OFF); } break; @@ -1132,15 +1134,17 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G UCA_PCO_CAMERA_TIMESTAMP_ASCII }; - pco_get_timestamp_mode(priv->pco, &mode); + err = pco_get_timestamp_mode (priv->pco, &mode); g_value_set_enum (value, table[mode]); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); - break; + return; } + + check_pco_property_error (err, property_id); } static void -- cgit v1.2.3 From a0e94969bbee79a6342f1608acffda0dc2f235bc Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 09:31:24 +0200 Subject: Use correct pixel rate property name --- plugins/pco/uca-pco-camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index e20d683..791d154 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -331,7 +331,7 @@ get_internal_delay (UcaPcoCamera *camera) { if (camera->priv->camera_description->camera_type == CAMERATYPE_PCO_DIMAX_STD) { gdouble sensor_rate; - g_object_get (camera, "sensor-rate", &sensor_rate, NULL); + g_object_get (camera, "sensor-pixelrate", &sensor_rate, NULL); if (sensor_rate == 55000000.0) return 0.000079; -- cgit v1.2.3 From fce1b3762b2a3b3035b9a3c2a6be038bde10aa1c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 09:49:49 +0200 Subject: Set timestamp as enum not flag --- plugins/pco/uca-pco-camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 791d154..725ffbf 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -834,7 +834,7 @@ uca_pco_camera_set_property(GObject *object, guint property_id, const GValue *va TIMESTAMP_MODE_ASCII, }; - err = pco_set_timestamp_mode(priv->pco, table[g_value_get_flags(value)]); + err = pco_set_timestamp_mode(priv->pco, table[g_value_get_enum(value)]); } break; -- cgit v1.2.3 From 0badcd14dc0ba8b3b6894be035237b846e3fb0e6 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 16:52:17 +0200 Subject: Remove unneccessary variable --- tools/gui/control.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index 178c809..89e932a 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -37,7 +37,6 @@ typedef struct { guchar *buffer, *pixels; GdkPixbuf *pixbuf; GtkWidget *image; - GtkTreeModel *property_model; UcaCamera *camera; GtkStatusbar *statusbar; @@ -242,7 +241,6 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); td.store = FALSE; td.camera = camera; - td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), -- cgit v1.2.3 From 9d84d920da67f857ef31a2a2b475b191ec3c6c55 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 9 Oct 2012 16:52:36 +0200 Subject: Use scrolled window for camera choice --- tools/gui/control.glade | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tools/gui/control.glade b/tools/gui/control.glade index d7ba2fc..ad5a91f 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -235,18 +235,28 @@ <property name="visible">True</property> <property name="spacing">2</property> <child> - <object class="GtkTreeView" id="treeview-cameras"> + <object class="GtkScrolledWindow" id="scrolledwindow3"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="model">camera-types</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> <child> - <object class="GtkTreeViewColumn" id="treeviewcolumn1"> - <property name="title">Choose camera</property> + <object class="GtkTreeView" id="treeview-cameras"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">camera-types</property> + <property name="headers_clickable">False</property> + <property name="search_column">0</property> <child> - <object class="GtkCellRendererText" id="cellrenderertext1"/> - <attributes> - <attribute name="text">0</attribute> - </attributes> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <property name="title">Choose camera</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> </child> </object> </child> -- cgit v1.2.3 From 08a794b59a02a36028da90f31e165e7f44ef28e5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 09:15:21 +0200 Subject: Add histogram view skeleton --- tools/gui/CMakeLists.txt | 3 +- tools/gui/egg-histogram-view.c | 100 +++++++++++++++++++++++++++++++++++++++++ tools/gui/egg-histogram-view.h | 54 ++++++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 tools/gui/egg-histogram-view.c create mode 100644 tools/gui/egg-histogram-view.h diff --git a/tools/gui/CMakeLists.txt b/tools/gui/CMakeLists.txt index 39afe98..b30f3ea 100644 --- a/tools/gui/CMakeLists.txt +++ b/tools/gui/CMakeLists.txt @@ -26,7 +26,8 @@ if (GTK2_FOUND) add_executable(control control.c egg-property-cell-renderer.c - egg-property-tree-view.c) + egg-property-tree-view.c + egg-histogram-view.c) target_link_libraries(control uca ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c new file mode 100644 index 0000000..809a2d9 --- /dev/null +++ b/tools/gui/egg-histogram-view.c @@ -0,0 +1,100 @@ +/* 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 <stdlib.h> +#include "egg-histogram-view.h" + +G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_CELL_RENDERER) + +#define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) + + +struct _EggHistogramViewPrivate +{ + guint foo; +}; + +enum +{ + PROP_0, + N_PROPERTIES +}; + +static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; + + +GtkWidget * +egg_histogram_view_new (void) +{ + EggHistogramView *view; + + view = EGG_HISTOGRAM_VIEW (g_object_new (EGG_TYPE_HISTOGRAM_VIEW, NULL)); + return GTK_WIDGET (view); +} + +static void +egg_histogram_view_dispose (GObject *object) +{ +} + +static void +egg_histogram_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_histogram_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_histogram_view_class_init (EggHistogramViewClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = egg_histogram_view_set_property; + gobject_class->get_property = egg_histogram_view_get_property; + gobject_class->dispose = egg_histogram_view_dispose; + + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); +} + +static void +egg_histogram_view_init (EggHistogramView *renderer) +{ + renderer->priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (renderer); +} diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h new file mode 100644 index 0000000..23581dc --- /dev/null +++ b/tools/gui/egg-histogram-view.h @@ -0,0 +1,54 @@ +/* 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 EGG_HISTOGRAM_VIEW_H +#define EGG_HISTOGRAM_VIEW_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_HISTOGRAM_VIEW (egg_histogram_view_get_type()) +#define EGG_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramView)) +#define EGG_IS_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_HISTOGRAM_VIEW)) +#define EGG_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) +#define EGG_IS_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_HISTOGRAM_VIEW)) +#define EGG_HISTOGRAM_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) + +typedef struct _EggHistogramView EggHistogramView; +typedef struct _EggHistogramViewClass EggHistogramViewClass; +typedef struct _EggHistogramViewPrivate EggHistogramViewPrivate; + +struct _EggHistogramView +{ + GtkDrawingArea parent_instance; + + /*< private >*/ + EggHistogramViewPrivate *priv; +}; + +struct _EggHistogramViewClass +{ + GtkDrawingAreaClass parent_class; +}; + +GType egg_histogram_view_get_type (void); +GtkWidget * egg_histogram_view_new (void); + +G_END_DECLS + +#endif -- cgit v1.2.3 From 46a6d028c5591b0775ef5862ff5c9e95fd68e7fd Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 10:20:08 +0200 Subject: (De-) activate tool buttons according to state --- tools/gui/control.c | 99 +++++++++++++++++++++++++++---------------------- tools/gui/control.glade | 20 +++------- 2 files changed, 59 insertions(+), 60 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index 89e932a..f7d3618 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -31,21 +31,22 @@ typedef struct { - gboolean running; - gboolean store; - - guchar *buffer, *pixels; - GdkPixbuf *pixbuf; - GtkWidget *image; - UcaCamera *camera; - - GtkStatusbar *statusbar; - guint statusbar_context_id; - - int timestamp; - int width; - int height; - int pixel_size; + UcaCamera *camera; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkWidget *start_button; + GtkWidget *stop_button; + GtkWidget *record_button; + + guchar *buffer; + guchar *pixels; + gboolean running; + gboolean store; + + int timestamp; + int width; + int height; + int pixel_size; } ThreadData; enum { @@ -145,16 +146,22 @@ on_destroy (GtkWidget *widget, gpointer data) } static void -on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) +set_tool_button_state (ThreadData *data) { - ThreadData *data = (ThreadData *) args; - - if (data->running) - return; + gtk_widget_set_sensitive (data->start_button, !data->running); + gtk_widget_set_sensitive (data->stop_button, data->running); + gtk_widget_set_sensitive (data->record_button, !data->running); +} +static void +on_start_button_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; GError *error = NULL; + data->running = TRUE; + set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); if (error != NULL) { @@ -169,12 +176,15 @@ on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) } static void -on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) +on_stop_button_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; + GError *error = NULL; + data->running = FALSE; data->store = FALSE; - GError *error = NULL; + + set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); if (error != NULL) @@ -182,22 +192,20 @@ on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) } static void -on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) +on_record_button_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; - data->timestamp = (int) time (0); - data->store = TRUE; GError *error = NULL; - gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); + data->timestamp = (int) time (0); + data->store = TRUE; + data->running = TRUE; - if (data->running != TRUE) { - data->running = TRUE; - uca_camera_start_recording (data->camera, &error); + set_tool_button_state (data); + uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (grab_thread, data, FALSE, &error)) - g_printerr ("Failed to create thread: %s\n", error->message); - } + if (!g_thread_create (grab_thread, data, FALSE, &error)) + g_printerr ("Failed to create thread: %s\n", error->message); } static void @@ -215,10 +223,10 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) guint bits_per_sample; g_object_get (camera, - "roi-width", &td.width, - "roi-height", &td.height, - "sensor-bitdepth", &bits_per_sample, - NULL); + "roi-width", &td.width, + "roi-height", &td.height, + "sensor-bitdepth", &bits_per_sample, + NULL); GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); @@ -237,18 +245,19 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.running = FALSE; - td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); - td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); td.store = FALSE; td.camera = camera; g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), - "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), - "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), - "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); + + td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); + td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); + td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + set_tool_button_state (&td); + + g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); + g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); + g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); gtk_widget_show (image); gtk_widget_show (window); @@ -295,7 +304,7 @@ create_choice_window (GtkBuilder *builder) GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); - GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "proceed-button")); GtkTreeIter iter; for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ad5a91f..ee888e8 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -117,7 +117,7 @@ <object class="GtkToolbar" id="toolbar"> <property name="visible">True</property> <child> - <object class="GtkToolButton" id="toolbutton_run"> + <object class="GtkToolButton" id="start-button"> <property name="visible">True</property> <property name="label" translatable="yes">Run</property> <property name="use_underline">True</property> @@ -129,7 +129,7 @@ </packing> </child> <child> - <object class="GtkToolButton" id="toolbutton_record"> + <object class="GtkToolButton" id="record-button"> <property name="visible">True</property> <property name="label" translatable="yes">Record</property> <property name="use_underline">True</property> @@ -141,7 +141,7 @@ </packing> </child> <child> - <object class="GtkToolButton" id="toolbutton_stop"> + <object class="GtkToolButton" id="stop-button"> <property name="visible">True</property> <property name="label" translatable="yes">Stop</property> <property name="use_underline">True</property> @@ -208,16 +208,6 @@ <property name="position">2</property> </packing> </child> - <child> - <object class="GtkStatusbar" id="statusbar"> - <property name="visible">True</property> - <property name="spacing">2</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">3</property> - </packing> - </child> </object> </child> </object> @@ -271,7 +261,7 @@ <property name="spacing">6</property> <property name="layout_style">end</property> <child> - <object class="GtkButton" id="button-cancel"> + <object class="GtkButton" id="cancel-button"> <property name="label">gtk-quit</property> <property name="visible">True</property> <property name="can_focus">True</property> @@ -286,7 +276,7 @@ </packing> </child> <child> - <object class="GtkButton" id="button-proceed"> + <object class="GtkButton" id="proceed-button"> <property name="label">gtk-ok</property> <property name="visible">True</property> <property name="can_focus">True</property> -- cgit v1.2.3 From 95a22bf2f02ad11c2602df5ac5ffd04fee93588c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 17:44:34 +0200 Subject: Implement experimental histogram view --- plugins/mock/uca-mock-camera.c | 4 - plugins/pf/uca-pf-camera.c | 1 + src/uca-camera.c | 10 +- tools/gui/control.c | 47 ++++--- tools/gui/control.glade | 75 ++++++++-- tools/gui/egg-histogram-view.c | 301 +++++++++++++++++++++++++++++++++++++++-- tools/gui/egg-histogram-view.h | 5 + 7 files changed, 400 insertions(+), 43 deletions(-) diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 7ab1d4a..65c4240 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -37,7 +37,6 @@ static const gint mock_overrideables[] = { PROP_SENSOR_HORIZONTAL_BINNINGS, PROP_SENSOR_VERTICAL_BINNING, PROP_SENSOR_VERTICAL_BINNINGS, - PROP_TRIGGER_MODE, PROP_EXPOSURE_TIME, PROP_ROI_X, PROP_ROI_Y, @@ -301,9 +300,6 @@ static void uca_mock_camera_get_property(GObject *object, guint property_id, GVa 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; diff --git a/plugins/pf/uca-pf-camera.c b/plugins/pf/uca-pf-camera.c index 35b5edd..473ffd3 100644 --- a/plugins/pf/uca-pf-camera.c +++ b/plugins/pf/uca-pf-camera.c @@ -234,6 +234,7 @@ static void uca_pf_camera_get_property(GObject *object, guint property_id, GValu g_value_set_boolean(value, FALSE); break; case PROP_EXPOSURE_TIME: + g_value_set_double(value, 1. / 488.0); break; case PROP_ROI_X: g_value_set_uint(value, 0); diff --git a/src/uca-camera.c b/src/uca-camera.c index 6d92e6a..5684888 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -132,15 +132,19 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara switch (property_id) { case PROP_IS_RECORDING: - g_value_set_boolean(value, priv->is_recording); + g_value_set_boolean (value, priv->is_recording); break; case PROP_IS_READOUT: - g_value_set_boolean(value, priv->is_readout); + g_value_set_boolean (value, priv->is_readout); break; case PROP_TRANSFER_ASYNCHRONOUSLY: - g_value_set_boolean(value, priv->transfer_async); + g_value_set_boolean (value, priv->transfer_async); + break; + + case PROP_TRIGGER_MODE: + g_value_set_enum (value, UCA_CAMERA_TRIGGER_AUTO); break; case PROP_FRAMES_PER_SECOND: diff --git a/tools/gui/control.c b/tools/gui/control.c index f7d3618..b36d188 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -28,6 +28,7 @@ #include "uca-camera.h" #include "uca-plugin-manager.h" #include "egg-property-tree-view.h" +#include "egg-histogram-view.h" typedef struct { @@ -37,6 +38,8 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkWidget *histogram_view; + GtkToggleButton *histogram_button; guchar *buffer; guchar *pixels; @@ -49,15 +52,9 @@ typedef struct { int pixel_size; } ThreadData; -enum { - COLUMN_NAME = 0, - COLUMN_VALUE, - COLUMN_EDITABLE, - NUM_COLUMNS -}; - static UcaPluginManager *plugin_manager; + static void convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) { @@ -106,7 +103,7 @@ grab_thread (void *args) uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter); FILE *fp = fopen (filename, "wb"); fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); fclose (fp); @@ -121,11 +118,18 @@ grab_thread (void *args) } gdk_threads_enter (); + gdk_flush (); gtk_image_clear (GTK_IMAGE (data->image)); gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); + gdk_threads_leave (); + + counter++; } return NULL; } @@ -211,6 +215,12 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { + GtkWidget *window; + GtkWidget *image; + GtkWidget *property_tree_view; + GdkPixbuf *pixbuf; + GtkBox *histogram_box; + GtkContainer *scrolled_property_window; static ThreadData td; GError *error = NULL; @@ -228,15 +238,12 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) "sensor-bitdepth", &bits_per_sample, NULL); - GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); gtk_container_add (scrolled_property_window, property_tree_view); - gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); - GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); td.pixel_size = bits_per_sample > 8 ? 2 : 1; @@ -247,7 +254,14 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.running = FALSE; td.store = FALSE; td.camera = camera; + td.histogram_view = egg_histogram_view_new (); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); @@ -259,8 +273,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); - gtk_widget_show (image); - gtk_widget_show (window); + gtk_widget_show_all (window); } static void diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ee888e8..6d6d791 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -164,28 +164,83 @@ <property name="can_focus">True</property> <property name="border_width">6</property> <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="width_request">300</property> + <object class="GtkVPaned" id="vpaned1"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> <child> - <object class="GtkViewport" id="viewport1"> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="width_request">640</property> + <property name="height_request">480</property> <property name="visible">True</property> - <property name="resize_mode">queue</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> <child> - <object class="GtkImage" id="image"> + <object class="GtkViewport" id="viewport1"> <property name="visible">True</property> - <property name="stock">gtk-missing-image</property> + <property name="resize_mode">queue</property> + <child> + <object class="GtkImage" id="image"> + <property name="width_request">640</property> + <property name="height_request">480</property> + <property name="visible">True</property> + <property name="stock">gtk-missing-image</property> + </object> + </child> </object> </child> </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + <child> + <object class="GtkNotebook" id="notebook1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkHBox" id="histogram-box"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkCheckButton" id="histogram-checkbutton"> + <property name="label" translatable="yes">Enable Live Update</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="border_width">6</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Histogram</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> </child> </object> <packing> - <property name="resize">True</property> - <property name="shrink">False</property> + <property name="resize">False</property> + <property name="shrink">True</property> </packing> </child> <child> diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 809a2d9..d3cb18b 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -15,17 +15,33 @@ 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 <math.h> #include "egg-histogram-view.h" -G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_CELL_RENDERER) +G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_DRAWING_AREA) #define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) +#define MIN_WIDTH 128 +#define MIN_HEIGHT 128 +#define BORDER 2 struct _EggHistogramViewPrivate { - guint foo; + GdkCursorType cursor_type; + gboolean grabbing; + + /* This could be moved into a real histogram class */ + guint n_bins; + gint *bins; + gint min_value; + gint max_value; + gint min_border; + gint max_border; + + gpointer data; + gint n_elements; + gint n_bits; }; enum @@ -46,9 +62,178 @@ egg_histogram_view_new (void) return GTK_WIDGET (view); } +void +egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins) +{ + EggHistogramViewPrivate *priv; + + priv = view->priv; + + if (priv->bins != NULL) + g_free (priv->bins); + + priv->data = data; + priv->bins = g_malloc0 (n_bins * sizeof (guint)); + priv->n_bins = n_bins; + priv->n_bits = n_bits; + priv->n_elements = n_elements; + + priv->min_value = 0; + priv->max_value = (gint) pow(2, n_bits) - 1; + + priv->min_border = 20; + priv->max_border = priv->max_value - 20; +} + +static void +compute_histogram (EggHistogramViewPrivate *priv) +{ + for (guint i = 0; i < priv->n_bins; i++) + priv->bins[i] = 0; + + if (priv->n_bits == 8) { + guint8 *data = (guint8 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint8 v = data[i]; + guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else if (priv->n_bits == 16) { + guint16 *data = (guint16 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint16 v = data[i]; + guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else + g_warning ("%i number of bits unsupported", priv->n_bits); +} + +static void +set_cursor_type (EggHistogramView *view, GdkCursorType cursor_type) +{ + if (cursor_type != view->priv->cursor_type) { + GdkCursor *cursor = gdk_cursor_new (cursor_type); + + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(view)), cursor); + gdk_cursor_unref (cursor); + view->priv->cursor_type = cursor_type; + } +} + +static void +egg_histogram_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + requisition->width = MIN_WIDTH; + requisition->height = MIN_HEIGHT; +} + +static gboolean +egg_histogram_view_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + GtkStyle *style; + cairo_t *cr; + gint width, height; + gint max_value = 0; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + + gdk_cairo_region (cr, event->region); + cairo_clip (cr); + + style = gtk_widget_get_style (widget); + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + /* Draw the background */ + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + height = allocation.height - 2 * BORDER; + + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_translate (cr, 0.5, 0.5); + cairo_rectangle (cr, BORDER, BORDER, width - 1, height - 1); + cairo_stroke (cr); + + if (priv->bins == NULL) + goto cleanup; + + compute_histogram (priv); + + /* Draw border areas */ + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + + if (priv->min_border > 0) { + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); + } + + /* Draw spikes */ + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + goto cleanup; + + gdk_cairo_set_source_color (cr, &style->black); + + if (width > priv->n_bins) { + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = 1; + + for (guint i = 0; i < priv->n_bins; i++, x += skip) { + if (priv->bins[i] == 0) + continue; + + gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; + cairo_move_to (cr, round (x + BORDER), height + BORDER - 1); + cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); + cairo_stroke (cr); + } + } + +cleanup: + cairo_destroy (cr); + return FALSE; +} + +static void +egg_histogram_view_finalize (GObject *object) +{ + EggHistogramViewPrivate *priv; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); + + if (priv->bins) + g_free (priv->bins); + + G_OBJECT_CLASS (egg_histogram_view_parent_class)->finalize (object); +} + static void egg_histogram_view_dispose (GObject *object) { + G_OBJECT_CLASS (egg_histogram_view_parent_class)->dispose (object); } static void @@ -81,20 +266,118 @@ egg_histogram_view_get_property (GObject *object, } } +static gint +get_mouse_distance (EggHistogramViewPrivate *priv, + gint x) +{ + return (priv->min_border + BORDER) - x; +} + +static gboolean +egg_histogram_view_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + if (priv->grabbing) { + priv->min_border = event->x + BORDER; + gtk_widget_queue_draw (widget); + } + else { + gint distance = get_mouse_distance (priv, event->x); + + if (ABS(distance) < 6) + set_cursor_type (view, GDK_FLEUR); + else + set_cursor_type (view, GDK_ARROW); + } + + return TRUE; +} + +static gboolean +egg_histogram_view_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gint width; + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + set_cursor_type (view, GDK_ARROW); + priv->grabbing = FALSE; + + return TRUE; +} + +static gboolean +egg_histogram_view_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + gint distance; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + distance = get_mouse_distance (priv, event->x); + + if (ABS (distance) < 6) { + priv->grabbing = TRUE; + set_cursor_type (view, GDK_FLEUR); + } + + return TRUE; +} + static void egg_histogram_view_class_init (EggHistogramViewClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - gobject_class->set_property = egg_histogram_view_set_property; - gobject_class->get_property = egg_histogram_view_get_property; - gobject_class->dispose = egg_histogram_view_dispose; + object_class->set_property = egg_histogram_view_set_property; + object_class->get_property = egg_histogram_view_get_property; + object_class->dispose = egg_histogram_view_dispose; + object_class->finalize = egg_histogram_view_finalize; + + widget_class->size_request = egg_histogram_view_size_request; + widget_class->expose_event = egg_histogram_view_expose; + widget_class->button_press_event = egg_histogram_view_button_press; + widget_class->button_release_event = egg_histogram_view_button_release; + widget_class->motion_notify_event = egg_histogram_view_motion_notify; g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } static void -egg_histogram_view_init (EggHistogramView *renderer) +egg_histogram_view_init (EggHistogramView *view) { - renderer->priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (renderer); + EggHistogramViewPrivate *priv; + + view->priv = priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (view); + + priv->bins = NULL; + priv->data = NULL; + priv->n_bins = 0; + priv->n_elements = 0; + + priv->cursor_type = GDK_ARROW; + priv->grabbing = FALSE; + + gtk_widget_add_events (GTK_WIDGET (view), + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_POINTER_MOTION_MASK); } diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 23581dc..a1df0ba 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -48,6 +48,11 @@ struct _EggHistogramViewClass GType egg_histogram_view_get_type (void); GtkWidget * egg_histogram_view_new (void); +void egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins); G_END_DECLS -- cgit v1.2.3 From 195ccad179d96766165b1dc846dbe066fffc43ac Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Wed, 10 Oct 2012 17:47:00 +0200 Subject: Disable unused variables --- tools/gui/egg-histogram-view.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index d3cb18b..7abc2be 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -305,11 +305,11 @@ egg_histogram_view_button_release (GtkWidget *widget, { EggHistogramView *view; EggHistogramViewPrivate *priv; - GtkAllocation allocation; - gint width; + /* GtkAllocation allocation; */ + /* gint width; */ - gtk_widget_get_allocation (widget, &allocation); - width = allocation.width - 2 * BORDER; + /* gtk_widget_get_allocation (widget, &allocation); */ + /* width = allocation.width - 2 * BORDER; */ view = EGG_HISTOGRAM_VIEW (widget); priv = view->priv; -- cgit v1.2.3 From 6200956f93eabb0fe040902fda3716b676b2921a Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 11 Oct 2012 08:45:56 +0200 Subject: Link explicitly against libm --- tools/gui/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/gui/CMakeLists.txt b/tools/gui/CMakeLists.txt index b30f3ea..ff5e9f6 100644 --- a/tools/gui/CMakeLists.txt +++ b/tools/gui/CMakeLists.txt @@ -30,7 +30,9 @@ if (GTK2_FOUND) egg-histogram-view.c) target_link_libraries(control uca - ${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES}) + ${GTK2_LIBRARIES} + ${GTHREAD2_LIBRARIES} + m) install(TARGETS control RUNTIME DESTINATION bin) -- cgit v1.2.3 From 0c0c93912094bb668a31703b2640f72a0f1b5df8 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 11 Oct 2012 09:07:50 +0200 Subject: Don't set the maximum size of the preview image --- tools/gui/control.glade | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 6d6d791..7ef712d 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -181,8 +181,6 @@ <property name="resize_mode">queue</property> <child> <object class="GtkImage" id="image"> - <property name="width_request">640</property> - <property name="height_request">480</property> <property name="visible">True</property> <property name="stock">gtk-missing-image</property> </object> -- cgit v1.2.3 From 13b2833ea9c16750efb923a981ea04d37aaa6789 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 11 Oct 2012 16:38:26 +0200 Subject: Implement adjustable histogram --- src/uca-camera.c | 2 +- tools/gui/control.c | 70 ++++++------ tools/gui/control.glade | 112 +++++++++++++++++--- tools/gui/egg-histogram-view.c | 234 +++++++++++++++++++++++++++++++---------- tools/gui/egg-histogram-view.h | 4 + 5 files changed, 316 insertions(+), 106 deletions(-) diff --git a/src/uca-camera.c b/src/uca-camera.c index 5684888..091ef54 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -128,7 +128,7 @@ uca_camera_set_property (GObject *object, guint property_id, const GValue *value static void uca_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE(object); + UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE (object); switch (property_id) { case PROP_IS_RECORDING: diff --git a/tools/gui/control.c b/tools/gui/control.c index b36d188..214e4da 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -19,10 +19,7 @@ #include <gtk/gtk.h> #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <errno.h> +#include <math.h> #include "config.h" #include "uca-camera.h" @@ -56,39 +53,28 @@ static UcaPluginManager *plugin_manager; static void -convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_8bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { + gdouble factor = 255.0 / (max - min); + for (int i = 0, j = 0; i < width*height; i++) { - output[j++] = input[i]; - output[j++] = input[i]; - output[j++] = input[i]; + guchar val = (guchar) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } static void -convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_16bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { - guint16 *in = (guint16 *) input; - guint16 min = G_MAXUINT16, max = 0; - gfloat spread = 0.0f; - - for (int i = 0; i < width * height; i++) { - guint16 v = in[i]; - if (v < min) - min = v; - if (v > max) - max = v; - } - - spread = (gfloat) max - min; + gdouble factor = 255.0 / (max - min); - if (spread > 0.0f) { - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } @@ -100,6 +86,9 @@ grab_thread (void *args) gint counter = 0; while (data->running) { + gdouble min_value; + gdouble max_value; + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { @@ -111,11 +100,12 @@ grab_thread (void *args) /* FIXME: We should actually check if this is really a new frame and * just do nothing if it is an already displayed one. */ + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min_value, &max_value); + if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - else if (data->pixel_size == 2) { - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - } + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); + else if (data->pixel_size == 2) + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); gdk_threads_enter (); @@ -221,6 +211,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) GdkPixbuf *pixbuf; GtkBox *histogram_box; GtkContainer *scrolled_property_window; + GtkAdjustment *max_bin_adjustment; static ThreadData td; GError *error = NULL; @@ -259,7 +250,8 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), + td.buffer, td.width * td.height, bits_per_sample, 256); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); @@ -269,6 +261,16 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); set_tool_button_state (&td); + g_object_bind_property (gtk_builder_get_object (builder, "min_bin_value_adjustment"), "value", + td.histogram_view, "minimum-bin-value", + G_BINDING_DEFAULT); + + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max_bin_value_adjustment")); + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + g_object_bind_property (max_bin_adjustment, "value", + td.histogram_view, "maximum-bin-value", + G_BINDING_DEFAULT); + g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 7ef712d..ebe2cc8 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -204,17 +204,97 @@ <placeholder/> </child> <child> - <object class="GtkCheckButton" id="histogram-checkbutton"> - <property name="label" translatable="yes">Enable Live Update</property> + <object class="GtkTable" id="table1"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> <property name="border_width">6</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="column_spacing">6</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Minimum Value:</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + <property name="x_padding">6</property> + <property name="y_padding">6</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton1"> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">•</property> + <property name="adjustment">min_bin_value_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_EXPAND</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Maximum Value:</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + <property name="x_padding">6</property> + <property name="y_padding">6</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton2"> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">•</property> + <property name="adjustment">max_bin_value_adjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_EXPAND</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="histogram-checkbutton"> + <property name="label" translatable="yes">Live Update</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="border_width">6</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options"></property> + <property name="y_options"></property> + </packing> + </child> + <child> + <placeholder/> + </child> </object> <packing> - <property name="pack_type">end</property> + <property name="expand">False</property> + <property name="fill">False</property> <property name="position">1</property> </packing> </child> @@ -264,13 +344,6 @@ </object> </child> </object> - <object class="GtkAdjustment" id="adjustment_scale"> - <property name="value">65535</property> - <property name="lower">1</property> - <property name="upper">65535</property> - <property name="step_increment">1</property> - <property name="page_increment">10</property> - </object> <object class="GtkWindow" id="choice-window"> <property name="border_width">6</property> <child> @@ -352,4 +425,15 @@ </object> </child> </object> + <object class="GtkAdjustment" id="min_bin_value_adjustment"> + <property name="upper">65535</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="max_bin_value_adjustment"> + <property name="value">256</property> + <property name="upper">65535</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> </interface> diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 7abc2be..91e61e8 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -34,11 +34,14 @@ struct _EggHistogramViewPrivate /* This could be moved into a real histogram class */ guint n_bins; gint *bins; - gint min_value; - gint max_value; - gint min_border; + gint *grabbed; + gint min_border; /* threshold set in screen units */ gint max_border; + gdouble min_value; /* lowest value of the first bin */ + gdouble max_value; /* highest value of the last bin */ + gdouble range; + gpointer data; gint n_elements; gint n_bits; @@ -47,6 +50,8 @@ struct _EggHistogramViewPrivate enum { PROP_0, + PROP_MINIMUM_BIN_VALUE, + PROP_MAXIMUM_BIN_VALUE, N_PROPERTIES }; @@ -71,6 +76,7 @@ egg_histogram_view_set_data (EggHistogramView *view, { EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); priv = view->priv; if (priv->bins != NULL) @@ -82,16 +88,46 @@ egg_histogram_view_set_data (EggHistogramView *view, priv->n_bits = n_bits; priv->n_elements = n_elements; - priv->min_value = 0; + priv->min_value = 0.0; priv->max_value = (gint) pow(2, n_bits) - 1; - priv->min_border = 20; - priv->max_border = priv->max_value - 20; + priv->min_border = 0; + priv->max_border = 256; + priv->range = priv->max_value - priv->min_value; +} + +void +egg_histogram_get_visible_range (EggHistogramView *view, gdouble *min, gdouble *max) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gdouble width; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + width = (gdouble) allocation.width - 2 * BORDER; + priv = view->priv; + + *min = (priv->min_border - 2) / width * priv->range; + *max = (priv->max_border - 2) / width * priv->range; +} + +static void +set_max_border (EggHistogramView *view) +{ + GtkAllocation allocation; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + view->priv->max_border = allocation.width - 2 * BORDER; } static void compute_histogram (EggHistogramViewPrivate *priv) { + guint n_bins = priv->n_bins - 1; + for (guint i = 0; i < priv->n_bins; i++) priv->bins[i] = 0; @@ -100,8 +136,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint8 v = data[i]; - guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) round (((gdouble) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else if (priv->n_bits == 16) { @@ -109,8 +148,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint16 v = data[i]; - guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) floor (((gdouble ) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else @@ -137,6 +179,36 @@ egg_histogram_view_size_request (GtkWidget *widget, requisition->height = MIN_HEIGHT; } +static void +draw_bins (EggHistogramViewPrivate *priv, + cairo_t *cr, + gint width, + gint height) +{ + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = BORDER; + gdouble ys = height + BORDER - 1; + gint max_value = 0; + + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + return; + + for (guint i = 0; i < priv->n_bins && x < (width - BORDER); i++, x += skip) { + if (priv->bins[i] == 0) + continue; + + gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; + cairo_move_to (cr, round (x), ys); + cairo_line_to (cr, round (x), ys - y); + cairo_stroke (cr); + } +} + static gboolean egg_histogram_view_expose (GtkWidget *widget, GdkEventExpose *event) @@ -146,7 +218,6 @@ egg_histogram_view_expose (GtkWidget *widget, GtkStyle *style; cairo_t *cr; gint width, height; - gint max_value = 0; priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); cr = gdk_cairo_create (gtk_widget_get_window (widget)); @@ -181,36 +252,15 @@ egg_histogram_view_expose (GtkWidget *widget, /* Draw border areas */ gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); - if (priv->min_border > 0) { - cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); - cairo_fill (cr); - } - - /* Draw spikes */ - for (guint i = 0; i < priv->n_bins; i++) { - if (priv->bins[i] > max_value) - max_value = priv->bins[i]; - } + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); - if (max_value == 0) - goto cleanup; + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->min_border - 0.5, height - 1); + cairo_fill (cr); + /* Draw spikes */ gdk_cairo_set_source_color (cr, &style->black); - - if (width > priv->n_bins) { - gdouble skip = ((gdouble) width) / priv->n_bins; - gdouble x = 1; - - for (guint i = 0; i < priv->n_bins; i++, x += skip) { - if (priv->bins[i] == 0) - continue; - - gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; - cairo_move_to (cr, round (x + BORDER), height + BORDER - 1); - cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); - cairo_stroke (cr); - } - } + draw_bins (priv, cr, width, height); cleanup: cairo_destroy (cr); @@ -242,9 +292,42 @@ egg_histogram_view_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { + EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v > priv->max_value) + g_warning ("Minimum value `%f' larger than maximum value `%f'", + v, priv->max_value); + else { + priv->min_value = v; + priv->range = priv->max_value - v; + priv->min_border = 0; + } + } + break; + + case PROP_MAXIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v < priv->min_value) + g_warning ("Maximum value `%f' larger than minimum value `%f'", + v, priv->min_value); + else { + priv->max_value = v; + priv->range = v - priv->min_value; + set_max_border (EGG_HISTOGRAM_VIEW (object)); + } + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); return; @@ -257,20 +340,48 @@ egg_histogram_view_get_property (GObject *object, GValue *value, GParamSpec *pspec) { + EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + g_value_set_double (value, priv->min_value); + break; + + case PROP_MAXIMUM_BIN_VALUE: + g_value_set_double (value, priv->max_value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); return; } } -static gint -get_mouse_distance (EggHistogramViewPrivate *priv, +static gboolean +is_on_border (EggHistogramViewPrivate *priv, + gint x) +{ + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + return ABS (d1) < 6 || ABS (d2) < 6; +} + +static gint * +get_grabbed_border (EggHistogramViewPrivate *priv, gint x) { - return (priv->min_border + BORDER) - x; + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + + if (ABS (d1) < 6) + return &priv->min_border; + else if (ABS (d2) < 6) + return &priv->max_border; + + return NULL; } static gboolean @@ -284,13 +395,12 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - priv->min_border = event->x + BORDER; + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); } else { - gint distance = get_mouse_distance (priv, event->x); - - if (ABS(distance) < 6) + if (is_on_border (priv, event->x)) set_cursor_type (view, GDK_FLEUR); else set_cursor_type (view, GDK_ARROW); @@ -304,18 +414,10 @@ egg_histogram_view_button_release (GtkWidget *widget, GdkEventButton *event) { EggHistogramView *view; - EggHistogramViewPrivate *priv; - /* GtkAllocation allocation; */ - /* gint width; */ - - /* gtk_widget_get_allocation (widget, &allocation); */ - /* width = allocation.width - 2 * BORDER; */ view = EGG_HISTOGRAM_VIEW (widget); - priv = view->priv; - set_cursor_type (view, GDK_ARROW); - priv->grabbing = FALSE; + view->priv->grabbing = FALSE; return TRUE; } @@ -326,14 +428,13 @@ egg_histogram_view_button_press (GtkWidget *widget, { EggHistogramView *view; EggHistogramViewPrivate *priv; - gint distance; view = EGG_HISTOGRAM_VIEW (widget); priv = view->priv; - distance = get_mouse_distance (priv, event->x); - if (ABS (distance) < 6) { + if (is_on_border (priv, event->x)) { priv->grabbing = TRUE; + priv->grabbed = get_grabbed_border (priv, event->x); set_cursor_type (view, GDK_FLEUR); } @@ -357,6 +458,23 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) widget_class->button_release_event = egg_histogram_view_button_release; widget_class->motion_notify_event = egg_histogram_view_motion_notify; + egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE] = + g_param_spec_double ("minimum-bin-value", + "Smallest possible bin value", + "Smallest possible bin value, everything below is discarded.", + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE); + + egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE] = + g_param_spec_double ("maximum-bin-value", + "Largest possible bin value", + "Largest possible bin value, everything above is discarded.", + 0.0, G_MAXDOUBLE, 256.0, + G_PARAM_READWRITE); + + g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); + g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } @@ -371,6 +489,8 @@ egg_histogram_view_init (EggHistogramView *view) priv->data = NULL; priv->n_bins = 0; priv->n_elements = 0; + priv->min_value = priv->min_border = 0; + priv->max_value = priv->max_border = 256; priv->cursor_type = GDK_ARROW; priv->grabbing = FALSE; diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index a1df0ba..61a1c8c 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -53,6 +53,10 @@ void egg_histogram_view_set_data (EggHistogramView *view, guint n_elements, guint n_bits, guint n_bins); +void egg_histogram_get_visible_range + (EggHistogramView *view, + gdouble *min, + gdouble *max); G_END_DECLS -- cgit v1.2.3 From 9e0c86218a6857965e4d257508322ae77f44fcf5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 11 Oct 2012 16:57:16 +0200 Subject: Use updated gtester.xml by Mihael Koep --- test/gtester.xsl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/gtester.xsl b/test/gtester.xsl index e8236d6..f2a5e97 100644 --- a/test/gtester.xsl +++ b/test/gtester.xsl @@ -1,7 +1,7 @@ <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - + <!-- I can't believe I have to do this --> <!-- Based on this code: http://geekswithblogs.net/Erik/archive/2008/04/01/120915.aspx @@ -29,19 +29,21 @@ <xsl:template match="/"> <xsl:for-each select="gtester"> <testsuite> + <!-- currently we do not support different test binaries and only take the path + of the first as the testsuite name --> <xsl:attribute name="name"> <xsl:value-of select="testbinary[1]/@path"/> </xsl:attribute> <xsl:attribute name="tests"> - <xsl:value-of select="count(testbinary[1]/testcase)"/> + <xsl:value-of select="count(testbinary/testcase[not(@skipped='1')])"/> </xsl:attribute> <xsl:attribute name="time"> - <xsl:value-of select="sum(testbinary[1]/testcase/duration)"/> + <xsl:value-of select="sum(testbinary/duration)"/> </xsl:attribute> <xsl:attribute name="failures"> - <xsl:value-of select="count(testbinary[1]/testcase/status[@result='failed'])"/> + <xsl:value-of select="count(testbinary/testcase/status[@result='failed'])"/> </xsl:attribute> - <xsl:for-each select="testbinary[1]/testcase"> + <xsl:for-each select="testbinary/testcase[not(@skipped='1')]"> <testcase> <xsl:variable name="classname"> <xsl:call-template name="strreplace"> -- cgit v1.2.3 From 6b82a9a175c92c39f25e9b5965b2e9f5c35f65c2 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 11 Oct 2012 17:48:48 +0200 Subject: Update API call --- docs/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual.md b/docs/manual.md index 5162ddf..8bf38aa 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -143,7 +143,7 @@ manager first: ~~~ {.c} manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, "pco", &error); + camera = uca_plugin_manager_get_camera (manager, "pco", &error); ~~~ Errors are indicated with a returned value `NULL` and `error` set to a value -- cgit v1.2.3 From ef7ff789e9c15f4f4b8c65585de7e7fa4f9c9438 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 12 Oct 2012 14:47:07 +0200 Subject: Add ring buffer recording for assessment --- plugins/mock/uca-mock-camera.c | 5 +- tools/gui/CMakeLists.txt | 1 + tools/gui/control.c | 190 ++++++++++++++++++++++++++--------------- tools/gui/control.glade | 33 ++++++- tools/gui/ring-buffer.c | 64 ++++++++++++++ tools/gui/ring-buffer.h | 28 ++++++ 6 files changed, 246 insertions(+), 75 deletions(-) create mode 100644 tools/gui/ring-buffer.c create mode 100644 tools/gui/ring-buffer.h diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 65c4240..38caf0d 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -146,9 +146,10 @@ static void print_number(gchar *buffer, guint number, guint x, guint y, guint wi static void print_current_frame(UcaMockCameraPrivate *priv, gchar *buffer) { guint number = priv->current_frame; - guint divisor = 100000000; + guint divisor = 10000000; int x = 10; - while (divisor > 1) { + + while (divisor > 0) { print_number(buffer, number / divisor, x, 10, priv->width); number = number % divisor; divisor = divisor / 10; diff --git a/tools/gui/CMakeLists.txt b/tools/gui/CMakeLists.txt index ff5e9f6..1000ac6 100644 --- a/tools/gui/CMakeLists.txt +++ b/tools/gui/CMakeLists.txt @@ -25,6 +25,7 @@ if (GTK2_FOUND) add_executable(control control.c + ring-buffer.c egg-property-cell-renderer.c egg-property-tree-view.c egg-histogram-view.c) diff --git a/tools/gui/control.c b/tools/gui/control.c index 214e4da..84799cb 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -22,11 +22,17 @@ #include <math.h> #include "config.h" +#include "ring-buffer.h" #include "uca-camera.h" #include "uca-plugin-manager.h" #include "egg-property-tree-view.h" #include "egg-histogram-view.h" +typedef enum { + IDLE, + RUNNING, + RECORDING +} State; typedef struct { UcaCamera *camera; @@ -35,13 +41,14 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; - GtkWidget *histogram_view; + + GtkWidget *histogram_view; GtkToggleButton *histogram_button; + GtkAdjustment *frame_slider; - guchar *buffer; + RingBuffer *buffer; guchar *pixels; - gboolean running; - gboolean store; + State state; int timestamp; int width; @@ -53,70 +60,66 @@ static UcaPluginManager *plugin_manager; static void -convert_8bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) +convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) { - gdouble factor = 255.0 / (max - min); - - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guchar) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; + gdouble min; + gdouble max; + gdouble factor; + guint8 *output; + + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); + factor = 255.0 / (max - min); + output = data->pixels; + + if (data->pixel_size == 1) { + guint8 *input = (guint8 *) buffer; + + for (int i = 0, j = 0; i < data->width * data->height; i++) { + guchar val = (guchar) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } + } + else if (data->pixel_size == 2) { + guint16 *input = (guint16 *) buffer; + + for (int i = 0, j = 0; i < data->width * data->height; i++) { + guchar val = (guint8) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } } } static void -convert_16bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) +update_pixbuf (ThreadData *data) { - gdouble factor = 255.0 / (max - min); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); } -static void * -grab_thread (void *args) +static gpointer +preview_frames (void *args) { ThreadData *data = (ThreadData *) args; - gchar filename[FILENAME_MAX] = {0,}; gint counter = 0; - while (data->running) { - gdouble min_value; - gdouble max_value; + while (data->state == RUNNING) { + gpointer buffer; - uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); - - if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter); - FILE *fp = fopen (filename, "wb"); - fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); - fclose (fp); - } - - /* FIXME: We should actually check if this is really a new frame and - * just do nothing if it is an already displayed one. */ - egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min_value, &max_value); - - if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); - else if (data->pixel_size == 2) - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, NULL); + convert_grayscale_to_rgb (data, buffer); gdk_threads_enter (); - - gdk_flush (); - gtk_image_clear (GTK_IMAGE (data->image)); - gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); - - if (gtk_toggle_button_get_active (data->histogram_button)) - gtk_widget_queue_draw (data->histogram_view); - + update_pixbuf (data); gdk_threads_leave (); counter++; @@ -124,6 +127,33 @@ grab_thread (void *args) return NULL; } +static gpointer +record_frames (gpointer args) +{ + ThreadData *data; + gpointer buffer; + guint n_frames = 0; + + data = (ThreadData *) args; + ring_buffer_reset (data->buffer); + + while (data->state == RECORDING) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, NULL); + ring_buffer_proceed (data->buffer); + n_frames++; + } + + n_frames = ring_buffer_get_num_blocks (data->buffer); + + gdk_threads_enter (); + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + gdk_threads_leave (); + + return NULL; +} + gboolean on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { @@ -134,17 +164,39 @@ void on_destroy (GtkWidget *widget, gpointer data) { ThreadData *td = (ThreadData *) data; - td->running = FALSE; + + td->state = IDLE; g_object_unref (td->camera); + ring_buffer_free (td->buffer); + gtk_main_quit (); } static void set_tool_button_state (ThreadData *data) { - gtk_widget_set_sensitive (data->start_button, !data->running); - gtk_widget_set_sensitive (data->stop_button, data->running); - gtk_widget_set_sensitive (data->record_button, !data->running); + gtk_widget_set_sensitive (data->start_button, + data->state == IDLE); + gtk_widget_set_sensitive (data->stop_button, + data->state == RUNNING || data->state == RECORDING); + gtk_widget_set_sensitive (data->record_button, + data->state == IDLE); +} + +static void +on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) +{ + ThreadData *data = (ThreadData *) user_data; + + if (data->state == IDLE) { + gpointer buffer; + gint index; + + index = (gint) gtk_adjustment_get_value (adjustment); + buffer = ring_buffer_get_pointer (data->buffer, index); + convert_grayscale_to_rgb (data, buffer); + update_pixbuf (data); + } } static void @@ -153,7 +205,7 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->running = TRUE; + data->state = RUNNING; set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); @@ -163,7 +215,7 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) return; } - if (!g_thread_create (grab_thread, data, FALSE, &error)) { + if (!g_thread_create (preview_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); return; } @@ -175,8 +227,7 @@ on_stop_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->running = FALSE; - data->store = FALSE; + data->state = IDLE; set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); @@ -192,13 +243,12 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) GError *error = NULL; data->timestamp = (int) time (0); - data->store = TRUE; - data->running = TRUE; + data->state = RECORDING; set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (grab_thread, data, FALSE, &error)) + if (!g_thread_create (record_frames, data, FALSE, &error)) g_printerr ("Failed to create thread: %s\n", error->message); } @@ -240,18 +290,19 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.pixel_size = bits_per_sample > 8 ? 2 : 1; td.image = image; td.pixbuf = pixbuf; - td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.buffer = ring_buffer_new (td.pixel_size * td.width * td.height, 256); td.pixels = gdk_pixbuf_get_pixels (pixbuf); - td.running = FALSE; - td.store = FALSE; + td.state = IDLE; td.camera = camera; td.histogram_view = egg_histogram_view_new (); td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), - td.buffer, td.width * td.height, bits_per_sample, 256); + ring_buffer_get_current_pointer (td.buffer), + td.width * td.height, bits_per_sample, 256); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); @@ -261,16 +312,17 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); set_tool_button_state (&td); - g_object_bind_property (gtk_builder_get_object (builder, "min_bin_value_adjustment"), "value", + g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", G_BINDING_DEFAULT); - max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max_bin_value_adjustment")); + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); g_object_bind_property (max_bin_adjustment, "value", td.histogram_view, "maximum-bin-value", G_BINDING_DEFAULT); + g_signal_connect (td.frame_slider, "value-changed", G_CALLBACK (on_frame_slider_changed), &td); g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ebe2cc8..c3008ec 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -230,7 +230,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="invisible_char">•</property> - <property name="adjustment">min_bin_value_adjustment</property> + <property name="adjustment">min-bin-value-adjustment</property> </object> <packing> <property name="left_attach">1</property> @@ -260,7 +260,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="invisible_char">•</property> - <property name="adjustment">max_bin_value_adjustment</property> + <property name="adjustment">max-bin-value-adjustment</property> </object> <packing> <property name="left_attach">1</property> @@ -309,6 +309,27 @@ <property name="tab_fill">False</property> </packing> </child> + <child> + <object class="GtkHScale" id="hscale1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">frames-adjustment</property> + <property name="digits">0</property> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="label" translatable="yes">Preview</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> </object> <packing> <property name="resize">True</property> @@ -425,15 +446,19 @@ </object> </child> </object> - <object class="GtkAdjustment" id="min_bin_value_adjustment"> + <object class="GtkAdjustment" id="min-bin-value-adjustment"> <property name="upper">65535</property> <property name="step_increment">1</property> <property name="page_increment">10</property> </object> - <object class="GtkAdjustment" id="max_bin_value_adjustment"> + <object class="GtkAdjustment" id="max-bin-value-adjustment"> <property name="value">256</property> <property name="upper">65535</property> <property name="step_increment">1</property> <property name="page_increment">10</property> </object> + <object class="GtkAdjustment" id="frames-adjustment"> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> </interface> diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c new file mode 100644 index 0000000..56c7620 --- /dev/null +++ b/tools/gui/ring-buffer.c @@ -0,0 +1,64 @@ + +#include <math.h> +#include "ring-buffer.h" + +RingBuffer * +ring_buffer_new (gsize block_size, + gsize n_blocks) +{ + RingBuffer *buffer; + + buffer = g_new0 (RingBuffer, 1); + buffer->block_size = block_size; + buffer->n_blocks_total = n_blocks; + buffer->n_blocks_used = 0; + buffer->start_index = 0; + buffer->data = g_malloc0 (n_blocks * buffer->block_size); + + return buffer; +} + +void +ring_buffer_free (RingBuffer *buffer) +{ + g_free (buffer->data); + g_free (buffer); +} + +void +ring_buffer_reset (RingBuffer *buffer) +{ + buffer->n_blocks_used = 0; + buffer->start_index = 0; +} + +gpointer +ring_buffer_get_current_pointer (RingBuffer *buffer) +{ + return ring_buffer_get_pointer (buffer, 0); +} + +gpointer +ring_buffer_get_pointer (RingBuffer *buffer, + guint index) +{ + g_assert (index < buffer->n_blocks_total); + return buffer->data + ((buffer->start_index + index) % buffer->n_blocks_total) * buffer->block_size; +} + +guint +ring_buffer_get_num_blocks (RingBuffer *buffer) +{ + return buffer->n_blocks_used; +} + +void +ring_buffer_proceed (RingBuffer *buffer) +{ + buffer->start_index++; + + if (buffer->n_blocks_used < buffer->n_blocks_total) + buffer->n_blocks_used++; + else + buffer->start_index = buffer->start_index % buffer->n_blocks_total; +} diff --git a/tools/gui/ring-buffer.h b/tools/gui/ring-buffer.h new file mode 100644 index 0000000..22cbde7 --- /dev/null +++ b/tools/gui/ring-buffer.h @@ -0,0 +1,28 @@ +#ifndef RING_BUFFER_H +#define RING_BUFFER_H + +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct { + guchar *data; + gsize block_size; + guint n_blocks_total; + guint n_blocks_used; + guint start_index; +} RingBuffer; + +RingBuffer * ring_buffer_new (gsize block_size, + gsize n_blocks); +void ring_buffer_free (RingBuffer *buffer); +void ring_buffer_reset (RingBuffer *buffer); +gpointer ring_buffer_get_current_pointer (RingBuffer *buffer); +gpointer ring_buffer_get_pointer (RingBuffer *buffer, + guint index); +guint ring_buffer_get_num_blocks (RingBuffer *buffer); +void ring_buffer_proceed (RingBuffer *buffer); + +G_END_DECLS + +#endif -- cgit v1.2.3 From c48496b50a72575438f87da69080a48e0878a121 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 12 Oct 2012 16:17:53 +0200 Subject: Control memory size via command line --- tools/gui/control.c | 110 ++++++++++++++++++++++++++++++++---------------- tools/gui/control.glade | 2 +- tools/gui/ring-buffer.c | 2 +- 3 files changed, 76 insertions(+), 38 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index 84799cb..eab2be7 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -57,7 +57,7 @@ typedef struct { } ThreadData; static UcaPluginManager *plugin_manager; - +static gsize mem_size = 2048; static void convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) @@ -255,69 +255,86 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { + static ThreadData td; + UcaCamera *camera; GtkWidget *window; GtkWidget *image; + GtkWidget *histogram_view; GtkWidget *property_tree_view; GdkPixbuf *pixbuf; GtkBox *histogram_box; - GtkContainer *scrolled_property_window; + GtkContainer *property_window; GtkAdjustment *max_bin_adjustment; - static ThreadData td; + RingBuffer *ring_buffer; + gsize image_size; + guint n_frames; + guint bits_per_sample; + guint pixel_size; + guint width, height; + GError *error = NULL; - GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); + camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); if ((camera == NULL) || (error != NULL)) { g_error ("%s\n", error->message); gtk_main_quit (); } - guint bits_per_sample; g_object_get (camera, - "roi-width", &td.width, - "roi-height", &td.height, + "roi-width", &width, + "roi-height", &height, "sensor-bitdepth", &bits_per_sample, NULL); - property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - gtk_container_add (scrolled_property_window, property_tree_view); + histogram_view = egg_histogram_view_new (); + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "property-window")); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); + + td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); + td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); + td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); + + /* Set initial data */ + pixel_size = bits_per_sample > 8 ? 2 : 1; + image_size = pixel_size * width * height; + n_frames = mem_size * 1024 * 1024 / image_size; + ring_buffer = ring_buffer_new (image_size, n_frames); + + set_tool_button_state (&td); + + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), + ring_buffer_get_current_pointer (ring_buffer), + width * height, bits_per_sample, 256); - image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); - td.pixel_size = bits_per_sample > 8 ? 2 : 1; + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + + g_message ("Allocated memory for %d frames", n_frames); + + td.pixel_size = pixel_size; td.image = image; td.pixbuf = pixbuf; - td.buffer = ring_buffer_new (td.pixel_size * td.width * td.height, 256); + td.buffer = ring_buffer; td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.state = IDLE; td.camera = camera; - td.histogram_view = egg_histogram_view_new (); - td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); - td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); - - histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); - gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), - ring_buffer_get_current_pointer (td.buffer), - td.width * td.height, bits_per_sample, 256); - - window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - - td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); - td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); - td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); - set_tool_button_state (&td); + td.width = width; + td.height = height; + td.histogram_view = histogram_view; + /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", G_BINDING_DEFAULT); - max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); - gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); g_object_bind_property (max_bin_adjustment, "value", td.histogram_view, "maximum-bin-value", G_BINDING_DEFAULT); @@ -326,6 +343,11 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + + /* Layout */ + gtk_container_add (property_window, property_tree_view); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); gtk_widget_show_all (window); } @@ -398,16 +420,32 @@ create_choice_window (GtkBuilder *builder) int main (int argc, char *argv[]) { + GtkBuilder *builder; + GOptionContext *context; GError *error = NULL; + static GOptionEntry entries[] = + { + { "mem-size", 'm', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, + { NULL } + }; + + context = g_option_context_new ("- control libuca cameras"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Option parsing failed: %s\n", error->message); + return 1; + } + g_thread_init (NULL); gdk_threads_init (); gtk_init (&argc, &argv); - GtkBuilder *builder = gtk_builder_new (); + builder = gtk_builder_new (); if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { - g_print ("Error: %s\n", error->message); + g_print ("Could not load UI file: %s\n", error->message); return 1; } diff --git a/tools/gui/control.glade b/tools/gui/control.glade index c3008ec..90d9511 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -343,7 +343,7 @@ </packing> </child> <child> - <object class="GtkScrolledWindow" id="scrolledwindow2"> + <object class="GtkScrolledWindow" id="property-window"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">automatic</property> diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c index 56c7620..5915d2a 100644 --- a/tools/gui/ring-buffer.c +++ b/tools/gui/ring-buffer.c @@ -13,7 +13,7 @@ ring_buffer_new (gsize block_size, buffer->n_blocks_total = n_blocks; buffer->n_blocks_used = 0; buffer->start_index = 0; - buffer->data = g_malloc0 (n_blocks * buffer->block_size); + buffer->data = g_malloc0_n (n_blocks, block_size); return buffer; } -- cgit v1.2.3 From 63a030a0d65f4ab77a2cbc138eaf5782e276e290 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 12 Oct 2012 16:29:21 +0200 Subject: Accept anything else than 8 bit as 16 bits For now, there is no other possible format. --- tools/gui/egg-histogram-view.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 91e61e8..5041ba2 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -143,7 +143,7 @@ compute_histogram (EggHistogramViewPrivate *priv) } } } - else if (priv->n_bits == 16) { + else { guint16 *data = (guint16 *) priv->data; for (guint i = 0; i < priv->n_elements; i++) { @@ -155,8 +155,6 @@ compute_histogram (EggHistogramViewPrivate *priv) } } } - else - g_warning ("%i number of bits unsupported", priv->n_bits); } static void -- cgit v1.2.3 From be1bfae1ecef5032e667174da4b4ad016d47887b Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 12 Oct 2012 16:31:06 +0200 Subject: Reflect correct state of camera --- tools/gui/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index eab2be7..5e8860f 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -205,8 +205,6 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->state = RUNNING; - set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); @@ -219,6 +217,8 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) g_printerr ("Failed to create thread: %s\n", error->message); return; } + + data->state = RUNNING; } static void -- cgit v1.2.3 From 6d4826f326f981a207ed6d64d5c481d0b1bddd00 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 12 Oct 2012 16:47:51 +0200 Subject: Fix button states --- tools/gui/control.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index 5e8860f..e01bc7d 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -191,7 +191,7 @@ on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) if (data->state == IDLE) { gpointer buffer; gint index; - + index = (gint) gtk_adjustment_get_value (adjustment); buffer = ring_buffer_get_pointer (data->buffer, index); convert_grayscale_to_rgb (data, buffer); @@ -205,7 +205,6 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); if (error != NULL) { @@ -213,12 +212,14 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) return; } + data->state = RUNNING; + set_tool_button_state (data); + if (!g_thread_create (preview_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); - return; + data->state = IDLE; + set_tool_button_state (data); } - - data->state = RUNNING; } static void @@ -242,14 +243,21 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + } + data->timestamp = (int) time (0); data->state = RECORDING; - set_tool_button_state (data); - uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (record_frames, data, FALSE, &error)) + if (!g_thread_create (record_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); + data->state = IDLE; + set_tool_button_state (data); + } } static void @@ -434,7 +442,7 @@ main (int argc, char *argv[]) g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Option parsing failed: %s\n", error->message); + g_print ("Option parsing failed: %s\n", error->message); return 1; } -- cgit v1.2.3 From 33a90d8dc20a513722f5fdf66a99cff91be422d5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 15 Oct 2012 10:33:14 +0200 Subject: Fix replay feature --- tools/gui/control.c | 54 ++++++++++++++++++++++++------------------ tools/gui/egg-histogram-view.c | 29 ++++++++++++++++++++--- tools/gui/egg-histogram-view.h | 3 +++ tools/gui/ring-buffer.c | 12 +++++----- tools/gui/ring-buffer.h | 2 +- 5 files changed, 67 insertions(+), 33 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index e01bc7d..f26cafc 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -79,6 +79,9 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[j++] = val; output[j++] = val; output[j++] = val; + /* if (i < 10) { */ + /* g_print ("%i->%i ", input[i], val); */ + /* } */ } } else if (data->pixel_size == 2) { @@ -161,13 +164,11 @@ on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) } void -on_destroy (GtkWidget *widget, gpointer data) +on_destroy (GtkWidget *widget, ThreadData *data) { - ThreadData *td = (ThreadData *) data; - - td->state = IDLE; - g_object_unref (td->camera); - ring_buffer_free (td->buffer); + data->state = IDLE; + g_object_unref (data->camera); + ring_buffer_free (data->buffer); gtk_main_quit (); } @@ -184,25 +185,27 @@ set_tool_button_state (ThreadData *data) } static void -on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) +update_current_frame (ThreadData *data) { - ThreadData *data = (ThreadData *) user_data; + gpointer buffer; + gint index; - if (data->state == IDLE) { - gpointer buffer; - gint index; + index = (gint) gtk_adjustment_get_value (data->frame_slider); + buffer = ring_buffer_get_pointer (data->buffer, index); + convert_grayscale_to_rgb (data, buffer); + update_pixbuf (data); +} - index = (gint) gtk_adjustment_get_value (adjustment); - buffer = ring_buffer_get_pointer (data->buffer, index); - convert_grayscale_to_rgb (data, buffer); - update_pixbuf (data); - } +static void +on_frame_slider_changed (GtkAdjustment *adjustment, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); } static void -on_start_button_clicked (GtkWidget *widget, gpointer args) +on_start_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -223,13 +226,11 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) } static void -on_stop_button_clicked (GtkWidget *widget, gpointer args) +on_stop_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; data->state = IDLE; - set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); @@ -238,9 +239,8 @@ on_stop_button_clicked (GtkWidget *widget, gpointer args) } static void -on_record_button_clicked (GtkWidget *widget, gpointer args) +on_record_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -260,6 +260,13 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) } } +static void +on_histogram_changed (EggHistogramView *view, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); +} + static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { @@ -351,6 +358,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); /* Layout */ diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 5041ba2..812af7a 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -55,8 +55,16 @@ enum N_PROPERTIES }; +enum +{ + CHANGED, + LAST_SIGNAL +}; + static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; +static guint egg_histogram_view_signals[LAST_SIGNAL] = { 0 }; + GtkWidget * egg_histogram_view_new (void) @@ -253,7 +261,7 @@ egg_histogram_view_expose (GtkWidget *widget, cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); cairo_fill (cr); - cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->min_border - 0.5, height - 1); + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->max_border + 0.5, height - 1); cairo_fill (cr); /* Draw spikes */ @@ -393,9 +401,14 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - *priv->grabbed = event->x; + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); - gtk_widget_queue_draw (widget); + if ((event->x + BORDER > 0) && (event->x + BORDER < allocation.width)) { + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); + } } else { if (is_on_border (priv, event->x)) @@ -416,6 +429,7 @@ egg_histogram_view_button_release (GtkWidget *widget, view = EGG_HISTOGRAM_VIEW (widget); set_cursor_type (view, GDK_ARROW); view->priv->grabbing = FALSE; + g_signal_emit (widget, egg_histogram_view_signals[CHANGED], 0); return TRUE; } @@ -473,6 +487,15 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); + egg_histogram_view_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggHistogramViewClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 61a1c8c..7a62fca 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -44,6 +44,9 @@ struct _EggHistogramView struct _EggHistogramViewClass { GtkDrawingAreaClass parent_class; + + /* signals */ + void (* changed) (EggHistogramView *view); }; GType egg_histogram_view_get_type (void); diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c index 5915d2a..ec2638c 100644 --- a/tools/gui/ring-buffer.c +++ b/tools/gui/ring-buffer.c @@ -12,7 +12,7 @@ ring_buffer_new (gsize block_size, buffer->block_size = block_size; buffer->n_blocks_total = n_blocks; buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; buffer->data = g_malloc0_n (n_blocks, block_size); return buffer; @@ -29,13 +29,13 @@ void ring_buffer_reset (RingBuffer *buffer) { buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; } gpointer ring_buffer_get_current_pointer (RingBuffer *buffer) { - return ring_buffer_get_pointer (buffer, 0); + return buffer->data + (buffer->current_index % buffer->n_blocks_total) * buffer->block_size; } gpointer @@ -43,7 +43,7 @@ ring_buffer_get_pointer (RingBuffer *buffer, guint index) { g_assert (index < buffer->n_blocks_total); - return buffer->data + ((buffer->start_index + index) % buffer->n_blocks_total) * buffer->block_size; + return buffer->data + ((buffer->current_index - buffer->n_blocks_used + index) % buffer->n_blocks_total) * buffer->block_size; } guint @@ -55,10 +55,10 @@ ring_buffer_get_num_blocks (RingBuffer *buffer) void ring_buffer_proceed (RingBuffer *buffer) { - buffer->start_index++; + buffer->current_index++; if (buffer->n_blocks_used < buffer->n_blocks_total) buffer->n_blocks_used++; else - buffer->start_index = buffer->start_index % buffer->n_blocks_total; + buffer->current_index = buffer->current_index % buffer->n_blocks_total; } diff --git a/tools/gui/ring-buffer.h b/tools/gui/ring-buffer.h index 22cbde7..9966eb7 100644 --- a/tools/gui/ring-buffer.h +++ b/tools/gui/ring-buffer.h @@ -10,7 +10,7 @@ typedef struct { gsize block_size; guint n_blocks_total; guint n_blocks_used; - guint start_index; + guint current_index; } RingBuffer; RingBuffer * ring_buffer_new (gsize block_size, -- cgit v1.2.3 From e1ab5f557171c94c0b86203cd2ecb50bb9a52ab0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 16 Oct 2012 11:09:39 +0200 Subject: Add zoom functionality --- tools/gui/control.c | 103 ++++++++++++++++++++++++++++++++++++------------ tools/gui/control.glade | 90 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 163 insertions(+), 30 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index f26cafc..c9fd2f6 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -41,6 +41,7 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkComboBox *zoom_box; GtkWidget *histogram_view; GtkToggleButton *histogram_button; @@ -48,12 +49,13 @@ typedef struct { RingBuffer *buffer; guchar *pixels; + gint display_width, display_height; + gdouble zoom_factor; State state; - int timestamp; - int width; - int height; - int pixel_size; + gint timestamp; + gint width, height; + gint pixel_size; } ThreadData; static UcaPluginManager *plugin_manager; @@ -66,32 +68,42 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) gdouble max; gdouble factor; guint8 *output; + gint i = 0; + gint stride; egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); factor = 255.0 / (max - min); output = data->pixels; + stride = (gint) 1 / data->zoom_factor; if (data->pixel_size == 1) { guint8 *input = (guint8 *) buffer; - for (int i = 0, j = 0; i < data->width * data->height; i++) { - guchar val = (guchar) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; - /* if (i < 10) { */ - /* g_print ("%i->%i ", input[i], val); */ - /* } */ + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + guchar val = (guchar) ((input[offset] - min) * factor); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } } } else if (data->pixel_size == 2) { guint16 *input = (guint16 *) buffer; - for (int i = 0, j = 0; i < data->width * data->height; i++) { - guchar val = (guint8) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + guchar val = (guchar) ((input[offset] - min) * factor); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } } } } @@ -100,14 +112,24 @@ static void update_pixbuf (ThreadData *data) { gdk_flush (); - gtk_image_clear (GTK_IMAGE (data->image)); gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gtk_widget_queue_draw_area (data->image, 0, 0, data->display_width, data->display_height); if (gtk_toggle_button_get_active (data->histogram_button)) gtk_widget_queue_draw (data->histogram_view); } +static void +update_pixbuf_dimensions (ThreadData *data) +{ + if (data->pixbuf != NULL) + g_object_unref (data->pixbuf); + + data->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, data->display_width, data->display_height); + data->pixels = gdk_pixbuf_get_pixels (data->pixbuf); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); +} + static gpointer preview_frames (void *args) { @@ -182,6 +204,8 @@ set_tool_button_state (ThreadData *data) data->state == RUNNING || data->state == RECORDING); gtk_widget_set_sensitive (data->record_button, data->state == IDLE); + gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), + data->state == IDLE); } static void @@ -267,6 +291,28 @@ on_histogram_changed (EggHistogramView *view, ThreadData *data) update_current_frame (data); } +static void +on_zoom_changed (GtkComboBox *widget, ThreadData *data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gdouble factor; + + enum { + DISPLAY_COLUMN, + FACTOR_COLUMN + }; + + model = gtk_combo_box_get_model (widget); + gtk_combo_box_get_active_iter (widget, &iter); + gtk_tree_model_get (model, &iter, FACTOR_COLUMN, &factor, -1); + + data->display_width = (gint) data->width * factor; + data->display_height = (gint) data->height * factor; + data->zoom_factor = factor; + update_pixbuf_dimensions (data); +} + static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { @@ -278,9 +324,9 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) GtkWidget *property_tree_view; GdkPixbuf *pixbuf; GtkBox *histogram_box; - GtkContainer *property_window; - GtkAdjustment *max_bin_adjustment; - RingBuffer *ring_buffer; + GtkContainer *property_window; + GtkAdjustment *max_bin_adjustment; + RingBuffer *ring_buffer; gsize image_size; guint n_frames; guint bits_per_sample; @@ -309,6 +355,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); + td.zoom_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "zoom-box")); td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); @@ -336,15 +383,18 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.pixel_size = pixel_size; td.image = image; - td.pixbuf = pixbuf; + td.pixbuf = NULL; + td.pixels = NULL; td.buffer = ring_buffer; - td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.state = IDLE; td.camera = camera; - td.width = width; - td.height = height; + td.width = td.display_width = width; + td.height = td.display_height = height; + td.zoom_factor = 1.0; td.histogram_view = histogram_view; + update_pixbuf_dimensions (&td); + /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", @@ -358,6 +408,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 90d9511..37f8150 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -200,6 +200,7 @@ <child> <object class="GtkHBox" id="histogram-box"> <property name="visible">True</property> + <property name="border_width">10</property> <child> <placeholder/> </child> @@ -310,11 +311,70 @@ </packing> </child> <child> - <object class="GtkHScale" id="hscale1"> + <object class="GtkTable" id="table2"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="adjustment">frames-adjustment</property> - <property name="digits">0</property> + <property name="border_width">10</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">6</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkHScale" id="hscale1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="adjustment">frames-adjustment</property> + <property name="digits">0</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Frame:</property> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Zoom:</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="zoom-box"> + <property name="visible">True</property> + <property name="model">zoom-values</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> </object> <packing> <property name="position">1</property> @@ -365,6 +425,28 @@ </object> </child> </object> + <object class="GtkListStore" id="zoom-values"> + <columns> + <!-- column-name display --> + <column type="gchararray"/> + <!-- column-name factor --> + <column type="gdouble"/> + </columns> + <data> + <row> + <col id="0" translatable="yes">100 %</col> + <col id="1">1</col> + </row> + <row> + <col id="0" translatable="yes">50 %</col> + <col id="1">0.5</col> + </row> + <row> + <col id="0" translatable="yes">25 %</col> + <col id="1">0.25</col> + </row> + </data> + </object> <object class="GtkWindow" id="choice-window"> <property name="border_width">6</property> <child> -- cgit v1.2.3 From d8743d20b93d34497183d05ccb17519194ec5abb Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 16 Oct 2012 12:27:47 +0200 Subject: Integrate initial unit facility --- src/uca-camera.c | 140 +++++++++++++++++++++++++++++++++++++++++++++---------- src/uca-camera.h | 18 ++++++- test/test-mock.c | 8 ++++ 3 files changed, 140 insertions(+), 26 deletions(-) diff --git a/src/uca-camera.c b/src/uca-camera.c index 091ef54..2cf17ff 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -50,7 +50,25 @@ G_DEFINE_TYPE(UcaCamera, uca_camera, G_TYPE_OBJECT) */ GQuark uca_camera_error_quark() { - return g_quark_from_static_string("uca-camera-error-quark"); + return g_quark_from_static_string ("uca-camera-error-quark"); +} + +/** + * UcaUnit: + * @UCA_UNIT_NA: Not applicable + * @UCA_UNIT_METER: SI meter + * @UCA_UNIT_SECOND: SI second + * @UCA_UNIT_PIXEL: Number of pixels in one dimension + * @UCA_UNIT_COUNT: Number + * + * Units should be registered by camera implementations using + * uca_camera_register_unit() and can be queried by client programs with + * uca_camera_get_unit(). + */ + +GQuark uca_unit_quark () +{ + return g_quark_from_static_string ("uca-unit-quark"); } enum { @@ -96,6 +114,12 @@ struct _UcaCameraPrivate { gboolean transfer_async; }; +static void +uca_camera_set_property_unit (GParamSpec *pspec, UcaUnit unit) +{ + g_param_spec_set_qdata (pspec, UCA_UNIT_QUARK, GINT_TO_POINTER (unit)); +} + static void uca_camera_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { @@ -149,7 +173,7 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara case PROP_FRAMES_PER_SECOND: { - gdouble exposure_time; + gdouble exposure_time; g_object_get (object, "exposure-time", &exposure_time, NULL); g_value_set_double (value, 1. / exposure_time); @@ -162,11 +186,18 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara } static void -uca_camera_class_init(UcaCameraClass *klass) +uca_camera_finalize (GObject *object) +{ + G_OBJECT_CLASS (uca_camera_parent_class)->finalize (object); +} + +static void +uca_camera_class_init (UcaCameraClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); gobject_class->set_property = uca_camera_set_property; gobject_class->get_property = uca_camera_get_property; + gobject_class->finalize = uca_camera_finalize; klass->start_recording = NULL; klass->stop_recording = NULL; @@ -342,7 +373,7 @@ uca_camera_class_init(UcaCameraClass *klass) } static void -uca_camera_init(UcaCamera *camera) +uca_camera_init (UcaCamera *camera) { camera->grab_func = NULL; @@ -351,26 +382,20 @@ uca_camera_init(UcaCamera *camera) camera->priv->is_readout = FALSE; camera->priv->transfer_async = FALSE; - /* - * This here would be the best place to instantiate the tango server object, - * along these lines: - * - * // I'd prefer if you expose a single C method, so we don't have to - * // compile uca-camera.c with g++ - * tango_handle = tango_server_new(camera); - * - * void tango_server_new(UcaCamera *camera) - * { - * // Do whatever is necessary. In the end you will have some kind of - * // Tango object t which needs to somehow hook up to the properties. A - * // list of all available properties can be enumerated with - * // g_object_class_list_properties(G_OBJECT_CLASS(camera), - * // &n_properties); - * - * // For setting/getting properties, use g_object_get/set_property() or - * // g_object_get/set() whatever is more suitable. - * } - */ + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_WIDTH], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_HEIGHT], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_BITDEPTH], UCA_UNIT_COUNT); + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_HORIZONTAL_BINNING], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_VERTICAL_BINNING], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_SENSOR_MAX_FRAME_RATE], UCA_UNIT_COUNT); + uca_camera_set_property_unit (camera_properties[PROP_EXPOSURE_TIME], UCA_UNIT_SECOND); + uca_camera_set_property_unit (camera_properties[PROP_FRAMES_PER_SECOND], UCA_UNIT_COUNT); + uca_camera_set_property_unit (camera_properties[PROP_ROI_X], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_ROI_Y], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_ROI_WIDTH], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_ROI_HEIGHT], UCA_UNIT_PIXEL); + uca_camera_set_property_unit (camera_properties[PROP_ROI_WIDTH_MULTIPLIER], UCA_UNIT_COUNT); + uca_camera_set_property_unit (camera_properties[PROP_ROI_HEIGHT_MULTIPLIER], UCA_UNIT_COUNT); } /** @@ -523,7 +548,8 @@ uca_camera_start_readout (UcaCamera *camera, GError **error) * * Set the grab function that is called whenever a frame is readily transfered. */ -void uca_camera_set_grab_func(UcaCamera *camera, UcaCameraGrabFunc func, gpointer user_data) +void +uca_camera_set_grab_func(UcaCamera *camera, UcaCameraGrabFunc func, gpointer user_data) { camera->grab_func = func; camera->user_data = user_data; @@ -600,3 +626,67 @@ uca_camera_grab (UcaCamera *camera, gpointer *data, GError **error) g_static_mutex_unlock (&mutex); } +/** + * uca_camera_register_unit: + * @camera: A #UcaCamera object + * @prop_name: Name of a property + * @unit: #UcaUnit + * + * Associates @prop_name of @camera with a specific @unit. + * + * Since: 1.1 + */ +void +uca_camera_register_unit (UcaCamera *camera, + const gchar *prop_name, + UcaUnit unit) +{ + UcaCameraClass *klass; + GObjectClass *oclass; + GParamSpec *pspec; + + klass = UCA_CAMERA_GET_CLASS (camera); + oclass = G_OBJECT_CLASS (klass); + pspec = g_object_class_find_property (oclass, prop_name); + + if (pspec == NULL) { + g_warning ("Camera does not have property `%s'", prop_name); + return; + } + + uca_camera_set_property_unit (pspec, unit); +} + +/** + * uca_camera_get_unit: + * @camera: A #UcaCamera object + * @prop_name: Name of a property + * + * Returns the unit associated with @prop_name of @camera. + * + * Returns: A #UcaUnit value associated with @prop_name. If there is none, the + * value will be #UCA_UNIT_NA. + * Since: 1.1 + */ +UcaUnit +uca_camera_get_unit (UcaCamera *camera, + const gchar *prop_name) +{ + UcaCameraClass *klass; + GObjectClass *oclass; + GParamSpec *pspec; + gpointer data; + + klass = UCA_CAMERA_GET_CLASS (camera); + oclass = G_OBJECT_CLASS (klass); + pspec = g_object_class_find_property (oclass, prop_name); + + if (pspec == NULL) { + g_warning ("Camera does not have property `%s'", prop_name); + return UCA_UNIT_NA; + } + + data = g_param_spec_get_qdata (pspec, UCA_UNIT_QUARK); + return data == NULL ? UCA_UNIT_NA : GPOINTER_TO_INT (data); +} + diff --git a/src/uca-camera.h b/src/uca-camera.h index 8bc48bc..4aad0b4 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -29,8 +29,11 @@ G_BEGIN_DECLS #define UCA_IS_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UCA_TYPE_CAMERA)) #define UCA_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UCA_TYPE_CAMERA, UcaCameraClass)) -#define UCA_CAMERA_ERROR uca_camera_error_quark() +#define UCA_CAMERA_ERROR uca_camera_error_quark() +#define UCA_UNIT_QUARK uca_unit_quark() + GQuark uca_camera_error_quark(void); +GQuark uca_unit_quark(void); typedef enum { UCA_CAMERA_ERROR_NOT_FOUND, @@ -46,6 +49,14 @@ typedef enum { UCA_CAMERA_TRIGGER_EXTERNAL } UcaCameraTrigger; +typedef enum { + UCA_UNIT_NA, + UCA_UNIT_METER, + UCA_UNIT_SECOND, + UCA_UNIT_PIXEL, + UCA_UNIT_COUNT +} UcaUnit; + typedef struct _UcaCamera UcaCamera; typedef struct _UcaCameraClass UcaCameraClass; typedef struct _UcaCameraPrivate UcaCameraPrivate; @@ -136,6 +147,11 @@ void uca_camera_grab (UcaCamera *camera, void uca_camera_set_grab_func (UcaCamera *camera, UcaCameraGrabFunc func, gpointer user_data); +void uca_camera_register_unit (UcaCamera *camera, + const gchar *prop_name, + UcaUnit unit); +UcaUnit uca_camera_get_unit (UcaCamera *camera, + const gchar *prop_name); GType uca_camera_get_type(void); diff --git a/test/test-mock.c b/test/test-mock.c index 17af329..08f24b8 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -168,6 +168,13 @@ test_fps_property (Fixture *fixture, gconstpointer data) g_assert_cmpfloat (frames_per_second, ==, 1.0 / exposure_time); } +static void +test_property_units (Fixture *fixture, gconstpointer data) +{ + g_assert (uca_camera_get_unit (fixture->camera, "sensor-width") == UCA_UNIT_PIXEL); + g_assert (uca_camera_get_unit (fixture->camera, "name") == UCA_UNIT_NA); +} + static void test_binnings_properties (Fixture *fixture, gconstpointer data) { @@ -210,6 +217,7 @@ int main (int argc, char *argv[]) g_test_add ("/properties/recording", Fixture, NULL, fixture_setup, test_recording_property, fixture_teardown); g_test_add ("/properties/binnings", Fixture, NULL, fixture_setup, test_binnings_properties, fixture_teardown); g_test_add ("/properties/frames-per-second", Fixture, NULL, fixture_setup, test_fps_property, fixture_teardown); + g_test_add ("/properties/units", Fixture, NULL, fixture_setup, test_property_units, fixture_teardown); g_test_add ("/signal", Fixture, NULL, fixture_setup, test_signal, fixture_teardown); return g_test_run (); -- cgit v1.2.3 From de2e8e3191eae37b91f672a03e028a35c8863c9d Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Tue, 16 Oct 2012 12:40:18 +0200 Subject: Add temperature unit and descriptions for pco --- plugins/mock/uca-mock-camera.c | 2 ++ plugins/pco/uca-pco-camera.c | 14 ++++++++++++++ src/uca-camera.c | 7 ++++--- src/uca-camera.h | 1 + test/test-mock.c | 4 ++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 38caf0d..bf3124e 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -397,6 +397,8 @@ static void uca_mock_camera_init(UcaMockCamera *self) g_value_init(&val, G_TYPE_UINT); g_value_set_uint(&val, 1); g_value_array_append(self->priv->binnings, &val); + + uca_camera_register_unit (UCA_CAMERA (self), "frame-rate", UCA_UNIT_COUNT); } G_MODULE_EXPORT UcaCamera * diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 725ffbf..92f814e 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -1363,6 +1363,8 @@ uca_pco_camera_class_init(UcaPcoCameraClass *klass) static void uca_pco_camera_init(UcaPcoCamera *self) { + UcaCamera *camera; + self->priv = UCA_PCO_CAMERA_GET_PRIVATE(self); self->priv->fg = NULL; self->priv->fg_mem = NULL; @@ -1376,6 +1378,18 @@ uca_pco_camera_init(UcaPcoCamera *self) self->priv->delay_timebase = TIMEBASE_INVALID; self->priv->exposure_timebase = TIMEBASE_INVALID; + + camera = UCA_CAMERA (self); + uca_camera_register_unit (camera, "sensor-width-extended", UCA_UNIT_PIXEL); + uca_camera_register_unit (camera, "sensor-height-extended", UCA_UNIT_PIXEL); + uca_camera_register_unit (camera, "temperature", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "cooling-point", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "cooling-point-min", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "cooling-point-max", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "cooling-point-default", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "sensor-adcs", UCA_UNIT_COUNT); + uca_camera_register_unit (camera, "sensor-max-adcs", UCA_UNIT_COUNT); + uca_camera_register_unit (camera, "delay-time", UCA_UNIT_SECOND); } G_MODULE_EXPORT UcaCamera * diff --git a/src/uca-camera.c b/src/uca-camera.c index 2cf17ff..8b08359 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -56,10 +56,11 @@ GQuark uca_camera_error_quark() /** * UcaUnit: * @UCA_UNIT_NA: Not applicable - * @UCA_UNIT_METER: SI meter - * @UCA_UNIT_SECOND: SI second + * @UCA_UNIT_METER: Length in SI meter + * @UCA_UNIT_SECOND: Time in SI second * @UCA_UNIT_PIXEL: Number of pixels in one dimension - * @UCA_UNIT_COUNT: Number + * @UCA_UNIT_DEGREE_CELSIUS: Temperature in degree Celsius + * @UCA_UNIT_COUNT: Generic number * * Units should be registered by camera implementations using * uca_camera_register_unit() and can be queried by client programs with diff --git a/src/uca-camera.h b/src/uca-camera.h index 4aad0b4..d84b5f2 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -54,6 +54,7 @@ typedef enum { UCA_UNIT_METER, UCA_UNIT_SECOND, UCA_UNIT_PIXEL, + UCA_UNIT_DEGREE_CELSIUS, UCA_UNIT_COUNT } UcaUnit; diff --git a/test/test-mock.c b/test/test-mock.c index 08f24b8..85c1ba4 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -171,8 +171,12 @@ test_fps_property (Fixture *fixture, gconstpointer data) static void test_property_units (Fixture *fixture, gconstpointer data) { + /* Default camera properties */ g_assert (uca_camera_get_unit (fixture->camera, "sensor-width") == UCA_UNIT_PIXEL); g_assert (uca_camera_get_unit (fixture->camera, "name") == UCA_UNIT_NA); + + /* Mock-specific properties */ + g_assert (uca_camera_get_unit (fixture->camera, "frame-rate") == UCA_UNIT_COUNT); } static void -- cgit v1.2.3 From a1ab005916ba3aa50923294c5be3da0ded16fbc0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 10:56:30 +0200 Subject: Add download button and make dimax work --- plugins/pco/uca-pco-camera.c | 3 ++- src/uca-camera.c | 5 +++++ src/uca-camera.h | 3 ++- tools/gui/control.c | 48 ++++++++++++++++++++++++++++++++++++++++---- tools/gui/control.glade | 12 +++++++++++ 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 92f814e..d5f5593 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -554,7 +554,8 @@ uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) if (is_readout) { if (priv->current_image == priv->num_recorded_images) { - *data = NULL; + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_END_OF_STREAM, + "End of data stream"); return; } diff --git a/src/uca-camera.c b/src/uca-camera.c index 8b08359..9210a05 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -47,6 +47,7 @@ G_DEFINE_TYPE(UcaCamera, uca_camera, G_TYPE_OBJECT) * @UCA_CAMERA_ERROR_NOT_RECORDING: Camera is not recording * @UCA_CAMERA_ERROR_NO_GRAB_FUNC: No grab callback was set * @UCA_CAMERA_ERROR_NOT_IMPLEMENTED: Virtual function is not implemented + * @UCA_CAMERA_ERROR_END_OF_STREAM: Data stream has ended. */ GQuark uca_camera_error_quark() { @@ -602,6 +603,10 @@ uca_camera_trigger (UcaCamera *camera, GError **error) * * You must have called uca_camera_start_recording() before, otherwise you will * get a #UCA_CAMERA_ERROR_NOT_RECORDING error. + * + * If *data is %NULL after returning from uca_camera_grab() and error is also + * %NULL, the data stream has ended. For example, with cameras that support + * in-camera memory, all frames have been transfered. */ void uca_camera_grab (UcaCamera *camera, gpointer *data, GError **error) diff --git a/src/uca-camera.h b/src/uca-camera.h index d84b5f2..ef3bf14 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -40,7 +40,8 @@ typedef enum { UCA_CAMERA_ERROR_RECORDING, UCA_CAMERA_ERROR_NOT_RECORDING, UCA_CAMERA_ERROR_NO_GRAB_FUNC, - UCA_CAMERA_ERROR_NOT_IMPLEMENTED + UCA_CAMERA_ERROR_NOT_IMPLEMENTED, + UCA_CAMERA_ERROR_END_OF_STREAM } UcaCameraError; typedef enum { diff --git a/tools/gui/control.c b/tools/gui/control.c index c9fd2f6..930c4d0 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -41,6 +41,7 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkWidget *download_button; GtkComboBox *zoom_box; GtkWidget *histogram_view; @@ -52,6 +53,7 @@ typedef struct { gint display_width, display_height; gdouble zoom_factor; State state; + gboolean data_in_camram; gint timestamp; gint width, height; @@ -88,7 +90,7 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[i++] = val; output[i++] = val; output[i++] = val; - } + } } } else if (data->pixel_size == 2) { @@ -103,7 +105,7 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[i++] = val; output[i++] = val; output[i++] = val; - } + } } } } @@ -204,6 +206,8 @@ set_tool_button_state (ThreadData *data) data->state == RUNNING || data->state == RECORDING); gtk_widget_set_sensitive (data->record_button, data->state == IDLE); + gtk_widget_set_sensitive (data->download_button, + data->data_in_camram); gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), data->state == IDLE); } @@ -254,12 +258,14 @@ on_stop_button_clicked (GtkWidget *widget, ThreadData *data) { GError *error = NULL; + g_object_get (data->camera, "has-camram-recording", &data->data_in_camram, NULL); data->state = IDLE; set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); if (error != NULL) g_printerr ("Failed to stop: %s\n", error->message); + } static void @@ -284,6 +290,38 @@ on_record_button_clicked (GtkWidget *widget, ThreadData *data) } } +static void +on_download_button_clicked (GtkWidget *widget, ThreadData *data) +{ + gpointer buffer; + GError *error = NULL; + + uca_camera_start_readout (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start read out of camera memory: %s\n", error->message); + return; + } + + ring_buffer_reset (data->buffer); + + while (error == NULL) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, &error); + ring_buffer_proceed (data->buffer); + } + + if (error->code != UCA_CAMERA_ERROR_END_OF_STREAM) { + guint n_frames = ring_buffer_get_num_blocks (data->buffer); + + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + } + else { + g_printerr ("Error while reading out frames: %s\n", error->message); + } +} + static void on_histogram_changed (EggHistogramView *view, ThreadData *data) { @@ -359,6 +397,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + td.download_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-button")); td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); @@ -368,8 +407,6 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) n_frames = mem_size * 1024 * 1024 / image_size; ring_buffer = ring_buffer_new (image_size, n_frames); - set_tool_button_state (&td); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), ring_buffer_get_current_pointer (ring_buffer), width * height, bits_per_sample, 256); @@ -392,8 +429,10 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.height = td.display_height = height; td.zoom_factor = 1.0; td.histogram_view = histogram_view; + td.data_in_camram = FALSE; update_pixbuf_dimensions (&td); + set_tool_button_state (&td); /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", @@ -408,6 +447,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (td.download_button, "clicked", G_CALLBACK (on_download_button_clicked), &td); g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 37f8150..2d2aaac 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -152,6 +152,18 @@ <property name="homogeneous">True</property> </packing> </child> + <child> + <object class="GtkToolButton" id="download-button"> + <property name="visible">True</property> + <property name="label" translatable="yes">Download</property> + <property name="use_underline">True</property> + <property name="icon_name">network-receive</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> -- cgit v1.2.3 From e16087fbe25df8901e9221602570c074ae887450 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 11:59:24 +0200 Subject: Add pco property documentation --- docs/manual.md | 2 + docs/pco.html | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 docs/pco.html diff --git a/docs/manual.md b/docs/manual.md index 8bf38aa..a68400e 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -260,9 +260,11 @@ The following cameras are supported: ## Property documentation * [Basic camera properties][base-doc] +* [pco][pco-doc] * [mock][mock-doc] [base-doc]: base.html +[pco-doc]: pco.html [mock-doc]: mock.html diff --git a/docs/pco.html b/docs/pco.html new file mode 100644 index 0000000..3f764e1 --- /dev/null +++ b/docs/pco.html @@ -0,0 +1,130 @@ +<html><head><link rel="stylesheet" href="style.css" type="text/css" /><link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Serif:400,400italic|Inconsolata' rel='stylesheet' type='text/css'><title>pco — properties</title></head><body><div id="header"><h1 class="title">Property documentation of pco</h1><h2>Properties</h2><ul id="toc"><li><code><a href=#name>"name"</a></code></li><li><code><a href=#sensor-width>"sensor-width"</a></code></li><li><code><a href=#sensor-height>"sensor-height"</a></code></li><li><code><a href=#sensor-bitdepth>"sensor-bitdepth"</a></code></li><li><code><a href=#sensor-horizontal-binning>"sensor-horizontal-binning"</a></code></li><li><code><a href=#sensor-horizontal-binnings>"sensor-horizontal-binnings"</a></code></li><li><code><a href=#sensor-vertical-binning>"sensor-vertical-binning"</a></code></li><li><code><a href=#sensor-vertical-binnings>"sensor-vertical-binnings"</a></code></li><li><code><a href=#sensor-max-frame-rate>"sensor-max-frame-rate"</a></code></li><li><code><a href=#trigger-mode>"trigger-mode"</a></code></li><li><code><a href=#exposure-time>"exposure-time"</a></code></li><li><code><a href=#frames-per-second>"frames-per-second"</a></code></li><li><code><a href=#roi-x0>"roi-x0"</a></code></li><li><code><a href=#roi-y0>"roi-y0"</a></code></li><li><code><a href=#roi-width>"roi-width"</a></code></li><li><code><a href=#roi-height>"roi-height"</a></code></li><li><code><a href=#roi-width-multiplier>"roi-width-multiplier"</a></code></li><li><code><a href=#roi-height-multiplier>"roi-height-multiplier"</a></code></li><li><code><a href=#has-streaming>"has-streaming"</a></code></li><li><code><a href=#has-camram-recording>"has-camram-recording"</a></code></li><li><code><a href=#transfer-asynchronously>"transfer-asynchronously"</a></code></li><li><code><a href=#is-recording>"is-recording"</a></code></li><li><code><a href=#is-readout>"is-readout"</a></code></li><li><code><a href=#sensor-extended>"sensor-extended"</a></code></li><li><code><a href=#sensor-width-extended>"sensor-width-extended"</a></code></li><li><code><a href=#sensor-height-extended>"sensor-height-extended"</a></code></li><li><code><a href=#sensor-temperature>"sensor-temperature"</a></code></li><li><code><a href=#sensor-pixelrates>"sensor-pixelrates"</a></code></li><li><code><a href=#sensor-pixelrate>"sensor-pixelrate"</a></code></li><li><code><a href=#sensor-adcs>"sensor-adcs"</a></code></li><li><code><a href=#sensor-max-adcs>"sensor-max-adcs"</a></code></li><li><code><a href=#delay-time>"delay-time"</a></code></li><li><code><a href=#has-double-image-mode>"has-double-image-mode"</a></code></li><li><code><a href=#double-image-mode>"double-image-mode"</a></code></li><li><code><a href=#offset-mode>"offset-mode"</a></code></li><li><code><a href=#record-mode>"record-mode"</a></code></li><li><code><a href=#acquire-mode>"acquire-mode"</a></code></li><li><code><a href=#cooling-point>"cooling-point"</a></code></li><li><code><a href=#cooling-point-min>"cooling-point-min"</a></code></li><li><code><a href=#cooling-point-max>"cooling-point-max"</a></code></li><li><code><a href=#cooling-point-default>"cooling-point-default"</a></code></li><li><code><a href=#noise-filter>"noise-filter"</a></code></li><li><code><a href=#timestamp-mode>"timestamp-mode"</a></code></li></ul><h2>Details</h2><dl><dt id="name"><a href="#toc">name</a></dt> +<dd><pre><code class="prop-type">"name" : gchararray : Read-only</code></pre> +<p>Name of the camera</p> +</dd><dt id="sensor-width"><a href="#toc">sensor-width</a></dt> +<dd><pre><code class="prop-type">"sensor-width" : guint : Read-only</code></pre> +<p>Width of the sensor in pixels</p> +</dd><dt id="sensor-height"><a href="#toc">sensor-height</a></dt> +<dd><pre><code class="prop-type">"sensor-height" : guint : Read-only</code></pre> +<p>Height of the sensor in pixels</p> +</dd><dt id="sensor-bitdepth"><a href="#toc">sensor-bitdepth</a></dt> +<dd><pre><code class="prop-type">"sensor-bitdepth" : guint : Read-only</code></pre> +<p>Number of bits per pixel</p> +</dd><dt id="sensor-horizontal-binning"><a href="#toc">sensor-horizontal-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in horizontal direction</p> +</dd><dt id="sensor-horizontal-binnings"><a href="#toc">sensor-horizontal-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-horizontal-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in horizontal direction</p> +</dd><dt id="sensor-vertical-binning"><a href="#toc">sensor-vertical-binning</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binning" : guint : Read / Write</code></pre> +<p>Number of sensor ADCs that are combined to one pixel in vertical direction</p> +</dd><dt id="sensor-vertical-binnings"><a href="#toc">sensor-vertical-binnings</a></dt> +<dd><pre><code class="prop-type">"sensor-vertical-binnings" : GValueArray : Read-only</code></pre> +<p>Array of possible binnings in vertical direction</p> +</dd><dt id="sensor-max-frame-rate"><a href="#toc">sensor-max-frame-rate</a></dt> +<dd><pre><code class="prop-type">"sensor-max-frame-rate" : gfloat : Read-only</code></pre> +<p>Maximum frame rate at full frame resolution</p> +</dd><dt id="trigger-mode"><a href="#toc">trigger-mode</a></dt> +<dd><pre><code class="prop-type">"trigger-mode" : UcaCameraTrigger : Read / Write</code></pre> +<p>Trigger mode</p> +</dd><dt id="exposure-time"><a href="#toc">exposure-time</a></dt> +<dd><pre><code class="prop-type">"exposure-time" : gdouble : Read / Write</code></pre> +<p>Exposure time in seconds</p> +</dd><dt id="frames-per-second"><a href="#toc">frames-per-second</a></dt> +<dd><pre><code class="prop-type">"frames-per-second" : gdouble : Read / Write</code></pre> +<p>Frames per second</p> +</dd><dt id="roi-x0"><a href="#toc">roi-x0</a></dt> +<dd><pre><code class="prop-type">"roi-x0" : guint : Read / Write</code></pre> +<p>Horizontal coordinate</p> +</dd><dt id="roi-y0"><a href="#toc">roi-y0</a></dt> +<dd><pre><code class="prop-type">"roi-y0" : guint : Read / Write</code></pre> +<p>Vertical coordinate</p> +</dd><dt id="roi-width"><a href="#toc">roi-width</a></dt> +<dd><pre><code class="prop-type">"roi-width" : guint : Read / Write</code></pre> +<p>Width of the region of interest</p> +</dd><dt id="roi-height"><a href="#toc">roi-height</a></dt> +<dd><pre><code class="prop-type">"roi-height" : guint : Read / Write</code></pre> +<p>Height of the region of interest</p> +</dd><dt id="roi-width-multiplier"><a href="#toc">roi-width-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-width-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of horizontal ROI</p> +</dd><dt id="roi-height-multiplier"><a href="#toc">roi-height-multiplier</a></dt> +<dd><pre><code class="prop-type">"roi-height-multiplier" : guint : Read-only</code></pre> +<p>Minimum possible step size of vertical ROI</p> +</dd><dt id="has-streaming"><a href="#toc">has-streaming</a></dt> +<dd><pre><code class="prop-type">"has-streaming" : gboolean : Read-only</code></pre> +<p>Is the camera able to stream the data</p> +</dd><dt id="has-camram-recording"><a href="#toc">has-camram-recording</a></dt> +<dd><pre><code class="prop-type">"has-camram-recording" : gboolean : Read-only</code></pre> +<p>Is the camera able to record the data in-camera</p> +</dd><dt id="transfer-asynchronously"><a href="#toc">transfer-asynchronously</a></dt> +<dd><pre><code class="prop-type">"transfer-asynchronously" : gboolean : Read / Write</code></pre> +<p>Specify whether data should be transfered asynchronously using a specified callback</p> +</dd><dt id="is-recording"><a href="#toc">is-recording</a></dt> +<dd><pre><code class="prop-type">"is-recording" : gboolean : Read-only</code></pre> +<p>Is the camera currently recording</p> +</dd><dt id="is-readout"><a href="#toc">is-readout</a></dt> +<dd><pre><code class="prop-type">"is-readout" : gboolean : Read-only</code></pre> +<p>Is camera in readout mode</p> +</dd><dt id="sensor-extended"><a href="#toc">sensor-extended</a></dt> +<dd><pre><code class="prop-type">"sensor-extended" : gboolean : Read / Write</code></pre> +<p>Use extended sensor format</p> +</dd><dt id="sensor-width-extended"><a href="#toc">sensor-width-extended</a></dt> +<dd><pre><code class="prop-type">"sensor-width-extended" : guint : Read-only</code></pre> +<p>Width of the extended sensor in pixels</p> +</dd><dt id="sensor-height-extended"><a href="#toc">sensor-height-extended</a></dt> +<dd><pre><code class="prop-type">"sensor-height-extended" : guint : Read-only</code></pre> +<p>Height of the extended sensor in pixels</p> +</dd><dt id="sensor-temperature"><a href="#toc">sensor-temperature</a></dt> +<dd><pre><code class="prop-type">"sensor-temperature" : gdouble : Read-only</code></pre> +<p>Temperature of the sensor in degree Celsius</p> +</dd><dt id="sensor-pixelrates"><a href="#toc">sensor-pixelrates</a></dt> +<dd><pre><code class="prop-type">"sensor-pixelrates" : GValueArray : Read-only</code></pre> +<p>Array of possible sensor pixel rates</p> +</dd><dt id="sensor-pixelrate"><a href="#toc">sensor-pixelrate</a></dt> +<dd><pre><code class="prop-type">"sensor-pixelrate" : guint : Read / Write</code></pre> +<p>Pixel rate</p> +</dd><dt id="sensor-adcs"><a href="#toc">sensor-adcs</a></dt> +<dd><pre><code class="prop-type">"sensor-adcs" : guint : Read / Write</code></pre> +<p>Number of ADCs to use</p> +</dd><dt id="sensor-max-adcs"><a href="#toc">sensor-max-adcs</a></dt> +<dd><pre><code class="prop-type">"sensor-max-adcs" : guint : Read-only</code></pre> +<p>Maximum number of ADCs that can be set with "sensor-adcs"</p> +</dd><dt id="delay-time"><a href="#toc">delay-time</a></dt> +<dd><pre><code class="prop-type">"delay-time" : gdouble : Read / Write</code></pre> +<p>Delay before starting actual exposure</p> +</dd><dt id="has-double-image-mode"><a href="#toc">has-double-image-mode</a></dt> +<dd><pre><code class="prop-type">"has-double-image-mode" : gboolean : Read-only</code></pre> +<p>Is double image mode supported by this model</p> +</dd><dt id="double-image-mode"><a href="#toc">double-image-mode</a></dt> +<dd><pre><code class="prop-type">"double-image-mode" : gboolean : Read / Write</code></pre> +<p>Use double image mode</p> +</dd><dt id="offset-mode"><a href="#toc">offset-mode</a></dt> +<dd><pre><code class="prop-type">"offset-mode" : gboolean : Read / Write</code></pre> +<p>Use offset mode</p> +</dd><dt id="record-mode"><a href="#toc">record-mode</a></dt> +<dd><pre><code class="prop-type">"record-mode" : UcaPcoCameraRecordMode : Read / Write</code></pre> +<p>Record mode</p> +</dd><dt id="acquire-mode"><a href="#toc">acquire-mode</a></dt> +<dd><pre><code class="prop-type">"acquire-mode" : UcaPcoCameraAcquireMode : Read / Write</code></pre> +<p>Acquire mode</p> +</dd><dt id="cooling-point"><a href="#toc">cooling-point</a></dt> +<dd><pre><code class="prop-type">"cooling-point" : gint : Read / Write</code></pre> +<p>Cooling point of the camera in degree celsius</p> +</dd><dt id="cooling-point-min"><a href="#toc">cooling-point-min</a></dt> +<dd><pre><code class="prop-type">"cooling-point-min" : gint : Read-only</code></pre> +<p>Minimum cooling point in degree celsius</p> +</dd><dt id="cooling-point-max"><a href="#toc">cooling-point-max</a></dt> +<dd><pre><code class="prop-type">"cooling-point-max" : gint : Read-only</code></pre> +<p>Maximum cooling point in degree celsius</p> +</dd><dt id="cooling-point-default"><a href="#toc">cooling-point-default</a></dt> +<dd><pre><code class="prop-type">"cooling-point-default" : gint : Read-only</code></pre> +<p>Default cooling point in degree celsius</p> +</dd><dt id="noise-filter"><a href="#toc">noise-filter</a></dt> +<dd><pre><code class="prop-type">"noise-filter" : gboolean : Read / Write</code></pre> +<p>Noise filter</p> +</dd><dt id="timestamp-mode"><a href="#toc">timestamp-mode</a></dt> +<dd><pre><code class="prop-type">"timestamp-mode" : UcaPcoCameraTimestamp : Read / Write</code></pre> +<p>Timestamp mode</p> +</dd></dl></body></html> -- cgit v1.2.3 From 983005dfbc3b07093145c0b964063e334b928d48 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@kit.edu> Date: Thu, 18 Oct 2012 12:44:40 +0200 Subject: Fix download of in-camera frames --- NEWS | 2 ++ plugins/pco/uca-pco-camera.c | 25 ++++++++++++++++++++++--- src/uca-camera.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/uca-camera.h | 3 +++ tools/gui/control.c | 10 +++++++--- 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index f0a4c30..7a91e80 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ Minor changes - It is now possible to generate GObject introspection meta data to bind libuca to all languages that support GObject introspection. +- Added uca_camera_stop_readout() to cleanup after using + uca_camera_start_readout(). Changes in libuca 1.0 aka 0.6 diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index d5f5593..03a1a17 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -385,7 +385,7 @@ check_pco_property_error (guint err, guint property_id) { if (err != PCO_NOERROR) { g_warning ("Call to libpco failed with error code %x for property `%s'", - err, + err, pco_properties[property_id]->name); } } @@ -523,9 +523,27 @@ uca_pco_camera_start_readout(UcaCamera *camera, GError **error) err = pco_get_num_images(priv->pco, priv->active_segment, &priv->num_recorded_images); 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); + + priv->last_frame = 0; priv->current_image = 1; } +static void +uca_pco_camera_stop_readout(UcaCamera *camera, GError **error) +{ + g_return_if_fail(UCA_IS_PCO_CAMERA(camera)); + UcaPcoCameraPrivate *priv = UCA_PCO_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_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_trigger(UcaCamera *camera, GError **error) { @@ -568,7 +586,7 @@ uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) } pco_request_image(priv->pco); - priv->last_frame = Fg_getLastPicNumberBlockingEx(priv->fg, priv->last_frame+1, priv->fg_port, MAX_TIMEOUT, priv->fg_mem); + 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; @@ -1189,6 +1207,7 @@ uca_pco_camera_class_init(UcaPcoCameraClass *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->stop_readout = uca_pco_camera_stop_readout; camera_class->trigger = uca_pco_camera_trigger; camera_class->grab = uca_pco_camera_grab; @@ -1383,7 +1402,7 @@ uca_pco_camera_init(UcaPcoCamera *self) camera = UCA_CAMERA (self); uca_camera_register_unit (camera, "sensor-width-extended", UCA_UNIT_PIXEL); uca_camera_register_unit (camera, "sensor-height-extended", UCA_UNIT_PIXEL); - uca_camera_register_unit (camera, "temperature", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "sensor-temperature", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point-min", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point-max", UCA_UNIT_DEGREE_CELSIUS); diff --git a/src/uca-camera.c b/src/uca-camera.c index 9210a05..053dcca 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -542,6 +542,50 @@ uca_camera_start_readout (UcaCamera *camera, GError **error) g_static_mutex_unlock (&mutex); } +/** + * uca_camera_stop_readout: + * @camera: A #UcaCamera object + * @error: Location to store a #UcaCameraError error or %NULL + * + * Stop reading out frames. + * + * Since: 1.1 + */ +void +uca_camera_stop_readout (UcaCamera *camera, GError **error) +{ + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (UCA_IS_CAMERA(camera)); + + klass = UCA_CAMERA_GET_CLASS(camera); + + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->start_readout != NULL); + + g_static_mutex_lock (&mutex); + + if (camera->priv->is_recording) { + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, + "Camera is still recording"); + } + else { + GError *tmp_error = NULL; + + (*klass->stop_readout) (camera, &tmp_error); + + if (tmp_error == NULL) { + camera->priv->is_readout = FALSE; + g_object_notify (G_OBJECT (camera), "is-readout"); + } + else + g_propagate_error (error, tmp_error); + } + + g_static_mutex_unlock (&mutex); +} + /** * uca_camera_set_grab_func: * @camera: A #UcaCamera object diff --git a/src/uca-camera.h b/src/uca-camera.h index ef3bf14..78edd95 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -126,6 +126,7 @@ struct _UcaCameraClass { void (*start_recording) (UcaCamera *camera, GError **error); void (*stop_recording) (UcaCamera *camera, GError **error); void (*start_readout) (UcaCamera *camera, GError **error); + void (*stop_readout) (UcaCamera *camera, GError **error); void (*trigger) (UcaCamera *camera, GError **error); void (*grab) (UcaCamera *camera, gpointer *data, GError **error); @@ -141,6 +142,8 @@ void uca_camera_stop_recording (UcaCamera *camera, GError **error); void uca_camera_start_readout (UcaCamera *camera, GError **error); +void uca_camera_stop_readout (UcaCamera *camera, + GError **error); void uca_camera_trigger (UcaCamera *camera, GError **error); void uca_camera_grab (UcaCamera *camera, diff --git a/tools/gui/control.c b/tools/gui/control.c index 930c4d0..aaeeb75 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -311,15 +311,19 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) ring_buffer_proceed (data->buffer); } - if (error->code != UCA_CAMERA_ERROR_END_OF_STREAM) { + if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { guint n_frames = ring_buffer_get_num_blocks (data->buffer); gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); gtk_adjustment_set_value (data->frame_slider, n_frames - 1); } - else { + else g_printerr ("Error while reading out frames: %s\n", error->message); - } + + uca_camera_stop_readout (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); } static void -- cgit v1.2.3 From 694d4b4edd93bc8fdba6f578454d6b7b9f95003f Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 13:40:58 +0200 Subject: Free error that will be set during download --- tools/gui/control.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/gui/control.c b/tools/gui/control.c index aaeeb75..a5ef410 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -320,6 +320,7 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) else g_printerr ("Error while reading out frames: %s\n", error->message); + g_error_free (error); uca_camera_stop_readout (data->camera, &error); if (error != NULL) -- cgit v1.2.3 From 4db2ac7026ae3bc85807016cb2510fed996a2a20 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 13:44:44 +0200 Subject: Don't make memory argument optional If `-m' is supplied, a number must follow. --- tools/gui/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index a5ef410..0d08893 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -538,7 +538,7 @@ main (int argc, char *argv[]) static GOptionEntry entries[] = { - { "mem-size", 'm', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, + { "mem-size", 'm', 0, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, { NULL } }; -- cgit v1.2.3 From 2c3028f55ae1985315b8e350c1cdb26c9f7aa1a3 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 13:47:44 +0200 Subject: Set error NULL to avoid printing false message --- tools/gui/control.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/gui/control.c b/tools/gui/control.c index 0d08893..07b7937 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -321,6 +321,8 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) g_printerr ("Error while reading out frames: %s\n", error->message); g_error_free (error); + error = NULL; + uca_camera_stop_readout (data->camera, &error); if (error != NULL) -- cgit v1.2.3 From 184fc22ce23f8ab7c8127b5ac0657fc20ddea924 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 16:07:00 +0200 Subject: Add "recorded-frames" property --- plugins/pco/uca-pco-camera.c | 9 +++++++++ src/uca-camera.c | 20 ++++++++++++++++++++ src/uca-camera.h | 1 + 3 files changed, 30 insertions(+) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 03a1a17..d34e0f4 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -139,6 +139,7 @@ static gint base_overrideables[] = { PROP_ROI_HEIGHT_MULTIPLIER, PROP_HAS_STREAMING, PROP_HAS_CAMRAM_RECORDING, + PROP_RECORDED_FRAMES, 0 }; @@ -504,6 +505,9 @@ uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) 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"); + + err = pco_get_num_images(priv->pco, priv->active_segment, &priv->num_recorded_images); + HANDLE_PCO_ERROR(err); } static void @@ -1024,6 +1028,10 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G g_value_set_boolean(value, priv->camera_description->has_camram); break; + case PROP_RECORDED_FRAMES: + g_value_set_uint(value, priv->num_recorded_images); + break; + case PROP_RECORD_MODE: { guint16 mode; @@ -1440,6 +1448,7 @@ uca_camera_impl_new (GError **error) priv->roi_y = roi[1] - 1; priv->roi_width = roi[2] - roi[0] + 1; priv->roi_height = roi[3] - roi[1] + 1; + priv->num_recorded_images = 0; guint16 camera_type, camera_subtype; pco_get_camera_type(priv->pco, &camera_type, &camera_subtype); diff --git a/src/uca-camera.c b/src/uca-camera.c index 053dcca..53b2d7a 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -103,6 +103,7 @@ const gchar *uca_camera_props[N_BASE_PROPERTIES] = { "roi-height-multiplier", "has-streaming", "has-camram-recording", + "recorded-frames", "transfer-asynchronously", "is-recording", "is-readout" @@ -182,6 +183,10 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara } break; + case PROP_RECORDED_FRAMES: + g_value_set_uint (value, 0); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -350,6 +355,20 @@ uca_camera_class_init (UcaCameraClass *klass) "Is the camera able to record the data in-camera", FALSE, G_PARAM_READABLE); + /** + * UcaCamera:recorded-frames + * + * Number of frames that are recorded into internal camera memory. + * + * Since: 1.1 + */ + camera_properties[PROP_RECORDED_FRAMES] = + g_param_spec_uint(uca_camera_props[PROP_RECORDED_FRAMES], + "Number of frames recorded into internal camera memory", + "Number of frames recorded into internal camera memory", + 0, G_MAXUINT, 0, + G_PARAM_READABLE); + camera_properties[PROP_TRANSFER_ASYNCHRONOUSLY] = g_param_spec_boolean(uca_camera_props[PROP_TRANSFER_ASYNCHRONOUSLY], "Specify whether data should be transfered asynchronously", @@ -398,6 +417,7 @@ uca_camera_init (UcaCamera *camera) uca_camera_set_property_unit (camera_properties[PROP_ROI_HEIGHT], UCA_UNIT_PIXEL); uca_camera_set_property_unit (camera_properties[PROP_ROI_WIDTH_MULTIPLIER], UCA_UNIT_COUNT); uca_camera_set_property_unit (camera_properties[PROP_ROI_HEIGHT_MULTIPLIER], UCA_UNIT_COUNT); + uca_camera_set_property_unit (camera_properties[PROP_RECORDED_FRAMES], UCA_UNIT_COUNT); } /** diff --git a/src/uca-camera.h b/src/uca-camera.h index 78edd95..87996c6 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -85,6 +85,7 @@ enum { PROP_ROI_HEIGHT_MULTIPLIER, PROP_HAS_STREAMING, PROP_HAS_CAMRAM_RECORDING, + PROP_RECORDED_FRAMES, /* These properties are handled internally */ PROP_TRANSFER_ASYNCHRONOUSLY, -- cgit v1.2.3 From bcf80f7ddb66ee213dc493904e1b743e99d90082 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Thu, 18 Oct 2012 16:07:13 +0200 Subject: Launch download dialog to ease waiting --- tools/gui/control.c | 34 ++++++++++++++++++++-- tools/gui/control.glade | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/tools/gui/control.c b/tools/gui/control.c index 07b7937..0b59837 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -44,6 +44,11 @@ typedef struct { GtkWidget *download_button; GtkComboBox *zoom_box; + GtkDialog *download_dialog; + GtkProgressBar *download_progressbar; + GtkWidget *download_close_button; + GtkAdjustment *download_adjustment; + GtkWidget *histogram_view; GtkToggleButton *histogram_button; GtkAdjustment *frame_slider; @@ -290,17 +295,21 @@ on_record_button_clicked (GtkWidget *widget, ThreadData *data) } } -static void -on_download_button_clicked (GtkWidget *widget, ThreadData *data) +static gpointer +download_frames (ThreadData *data) { gpointer buffer; + guint n_frames; GError *error = NULL; + g_object_get (data->camera, "recorded-frames", &n_frames, NULL); + g_print ("recorded %i frames\n", n_frames); + uca_camera_start_readout (data->camera, &error); if (error != NULL) { g_printerr ("Failed to start read out of camera memory: %s\n", error->message); - return; + return NULL; } ring_buffer_reset (data->buffer); @@ -327,6 +336,22 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) if (error != NULL) g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); + + return NULL; +} + +static void +on_download_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + if (!g_thread_create ((GThreadFunc) download_frames, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + } + + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); + gtk_dialog_run (data->download_dialog); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); } static void @@ -408,6 +433,9 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); + td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); + td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); + /* Set initial data */ pixel_size = bits_per_sample > 8 ? 2 : 1; image_size = pixel_size * width * height; diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 2d2aaac..eec9dde 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -555,4 +555,81 @@ <property name="step_increment">1</property> <property name="page_increment">10</property> </object> + <object class="GtkDialog" id="download-dialog"> + <property name="border_width">5</property> + <property name="type_hint">normal</property> + <child internal-child="vbox"> + <object class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <object class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="border_width">10</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Downloading Frames …</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkProgressBar" id="download-progressbar"> + <property name="visible">True</property> + <property name="adjustment">download-adjustment</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <object class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="download-close-button"> + <property name="label">gtk-close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">download-close-button</action-widget> + </action-widgets> + </object> + <object class="GtkAdjustment" id="download-adjustment"> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> </interface> -- cgit v1.2.3 From a7a48c55df8dc3e34a2ce50b18b70c0cd101766d Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@kit.edu> Date: Thu, 18 Oct 2012 16:27:45 +0200 Subject: Show download progress --- plugins/pco/uca-pco-camera.c | 4 ++++ tools/gui/control.c | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index d34e0f4..5d08acf 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -506,7 +506,11 @@ uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) if (err == FG_INVALID_PARAMETER) g_warning(" Unable to unblock all\n"); + 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); + g_print ("images: %i\n", priv->num_recorded_images); HANDLE_PCO_ERROR(err); } diff --git a/tools/gui/control.c b/tools/gui/control.c index 0b59837..877473e 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -36,6 +36,7 @@ typedef enum { typedef struct { UcaCamera *camera; + GtkWidget *main_window; GdkPixbuf *pixbuf; GtkWidget *image; GtkWidget *start_button; @@ -300,10 +301,14 @@ download_frames (ThreadData *data) { gpointer buffer; guint n_frames; + guint current_frame = 1; GError *error = NULL; g_object_get (data->camera, "recorded-frames", &n_frames, NULL); - g_print ("recorded %i frames\n", n_frames); + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, FALSE); + gtk_adjustment_set_upper (data->download_adjustment, n_frames); + gdk_threads_leave (); uca_camera_start_readout (data->camera, &error); @@ -318,6 +323,9 @@ download_frames (ThreadData *data) buffer = ring_buffer_get_current_pointer (data->buffer); uca_camera_grab (data->camera, &buffer, &error); ring_buffer_proceed (data->buffer); + gdk_threads_enter (); + gtk_adjustment_set_value (data->download_adjustment, current_frame++); + gdk_threads_leave (); } if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { @@ -337,6 +345,10 @@ download_frames (ThreadData *data) if (error != NULL) g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, TRUE); + gdk_threads_leave (); + return NULL; } @@ -349,9 +361,13 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) g_printerr ("Failed to create thread: %s\n", error->message); } + gtk_widget_set_sensitive (data->main_window, FALSE); gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); gtk_dialog_run (data->download_dialog); + gtk_widget_hide (GTK_WIDGET (data->download_dialog)); gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); + gtk_widget_set_sensitive (data->main_window, TRUE); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); } static void @@ -435,6 +451,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); + td.download_close_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-close-button")); /* Set initial data */ pixel_size = bits_per_sample > 8 ? 2 : 1; @@ -465,6 +482,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.zoom_factor = 1.0; td.histogram_view = histogram_view; td.data_in_camram = FALSE; + td.main_window = window; update_pixbuf_dimensions (&td); set_tool_button_state (&td); -- cgit v1.2.3 From 7fe0adeb842c3aa47b380a9290465b1250025878 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 19 Oct 2012 10:39:40 +0200 Subject: Update uca_plugin_manager_get_camera annotation --- src/uca-plugin-manager.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index 373ccb2..e99f478 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -209,10 +209,14 @@ find_camera_module_path (GList *search_paths, const gchar *name) } /** - * uca_plugin_manager_new_camera: + * uca_plugin_manager_get_camera: * @manager: A #UcaPluginManager * @name: Name of the camera module, that maps to libuca<name>.so * @error: Location for a #GError + * + * Create a new camera instance with camera @name. + * + * Returns: (transfer full): A new #UcaCamera object. */ UcaCamera * uca_plugin_manager_get_camera (UcaPluginManager *manager, -- cgit v1.2.3 From f9c8476e1ce1a5089cd5fc7f4a40329e0c5a70b7 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 19 Oct 2012 14:26:04 +0200 Subject: Don't soft trigger on external signal --- plugins/ufo/uca-ufo-camera.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/plugins/ufo/uca-ufo-camera.c b/plugins/ufo/uca-ufo-camera.c index 7542fdf..0b040c6 100644 --- a/plugins/ufo/uca-ufo-camera.c +++ b/plugins/ufo/uca-ufo-camera.c @@ -79,7 +79,6 @@ static gint base_overrideables[] = { PROP_ROI_HEIGHT_MULTIPLIER, PROP_HAS_STREAMING, PROP_HAS_CAMRAM_RECORDING, - PROP_TRIGGER_MODE, 0, }; @@ -101,6 +100,7 @@ struct _UcaUfoCameraPrivate { FPGA_48MHZ = 0, FPGA_40MHZ } frequency; + UcaCameraTrigger trigger; }; static void @@ -244,6 +244,7 @@ static void uca_ufo_camera_start_recording(UcaCamera *camera, GError **error) g_object_get(G_OBJECT(camera), "transfer-asynchronously", &transfer_async, "exposure-time", &exposure_time, + "trigger-mode", &priv->trigger, NULL); priv->timeout = ((pcilib_timeout_t) (exposure_time * 1000 + 50.0) * 1000); @@ -265,8 +266,11 @@ static void uca_ufo_camera_stop_recording(UcaCamera *camera, GError **error) 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_stop_readout(UcaCamera *camera, GError **error) +{ + g_return_if_fail(UCA_IS_UFO_CAMERA(camera)); } static void uca_ufo_camera_grab(UcaCamera *camera, gpointer *data, GError **error) @@ -279,8 +283,10 @@ static void uca_ufo_camera_grab(UcaCamera *camera, gpointer *data, GError **erro 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); + if (priv->trigger != UCA_CAMERA_TRIGGER_EXTERNAL) { + 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); @@ -429,8 +435,6 @@ uca_ufo_camera_get_property(GObject *object, guint property_id, GValue *value, G 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)); @@ -462,6 +466,7 @@ static void uca_ufo_camera_class_init(UcaUfoCameraClass *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->stop_readout = uca_ufo_camera_stop_readout; camera_class->grab = uca_ufo_camera_grab; for (guint i = 0; base_overrideables[i] != 0; i++) -- cgit v1.2.3 From e4deaf621246d6e97950d56e244345c8e13a6044 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 19 Oct 2012 14:29:29 +0200 Subject: Store trigger mode --- plugins/ufo/uca-ufo-camera.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/ufo/uca-ufo-camera.c b/plugins/ufo/uca-ufo-camera.c index 0b040c6..2b289a5 100644 --- a/plugins/ufo/uca-ufo-camera.c +++ b/plugins/ufo/uca-ufo-camera.c @@ -79,6 +79,7 @@ static gint base_overrideables[] = { PROP_ROI_HEIGHT_MULTIPLIER, PROP_HAS_STREAMING, PROP_HAS_CAMRAM_RECORDING, + PROP_TRIGGER_MODE, 0, }; @@ -338,6 +339,10 @@ uca_ufo_camera_set_property(GObject *object, guint property_id, const GValue *va g_debug("ROI feature not implemented yet"); break; + case PROP_TRIGGER_MODE: + priv->trigger = g_value_get_enum (value); + break; + default: { RegisterInfo *reg_info = g_hash_table_lookup (ufo_property_table, GINT_TO_POINTER (property_id)); @@ -435,6 +440,9 @@ uca_ufo_camera_get_property(GObject *object, guint property_id, GValue *value, G case PROP_NAME: g_value_set_string(value, "Ufo Camera w/ CMOSIS CMV2000"); break; + case PROP_TRIGGER_MODE: + g_value_set_enum (value, priv->trigger); + break; default: { RegisterInfo *reg_info = g_hash_table_lookup (ufo_property_table, GINT_TO_POINTER (property_id)); -- cgit v1.2.3 From 9e45cb5ffdea8592077ee42223caecda492326cd Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 19 Oct 2012 15:40:10 +0200 Subject: Always return correct number of recorded frames --- plugins/pco/uca-pco-camera.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 5d08acf..2a5d034 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -506,11 +506,6 @@ uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) if (err == FG_INVALID_PARAMETER) g_warning(" Unable to unblock all\n"); - 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); - g_print ("images: %i\n", priv->num_recorded_images); HANDLE_PCO_ERROR(err); } @@ -525,9 +520,6 @@ uca_pco_camera_start_readout(UcaCamera *camera, GError **error) * 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); @@ -1033,6 +1025,7 @@ uca_pco_camera_get_property(GObject *object, guint property_id, GValue *value, G break; case PROP_RECORDED_FRAMES: + err = pco_get_num_images (priv->pco, priv->active_segment, &priv->num_recorded_images); g_value_set_uint(value, priv->num_recorded_images); break; @@ -1439,6 +1432,7 @@ uca_camera_impl_new (GError **error) UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera); priv->pco = pco; + pco_get_active_segment(priv->pco, &priv->active_segment); 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); -- cgit v1.2.3 From 6f12303cf4c4130d544c30f8ad5e2445a1fa3e61 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Fri, 19 Oct 2012 15:41:02 +0200 Subject: Fix compile error --- plugins/pco/uca-pco-camera.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 2a5d034..bb7bd5a 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -512,6 +512,8 @@ uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) static void uca_pco_camera_start_readout(UcaCamera *camera, GError **error) { + guint err; + g_return_if_fail(UCA_IS_PCO_CAMERA(camera)); UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera); -- cgit v1.2.3