Logo Search packages:      
Sourcecode: libgphoto2 version File versions  Download package

gphoto2-camera.c

Go to the documentation of this file.
/** \file
 *
 * Implement Camera object representing a camera attached to the system.
 *
 * \author Copyright 2000 Scott Fritzinger
 * \author Copyright 2001-2002 Lutz Müller <lutz@users.sf.net>
 *
 * \note
 * 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 of the License, or (at your option) any later version.
 *
 * \note
 * 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. 
 *
 * \note
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"
#include <gphoto2/gphoto2-camera.h>

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include <ltdl.h>

#include <gphoto2/gphoto2-result.h>
#include <gphoto2/gphoto2-library.h>
#include <gphoto2/gphoto2-port-log.h>

#ifdef ENABLE_NLS
#  include <libintl.h>
#  undef _
#  define _(String) dgettext (GETTEXT_PACKAGE, String)
#  ifdef gettext_noop
#    define N_(String) gettext_noop (String)
#  else
#    define N_(String) (String)
#  endif
#else
#  define textdomain(String) (String)
#  define gettext(String) (String)
#  define dgettext(Domain,Message) (Message)
#  define dcgettext(Domain,Message,Type) (Message)
#  define bindtextdomain(Domain,Directory) (Domain)
#  define _(String) (String)
#  define N_(String) (String)
#endif

#define CHECK_NULL(r)              {if (!(r)) return (GP_ERROR_BAD_PARAMETERS);}

#define CAMERA_UNUSED(c,ctx)                                \
{                                                     \
      (c)->pc->used--;                                \
      if (!(c)->pc->used) {                                 \
            if ((c)->pc->exit_requested)                    \
                  gp_camera_exit ((c), (ctx));              \
            if (!(c)->pc->ref_count)                        \
                  gp_camera_free (c);                       \
      }                                               \
}

#define CR(c,result,ctx)                                    \
{                                                     \
      int r1 = (result);                                    \
                                                      \
      if (r1 < 0) {                                         \
                                                      \
            /* libgphoto2_port doesn't have a GPContext */        \
            if (r1 > -100)                                  \
                  gp_context_error ((ctx), _("An error occurred " \
                        "in the io-library ('%s'): %s"),    \
                        gp_port_result_as_string (r1),            \
                        (c) ? gp_port_get_error ((c)->port) :     \
                              _("No additional information "      \
                              "available."));               \
            if (c)                                          \
                  CAMERA_UNUSED((c),(ctx));                 \
            return (r1);                                    \
      }                                               \
}

/*
 * HAVE_MULTI
 * ----------
 *
 * The problem: Several different programs (gtkam, gphoto2, gimp) accessing
 *          one camera.
 * The solutions:
 *  (1) gp_port_open before each operation, gp_port_close after. This has
 *      shown to not work with some drivers (digita/dc240) for serial ports,
 *      because the camera will notice that [1],
 *      reset itself and will therefore need to be reinitialized. If you want
 *      this behaviour, #define HAVE_MULTI.
 *  (2) Leave it up to the frontend to release the camera by calling
 *      gp_camera_exit after camera operations. This is what is implemented
 *      right now. The drawback is that re-initialization takes more time than
 *      just reopening the port. However, it works for all camera drivers.
 *
 * [1] Marr <marr@shianet.org> writes:
 *
 *     With the Digita-OS cameras at least, one of the RS-232 lines is tied
 *     to a 'Reset' signal on the camera.  I quote from the Digita 'Host
 *     Interface Specification' document:
 *
 *     "The Reset signal is a pulse on the Reset/Att line (which cooresponds 
 *     [sic] to pin 2 at the camera side) sent from the host computer to the 
 *     camera.  This pulse must be at least 50us."
 */

#ifdef HAVE_MULTI
#define CHECK_OPEN(c,ctx)                                   \
{                                                     \
      int r2;                                               \
                                                      \
      if (strcmp ((c)->pc->a.model,"Directory Browse")) {         \
            r2 = gp_port_open ((c)->port);                        \
            if (r2 < 0) {                                   \
                  CAMERA_UNUSED (c,ctx);                    \
                  return (r2);                              \
            }                                         \
      }                                               \
      if ((c)->functions->pre_func) {                             \
            r2 = (c)->functions->pre_func (c,ctx);                \
            if (r2 < 0) {                                   \
                  CAMERA_UNUSED (c,ctx);                    \
                  return (r2);                              \
            }                                         \
      }                                               \
}
#else
#define CHECK_OPEN(c,ctx)                                   \
{                                                                       \
      if ((c)->functions->pre_func) {                             \
            int r2 = (c)->functions->pre_func (c,ctx);            \
            if (r2 < 0) {                                           \
                  CAMERA_UNUSED (c,ctx);                    \
                  return (r2);                                    \
            }                                                       \
      }                                                               \
}
#endif

