Logo Search packages:      
Sourcecode: libgphoto2 version File versions

pdc640.c

/* pdc640.c
 *
 * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net>
 * Copyright © 2002 Marcus Meissner <marcus@jet.franken.de>
 *
 * 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.
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include "config.h"

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

#include <gphoto2-library.h>
#include <gphoto2-port-log.h>
#include <bayer.h>

#include "jd350e.h"
#include "dlink350f.h"

#define GP_MODULE "pdc640"

#define PDC640_PING  "\x01"
#define PDC640_SPEED "\x69\x0b"

#define PDC640_MAXTRIES 3

#define CHECK_RESULT(result) {int r = (result); if (r < 0) return (r);}

#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


typedef enum{
      pdc640,
      jd350e,
      dlink350f
} Model;

typedef int postproc_func(int,int,unsigned char*);

struct _CameraPrivateLibrary{
      Model             model;
      BayerTile         bayer_tile;
      postproc_func*    postprocessor;
      char*             filespec;
};

static int flip_vertical (int width, int height, unsigned char *rgb);
static int flip_both     (int width, int height, unsigned char *rgb);

static struct {
      const char*                   model;
      int vendor,product;
      struct _CameraPrivateLibrary  pl;
} models[] = {
      {"Polaroid Fun Flash 640", 0, 0, {
                  pdc640,
                  BAYER_TILE_RGGB,
                  NULL, /* add postprocessor here! */
                  "pdc640%04i.ppm"
            }
      },
      {"Novatech Digital Camera CC30", 0, 0, {
                  pdc640,
                  BAYER_TILE_RGGB,
                  NULL, /* add postprocessor here! */
                  "pdc640%04i.ppm"
            }
      },
      {"Jenoptik JD350 entrance", 0x5da, 0x1006, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350e%04i.ppm"
            }
      },
      {"Jenoptik JD350 video", 0xd96, 0x0000, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350v%04i.ppm"
            }
      },
      {"ScanHex SX-35a", 0x797, 0x8901, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350v%04i.ppm"
            }
      },
      {"ScanHex SX-35b", 0x797, 0x8909, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350v%04i.ppm"
            }
      },
      {"ScanHex SX-35c", 0x797, 0x8911, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350v%04i.ppm"
            }
      },
      {"ScanHex SX-35d", 0x84d, 0x1001, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing,
                  "jd350v%04i.ppm"
            }
      },
      {"Typhoon StyloCam", 0x797, 0x801a, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &flip_vertical,
                  "stylo%04i.ppm"
            }
      },
      {"Trust PowerC@m 350FS", 0x6d6, 0x002e, {
                  jd350e,
                  BAYER_TILE_RGGB,
                  &trust350fs_postprocessing,
                  "trust%04i.ppm"
            }
      },
      {"Trust PowerC@m 350FT", 0x6d6, 0x002d, {
                  jd350e,
                  BAYER_TILE_RGGB,
                  &trust350fs_postprocessing,
                  "trust%04i.ppm"
            }
      },
      /* http://www.meade.com/sportsoptics/catalog/captureview/index.html */
      {"GrandTek ScopeCam", 0x797, 0x801c, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &jd350e_postprocessing_and_flip,
                  "scope%04i.ppm"
            }
      },
      /* http://www.sipixdigital.com/cameras/stylecam/ */
      /* Ids glanced from downloaded driver / .inf file. */
      {"SiPix Stylecam", 0xd64, 0x1001, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &flip_both,
                  "style%04i.ppm"
            }
      },
      /* http://www.umax.de/digicam/AstraPix320S.htm */
      /* reportedly has same ids as SiPix StyleCam and also
       * looks identical. */
      {"UMAX AstraPix 320s", 0xd64, 0x1001, {
                  jd350e,
                  BAYER_TILE_BGGR,
                  &flip_both,
                  "astra%04i.ppm"
            }
      },

      /* http://www.dlink.com/products/usb/dsc350/ */
      /* ids from driver download */
      {"D-Link DSC 350F", 0xd64, 0x1021, {
                  dlink350f,
                  BAYER_TILE_BGGR,
                  &dlink_dsc350f_postprocessing_and_flip_both,
                  "dlink%04i.ppm"
            }
      },
      {NULL,}
};

