Logo Search packages:      
Sourcecode: libgphoto2 version File versions

library.c

/****************************************************************/
/* library.c  - Gphoto2 library for the KBGear JamCam v2 and v3 */
/*                                                              */
/* Copyright  2001 Chris Pinkham                             */
/*                                                              */
/* Author: Chris Pinkham <cpinkham@infi.net>                    */
/*                                                              */
/* This library is free software; you can redistribute it       */
/* and/or modify it under the terms of the GNU Library 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 Library General Public License for     */
/* more details.                                                */
/*                                                              */
/* You should have received a copy of the GNU Library 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 <string.h>
#include <stdlib.h>
#include <gphoto2/gphoto2.h>
#include <time.h>
#include <unistd.h>
#include <math.h>

#include "library.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 GP_MODULE

static struct jamcam_file jamcam_files[1024];
static int jamcam_count = 0;
static int jamcam_mmc_card_size = 0;

static int jamcam_read_packet (Camera *camera, char *packet, int length);
static int jamcam_write_packet (Camera *camera, char *packet, int length);
static int jamcam_fetch_memory( Camera *camera, CameraFile *file,
            char *data, int start, int length, GPContext *context);
static int jamcam_query_mmc_card (Camera *camera);

static int jamcam_set_int_at_pos( unsigned char *buf, int pos, int value ) {
      
      buf[pos + 0] = ( value       ) & 0xff;
      buf[pos + 1] = ( value >>  8 ) & 0xff;
      buf[pos + 2] = ( value >> 16 ) & 0xff;
      buf[pos + 3] = ( value >> 24 ) & 0xff;

      return( value );
}

static int jamcam_get_int_at_pos( unsigned char *buf, int pos ) {
      int ret = 0;

      ret += buf[pos + 0];
      ret += buf[pos + 1] * 256;
      ret += buf[pos + 2] * 256 * 256;
      ret += buf[pos + 3] * 256 * 256 * 256;

      return( ret );
}

static int jamcam_set_usb_mem_pointer( Camera *camera, int position ) {
      char reply[8];

      GP_DEBUG ("* jamcam_set_usb_mem_pointer");
      GP_DEBUG ("*** position:  %d (0x%x)",
            position, position);

      gp_port_usb_msg_write( camera->port,
            0xa1,
            ( position       ) & 0xffff,
            ( position >> 16 ) & 0xffff,
            NULL, 0 );

      gp_port_usb_msg_read( camera->port,
            0xa0,
            0,
            0,
            reply, 8 );

      return( GP_OK );
}


/* get the number of images on the mmc card */
static int jamcam_mmc_card_file_count (Camera *camera) {
      char buf[16];
      unsigned char reply[512];
      unsigned int position = 0x40000000;
      int data_incr;
      int width;
      int height;

      GP_DEBUG ("* jamcam_mmc_card_file_count");

      memset( buf, 0, sizeof( buf ));

      switch( camera->port->type ) {
            default:
            case GP_PORT_SERIAL:
                  strcpy( buf, "KB00" );
                  jamcam_set_int_at_pos( buf, 4, position );
                  jamcam_write_packet( camera, buf, 8 );

                  jamcam_read_packet( camera, reply, 16 );

                  while( strncmp( reply, "KB", 2 ) == 0 ) {
                        width  = (reply[5] * 256) + reply[4];
                        height = (reply[7] * 256) + reply[6];

                        data_incr = jamcam_get_int_at_pos( reply, 8 );

                        jamcam_files[jamcam_count].position = position;
                        jamcam_files[jamcam_count].width = width;
                        jamcam_files[jamcam_count].height = height;
                        jamcam_files[jamcam_count].data_incr = data_incr;

                        jamcam_count++;

                        position += data_incr;

                        jamcam_set_int_at_pos( buf, 4, position );
                        jamcam_write_packet( camera, buf, 8 );
                  
                        jamcam_read_packet( camera, reply, 16 );
                  }
                  break;

            case GP_PORT_USB:
                  gp_port_usb_msg_write( camera->port,
                        0xa5,
                        0x0005,
                        0x0000,
                        NULL, 0 );

                  jamcam_set_usb_mem_pointer( camera, position );

                  CHECK( gp_port_read (camera->port, reply, 0x10 ));

                  width  = (reply[13] * 256) + reply[12];
                  height = (reply[15] * 256) + reply[14];

                  jamcam_set_usb_mem_pointer( camera, position + 8 );

                  CHECK( gp_port_read (camera->port, reply, 512 ));

                  gp_port_usb_msg_write( camera->port,
                        0xa5,
                        0x0006,
                        0x0000,
                        NULL, 0 );

                  while(((unsigned char)reply[0] != 0xff ) &&
                        ((unsigned char)reply[0] != 0xaa ) &&
                          (((unsigned char)reply[0] != 0x00 ) ||
                           ((unsigned char)reply[1] != 0x00 ))) {
                        data_incr = jamcam_get_int_at_pos( reply, 0 );

                        jamcam_files[jamcam_count].position = position;
                        jamcam_files[jamcam_count].width = width;
                        jamcam_files[jamcam_count].height = height;
                        jamcam_files[jamcam_count].data_incr = data_incr;
                        jamcam_count++;

                        position += data_incr;

                        gp_port_usb_msg_write( camera->port,
                              0xa5,
                              0x0005,
                              0x0000,
                              NULL, 0 );

                        jamcam_set_usb_mem_pointer( camera, position );

                        CHECK( gp_port_read (camera->port, reply, 0x10 ));

                        width  = (reply[13] * 256) + reply[12];
                        height = (reply[15] * 256) + reply[14];

                        jamcam_set_usb_mem_pointer( camera, position + 8 );

                        CHECK( gp_port_read (camera->port, reply, 512 ));

                        gp_port_usb_msg_write( camera->port,
                              0xa5,
                              0x0006,
                              0x0000,
                              NULL, 0 );
                  }
                  break;
      }

      GP_DEBUG (        "*** returning with jamcam_count = %d", jamcam_count);
      return( 0 );
}