#ifdef HAVE_MULTI
#define CHECK_CLOSE(c,ctx)                            \
{                                               \
      if (strcmp ((c)->pc->a.model,"Directory Browse"))     \
            gp_port_close ((c)->port);                \
      if ((c)->functions->post_func) {                \
            int r3 = (c)->functions->post_func (c,ctx);     \
            if (r3 < 0) {                             \
                  CAMERA_UNUSED (c,ctx);              \
                  return (r3);                        \
            }                                   \
      }                                         \
}
#else
#define CHECK_CLOSE(c,ctx)                            \
{                                               \
      if ((c)->functions->post_func) {                \
            int r3 = (c)->functions->post_func (c,ctx);     \
            if (r3 < 0) {                             \
                  CAMERA_UNUSED (c,ctx);              \
                  return (r3);                        \
            }                                   \
      }                                         \
}
#endif

#define CRS(c,res,ctx)                                      \
{                                                     \
      int r4 = (res);                                       \
                                                      \
      if (r4 < 0) {                                         \
            CAMERA_UNUSED (c,ctx);                                \
            return (r4);                                    \
      }                                               \
}

#define CRSL(c,res,ctx,list)                                \
{                                                     \
      int r5 = (res);                                       \
                                                      \
      if (r5 < 0) {                                         \
            CAMERA_UNUSED (c,ctx);                                \
            gp_list_free (list);                            \
            return (r5);                                    \
      }                                               \
}

#define CHECK_RESULT_OPEN_CLOSE(c,result,ctx)                     \
{                                                     \
      int r6;                                               \
                                                      \
      CHECK_OPEN (c,ctx);                                   \
      r6 = (result);                                        \
      if (r6 < 0) {                                         \
            CHECK_CLOSE (c,ctx);                            \
            gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Operation failed!");\
            CAMERA_UNUSED (c,ctx);                                \
            return (r6);                                    \
      }                                               \
      CHECK_CLOSE (c,ctx);                                  \
}

#define CHECK_INIT(c,ctx)                                   \
{                                                     \
      if ((c)->pc->used)                                    \
            return (GP_ERROR_CAMERA_BUSY);                        \
      (c)->pc->used++;                                \
      if (!(c)->pc->lh)                               \
            CR((c), gp_camera_init (c, ctx), ctx);                \
}

struct _CameraPrivateCore {

      /* Some information about the port */
      unsigned int speed;

      /* The abilities of this camera */
      CameraAbilities a;

      /* Library handle */
      lt_dlhandle lh;

      char error[2048];

      unsigned int ref_count;
      unsigned char used;
      unsigned char exit_requested;

      int initialized;

      /* Timeout functions */
      CameraTimeoutStartFunc timeout_start_func;
      CameraTimeoutStopFunc  timeout_stop_func;
      void                  *timeout_data;
      unsigned int          *timeout_ids;
      unsigned int           timeout_ids_len;
};


/**
 * Close connection to camera.
 *
 * @param camera a #Camera object
 * @param context a #GPContext object
 * @return a gphoto2 error code.
 *
 * Closes a connection to the camera and therefore gives other application
 * the possibility to access the camera, too.
 *
 * It is recommended that you 
 * call this function when you currently don't need the camera. The camera
 * will get reinitialized by gp_camera_init() automatically if you try to 
 * access the camera again.
 *
 */
int
00270 gp_camera_exit (Camera *camera, GPContext *context)
{
      CHECK_NULL (camera);

      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Exiting camera ('%s')...",
            camera->pc->a.model);

      /*
       * We have to postpone this operation if the camera is currently 
       * in use. gp_camera_exit will be called again if the
       * camera->pc->used will drop to zero.
       */
      if (camera->pc->used) {
            camera->pc->exit_requested = 1;
            return (GP_OK);
      }

      /* Remove every timeout that is still pending */
      while (camera->pc->timeout_ids_len)
            gp_camera_stop_timeout (camera, camera->pc->timeout_ids[0]);
      free (camera->pc->timeout_ids);
      camera->pc->timeout_ids = NULL;

      if (camera->functions->exit) {
#ifdef HAVE_MULTI
            gp_port_open (camera->port);
#endif
            camera->functions->exit (camera, context);
      }
      gp_port_close (camera->port);
      memset (camera->functions, 0, sizeof (CameraFunctions));

      if (camera->pc->lh) {
            lt_dlclose (camera->pc->lh);
            lt_dlexit ();
            camera->pc->lh = NULL;
      }

      gp_filesystem_reset (camera->fs);

      return (GP_OK);
}


/**
 * Allocates the memory for a #Camera.
 *
 * @param camera the #Camera object to initialize.
 * @return a gphoto2 error code
 *
 */
int
00322 gp_camera_new (Camera **camera)
{
      int result;

      CHECK_NULL (camera);

        *camera = malloc (sizeof (Camera));
      if (!*camera) 
            return (GP_ERROR_NO_MEMORY);
      memset (*camera, 0, sizeof (Camera));

        (*camera)->functions = malloc(sizeof(CameraFunctions));
      if (!(*camera)->functions) {
            gp_camera_free (*camera);
            return (GP_ERROR_NO_MEMORY);
      }
      memset ((*camera)->functions, 0, sizeof (CameraFunctions));

      (*camera)->pc = malloc (sizeof (CameraPrivateCore));
      if (!(*camera)->pc) {
            gp_camera_free (*camera);
            return (GP_ERROR_NO_MEMORY);
      }
      memset ((*camera)->pc, 0, sizeof (CameraPrivateCore));

        (*camera)->pc->ref_count = 1;

      /* Create the filesystem */
      result = gp_filesystem_new (&(*camera)->fs);
      if (result != GP_OK) {
            gp_camera_free (*camera);
            return (result);
      }

      /* Create the port */
      result = gp_port_new (&(*camera)->port);
      if (result < 0) {
            gp_camera_free (*camera);
            return (result);
      }

        return(GP_OK);
}


/**
 * \brief Sets the camera abilities. 
 *
 * @param camera a #Camera
 * @param abilities the #CameraAbilities to be set
 * @return a gphoto2 error code
 *
 * You need to call this function before calling #gp_camera_init the
 * first time unless you want gphoto2 to autodetect cameras and choose
 * the first detected one. By setting the \c abilities, you 
 * tell gphoto2 what model the \c camera is and what camera driver should 
 * be used for accessing the \c camera. You can get \c abilities by calling
 * #gp_abilities_list_get_abilities.
 *
 */
int
00383 gp_camera_set_abilities (Camera *camera, CameraAbilities abilities)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Setting abilities ('%s')...",
            abilities.model);

      CHECK_NULL (camera);

      /*
       * If the camera is currently initialized, terminate that connection.
       * We don't care if we are successful or not.
       */
      if (camera->pc->lh)
            gp_camera_exit (camera, NULL);

      memcpy (&camera->pc->a, &abilities, sizeof (CameraAbilities));

      return (GP_OK);
}