static int
pdc640_read_packet (GPPort *port, char *buf, int buf_size)
{
      int i;
      char checksum, c;

      /* Calculate the checksum */
      for (i = 0, checksum = 0; i < buf_size; i++)
            buf[i] = 0;

      /* Read the packet */
      CHECK_RESULT (gp_port_read (port, buf, buf_size));

      /* Calculate the checksum */
      for (i = 0, checksum = 0; i < buf_size; i++)
            checksum += buf[i];

      /* Read the checksum */
      CHECK_RESULT (gp_port_read (port, &c, 1));
      GP_DEBUG ("Checksum: %d calculated, %d received", checksum, c);
      if (checksum != c)
            return (GP_ERROR_CORRUPTED_DATA);

      return (GP_OK);
}

static int
pdc640_transmit (GPPort *port, char *cmd, int cmd_size,
                           char *buf, int buf_size)
{
      int r, tries;

      if (port->type == GP_PORT_USB) {
            unsigned char xbuf[64];
            unsigned char xcmd[4];
            int checksum;

            /* USB has always just 3 bytes + 1 byte checksum */
            memset(xcmd,0,4);memcpy(xcmd,cmd,cmd_size);
            checksum = (xcmd[0]^0x34)+(xcmd[1]^0xcb)+0x14f+(xcmd[2]^0x67);
            xcmd[3] = checksum & 0xff;

            /* Wait until we get back the echo of the command. */
            r = gp_port_usb_msg_read( port, 0x10, xcmd[0]|(xcmd[1]<<8),xcmd[2]|(xcmd[3]<<8),xbuf,sizeof(xbuf));
                  /* Sometimes we want to read here, sometimes not.
            if (r < GP_OK)
                  return r;
                   */
            if (buf && buf_size) {
                  /* bulk read things. The JD350v can read in 1 block,
                   * the Stylocam returns only 64byte blocks here.
                   */
                  int curr = 0, readsize = (buf_size + 63) & ~63;
                  while (curr < readsize) {
                        r = gp_port_read( port, buf + curr, readsize - curr);
                        if (r < GP_OK) break;
                        curr += r;
                  }
            }
            return r;
      } else {
            char c;

            /* In event of a checksum or timing failure, retry */
            for (tries = 0; tries < PDC640_MAXTRIES; tries++) {
                  /*
                   * The first byte returned is always the same as the first byte
                   * of the command.
                   */
                  CHECK_RESULT (gp_port_write (port, cmd, cmd_size));
                  r = gp_port_read (port, &c, 1);
                  if ((r < 0) || (c != cmd[0]))
                        continue;

                  if (buf) {
                        r = pdc640_read_packet (port, buf, buf_size);
                        if (r < 0)
                              continue;
                  }

                  return (GP_OK);
            }
            return (GP_ERROR_CORRUPTED_DATA);
      }
}