int jamcam_file_count (Camera *camera) {
      char buf[16];
      unsigned char reply[16];
      int position = 0;
      int data_incr;
      int width;
      int height;
      int last_offset_size = 0;

      GP_DEBUG ("* jamcam_file_count");

      jamcam_count = 0;

      memset( buf, 0, sizeof( buf ));

      switch( camera->port->type ) {
            default:
            case GP_PORT_SERIAL:
                  strcpy( buf, "KB00" );
                  jamcam_set_int_at_pos( buf, 4, position );
                  jamcam_write_packet( camera, buf, 8 );

                  jamcam_read_packet( camera, reply, 16 );

                  while( reply[0] == 'K' ) {
                        width  = (reply[5] * 256) + reply[4];
                        height = (reply[7] * 256) + reply[6];

                        data_incr = jamcam_get_int_at_pos( reply, 8 );

                        last_offset_size = data_incr;

                        jamcam_files[jamcam_count].position = position;
                        jamcam_files[jamcam_count].width = width;
                        jamcam_files[jamcam_count].height = height;
                        jamcam_files[jamcam_count].data_incr = data_incr;

                        jamcam_count++;

                        position += data_incr;

                        jamcam_set_int_at_pos( buf, 4, position );
                        jamcam_write_packet( camera, buf, 8 );
                  
                        jamcam_read_packet( camera, reply, 16 );
                  }

                  /* the v3 camera uses 0x3fdf0 data increments so check for MMC */
                  if ( last_offset_size == 0x03fdf0 ) {
                        jamcam_query_mmc_card( camera );
                  }
                  break;

            case GP_PORT_USB:
                  jamcam_set_usb_mem_pointer( camera, position );

                  CHECK( gp_port_read (camera->port, reply, 0x10 ));

                  width  = (reply[13] * 256) + reply[12];
                  height = (reply[15] * 256) + reply[14];

                  jamcam_set_usb_mem_pointer( camera, position + 8 );

                  CHECK( gp_port_read (camera->port, reply, 0x10 ));

                  while((unsigned char)reply[0] != 0xff ) {
                        data_incr = jamcam_get_int_at_pos( reply, 0 );

                        jamcam_files[jamcam_count].position = position;
                        jamcam_files[jamcam_count].width = width;
                        jamcam_files[jamcam_count].height = height;
                        jamcam_files[jamcam_count].data_incr = data_incr;
                        jamcam_count++;

                        position += data_incr;

                        jamcam_set_usb_mem_pointer( camera, position );

                        CHECK( gp_port_read (camera->port, reply, 0x10 ));

                        width  = (reply[13] * 256) + reply[12];
                        height = (reply[15] * 256) + reply[14];

                        jamcam_set_usb_mem_pointer( camera, position + 8 );

                        CHECK( gp_port_read (camera->port, reply, 0x10 ));
                  }
                  break;
      }

      if ( jamcam_mmc_card_size ) {
            jamcam_count += jamcam_mmc_card_file_count( camera );
      }

      GP_DEBUG (        "*** returning jamcam_count = %d", jamcam_count);
      return( jamcam_count );
}