/**
 * Retrieve the \c abilities of the \c camera. 
 *
 * @param camera a #Camera
 * @param abilities
 * @return a gphoto2 error code
 *
 */
int
00412 gp_camera_get_abilities (Camera *camera, CameraAbilities *abilities)
{
      CHECK_NULL (camera && abilities);

      memcpy (abilities, &camera->pc->a, sizeof (CameraAbilities));

      return (GP_OK);
}


int
gp_camera_get_port_info (Camera *camera, GPPortInfo *info)
{
      CHECK_NULL (camera && info);

      CR (camera, gp_port_get_info (camera->port, info), NULL);

      return (GP_OK);
}


int
gp_camera_set_port_info (Camera *camera, GPPortInfo info)
{
      CHECK_NULL (camera);

      /*
       * If the camera is currently initialized, terminate that connection.
       * We don't care if we are successful or not.
       */
      if (camera->pc->lh)
            gp_camera_exit (camera, NULL);

      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Setting port info for "
            "port '%s' at '%s'...", info.name, info.path);
      CR (camera, gp_port_set_info (camera->port, info), NULL);

      return (GP_OK);
}


/**
 * Set the camera speed.
 *
 * @param camera a #Camera
 * @param speed the speed
 * @return a gphoto2 error code
 *
 * This function is typically used prior first initialization 
 * using #gp_camera_init for debugging purposes. Normally, a camera driver
 * will try to figure out the current speed of the camera and set the speed
 * to the optimal one automatically. Note that this function only works with 
 * serial ports. In other words, you have to set the camera's port to a 
 * serial one (using #gp_camera_set_port_path or #gp_camera_set_port_name)
 * prior calling this function.
 *
 */
int
00470 gp_camera_set_port_speed (Camera *camera, int speed)
{
      GPPortSettings settings;

      CHECK_NULL (camera);

      if (!camera->port) {
            gp_log (GP_LOG_ERROR, "camera", "You need to set "
                  "a port prior trying to set the speed");
            return (GP_ERROR_BAD_PARAMETERS);
      }

      if (camera->port->type != GP_PORT_SERIAL) {
            gp_log (GP_LOG_ERROR, "camera", "You can specify "
                  "a speed only with serial ports");
            return (GP_ERROR_BAD_PARAMETERS);
      }

      /*
       * If the camera is currently initialized, terminate that connection.
       * We don't care if we are successful or not.
       */
      if (camera->pc->lh)
            gp_camera_exit (camera, NULL);

      CR (camera, gp_port_get_settings (camera->port, &settings), NULL);
      settings.serial.speed = speed;
      CR (camera, gp_port_set_settings (camera->port, settings), NULL);
      camera->pc->speed = speed;

      return (GP_OK);
}