static int
pdc640_transmit_pic (GPPort *port, char cmd, int width, int thumbnail,
                 char *buf, int buf_size)
{
      char cmd1[] = {0x61, 0x00};
      char cmd2[] = {0x15, 0x00, 0x00, 0x00, 0x00};

      /* First send the command ... */
      cmd1[1] = cmd;
      CHECK_RESULT (pdc640_transmit (port, cmd1, 2, NULL, 0));

      if (port->type == GP_PORT_USB) {
            cmd2[1] = (buf_size + 63) >> 6;
            cmd2[2] = ((buf_size + 63) >> 6) >> 8;
            return pdc640_transmit (port, cmd2, 4, buf, buf_size);
      } else {
            int i, packet_size, result, size, ofs;
            char *data;

            /* Set how many scanlines worth of data to get at once */
            cmd2[4] = 0x06;

            /* Packet size is a multiple of the image width */
            packet_size = width * cmd2[4];

            /* Allocate memory to temporarily store received data */
            data = malloc (packet_size);
            if (!data)
                  return (GP_ERROR_NO_MEMORY);

            /* Now get the packets */
            ofs = 0;
            result = GP_OK;
            for (i = 0; i < buf_size; i += packet_size) {
                  /* Read the packet */
                  result = pdc640_transmit (port, cmd2, 5,
                                    data, packet_size);
                  if (result < 0)
                        break;

                  /* Copy from temp buffer -> actual */
                  size = packet_size;
                  if (size > buf_size - i)
                        size = buf_size - i;
                  memcpy(buf + i, data, size);

                  /* Move to next offset */
                  ofs += cmd2[4];
                  cmd2[2] = ofs & 0xFF;
                  cmd2[1] = (ofs >> 8) & 0xFF;
            }
            free (data);
            return (result);
      }
}

static int
pdc640_transmit_packet (GPPort *port, char cmd, char *buf, int buf_size) {
      char cmd1[] = {0x61, 0x00};
      /* Send the command and get the packet */
      cmd1[1] = cmd;
      CHECK_RESULT (pdc640_transmit (port, cmd1, 2, NULL, 0));

      if (port->type == GP_PORT_USB) {
            char cmd2[] = {0x15, 0x00, 0x00, 0x00};

            cmd2[1] = ((buf_size+63)/64) & 0xff;
            cmd2[2] = (((buf_size+63)/64) >> 8) & 0xff;
            return pdc640_transmit (port, cmd2, 4, buf, buf_size);
      } else {
            char cmd2[] = {0x15, 0x00, 0x00, 0x00, 0x01};

            return pdc640_transmit (port, cmd2, 5, buf, buf_size);
      }
}


static int
pdc640_ping_low (GPPort *port)
{
      char cmd[] = {0x01};

      CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0));

      return (GP_OK);
}

#if 0
static int
pdc640_push_button (GPPort *port)
{
      char cmd[] = {0xfd};

      CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0));

      return (GP_OK);
}
#endif

static int
pdc640_ping_high (GPPort *port)
{
      char cmd[] = {0x41};

      CHECK_RESULT (pdc640_transmit (port, cmd, 1, NULL, 0));

      return (GP_OK);
}

static int
pdc640_speed (GPPort *port, int speed)
{
      char cmd[] = {0x69, 0x00};

      cmd[1] = (speed / 9600) - 1;
      CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0));

      return (GP_OK);
}

#if 0
/* read version I think */
static int
pdc640_unknown5 (GPPort *port)
{
      char cmd[] = {0x05};
      char buf[3];

      CHECK_RESULT (pdc640_transmit (port, cmd, 1, buf, 3));
      if ((buf[0] != 0x33) || (buf[1] != 0x02) || (buf[2] != 0x35))
            return (GP_ERROR_CORRUPTED_DATA);

      return (GP_OK);
}
#endif

#if 0
/* get calibration param */
static int
pdc640_unknown20 (GPPort* port)
{
      char buf[128];

      CHECK_RESULT (pdc640_transmit_packet (port, 0x20, buf, 128));

      return (GP_OK);
}
#endif

static int
pdc640_caminfo (GPPort *port, int *numpic)
{
      char buf[1280];

      CHECK_RESULT (pdc640_transmit_packet (port, 0x40, buf, 1280));
      *numpic = buf[2]; /* thats the only useful info :( */
      return (GP_OK);
}

static int
pdc640_setpic (GPPort *port, char n)
{
      char cmd[2] = {0xf6, 0x00};

      cmd[1] = n;
      if (port->type == GP_PORT_USB) {
            /* USB does not like a bulkread afterwards */
            return pdc640_transmit (port, cmd, 2, NULL, 0);
      } else {
            char buf[8];

            return pdc640_transmit (port, cmd, 2, buf, 7);
      }
}