static int jamcam_fetch_memory( Camera *camera, CameraFile *file,
            char *data, int start, int length, GPContext *context) {
      char tmp_buf[16];
      char packet[16];
      int new_start;
      int new_end;
      int bytes_read = 0;
      int bytes_to_read;
      int bytes_left = length;
      int res = GP_OK;
      unsigned int id = 0;

      GP_DEBUG ("* jamcam_fetch_memory");
      GP_DEBUG ("  * start:  %d (0x%x)",
            start, start);
      GP_DEBUG ("  * length: %d (0x%x)",
            length, length);

      if ( length > 1000 )
            id = gp_context_progress_start (context, length,
                  _("Downloading data..."));

      while( bytes_left ) {
            switch( camera->port->type ) {
                  default:
                  case GP_PORT_SERIAL:
                        bytes_to_read =
                              bytes_left > SER_PKT_SIZE ? SER_PKT_SIZE : bytes_left;

                        memset( packet, 0, sizeof( packet ));
                        strcpy( packet, "KB01" );

                        new_start = start + bytes_read;
                        new_end   = start + bytes_read + bytes_to_read - 1;

                        /* start and end (inclusive) */
                        jamcam_set_int_at_pos( packet, 4, new_start );
                        jamcam_set_int_at_pos( packet, 8, new_end );

                        jamcam_write_packet( camera, packet, 12 );

                        CHECK (jamcam_read_packet( camera, data + bytes_read,
                              bytes_to_read ));
                        break;
                  case GP_PORT_USB:
                        bytes_to_read = bytes_left > USB_PKT_SIZE ? USB_PKT_SIZE : bytes_left;

                        /* for some reason this priming read fixes an offset problem */
                        /* in the images, we are only reading the first 16 bytes of  */
                        /* data twice by doing this, so I don't know why it works    */
                        jamcam_set_usb_mem_pointer( camera, start + bytes_read );
                        CHECK( gp_port_read (camera->port, tmp_buf, 16 ));


                        jamcam_set_usb_mem_pointer( camera, start + bytes_read );
                        CHECK( gp_port_read (camera->port, data + bytes_read, bytes_to_read ));


                        break;
            }
                        
            bytes_left -= bytes_to_read;
            bytes_read += bytes_to_read;

            /* hate this hardcoded, but don't want to update here */
            /* when downloading parts of a thumbnail              */
            if ( length > 1000 ) {
                  gp_context_progress_update (context, id, bytes_read);
                  if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
                        GP_DEBUG ("  * CANCELED");
                        break;
                  }
            }
      }

      if ( length > 1000 )
            gp_context_progress_stop (context, id);

      if ( res == GP_OK ) {
            GP_DEBUG ("  * returning OK");
      }
      return( res );
}

int jamcam_request_image( Camera *camera, CameraFile *file,
            char *buf, int *len, int number, GPContext *context ) {
      int position;
      int result;
      char *tmp_buf;

      GP_DEBUG ("* jamcam_request_image");
      tmp_buf = malloc(640*480*3);

      position = jamcam_files[number].position;

      /* don't know why this is necessary, but do it anyway */
      if ( camera->port->type == GP_PORT_USB ) {
            position += 8;
      }

      if ( camera->port->type == GP_PORT_USB ) {
            gp_port_usb_msg_write( camera->port,
                  0xa5,
                  0x0005,
                  0x0000,
                  NULL, 0 );
      }
      
      result = jamcam_fetch_memory( camera, file, tmp_buf, position,
            jamcam_files[number].data_incr, context );

      /* this seems to reset the camera to a sane status */
      if ( camera->port->type == GP_PORT_USB ) {
            gp_port_usb_msg_write( camera->port,
                  0xa5,
                  0x0006,
                  0x0000,
                  NULL, 0 );
      }

      if ( result == GP_OK ) {
            *len = jamcam_files[number].width * jamcam_files[number].height;
            memcpy( buf, tmp_buf + 0x10, *len );
      }
      free (tmp_buf);

      return( result );
}