/** 
 * Retrieve the current speed.
 *
 * @param camera a #Camera
 * @return The current speed or a gphoto2 error code
 *
 */
int
00512 gp_camera_get_port_speed (Camera *camera)
{
      CHECK_NULL (camera);

      return (camera->pc->speed);
}


/**
 * Increment the reference count of a \c camera.
 *
 * @param camera a #Camera
 * @return a gphoto2 error code
 *
 */
int
00528 gp_camera_ref (Camera *camera)
{
      CHECK_NULL (camera);

      camera->pc->ref_count += 1;

      return (GP_OK);
}


/**
 * Decrements the reference count of a #Camera.
 *
 * @param camera a #Camera
 * @return a gphoto2 error code
 *
 * If the reference count reaches %0, the \c camera will be freed 
 * automatically.
 *
 */
int
00549 gp_camera_unref (Camera *camera)
{
      CHECK_NULL (camera);

      if (!camera->pc->ref_count) {
            gp_log (GP_LOG_ERROR, "gphoto2-camera", "gp_camera_unref on "
                  "a camera with ref_count == 0 should not happen "
                  "at all");
            return (GP_ERROR);
      }

      camera->pc->ref_count -= 1;

      if (!camera->pc->ref_count) {

            /* We cannot free a camera that is currently in use */
            if (!camera->pc->used)
                  gp_camera_free (camera);
      }

      return (GP_OK);
}


/**
 * Free the \c camera.
 *
 * @param camera a #Camera
 * @return a gphoto2 error code
 *
 * \deprecated 
 * This function should never be used. Please use #gp_camera_unref instead.
 *
 */
int
00584 gp_camera_free (Camera *camera)
{
      CHECK_NULL (camera);

      gp_log (GP_LOG_DEBUG, "gp-camera", "Freeing camera...");

      /*
       * If the camera is currently initialized, close the connection.
       * We don't care if we are successful or not.
       */
      if (camera->port && camera->pc && camera->pc->lh)
            gp_camera_exit (camera, NULL);

      /* We don't care if anything goes wrong */
      if (camera->port) {
            gp_port_free (camera->port);
            camera->port = NULL;
      }

      if (camera->pc) {
            if (camera->pc->timeout_ids)
                  free (camera->pc->timeout_ids);
            free (camera->pc);
            camera->pc = NULL;
      }

      if (camera->fs) {
            gp_filesystem_free (camera->fs);
            camera->fs = NULL;
      }

        if (camera->functions) {
                free (camera->functions);
            camera->functions = NULL;
      }
 
      free (camera);

      return (GP_OK);
}


/**
 * Initiate a connection to the \c camera. 
 *
 * @param camera a #Camera
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * Before calling this function, the
 * \c camera should be set up using #gp_camera_set_port_path or
 * #gp_camera_set_port_name and #gp_camera_set_abilities. If that has been
 * omitted, gphoto2 tries to autodetect any cameras and chooses the first one
 * if any cameras are found. It is generally a good idea to call
 * #gp_camera_exit after transactions have been completed in order to give
 * other applications the chance to access the camera, too.
 *
 */