static int
pdc640_picinfo (GPPort *port, char n,
            int *size_pic,   int *width_pic,   int *height_pic,
            int *size_thumb, int *width_thumb, int *height_thumb,
            int *compression_type )
{
      unsigned char buf[64];

      CHECK_RESULT (pdc640_setpic (port, n));
      CHECK_RESULT (pdc640_transmit_packet (port, 0x80, buf, 32));

      /* Check image number matches */
      if (buf[0] != n)
            return (GP_ERROR_CORRUPTED_DATA);

      /* Picture size, width and height */
      *size_pic   = buf[2] | (buf[3] << 8) | (buf[4] << 16);
      *width_pic  = buf[5] | (buf[6] << 8);
      *height_pic = buf[7] | (buf[8] << 8);

      /* Compression Type */
      *compression_type = buf[9];

      *size_thumb   = buf[25] | (buf[26] << 8) | (buf[27] << 16);

      *width_thumb  = buf[28] | (buf[29] << 8);
      *height_thumb  = buf[30] | (buf[31] << 8);

      /* Even though it should the be the correct size, the Typhoon
       * Stylocam returns junk in there. So calculate for ourselves.
       */
      if (*size_thumb > *width_thumb  * *height_thumb)
            *size_thumb = *width_thumb  * *height_thumb;
      return (GP_OK);
}

static int
pdc640_processtn (int width, int height, char **data, int size) {
      char *newdata;
      int y;

      /* Sanity checks */
      if ((data == NULL) || (size < width * height))
            return (GP_ERROR_CORRUPTED_DATA);

      /* Allocate a new buffer */
      newdata = malloc(size);
      if (!newdata)
            return (GP_ERROR_NO_MEMORY);

      /* Flip the thumbnail */
      for (y = 0; y < height; y++) {
            memcpy(&newdata[(height - y - 1) * width],
                  &((*data)[y * width]), width);
      }

      /* Set new buffer */
      free (*data);
      *data = newdata;

      return (GP_OK);
}

static int
pdc640_getbit (char *data, int *ofs, int size, int *bit) {
      static char c;
      int b;

      /* Check if next byte required */
      if (*bit == 0) {
            if (*ofs >= size)
                  return (-1);

            c = data[*ofs];
            (*ofs)++;
      }

      /* Get current bit value */
      b = (c >> *bit) & 1;

      /* Then move onto the next bit */
      (*bit)++;
      if (*bit >= 8)
            *bit = 0;

      return (b);
}

static int
pdc640_deltadecode (int width, int height, char **rawdata, int *rawsize)
{
      char col1, col2;
      char *data;
      int rawofs, x, y, ofs, bit, ones;
      int size;
      int e, d, o, val;

      GP_DEBUG ("pdc640_deltacode ()");

      /* Create a buffer to store RGB data in */
      size = width * height;
      data = malloc (size * sizeof (char));
      if (!data)
            return (GP_ERROR_NO_MEMORY);

      /* Delta decode scanline by scanline */
      rawofs = 0;
      for (y = height-1; y >= 0; y--) {
            /* Word alignment */
            if (rawofs & 1)
                  rawofs++;

            /* Sanity check */
            if (rawofs >= *rawsize) {
                  free (data);
                  return (GP_ERROR_CORRUPTED_DATA);
            }

            /* Offset into the uncompressed data */
            ofs = y * width;

            /* Get the first two pixel values */
            col1 = (*rawdata)[rawofs];
            col2 = (*rawdata)[rawofs + 1];
            rawofs += 2;
            data[ofs + 0] = col1 << 1;
            data[ofs + 1] = col2 << 1;

            /* Work out the remaining pixels */
            bit = 0;
            for (x = 2; x < width; x++) {
                  /* Count number of ones */
                  ones = 0;
                  while (pdc640_getbit(*rawdata, &rawofs, *rawsize, &bit) == 1)
                        ones++;

                  /*
                   * Get the delta value
                   * (size dictated by number of ones)
                   */
                  val = 0;
                  for (o = 0, e = 0, d = 1; o < ones; o++, d <<= 1) {
                        e = pdc640_getbit(*rawdata, &rawofs, *rawsize, &bit);
                        if (e == 1) val += d;
                  }
                  if (e == 0) val += 1 - d; /* adjust for negatives */

                  /* Adjust the corresponding pixel value */
                  if (x & 1)
                        val = (col2 += val);
                  else
                        val = (col1 += val);

                  data[ofs + x] = val << 1;
            }
      }

      /* Set new buffer */
      free (*rawdata);
      *rawdata = data;
      *rawsize = size;

      return (GP_OK);
}

