/* Copyright (C) 2011, 2012 Matthias Vogelgesang (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 #include #include "config.h" #include "uca.h" #include "uca-cam.h" #include "uca-grabber.h" #ifdef HAVE_PTHREADS #include #endif #ifdef HAVE_DUMMY_CAMERA #include "cameras/dummy.h" #endif #ifdef HAVE_ME4 #include "grabbers/me4.h" #endif #ifdef HAVE_PCO_CL #include "cameras/pco.h" #endif #ifdef HAVE_PHOTON_FOCUS #include "cameras/pf.h" #endif #ifdef HAVE_IPE_CAMERA #include "cameras/ipe.h" #endif #ifdef HAVE_SIMPLE_CAMERA #include "cameras/simple.h" #endif const char *uca_unit_map[] = { "px", "bits", "ns", "µs", "ms", "s", "rows", "fps", "°C", "[0/1]", "" }; static struct uca_property property_map[UCA_PROP_LAST+1] = { { "General.Name", uca_na, uca_string, uca_read }, { "Image.Width", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Width.Min", uca_pixel, uca_uint32t, uca_read }, { "Image.Width.Max", uca_pixel, uca_uint32t, uca_read }, { "Image.Height", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Height.Min", uca_pixel, uca_uint32t, uca_read }, { "Image.Height.Max", uca_pixel, uca_uint32t, uca_read }, { "Image.Offset.x", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Offset.x.Min", uca_pixel, uca_uint32t, uca_read }, { "Image.Offset.x.Max", uca_pixel, uca_uint32t, uca_read }, { "Image.Offset.y", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Offset.y.Min", uca_pixel, uca_uint32t, uca_read }, { "Image.Offset.y.Max", uca_pixel, uca_uint32t, uca_read }, { "Image.Binning.x", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Binning.y", uca_pixel, uca_uint32t, uca_readwrite }, { "Image.Bitdepth", uca_bits, uca_uint32t, uca_read}, { "Time.Exposure", uca_us, uca_uint32t, uca_readwrite }, { "Time.Exposure.Min", uca_us, uca_uint32t, uca_read }, { "Time.Exposure.Max", uca_us, uca_uint32t, uca_read }, { "Time.Delay", uca_us, uca_uint32t, uca_readwrite }, { "Time.Delay.Min", uca_us, uca_uint32t, uca_read }, { "Time.Delay.Max", uca_us, uca_uint32t, uca_read }, { "Time.Framerate", uca_fps, uca_uint32t, uca_read }, { "Temperature.Sensor", uca_dc, uca_uint32t, uca_read }, { "Temperature.Camera", uca_dc, uca_uint32t, uca_read }, { "Trigger.Mode", uca_na, uca_uint32t, uca_readwrite }, { "Trigger.Exposure", uca_na, uca_uint32t, uca_readwrite }, { "Gain.PGA", uca_na, uca_uint32t, uca_readwrite }, { "Gain.PGA.Min", uca_na, uca_uint32t, uca_read }, { "Gain.PGA.Max", uca_na, uca_uint32t, uca_read }, { "Gain.PGA.Step", uca_na, uca_uint32t, uca_read }, { "Gain.ADC", uca_na, uca_uint32t, uca_readwrite }, { "Gain.ADC.Min", uca_na, uca_uint32t, uca_read }, { "Gain.ADC.Max", uca_na, uca_uint32t, uca_read }, { "Gain.ADC.Step", uca_na, uca_uint32t, uca_read }, { "Grabber.Timeout", uca_s, uca_uint32t, uca_readwrite }, { "Grabber.Synchronous", uca_bool, uca_uint32t, uca_readwrite }, { "Grabber.Auto", uca_bool, uca_uint32t, uca_readwrite }, { "Mode.Timestamp", uca_na, uca_uint32t, uca_readwrite }, { "Mode.Scan", uca_na, uca_uint32t, uca_readwrite }, { "Mode.Hotpixel", uca_na, uca_uint32t, uca_readwrite }, { "Interlace.Samplerate", uca_na, uca_uint32t, uca_readwrite }, { "Interlace.Threshold.Pixel", uca_na, uca_uint32t, uca_readwrite }, { "Interlace.Threshold.Row", uca_na, uca_uint32t, uca_readwrite }, { "Mode.correction", uca_na, uca_uint32t, uca_readwrite }, { NULL, 0, 0, 0 } }; #ifdef HAVE_PTHREADS static pthread_mutex_t g_uca_init_lock = PTHREAD_MUTEX_INITIALIZER; #define uca_lock() pthread_mutex_lock((&g_uca_init_lock)) #define uca_unlock() pthread_mutex_unlock((&g_uca_init_lock)) #else #define uca_lock(lock) #define uca_unlock(lock) #endif struct uca *g_uca = NULL; struct uca *uca_init(const char *config_filename) { uca_lock(); if (g_uca != NULL) { uca_unlock(); return g_uca; } g_uca = (struct uca *) malloc(sizeof(struct uca)); g_uca->cameras = NULL; uca_grabber_init grabber_inits[] = { #ifdef HAVE_ME4 uca_me4_init, #endif NULL }; uca_cam_init cam_inits[] = { #ifdef HAVE_PCO_CL uca_pco_init, #endif #ifdef HAVE_PHOTON_FOCUS uca_pf_init, #endif #ifdef HAVE_IPE_CAMERA uca_ipe_init, #endif #ifdef HAVE_DUMMY_CAMERA uca_dummy_init, #endif #ifdef HAVE_SIMPLE_CAMERA uca_simple_init, #endif NULL }; /* Probe each frame grabber that is configured */ int i = 0; struct uca_grabber_priv *grabber = NULL; while (grabber_inits[i] != NULL) { uca_grabber_init init = grabber_inits[i]; /* FIXME: we don't want to take the only first one */ if (init(&grabber) == UCA_NO_ERROR) break; i++; } /* XXX: We could have no grabber (aka NULL) which is good anyway, since * some cameras don't need a grabber device (such as the IPE camera), * therefore we also probe each camera against the NULL grabber. However, * each camera must make sure to check for such a situation. */ if (grabber != NULL) { g_uca->grabbers = (struct uca_grabber *) malloc(sizeof(struct uca_grabber)); g_uca->grabbers->priv = grabber; g_uca->grabbers->next = NULL; } i = 0; struct uca_camera *current = NULL; /* Probe each camera that is configured and append a found camera to the * linked list. */ while (cam_inits[i] != NULL) { struct uca_camera_priv *cam = NULL; uca_cam_init init = cam_inits[i]; if (init(&cam, grabber) == UCA_NO_ERROR) { if (current == NULL) { g_uca->cameras = (struct uca_camera *) malloc(sizeof(struct uca_camera)); g_uca->cameras->priv = cam; g_uca->cameras->next = NULL; current = g_uca->cameras; } else { current->next = (struct uca_camera *) malloc(sizeof(struct uca_camera)); current->next->priv = cam; current = current->next; } current->next = NULL; } i++; } if (g_uca->cameras == NULL) { free(g_uca); g_uca = NULL; uca_unlock(); return NULL; } uca_unlock(); return g_uca; } void uca_destroy(struct uca *u) { uca_lock(); if (u != NULL) { struct uca_camera *cam = u->cameras, *tmp; struct uca_camera_priv *cam_priv; while (cam != NULL) { tmp = cam; cam_priv = cam->priv; cam_priv->destroy(cam_priv); cam = cam->next; free(tmp); } struct uca_grabber *grabber = u->grabbers, *tmpg; struct uca_grabber_priv *grabber_priv; while (grabber != NULL) { tmpg = grabber; grabber_priv = grabber->priv; grabber_priv->destroy(grabber_priv); grabber = grabber->next; free(tmpg); } free(u); } uca_unlock(); } uint32_t uca_get_property_id(const char *property_name, enum uca_property_ids *prop_id) { int i = 0; while (property_map[i].name != NULL) { if (!strcmp(property_map[i].name, property_name)) { *prop_id = (enum uca_property_ids) i; return UCA_NO_ERROR; } i++; } return UCA_ERR_CAMERA | UCA_ERR_PROP | UCA_ERR_INVALID; } struct uca_property *uca_get_full_property(enum uca_property_ids property_id) { if ((property_id >= 0) && (property_id < UCA_PROP_LAST)) return &property_map[property_id]; return NULL; } const char* uca_get_property_name(enum uca_property_ids property_id) { if ((property_id >= 0) && (property_id < UCA_PROP_LAST)) return property_map[property_id].name; return UCA_NO_ERROR; } uint32_t uca_cam_alloc(struct uca_camera *cam, uint32_t n_buffers) { uint32_t bitdepth; struct uca_camera_priv *priv = cam->priv; priv->get_property(priv, UCA_PROP_BITDEPTH, &bitdepth, 0); const int pixel_size = bitdepth == 8 ? 1 : 2; if (priv->grabber != NULL) return priv->grabber->alloc(priv->grabber, pixel_size, n_buffers); return UCA_NO_ERROR; } enum uca_cam_state uca_cam_get_state(struct uca_camera *cam) { struct uca_camera_priv *priv = cam->priv; return priv->state; } uint32_t uca_cam_set_property(struct uca_camera *cam, enum uca_property_ids property, void *data) { struct uca_camera_priv *priv = cam->priv; return priv->set_property(priv, property, data); } uint32_t uca_cam_get_property(struct uca_camera *cam, enum uca_property_ids property, void *data, size_t num) { struct uca_camera_priv *priv = cam->priv; return priv->get_property(priv, property, data, num); } uint32_t uca_cam_start_recording(struct uca_camera *cam) { struct uca_camera_priv *priv = cam->priv; if (priv->state == UCA_CAM_RECORDING) return UCA_ERR_CAMERA | UCA_ERR_CONFIGURATION | UCA_ERR_IS_RECORDING; uint32_t err = priv->start_recording(priv); if (err == UCA_NO_ERROR) priv->state = UCA_CAM_RECORDING; return err; } uint32_t uca_cam_stop_recording(struct uca_camera *cam) { struct uca_camera_priv *priv = cam->priv; if (priv->state != UCA_CAM_RECORDING) return UCA_ERR_CAMERA | UCA_ERR_CONFIGURATION | UCA_ERR_NOT_RECORDING; uint32_t err = priv->stop_recording(priv); if (err == UCA_NO_ERROR) priv->state = UCA_CAM_CONFIGURABLE; return err; } uint32_t uca_cam_trigger(struct uca_camera *cam) { struct uca_camera_priv *priv = cam->priv; if (priv->state != UCA_CAM_RECORDING) return UCA_ERR_CAMERA | UCA_ERR_TRIGGER | UCA_ERR_NOT_RECORDING; return priv->trigger(priv); } uint32_t uca_cam_register_callback(struct uca_camera *cam, uca_cam_grab_callback callback, void *user) { struct uca_camera_priv *priv = cam->priv; return priv->register_callback(priv, callback, user); } uint32_t uca_cam_release_buffer(struct uca_camera *cam, void *buffer) { struct uca_camera_priv *priv = cam->priv; if (priv->release_buffer != NULL) return priv->release_buffer(priv, buffer); return UCA_ERR_NOT_IMPLEMENTED; } uint32_t uca_cam_grab(struct uca_camera *cam, char *buffer, void *meta_data) { struct uca_camera_priv *priv = cam->priv; if ((priv->state != UCA_CAM_RECORDING) && (priv->state != UCA_CAM_READOUT)) return UCA_ERR_CAMERA | UCA_ERR_NOT_RECORDING; return priv->grab(priv, buffer, meta_data); } uint32_t uca_cam_readout(struct uca_camera *cam) { struct uca_camera_priv *priv = cam->priv; if (priv->state == UCA_CAM_RECORDING) return UCA_ERR_CAMERA | UCA_ERR_IS_RECORDING; if (priv->readout == NULL) return UCA_ERR_CAMERA | UCA_ERR_NOT_IMPLEMENTED; priv->state = UCA_CAM_READOUT; return priv->readout(priv); }