int
00643 gp_camera_init (Camera *camera, GPContext *context)
{
      CameraAbilities a;
      const char *model, *port;
      CameraLibraryInitFunc init_func;
      int result;

      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Initializing camera...");

      CHECK_NULL (camera);
      /*
       * Reset the exit_requested flag. If this flag is set, 
       * gp_camera_exit will be called as soon as the camera is no
       * longer in use (used flag).
       */
      camera->pc->exit_requested = 0;

      /*
       * If the model hasn't been indicated, try to
       * figure it out (USB only). Beware of "Directory Browse".
       */
      if (strcasecmp (camera->pc->a.model, "Directory Browse") &&
          !strcmp ("", camera->pc->a.model)) {
            CameraAbilitiesList *al;
            GPPortInfoList *il;
            int m, p;
            GPPortInfo info;
            CameraList *list;

            result = gp_list_new (&list);
            if (result < GP_OK)
                  return result;

            gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Neither "
                  "port nor model set. Trying auto-detection...");

            /* Call auto-detect and choose the first camera */
            gp_abilities_list_new (&al);
            gp_abilities_list_load (al, context);
            gp_port_info_list_new (&il);
            gp_port_info_list_load (il);
            gp_abilities_list_detect (al, il, list, context);
            if (!gp_list_count (list)) {
                  gp_abilities_list_free (al);
                  gp_port_info_list_free (il);
                  gp_context_error (context, _("Could not detect "
                                   "any camera"));
                  gp_list_free (list);
                  return (GP_ERROR_MODEL_NOT_FOUND);
            }

            gp_list_get_name  (list, 0, &model);
            m = gp_abilities_list_lookup_model (al, model);
            gp_abilities_list_get_abilities (al, m, &a);
            gp_abilities_list_free (al);
            CRSL (camera, gp_camera_set_abilities (camera, a), context, list);
            CRSL (camera, gp_list_get_value (list, 0, &port), context, list);
            p = gp_port_info_list_lookup_path (il, port);
            gp_port_info_list_get_info (il, p, &info);
            gp_port_info_list_free (il);
            CRSL (camera, gp_camera_set_port_info (camera, info), context, list);
            gp_list_free (list);
      }

      if (strcasecmp (camera->pc->a.model, "Directory Browse")) {
            switch (camera->port->type) {
            case GP_PORT_NONE:
                  gp_context_error (context, _("You have to set the "
                        "port prior to initialization of the camera."));
                  return (GP_ERROR_UNKNOWN_PORT);
            case GP_PORT_USB:
                  if (gp_port_usb_find_device (camera->port,
                              camera->pc->a.usb_vendor,
                              camera->pc->a.usb_product) != GP_OK) {
                        CRS (camera, gp_port_usb_find_device_by_class
                              (camera->port,
                              camera->pc->a.usb_class,
                              camera->pc->a.usb_subclass,
                              camera->pc->a.usb_protocol), context);
                              }
                  break;
            default:
                  break;
            }
      }

      /* Load the library. */
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Loading '%s'...",
            camera->pc->a.library);
      lt_dlinit ();
      camera->pc->lh = lt_dlopenext (camera->pc->a.library);
      if (!camera->pc->lh) {
            gp_context_error (context, _("Could not load required "
                  "camera driver '%s' (%s)."), camera->pc->a.library,
                  lt_dlerror ());
            lt_dlexit ();
            return (GP_ERROR_LIBRARY);
      }

      /* Initialize the camera */
      init_func = lt_dlsym (camera->pc->lh, "camera_init");
      if (!init_func) {
            lt_dlclose (camera->pc->lh);
            lt_dlexit ();
            camera->pc->lh = NULL;
            gp_context_error (context, _("Camera driver '%s' is "
                  "missing the 'camera_init' function."), 
                  camera->pc->a.library);
            return (GP_ERROR_LIBRARY);
      }

      if (strcasecmp (camera->pc->a.model, "Directory Browse")) {
            result = gp_port_open (camera->port);
            if (result < 0) {
                  lt_dlclose (camera->pc->lh);
                  lt_dlexit ();
                  camera->pc->lh = NULL;
                  return (result);
            }
      }

      result = init_func (camera, context);
      if (result < 0) {
            gp_port_close (camera->port);
            lt_dlclose (camera->pc->lh);
            lt_dlexit ();
            camera->pc->lh = NULL;
            memset (camera->functions, 0, sizeof (CameraFunctions));
            return (result);
      }

      /* We don't care if that goes wrong */
#ifdef HAVE_MULTI
      gp_port_close (camera->port);
#endif

      return (GP_OK);
}


/**
 * Retrieve a configuration \c window for the \c camera.
 *
 * @param camera a #Camera
 * @param window a #CameraWidget
 * @param context a #GPContext
 * @return gphoto2 error code
 *
 * This \c window can be used for construction of a configuration dialog.
 *
 */