static int
pdc640_getpic (Camera *camera, int n, int thumbnail, int justraw,
            char **data, int *size)
{
      char cmd, ppmheader[100];
      int size_pic, width_pic, height_pic;
      int size_thumb, width_thumb, height_thumb;
      int height, width, outsize, result, pmmhdr_len;
      int compression_type;
      char *outdata;

      /* Get the size of the picture */
      CHECK_RESULT (pdc640_picinfo (camera->port, n,
                        &size_pic,   &width_pic,   &height_pic,
                        &size_thumb, &width_thumb, &height_thumb,
                        &compression_type));

      /* Evaluate parameters */
      if (thumbnail) {
            GP_DEBUG ("Size %d, width %d, height %d, comptype %d",
                  size_thumb, width_thumb, height_thumb,
                  (compression_type>>2) & 3);

            *size = size_thumb;
            width = width_thumb;
            height = height_thumb;
            if ((compression_type >> 2) & 3)
                  cmd = 0x02;
            else
                  cmd = 0x03;
      } else {
            GP_DEBUG ("Size %d, width %d, height %d, comptype %d",
                  size_pic, width_pic, height_pic, compression_type & 3);

            *size = size_pic;
            width = width_pic;
            height = height_pic;
            switch (compression_type & 3) {
            case 1:
            case 2:     cmd = 0x10; /* delta compressed */
                  break;
            case 0:     cmd = 0x00; /* uncompressed */
                  break;
            default:          /* unknown compression type */
                  GP_DEBUG ("Unknown compression type %d", compression_type & 3);
                  return (GP_ERROR_CORRUPTED_DATA);
            }
      }

      /* Sanity check */
      if ((*size <= 0) || (width <= 0) || (height <= 0))
            return (GP_ERROR_CORRUPTED_DATA);

      /* Allocate the memory, including 64byte align */
      *data = malloc ((*size + 64) * sizeof (char));
      if (!*data)
            return (GP_ERROR_NO_MEMORY);

      /* Get the raw picture */
      CHECK_RESULT (pdc640_setpic (camera->port, n));
      CHECK_RESULT (pdc640_transmit_pic (camera->port, cmd, width, thumbnail,
                              *data, *size));

      if (thumbnail || (compression_type == 0 )) {
            /* Process uncompressed data */
            CHECK_RESULT (pdc640_processtn (width, height,
                                    data, *size));
      } else if (compression_type & 3) {
            /* Image data is delta encoded so decode it */
            CHECK_RESULT (pdc640_deltadecode (width, height,
                                      data, size));
      }

      /* Just wanted the raw camera data */
      if (justraw)
            return(GP_OK);

      GP_DEBUG ("Bayer decode...");
      sprintf (ppmheader, "P6\n"
                      "# CREATOR: gphoto2, pdc640/jd350e library\n"
                      "%d %d\n"
                      "255\n", width, height);

      /* Allocate memory for Interpolated ppm image */
      pmmhdr_len = strlen(ppmheader);
      outsize = width * height * 3 + pmmhdr_len + 1;
      outdata = malloc(outsize);
      if (!outdata)
            return (GP_ERROR_NO_MEMORY);

      /* Set header */
      strcpy(outdata, ppmheader);

      /* Decode and interpolate the Bayer Mask */
      result = gp_bayer_decode(*data, width, height,
                        &outdata[pmmhdr_len], camera->pl->bayer_tile );
      if (result < 0) {
            free (outdata);
            return (result);
      }

      /* Call a specific postprocessor if available*/
      if( camera->pl->postprocessor ){
            result = camera->pl->postprocessor(width,height,&outdata[pmmhdr_len]);
            if (result < 0) {
                  free (outdata);
                  return (result);
            }
      }

      /* Fix up data pointers */
      free (*data);
      *data = outdata;
      *size = outsize;

      return (GP_OK);
}