struct jamcam_file *jamcam_file_info(Camera *camera, int number)
{
      GP_DEBUG(" * jamcam_file_info, nr is %d", number);
      return( &jamcam_files[number] );
}

int jamcam_request_thumbnail( Camera *camera, CameraFile *file,
            char *buf, int *len, int number, GPContext *context ) {
      char line[2048];
      char packet[16];
      int position;
      int x, y;
      int res = GP_OK;
      char *ptr;
      int bytes_to_read;
      unsigned int id;

      GP_DEBUG ("* jamcam_request_thumbnail");

      memset( packet, 0, sizeof( packet ));

      position = jamcam_files[number].position + 0x10;

      *len = 4800;

      ptr = buf;

      if ( camera->port->type == GP_PORT_USB ) {
            /* windows driver does this sometimes */
            gp_port_usb_msg_write( camera->port,
                  0xa5,
                  0x0005,
                  0x0000,
                  NULL, 0 );

            /* just read one row of data at a time */
            bytes_to_read = jamcam_files[number].width;
      } else {
            /* MMC card is quirky, need to fetch larger amounts of data */
            if ( position >= 0x40000000 ) {
                  /* serial with mmc card needs bigger packets */
                  bytes_to_read = 2048;
            } else {
                  /* just read one row of data at a time */
                  bytes_to_read = jamcam_files[number].width;
            }
      }

      /* fetch thumbnail lines and build the thumbnail */
      position += 10 * jamcam_files[number].width;
      id = gp_context_progress_start (context, 60.,
                              _("Downloading thumbnail..."));
      for( y = 0 ; y < 60 ; y++ ) {
            jamcam_fetch_memory( camera, file, line, position, bytes_to_read, context );

            gp_context_progress_update (context, id, y);
            if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
                  res = GP_ERROR_CANCEL;
                  break;
            }

            if ( jamcam_files[number].width == 600 ) {
                  for( x = 22; x < 578 ; x += 7 ) {
                        *(ptr++) = line[x];
                  }
                  position += 7 * 600;
            } else {
                  for( x = 0; x < 320 ; ) {
                        *(ptr++) = line[x];
                        x += 3;
                        *(ptr++) = line[x];
                        x += 5;
                  }

                  if ( y % 2 ) {
                        position += 5 * 320;
                  } else {
                        position += 3 * 320;
                  }
            }
      }
      gp_context_progress_stop (context, id);

      /* this seems to reset the camera to a sane status */
      if ( camera->port->type == GP_PORT_USB ) {
            gp_port_usb_msg_write( camera->port,
                  0xa5,
                  0x0006,
                  0x0000,
                  NULL, 0 );
      }

      return( res );
}

static int jamcam_write_packet (Camera *camera, char *packet, int length) {
      int ret, r;

      GP_DEBUG ("* jamcam_write_packet");

      for (r = 0; r < RETRIES; r++) {
            ret = gp_port_write (camera->port, packet, length);
            if (ret == GP_ERROR_TIMEOUT)
                  continue;

            return (ret);
      }

      return (GP_ERROR_TIMEOUT);
}

static int jamcam_read_packet (Camera *camera, char *packet, int length) {
      int r = 0;
      int bytes_read;

      GP_DEBUG ("* jamcam_read_packet");
      GP_DEBUG ("*** length: %d (0x%x)",
            length, length);

      for (r = 0; r < RETRIES; r++) {
            bytes_read = gp_port_read (camera->port, packet, length);
            if (bytes_read == GP_ERROR_TIMEOUT)
                  continue;
            if (bytes_read < 0)
                  return (bytes_read);

            if ( bytes_read == length ) {
                  return( GP_OK );
            }
      }

      return (GP_ERROR_TIMEOUT);
}