int
00795 gp_camera_get_config (Camera *camera, CameraWidget **window, GPContext *context)
{
      CHECK_NULL (camera);
      CHECK_INIT (camera, context);

      if (!camera->functions->get_config) {
            gp_context_error (context, _("This camera does "
                  "not offer any configuration options."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->get_config (
                              camera, window, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}


/**
 * Sets the configuration.
 *
 * @param camera a #Camera
 * @param window a #CameraWidget
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * Typically, a \c window is retrieved using #gp_camera_get_config and passed 
 * to this function in order to adjust the settings on the camera.
 *
 **/
int
00828 gp_camera_set_config (Camera *camera, CameraWidget *window, GPContext *context)
{
      CHECK_NULL (camera && window);
      CHECK_INIT (camera, context);

      if (!camera->functions->set_config) {
            gp_context_error (context, _("This camera does "
                  "not support setting configuration options."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->set_config (camera,
                                    window, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Retrieves a camera summary.
 *
 * @param camera a #Camera
 * @param summary a #CameraText
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * This summary typically contains information like manufacturer, pictures
 * taken, or generally information that is not configurable.
 *
 **/
int
00860 gp_camera_get_summary (Camera *camera, CameraText *summary, GPContext *context)
{
      CHECK_NULL (camera && summary);
      CHECK_INIT (camera, context);

      if (!camera->functions->summary) {
            gp_context_error (context, _("This camera does "
                          "not support summaries."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->summary (camera,
                                    summary, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Retrieves the \c manual for given \c camera.
 *
 * @param camera a #Camera
 * @param manual a #CameraText
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * This manual typically contains information about using the camera.
 *
 **/
int
00891 gp_camera_get_manual (Camera *camera, CameraText *manual, GPContext *context)
{
      CHECK_NULL (camera && manual);
      CHECK_INIT (camera, context);

      if (!camera->functions->manual) {
            gp_context_error (context, _("This camera "
                  "does not offer a manual."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->manual (camera,
                                    manual, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Retrieves information about the camera driver.
 *
 * @param camera a #Camera
 * @param about a #CameraText
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * Typically, this information contains name and address of the author,
 * acknowledgements, etc.
 *
 **/
int
00923 gp_camera_get_about (Camera *camera, CameraText *about, GPContext *context)
{
      CHECK_NULL (camera && about);
      CHECK_INIT (camera, context);

      if (!camera->functions->about) {
            gp_context_error (context, _("This camera does "
                  "not provide information about the driver."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->about (camera,
                                    about, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Captures an image, movie, or sound clip depending on the given \c type.
 *
 * @param camera a #Camera
 * @param type a #CameraCaptureType
 * @param path a #CameraFilePath
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * The resulting file will be stored on the camera. The location gets stored
 * in \c path. The file can then be downloaded using #gp_camera_file_get.
 *
 **/
int
00956 gp_camera_capture (Camera *camera, CameraCaptureType type,
               CameraFilePath *path, GPContext *context)
{
      CHECK_NULL (camera);
      CHECK_INIT (camera, context);

      if (!camera->functions->capture) {
            gp_context_error (context, _("This camera can not capture."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->capture (camera,
                                    type, path, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Captures a preview that won't be stored on the camera but returned in 
 * supplied file. 
 *
 * @param camera a #Camera
 * @param file a #CameraFile
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 * For example, you could use #gp_capture_preview for taking some sample
 * pictures before calling #gp_capture.
 *
 **/
int
00989 gp_camera_capture_preview (Camera *camera, CameraFile *file, GPContext *context)
{
      CHECK_NULL (camera && file);
      CHECK_INIT (camera, context);

      CR (camera, gp_file_clean (file), context);

      if (!camera->functions->capture_preview) {
            gp_context_error (context, _("This camera can "
                  "not capture previews."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->capture_preview (
                              camera, file, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}


/**
 * Wait for an event from the camera.
 *
 * @param camera a Camera
 * @param timeout amount of time to wait in 1/1000 seconds
 * @param eventtype received CameraEventType [out]
 * @param eventdata received event specific data [out]
 * @param context a GPContext
 * @return gphoto2 error code
 *
 * This function blocks and waits for an event to come from the camera.  If
 * timeout occurs before an event is received then
 * *eventtype==GP_EVENT_TIMEOUT and eventdata is left unchanged.
 * If an event is received then eventtype is set to the type of event, and
 * eventdata is set to event specific data.  See the CameraEventType enum
 * to see which eventtype's match to which types of eventdata.
 *
 */
int
01030 gp_camera_wait_for_event (Camera *camera, int timeout,
                      CameraEventType *eventtype, void **eventdata,
                    GPContext *context)
{
      CHECK_NULL (camera);
      CHECK_INIT (camera, context);

      if (!camera->functions->wait_for_event) {
            gp_context_error (context, _("This camera does "
                  "not support event handling."));
            CAMERA_UNUSED (camera, context);
                return (GP_ERROR_NOT_SUPPORTED);
      }
      CHECK_RESULT_OPEN_CLOSE (camera, camera->functions->wait_for_event (
                              camera, timeout, eventtype, eventdata,
                              context), context);
      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Lists the files in supplied \c folder.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param list a #CameraList
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01061 gp_camera_folder_list_files (Camera *camera, const char *folder, 
                       CameraList *list, GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Listing files in '%s'...",
            folder);

      CHECK_NULL (camera && folder && list);
      CHECK_INIT (camera, context);
      CR (camera, gp_list_reset (list), context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_list_files (camera->fs,
                              folder, list, context), context);

      CR (camera, gp_list_sort (list), context);
      CAMERA_UNUSED (camera, context);
        return (GP_OK);
}

/**
 * Lists the folders in supplied \c folder.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param list a #CameraList
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01090 gp_camera_folder_list_folders (Camera *camera, const char* folder, 
                         CameraList *list, GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Listing folders in '%s'...",
            folder);

      CHECK_NULL (camera && folder && list);
      CHECK_INIT (camera, context);
      CR (camera, gp_list_reset (list), context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_list_folders (
                        camera->fs, folder, list, context), context);

      CR (camera, gp_list_sort (list), context);
      CAMERA_UNUSED (camera, context);
        return (GP_OK);
}

/**
 * Deletes all files in a given \c folder.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01118 gp_camera_folder_delete_all (Camera *camera, const char *folder,
                       GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Deleting all files in "
            "'%s'...", folder);

      CHECK_NULL (camera && folder);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_delete_all (camera->fs,
                                    folder, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Uploads a file into given \c folder.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param file a #CameraFile
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01145 gp_camera_folder_put_file (Camera *camera, const char *folder,
                     CameraFile *file, GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Uploading file into '%s'...",
            folder);

      CHECK_NULL (camera && folder && file);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_put_file (camera->fs,
                              folder, file, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Retrieves information about a file.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param file the name of the file
 * @param info
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01173 gp_camera_file_get_info (Camera *camera, const char *folder, 
                   const char *file, CameraFileInfo *info,
                   GPContext *context)
{
      int result = GP_OK;
      const char *mime_type;
      const char *data;
      /* long int size; */
      CameraFile *cfile;

      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Getting file info for '%s' "
            "in '%s'...", file, folder);

      CHECK_NULL (camera && folder && file && info);
      CHECK_INIT (camera, context);

      memset (info, 0, sizeof (CameraFileInfo));

      /* Check first if the camera driver supports the filesystem */
      CHECK_OPEN (camera, context);
      result = gp_filesystem_get_info (camera->fs, folder, file, info,
                               context);
      CHECK_CLOSE (camera, context);
      if (result != GP_ERROR_NOT_SUPPORTED) {
            CAMERA_UNUSED (camera, context);
            return (result);
      }

      /*
       * The CameraFilesystem doesn't support file info. We simply get
       * the preview and the file and look for ourselves...
       */

      /* It takes too long to get the file */
      info->file.fields = GP_FILE_INFO_NONE;

      /* Get the preview */
      info->preview.fields = GP_FILE_INFO_NONE;
      CRS (camera, gp_file_new (&cfile), context);
      if (gp_camera_file_get (camera, folder, file, GP_FILE_TYPE_PREVIEW,
                                    cfile, context) == GP_OK) {
            unsigned long size;
            info->preview.fields |= GP_FILE_INFO_SIZE | GP_FILE_INFO_TYPE;
            gp_file_get_data_and_size (cfile, &data, &size);
            info->preview.size = size;
            gp_file_get_mime_type (cfile, &mime_type);
            strncpy (info->preview.type, mime_type,
                   sizeof (info->preview.type));
      }
      gp_file_unref (cfile);

      /* We don't trust the camera libraries */
      info->file.fields |= GP_FILE_INFO_NAME;
      strncpy (info->file.name, file, sizeof (info->file.name));
      info->preview.fields &= ~GP_FILE_INFO_NAME;

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Sets some file properties like name or permissions.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param file the name of a file
 * @param info the #CameraFileInfo
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01245 gp_camera_file_set_info (Camera *camera, const char *folder, 
                   const char *file, CameraFileInfo info,
                   GPContext *context)
{
      CHECK_NULL (camera && folder && file);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_set_info (camera->fs,
                              folder, file, info, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Retrieves a file from the #Camera.
 *
 * @param camera a #Camera
 * @param folder a folder
 * @param file the name of a file
 * @param type the #CameraFileType
 * @param camera_file a #CameraFile
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int 
01272 gp_camera_file_get (Camera *camera, const char *folder, const char *file,
                CameraFileType type, CameraFile *camera_file,
                GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Getting file '%s' in "
            "folder '%s'...", file, folder);

      CHECK_NULL (camera && folder && file && camera_file);
      CHECK_INIT (camera, context);

      CR (camera, gp_file_clean (camera_file), context);

      /* Did we get reasonable foldername/filename? */
      if (strlen (folder) == 0) {
            CAMERA_UNUSED (camera, context);
            return (GP_ERROR_DIRECTORY_NOT_FOUND);
      }
      if (strlen (file) == 0) {
            CAMERA_UNUSED (camera, context);
            return (GP_ERROR_FILE_NOT_FOUND);
      }
  
      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_get_file (camera->fs,
                  folder, file, type, camera_file, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Deletes the file from \c folder.
 *
 * \param camera a #Camera
 * \param folder a folder
 * \param file the name of a file
 * \param context a #GPContext
 * \return a gphoto2 error code
 *
 **/
int
01312 gp_camera_file_delete (Camera *camera, const char *folder, const char *file,
                   GPContext *context)
{
      gp_log (GP_LOG_DEBUG, "gphoto2-camera", "Deleting file '%s' in "
            "folder '%s'...", file, folder);

      CHECK_NULL (camera && folder && file);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_delete_file (
                        camera->fs, folder, file, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Creates a new directory called \c name in the given \c folder.
 *
 * @param camera a #Camera
 * @param folder the location where to create the new directory
 * @param name the name of the directory to be created
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 **/
int
01339 gp_camera_folder_make_dir (Camera *camera, const char *folder,
                     const char *name, GPContext *context)
{
      CHECK_NULL (camera && folder && name);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_make_dir (camera->fs,
                              folder, name, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Removes an (empty) directory called \c name from the given \c folder.
 *
 * @param camera a #Camera
 * @param folder the folder from which to remove the directory
 * @param name the name of the directory to be removed
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 */
int
01363 gp_camera_folder_remove_dir (Camera *camera, const char *folder,
                       const char *name, GPContext *context)
{
      CHECK_NULL (camera && folder && name);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera, gp_filesystem_remove_dir (camera->fs,
                              folder, name, context), context);

      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * Gets information on the camera attached storage.
 *
 * @param camera a #Camera
 * @param folder the folder from which to remove the directory
 * @param name the name of the directory to be removed
 * @param context a #GPContext
 * @return a gphoto2 error code
 *
 */
int
01387 gp_camera_get_storageinfo (
      Camera *camera, CameraStorageInformation **sifs,
      int *nrofsifs, GPContext *context)
{
      CHECK_NULL (camera && sifs && nrofsifs);
      CHECK_INIT (camera, context);

      CHECK_RESULT_OPEN_CLOSE (camera,
            gp_filesystem_get_storageinfo (
                  camera->fs, sifs, nrofsifs, context
            ),
            context
      );
      CAMERA_UNUSED (camera, context);
      return (GP_OK);
}

/**
 * @param camera a Camera
 * @param start_func
 * @param stop_func
 * @param data
 * @return a gphoto2 error code
 *
 * If your frontend has something like idle loops, it is recommended you
 * use #gp_camera_set_timeout_funcs in order to give the camera driver the
 * possibility to keep up the connection to the camera.
 *
 */
void
01417 gp_camera_set_timeout_funcs (Camera *camera, CameraTimeoutStartFunc start_func,
                       CameraTimeoutStopFunc stop_func,
                       void *data)
{
      if (!camera || !camera->pc)
            return;

      camera->pc->timeout_start_func = start_func;
      camera->pc->timeout_stop_func = stop_func;
      camera->pc->timeout_data = data;
}


/**
 * @param camera a #Camera
 * @param timeout number of seconds that should pass between each call to
 *         \c func
 * @param func the function that should be called each \c timeout seconds
 * @return The id of the background process or a gphoto2 error code
 *
 * This function should be called by the camera driver during camera_init()
 * if the camera needs to be sent messages periodically in order to prevent
 * it from shutting down.
 *
 */
int
01443 gp_camera_start_timeout (Camera *camera, unsigned int timeout,
                   CameraTimeoutFunc func)
{
      int id;
      unsigned int *ids;

      if (!camera || !camera->pc)
            return (GP_ERROR_BAD_PARAMETERS);

      if (!camera->pc->timeout_start_func)
            return (GP_ERROR_NOT_SUPPORTED);

      /*
       * We remember the id here in order to automatically remove
       * the timeout on gp_camera_exit.
       */
      ids = realloc (camera->pc->timeout_ids, sizeof (int) *
                              (camera->pc->timeout_ids_len + 1));
      if (!ids)
            return (GP_ERROR_NO_MEMORY);
      camera->pc->timeout_ids = ids;

      id = camera->pc->timeout_start_func (camera, timeout, func,
                                   camera->pc->timeout_data);
      if (id < 0)
            return (id);
      camera->pc->timeout_ids[camera->pc->timeout_ids_len] = id;
      camera->pc->timeout_ids_len++;

      return (id);
}


/**
 * Stop periodic calls to keepalive function.
 *
 * @param camera a #Camera
 * @param id the id of the background process previously returned by 
 *       #gp_camera_start_timeout
 *
 * Call this function in the camera driver if you want to stop a periodic
 * call to a function that has been started using #gp_camera_start_timeout.
 *
 */
void
01488 gp_camera_stop_timeout (Camera *camera, unsigned int id)
{
      unsigned int i;

      if (!camera || !camera->pc)
            return;

      if (!camera->pc->timeout_stop_func)
            return;

      /* Check if we know this id. If yes, remove it. */
      for (i = 0; i < camera->pc->timeout_ids_len; i++)
            if (camera->pc->timeout_ids[i] == id)
                  break;
      if (i == camera->pc->timeout_ids_len)
            return;
      memmove (camera->pc->timeout_ids + i, camera->pc->timeout_ids + i + 1,
             sizeof (int) * (camera->pc->timeout_ids_len - i - 1));
      camera->pc->timeout_ids_len--;
      camera->pc->timeout_ids = realloc (camera->pc->timeout_ids,
                        sizeof (int) * camera->pc->timeout_ids_len);

      camera->pc->timeout_stop_func (camera, id, camera->pc->timeout_data);
}

Generated by  Doxygen 1.6.0   Back to index