static int
pdc640_delpic (GPPort *port)
{
      char cmd[2] = {0x59, 0x01};

      CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0));

      return (GP_OK);
}

static int
pdc640_takepic (GPPort *port)
{
      char cmd[2] = {0x2D, 0x00};

      CHECK_RESULT (pdc640_transmit (port, cmd, 2, NULL, 0));

      return (GP_OK);
}

int
camera_id (CameraText *id)
{
      strcpy (id->text, "pdc640/jd350e");
      return (GP_OK);
}

int
camera_abilities (CameraAbilitiesList *list)
{
      int i;
      CameraAbilities a;

      for (i = 0; models[i].model; i++) {
            memset(&a, 0, sizeof(a));
            strcpy (a.model, models[i].model);

            if (models[i].vendor) {
                  a.status = GP_DRIVER_STATUS_TESTING;
                  a.port = GP_PORT_USB | GP_PORT_SERIAL;
                  a.usb_vendor = models[i].vendor;
                  a.usb_product = models[i].product;
                  a.speed[0] = 0;
            } else {
                  a.status = GP_DRIVER_STATUS_EXPERIMENTAL;
                  a.port = GP_PORT_SERIAL;
                  a.speed[0] = 0;
            }

            a.operations        = GP_OPERATION_CAPTURE_IMAGE;
            a.file_operations   = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_PREVIEW;
            a.folder_operations = GP_FOLDER_OPERATION_NONE;

            CHECK_RESULT (gp_abilities_list_append (list, a));
      }
      return (GP_OK);
}

static int
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
             CameraFileType type, CameraFile *file, void *user_data,
             GPContext *context)
{
      Camera *camera = user_data;
      int n, size;
      char *data, *p;

      /*
       * Get the number of the picture from the filesystem and increment
       * since we need a range starting with 1.
       */
      CHECK_RESULT (n = gp_filesystem_number (camera->fs, folder, filename,
                                    context));
      n++;

      CHECK_RESULT (gp_file_set_name (file, filename));

      /* Get the picture */
      switch (type) {
      case GP_FILE_TYPE_NORMAL:
            CHECK_RESULT (pdc640_getpic (camera, n, 0, 0, &data, &size));
            CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_PPM));
            break;
      case GP_FILE_TYPE_RAW:
            CHECK_RESULT (pdc640_getpic (camera, n, 0, 1, &data, &size));
            CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_RAW));

            /* Change extension to raw */
            n = strlen(filename);
            p = malloc (n + 1);
            if (p) {
                  strcpy (p, filename);
                  p[n-3] = 'r';
                  p[n-2] = 'a';
                  p[n-1] = 'w';
                  CHECK_RESULT (gp_file_set_name (file, p));
                  free (p);
            }
            break;
      case GP_FILE_TYPE_PREVIEW:
            CHECK_RESULT (pdc640_getpic (camera, n, 1, 0, &data, &size));
            CHECK_RESULT (gp_file_set_mime_type (file, GP_MIME_PPM));
            break;
      default:
            return (GP_ERROR_NOT_SUPPORTED);
      }

      CHECK_RESULT (gp_file_set_data_and_size (file, data, size));

      return (GP_OK);
}

