diff options
Diffstat (limited to 'plugins/ufo/uca-ufo-camera.c')
-rw-r--r-- | plugins/ufo/uca-ufo-camera.c | 323 |
1 files changed, 231 insertions, 92 deletions
diff --git a/plugins/ufo/uca-ufo-camera.c b/plugins/ufo/uca-ufo-camera.c index c4e05b0..145c2ee 100644 --- a/plugins/ufo/uca-ufo-camera.c +++ b/plugins/ufo/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 <gio/gio.h> #include <gmodule.h> #include <stdlib.h> #include <stdio.h> @@ -33,9 +34,22 @@ return; \ } +#define PCILIB_SET_ERROR_RETURN_FALSE(err, err_type) \ + if (err != 0) { \ + g_set_error(error, UCA_UFO_CAMERA_ERROR, \ + err_type, \ + "%s:%i pcilib: %s (errcode = %d)", \ + __FILE__, __LINE__, strerror(err), err);\ + return FALSE; \ + } + #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 void uca_ufo_camera_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (UcaUfoCamera, uca_ufo_camera, UCA_TYPE_CAMERA, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + uca_ufo_camera_initable_iface_init)) static const guint SENSOR_WIDTH = 2048; static const guint SENSOR_HEIGHT = 1088; @@ -80,7 +94,6 @@ static gint base_overrideables[] = { PROP_ROI_HEIGHT_MULTIPLIER, PROP_HAS_STREAMING, PROP_HAS_CAMRAM_RECORDING, - PROP_TRIGGER_MODE, 0, }; @@ -92,9 +105,11 @@ typedef struct _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 { + GError *construct_error; + GHashTable *property_table; /* maps from prop_id to RegisterInfo* */ + GThread *async_thread; pcilib_t *handle; pcilib_timeout_t timeout; guint n_bits; @@ -102,7 +117,6 @@ struct _UcaUfoCameraPrivate { FPGA_48MHZ = 0, FPGA_40MHZ } frequency; - UcaCameraTrigger trigger; }; static void @@ -126,7 +140,8 @@ read_register_value (pcilib_t *handle, const gchar *name) return (guint) reg_value; } -static int event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) +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); @@ -134,47 +149,32 @@ static int event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *buffer = pcilib_get_data(priv->handle, event_id, PCILIB_EVENT_DATA, &error); - if (buffer == NULL) { - pcilib_trigger(priv->handle, PCILIB_EVENT0, 0, NULL); + if (buffer == 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); + camera->grab_func (buffer, camera->user_data); + pcilib_return_data (priv->handle, event_id, PCILIB_EVENT_DATA, buffer); return PCILIB_STREAMING_CONTINUE; } -G_MODULE_EXPORT UcaCamera * -uca_camera_impl_new (GError **error) +static guint +update_properties (UcaUfoCameraPrivate *priv) { - 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; - } + guint prop; + pcilib_model_description_t *description; - pcilib_set_error_handler(&error_handler, &error_handler); + prop = PROP_UFO_START; + description = pcilib_get_model_description (priv->handle); - /* 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++) { + for (guint i = 0; 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]; + reg = &description->registers[i]; switch (reg->mode) { case PCILIB_REGISTER_R: @@ -190,12 +190,12 @@ uca_camera_impl_new (GError **error) break; } - pcilib_read_register (handle, NULL, reg->name, &value); + pcilib_read_register (priv->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); + g_hash_table_insert (priv->property_table, GINT_TO_POINTER (prop), reg_info); prop_name = g_strdup_printf ("ufo-%s", reg->name); ufo_properties[prop++] = g_param_spec_uint ( @@ -205,13 +205,32 @@ uca_camera_impl_new (GError **error) g_free (prop_name); } - N_PROPERTIES = prop; + return prop; +} - UcaUfoCamera *camera = g_object_new(UCA_TYPE_UFO_CAMERA, NULL); - UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera); +static gboolean +setup_pcilib (UcaUfoCameraPrivate *priv) +{ + pcilib_model_t model; + guint adc_resolution; + + model = PCILIB_MODEL_DETECT; + priv->handle = pcilib_open("/dev/fpga0", model); - priv->frequency = read_register_value (handle, "bit_mode"); - adc_resolution = read_register_value (handle, "adc_resolution"); + if (priv->handle == NULL) { + g_set_error (&priv->construct_error, + UCA_UFO_CAMERA_ERROR, UCA_UFO_CAMERA_ERROR_INIT, + "Initializing pcilib failed"); + return FALSE; + } + + pcilib_set_error_handler (&error_handler, &error_handler); + + priv->property_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); + N_PROPERTIES = update_properties (priv); + priv->frequency = read_register_value (priv->handle, "bit_mode"); + adc_resolution = read_register_value (priv->handle, "adc_resolution"); switch (adc_resolution) { case 0: @@ -225,59 +244,115 @@ uca_camera_impl_new (GError **error) break; } - priv->handle = handle; + return TRUE; +} + +static void +set_control_bit (UcaUfoCameraPrivate *priv, guint bit, gboolean set) +{ + static const gchar *name = "control"; + pcilib_register_value_t flags; + pcilib_register_value_t mask; + + pcilib_read_register (priv->handle, NULL, name, &flags); + mask = 1 << bit; + + if (set) + flags |= mask; + else + flags = flags & ~mask; - return UCA_CAMERA (camera); + pcilib_write_register(priv->handle, NULL, name, flags); } -static void uca_ufo_camera_start_recording(UcaCamera *camera, GError **error) +static void +set_streaming (UcaUfoCameraPrivate *priv, gboolean enable) +{ + set_control_bit (priv, 11, enable); +} + +static gpointer +stream_async (UcaCamera *camera) { UcaUfoCameraPrivate *priv; + priv = UCA_UFO_CAMERA_GET_PRIVATE (camera); + pcilib_stream (priv->handle, &event_callback, camera); + + return NULL; +} + +static void +uca_ufo_camera_start_recording(UcaCamera *camera, GError **error) +{ + UcaUfoCameraPrivate *priv; + UcaCameraTrigger trigger; gdouble exposure_time; - int err; + gboolean transfer_async; + int err; g_return_if_fail(UCA_IS_UFO_CAMERA(camera)); priv = UCA_UFO_CAMERA_GET_PRIVATE(camera); + + g_object_get (G_OBJECT(camera), + "transfer-asynchronously", &transfer_async, + "exposure-time", &exposure_time, + "trigger-mode", &trigger, + NULL); + 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, - "trigger-mode", &priv->trigger, - NULL); + if (trigger == UCA_CAMERA_TRIGGER_AUTO) + set_streaming (priv, TRUE); 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); - } + if (transfer_async) + priv->async_thread = g_thread_create ((GThreadFunc) stream_async, camera, TRUE, error); } -static void uca_ufo_camera_stop_recording(UcaCamera *camera, GError **error) +static void +uca_ufo_camera_stop_recording(UcaCamera *camera, GError **error) { + UcaUfoCameraPrivate *priv; + UcaCameraTrigger trigger; 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); + + priv = UCA_UFO_CAMERA_GET_PRIVATE(camera); + + g_object_get (G_OBJECT (camera), "trigger-mode", &trigger, NULL); + + if (priv->async_thread) { + int err = pcilib_stop(priv->handle, PCILIB_EVENT_FLAG_STOP_ONLY); + PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_STOP_RECORDING); + g_thread_join(priv->async_thread); + priv->async_thread = NULL; + } + + int err = pcilib_stop (priv->handle, PCILIB_EVENT_FLAGS_DEFAULT); + PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_STOP_RECORDING); + + if (trigger == UCA_CAMERA_TRIGGER_AUTO) + set_streaming (priv, FALSE); } -static void uca_ufo_camera_start_readout(UcaCamera *camera, GError **error) +static void +uca_ufo_camera_start_readout(UcaCamera *camera, GError **error) { g_return_if_fail(UCA_IS_UFO_CAMERA(camera)); } -static void uca_ufo_camera_stop_readout(UcaCamera *camera, GError **error) +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) +static gboolean +uca_ufo_camera_grab(UcaCamera *camera, gpointer data, GError **error) { - g_return_if_fail(UCA_IS_UFO_CAMERA(camera)); + g_return_val_if_fail (UCA_IS_UFO_CAMERA(camera), FALSE); UcaUfoCameraPrivate *priv = UCA_UFO_CAMERA_GET_PRIVATE(camera); pcilib_event_id_t event_id; pcilib_event_info_t event_info; @@ -285,21 +360,13 @@ static void uca_ufo_camera_grab(UcaCamera *camera, gpointer *data, GError **erro const gsize size = SENSOR_WIDTH * SENSOR_HEIGHT * sizeof(guint16); - 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); - - if (*data == NULL) - *data = g_malloc0(SENSOR_WIDTH * SENSOR_HEIGHT * sizeof(guint16)); + err = pcilib_get_next_event (priv->handle, priv->timeout, &event_id, sizeof(pcilib_event_info_t), &event_info); + PCILIB_SET_ERROR_RETURN_FALSE (err, UCA_UFO_CAMERA_ERROR_NEXT_EVENT); - gpointer src = pcilib_get_data(priv->handle, event_id, PCILIB_EVENT_DATA, (size_t *) &err); + gpointer src = pcilib_get_data (priv->handle, event_id, PCILIB_EVENT_DATA, (size_t *) &err); if (src == NULL) - PCILIB_SET_ERROR(err, UCA_UFO_CAMERA_ERROR_NO_DATA); + PCILIB_SET_ERROR_RETURN_FALSE (err, UCA_UFO_CAMERA_ERROR_NO_DATA); /* * Apparently, we checked that err equals total size in previous version. @@ -309,15 +376,29 @@ static void uca_ufo_camera_grab(UcaCamera *camera, gpointer *data, GError **erro */ /* assert(err == size); */ - memcpy(*data, src, 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); + err = pcilib_return_data (priv->handle, event_id, PCILIB_EVENT_DATA, data); + PCILIB_SET_ERROR_RETURN_FALSE (err, UCA_UFO_CAMERA_ERROR_MAYBE_CORRUPTED); + + return TRUE; +} + +static void +uca_ufo_camera_trigger (UcaCamera *camera, GError **error) +{ + UcaUfoCameraPrivate *priv; + g_return_if_fail (UCA_IS_UFO_CAMERA(camera)); + + priv = UCA_UFO_CAMERA_GET_PRIVATE(camera); + + /* XXX: What is PCILIB_EVENT0? */ + pcilib_trigger (priv->handle, PCILIB_EVENT0, 0, NULL); } static void @@ -340,19 +421,18 @@ 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)); + RegisterInfo *reg_info; + + reg_info = g_hash_table_lookup (priv->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_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; } @@ -441,12 +521,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)); + RegisterInfo *reg_info = g_hash_table_lookup (priv->property_table, GINT_TO_POINTER (property_id)); if (reg_info != NULL) g_value_set_uint (value, reg_info->cached_value); @@ -457,14 +534,56 @@ uca_ufo_camera_get_property(GObject *object, guint property_id, GValue *value, G } } -static void uca_ufo_camera_finalize(GObject *object) +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); + UcaUfoCameraPrivate *priv; + + priv = UCA_UFO_CAMERA_GET_PRIVATE (object); + + pcilib_close (priv->handle); + g_clear_error (&priv->construct_error); + + G_OBJECT_CLASS (uca_ufo_camera_parent_class)->finalize (object); } -static void uca_ufo_camera_class_init(UcaUfoCameraClass *klass) +static gboolean +ufo_ufo_camera_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + UcaUfoCamera *camera; + UcaUfoCameraPrivate *priv; + + g_return_val_if_fail (UCA_IS_UFO_CAMERA (initable), FALSE); + + if (cancellable != NULL) { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cancellable initialization not supported"); + return FALSE; + } + + camera = UCA_UFO_CAMERA (initable); + priv = camera->priv; + + if (priv->construct_error != NULL) { + if (error) + *error = g_error_copy (priv->construct_error); + + return FALSE; + } + + return TRUE; +} + +static void +uca_ufo_camera_initable_iface_init (GInitableIface *iface) +{ + iface->init = ufo_ufo_camera_initable_init; +} + +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; @@ -477,6 +596,7 @@ static void uca_ufo_camera_class_init(UcaUfoCameraClass *klass) 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; + camera_class->trigger = uca_ufo_camera_trigger; 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]]); @@ -505,7 +625,26 @@ static void uca_ufo_camera_class_init(UcaUfoCameraClass *klass) g_type_class_add_private(klass, sizeof(UcaUfoCameraPrivate)); } -static void uca_ufo_camera_init(UcaUfoCamera *self) +static void +uca_ufo_camera_init(UcaUfoCamera *self) +{ + UcaCamera *camera; + UcaUfoCameraPrivate *priv; + + self->priv = priv = UCA_UFO_CAMERA_GET_PRIVATE(self); + priv->construct_error = NULL; + priv->async_thread = NULL; + + if (!setup_pcilib (priv)) + return; + + camera = UCA_CAMERA (self); + uca_camera_register_unit (camera, "sensor-temperature", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "fpga-temperature", UCA_UNIT_DEGREE_CELSIUS); +} + +G_MODULE_EXPORT GType +uca_camera_get_type (void) { - self->priv = UCA_UFO_CAMERA_GET_PRIVATE(self); + return UCA_TYPE_UFO_CAMERA; } |