int jamcam_enq (Camera *camera)
{
      int ret, r = 0;
      unsigned char buf[16];

      GP_DEBUG ("* jamcam_enq");

      memset( buf, 0, 16 );

      switch( camera->port->type ) {
            default:
            case GP_PORT_SERIAL:
                  for (r = 0; r < RETRIES; r++) {
                        strcpy((char *)buf, "KB99" );

                        ret = jamcam_write_packet (camera, (char *)buf, 4);
                        if (ret == GP_ERROR_TIMEOUT)
                              continue;
                        if (ret != GP_OK)
                              return (ret);

                        ret = jamcam_read_packet (camera, (char *)buf, 4);
                        if (ret == GP_ERROR_TIMEOUT)
                              continue;
                        if (ret != GP_OK)
                              return (ret);

                        if ( !strncmp( (char *)buf, "KIDB", 4 )) {
                              return (GP_OK);
                        }
                  }
                  return (GP_ERROR_CORRUPTED_DATA);
                  break;

            case GP_PORT_USB:
                  for (r = 0; r < RETRIES; r++) {
                        gp_port_usb_msg_write( camera->port,
                              0xa5,
                              0x0004,
                              0x0000,
                              NULL, 0 );
                        jamcam_set_usb_mem_pointer( camera, 0x0000 );

                        CHECK( gp_port_read( camera->port, (char *)buf, 0x0c ));

                        if (( !strncmp( (char *)buf, "KB00", 4 )) ||
                              (( buf[0] == 0xff ) && ( buf[1] == 0xff ) &&
                               ( buf[2] == 0xff ) && ( buf[3] == 0xff ) &&
                               ( buf[4] == 0xff ) && ( buf[5] == 0xff ) &&
                               ( buf[6] == 0xff ) && ( buf[7] == 0xff ))) {
                              /* found a JamCam v3 camera */
                              /* reply contains 4-bytes with MMC card size if present */
                              /* set to 0 if none */
                              jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 8 );

                              if ( jamcam_mmc_card_size ) {
                                    GP_DEBUG (                                      "* jamcam_enq, MMC card size = %d",
                                          jamcam_mmc_card_size );
                              }

                              return (GP_OK);
                        } else if ( !strncmp( (char *)buf + 8, "KB00", 4 )) {
                              /* found a JamCam v2 camera */
                              /* JamCam v2 doesn't support MMC card so no need to check */
                              return (GP_OK);
                        } else if (( buf[0] == 0xf0 ) &&
                                     ( buf[1] == 0xfd ) &&
                                     ( buf[2] == 0x03 )) {
                              return( GP_OK );
                        }
                  }
                  return (GP_ERROR_CORRUPTED_DATA);
                  break;
      }

      return (GP_ERROR_TIMEOUT);
}

static int jamcam_query_mmc_card (Camera *camera)
{
      int ret, r = 0;
      char buf[16];

      GP_DEBUG ("* jamcam_query_mmc_card");

      /* usb port doesn't need this packet, this info found in enquiry reply */
      if ( camera->port->type == GP_PORT_USB ) {
            return( GP_OK );
      }

      strcpy( buf, "KB04" );

      for (r = 0; r < RETRIES; r++) {

            ret = jamcam_write_packet (camera, buf, 4);
            if (ret == GP_ERROR_TIMEOUT)
                  continue;
            if (ret != GP_OK)
                  return (ret);

            ret = jamcam_read_packet (camera, buf, 4);
            if (ret == GP_ERROR_TIMEOUT)
                  continue;
            if (ret != GP_OK)
                  return (ret);

            /* reply is 4-byte int showing length of MMC card if any, 0 if none */
            jamcam_mmc_card_size = jamcam_get_int_at_pos( buf, 0 );

            if ( jamcam_mmc_card_size ) {
                  GP_DEBUG ("* jamcam_query_mmc_card, MMC card size = %d",
                        jamcam_mmc_card_size );
            }

            return (GP_OK);
      }
      return (GP_ERROR_TIMEOUT);
}


Generated by  Doxygen 1.6.0   Back to index