static int
delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
             GPContext *context)
{
      Camera *camera = data;
      char cmd[2] = {0x59, 0x00};

      CHECK_RESULT (pdc640_transmit (camera->port, cmd, 2, NULL, 0));

      return (GP_OK);
}

static int
delete_file_func (CameraFilesystem *fs, const char *folder, const char *file,
              void *data, GPContext *context)
{
      Camera *camera = data;
      int n, count;

      /* We can only delete the last picture */
      CHECK_RESULT (n = gp_filesystem_number (camera->fs, folder, file,
                                    context));
      n++;

      CHECK_RESULT (pdc640_caminfo (camera->port, &count));
      if (count != n)
            return (GP_ERROR_NOT_SUPPORTED);

      CHECK_RESULT (pdc640_delpic (camera->port));

      return (GP_OK);
}

static int
camera_about (Camera *camera, CameraText *about, GPContext *context)
{
      strcpy (about->text, _("Download program for GrandTek 98x based cameras. "
            "Originally written by Chris Byrne <adapt@ihug.co.nz>, "
            "and adapted for gphoto2 by Lutz Mueller "
            "<lutz@users.sf.net>."
            "Protocol enhancements and postprocessing "
            " for Jenoptik JD350e by Michael Trawny "
            "<trawny99@users.sourceforge.net>."
            "Bugfixes by Marcus Meissner <marcus@jet.franken.de>."));

      return (GP_OK);
}

static int
camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path,
            GPContext *context)
{
      int num, numpic;

      if (type != GP_CAPTURE_IMAGE)
            return (GP_ERROR_NOT_SUPPORTED);

      /* First get the current number of images */
      CHECK_RESULT (pdc640_caminfo (camera->port, &numpic));

      /* Take a picture */
      CHECK_RESULT (pdc640_takepic (camera->port));

      /* Wait a bit for the camera */
      sleep(4);

      /* Picture will be the last one in the camera */
      CHECK_RESULT (pdc640_caminfo (camera->port, &num));
      if (num <= numpic)
            return (GP_ERROR);

      /* Set the filename */
        sprintf (path->name, camera->pl->filespec, num);
        strcpy (path->folder, "/");

      CHECK_RESULT (gp_filesystem_append (camera->fs, "/", path->name,
                                  context));

        return (GP_OK);
}

static int
file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
            void *data, GPContext *context)
{
      int n;
      Camera *camera = data;

      /* Fill the list */
      CHECK_RESULT (pdc640_caminfo (camera->port, &n));
      CHECK_RESULT (gp_list_populate (list, camera->pl->filespec, n));

      return (GP_OK);
}

static int
get_info_func (CameraFilesystem *fs, const char *folder, const char *file,
             CameraFileInfo *info, void *data, GPContext *context)
{
      Camera *camera = data;
      int n, dummy;
      int size_pic, size_thumb;
      int width_pic, width_thumb, height_pic, height_thumb;

      CHECK_RESULT (n = gp_filesystem_number (fs, folder, file, context));
      n++;

      CHECK_RESULT (pdc640_picinfo (camera->port, n,
                        &size_pic,   &width_pic,   &height_pic,
                        &size_thumb, &width_thumb, &height_thumb,
                        &dummy ));

      info->file.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_WIDTH |
                      GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE;
      info->file.width  = width_pic;
      info->file.height = height_pic;
/*
      info->file.size   = size_pic;
*/
      info->file.size   = width_pic * height_pic * 3;
      strcpy (info->file.type, GP_MIME_PPM);

      info->preview.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_WIDTH |
                         GP_FILE_INFO_HEIGHT | GP_FILE_INFO_TYPE;
      info->preview.width  = width_thumb;
      info->preview.height = height_thumb;
      info->preview.size   = size_thumb * 3;
      strcpy (info->preview.type, GP_MIME_PPM);

      return (GP_OK);
}

static int
camera_exit (Camera *camera, GPContext *context)
{
      if (camera->pl) {
            free (camera->pl);
            camera->pl = NULL;
      }

      return (GP_OK);
}

int
camera_init (Camera *camera, GPContext *context)
{
      int result, i;
      GPPortSettings settings;
      CameraAbilities abilities;

      /*
       * First of all, tell gphoto2 about the functions we
       * implement (especially camera_exit so that everything
       * gets correctly cleaned up even in case of error).
       */
      camera->functions->about   = camera_about;
      camera->functions->capture = camera_capture;
      camera->functions->exit    = camera_exit;

      CHECK_RESULT (gp_camera_get_abilities(camera,&abilities) );
      camera->pl = 0;
      for( i=0; models[i].model; i++ ){
            if (!strcmp(models[i].model, abilities.model)) {
                  GP_DEBUG ("Model: %s", abilities.model);
                  camera->pl = malloc( sizeof(struct _CameraPrivateLibrary) );
                  if( camera->pl ){
                        *(camera->pl) = models[i].pl;
                        break;
                  }
                  else{
                        return (GP_ERROR_NO_MEMORY);
                  }
            }
      }
      if( ! camera->pl ){
            return (GP_ERROR_NOT_SUPPORTED);
      }

      /* Tell the filesystem where to get lists and info */
      CHECK_RESULT (gp_filesystem_set_list_funcs (camera->fs, file_list_func,
                                        NULL, camera));
      CHECK_RESULT (gp_filesystem_set_info_funcs (camera->fs, get_info_func,
                                        NULL, camera));
      CHECK_RESULT (gp_filesystem_set_folder_funcs (camera->fs, NULL,
                              delete_all_func, NULL, NULL, camera));
      CHECK_RESULT (gp_filesystem_set_file_funcs (camera->fs, get_file_func,
                                    delete_file_func, camera));

      if (camera->port->type == GP_PORT_SERIAL) {
            /* Open the port */
            CHECK_RESULT (gp_port_get_settings (camera->port, &settings));
            settings.serial.speed = 9600;
            CHECK_RESULT (gp_port_set_settings (camera->port, settings));

            /* Start with a low timeout (so we don't have to wait if already initialized) */
            CHECK_RESULT (gp_port_set_timeout (camera->port, 1000));

            /* Is the camera at 9600? */
            result = pdc640_ping_low (camera->port);
            if (result == GP_OK)
                  CHECK_RESULT (pdc640_speed (camera->port, 115200));

            /* Switch to 115200 */
            settings.serial.speed = 115200;
            CHECK_RESULT (gp_port_set_settings (camera->port, settings));

            /* Is the camera at 115200? */
            CHECK_RESULT (pdc640_ping_high (camera->port));

            /* Switch to a higher timeout */
            CHECK_RESULT (gp_port_set_timeout (camera->port, 5000));
      }
      return (GP_OK);
}

static int
flip_both (int width, int height, unsigned char *rgb)
{
      unsigned char *end, c;

      end = rgb + ((width * height) * 3);
      while (rgb < end) {
            c = *rgb;
            *rgb++ = *--end;
            *end = c;
      }

      return GP_OK;
}

static int
flip_vertical (int width, int height, unsigned char* rgb) {
      int         i;
      unsigned char     *buf;

      buf = malloc(width*3);
      if (!buf) return GP_ERROR_NO_MEMORY;
      for (i=0;i<height/2;i++) {
            memcpy(buf,rgb+i*width*3,width*3);
            memcpy(rgb+i*width*3,rgb+(height-i-1)*width*3,width*3);
            memcpy(rgb+(height-i-1)*width*3,buf,width*3);
      }
      free(buf);
      return GP_OK;
}

Generated by  Doxygen 1.6.0   Back to index