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

library.c

#include "config.h"

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

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

static int dc210_cmd_error = 0;
static const char ppmheader[] = "P6\n96 72\n255\n";

#ifdef DEBUG
static int firststatus = 1;
static char oldstatus[DC210_STATUS_SIZE];
#endif

/***************************************************************************

 Global in- and output procedures

****************************************************************************/

static void cfa2ppm 
(CameraFile * file)
{
      /* this is a very quick and dirty hack to convert cfa into ppm */
      unsigned char buf[THUMBHEIGHT][THUMBWIDTH];  
      unsigned char rgb[THUMBHEIGHT][THUMBWIDTH][3];
      unsigned char val;
      unsigned int addval;
      const char * data;
      unsigned long datasize;
      int i, x, y;

      /* get data */

      DC210_DEBUG("Converting CFA to PPM\n");

      gp_file_get_data_and_size(file, &data, &datasize);

      /* split 8 bit values into to 4 bit values and blow up again to 8 bit*/

      i = 0;
      for(y = 0; y < THUMBHEIGHT; y++ )
            for(x = 0; x < THUMBWIDTH; x+=2 ){
                  val = (unsigned char) data[i] >> 4;
                  buf[y][x] = (val << 4) | val;
                  val = (unsigned char) data[i++] & 0x0F;
                  buf[y][x+1] = (val << 4) | val;
            };

      /* fill in the exact values */
      for( y = 0; y < THUMBHEIGHT; y += 2 )
            for( x = 0; x < THUMBWIDTH; x += 2 )
            {
                  rgb[y][x][GREEN] = buf[y][x];
                  rgb[y][x+1][GREEN] = buf[y][x];
                  rgb[y+1][x][GREEN] = buf[y+1][x+1];
                  rgb[y+1][x+1][GREEN] = buf[y+1][x+1];
                  rgb[y][x][RED] = buf[y][x+1];
                  rgb[y][x+1][RED] = buf[y][x+1];
                  rgb[y+1][x][RED] = buf[y][x+1];
                  rgb[y+1][x+1][RED] = buf[y][x+1];
                  rgb[y][x][BLUE] = buf[y+1][x]; 
                  rgb[y][x+1][BLUE] = buf[y+1][x];
                  rgb[y+1][x][BLUE] = buf[y+1][x];
                  rgb[y+1][x+1][BLUE] = buf[y+1][x];
            };

      /* fill in the interpolated values, don't care about borders */
      for ( y = 1; y < THUMBHEIGHT - 2; y+= 2)
            for ( x = 0; x < THUMBWIDTH - 2; x +=2){
                  /* 2 missing green values */
                  addval = rgb[y][x][GREEN] + rgb[y][x+2][GREEN] 
                        + rgb[y-1][x+1][GREEN] + rgb[y+1][x+1][GREEN];
                  rgb[y][x+1][GREEN] = addval / 4;

                  addval = rgb[y+1][x-1][GREEN] + rgb[y+1][x+1][GREEN]
                        + rgb[y][x][GREEN] + rgb[y+2][x][GREEN];
                  rgb[y+1][x][GREEN] = addval / 4;

                  /* 3 missing red values */
                  addval = rgb[y-1][x][RED] + rgb[y+1][x][RED];
                  rgb[y][x][RED] = addval / 2;

                  addval = rgb[y-1][x][RED] + rgb[y-1][x+2][RED] 
                        + rgb[y+1][x][RED] + rgb[y+1][x+2][RED];
                  rgb[y][x+1][RED] = addval / 4;

                  addval = rgb[y+1][x][RED] + rgb[y+1][x+2][RED];
                  rgb[y+1][x+1][RED] = addval / 2;

                  /* 3 missing blue values */
                  addval = rgb[y][x-1][BLUE] + rgb[y][x+1][BLUE];
                  rgb[y][x][BLUE] = addval / 2;

                  addval = rgb[y][x-1][BLUE] + rgb[y][x+1][BLUE] 
                        + rgb[y+2][x-1][BLUE] + rgb[y+2][x+1][BLUE];
                  rgb[y+1][x][BLUE] = addval / 4;

                  addval = rgb[y][x+1][BLUE] + rgb[y+2][x+1][BLUE];
                  rgb[y+1][x+1][BLUE] = addval / 2;
            };

      gp_file_clean(file);
      gp_file_append(file, ppmheader, sizeof(ppmheader) - 1);
      gp_file_append(file, (char *) rgb, THUMBWIDTH * THUMBHEIGHT * 3);
      gp_file_set_mime_type(file, GP_MIME_PPM);

};

/* Utility procedures for command execution */

static void dc210_cmd_init
(char * cmd, unsigned char command_byte)
{
      /* utility procedure to initalize a command string */

      memset (cmd, 0, 8);

      cmd[0] = command_byte;
      cmd[7] = 0x1a;

};

static void dc210_cmd_packet_init
(char * cmd_packet, const char * filename)
{
      /* prepare command packet */
      memset (cmd_packet, 0x00, DC210_CMD_DATA_SIZE);
      memset (cmd_packet + 48, 0xFF, 8);
      strcpy(cmd_packet, "\\PCCARD\\DCIMAGES\\");
      strcpy(cmd_packet + 17, filename);

      DC210_DEBUG("Complete filename is %s\n", cmd_packet);

};

static int dc210_write_single_char 
(Camera *camera, unsigned char response) 
{
      /* utility procedure to write a single character */

      int i;

      for (i=0; i< RETRIES; i++){
            if (gp_port_write(camera->port, &response, 1) >= 0)
                  return (GP_OK);
      };

      return GP_ERROR;

};

static int dc210_read_single_char 
(Camera *camera, unsigned char * response)
{

      /* utility procedure to read a single character */

      int i;
      signed char error;

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

            error = gp_port_read(camera->port, response, 1);

            if (error < 0){
                  if (error == GP_ERROR_TIMEOUT)
                        continue;
                  else{
                        DC210_DEBUG("Real bad error reading single character. Errornumber: %d\n", error);
                        return GP_ERROR;
                  };
            };
            
            return GP_OK;

      };
      
      return GP_ERROR_TIMEOUT;

};

/* Command execution */

static int dc210_execute_command 
(Camera *camera, char *cmd)
{

      /* This procedure sends a command to the camera and
         waits for acknowledgement. Calling procedures have
         to check the returncode; if the command succeeded
         there are three possible follow ups:
         - Read a DC210_COMMAND_COMPLETE in case of
           simple commands
           - Send an additional command package in case of
           sophisticated commands
         - Read data from the camera
         But all this depends on the command and should not
         be mixed in this procedure. */

      int i,k ;
      unsigned char response;
      signed char error;
  
      dc210_cmd_error = DC210_CMD_OKAY;

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

            /* write command */
            if (gp_port_write(camera->port, cmd, 8) < 0){
                  DC210_DEBUG("Could not write to port.\n");
                  dc210_cmd_error = DC210_WRITE_ERROR;
                  continue; /* try again */
            };

            for (k = 0; k < RETRIES; k++){
                  error = gp_port_read(camera->port, &response, 1);
                  if (error != 1){
                        if (error == GP_ERROR_TIMEOUT){
                              dc210_cmd_error = DC210_TIMEOUT_ERROR;
                              continue; /* wait a little bit longer */
                        }
                        else{
                              DC210_DEBUG("Real bad error reading answer. Errornumber: %d\n", error);
                              dc210_cmd_error = DC210_READ_ERROR;
                              return error;
                        };
                  };
                  
                  switch (response){
                  case DC210_COMMAND_ACK:
                        DC210_DEBUG("Command 0x%02X acknowledged.\n", (unsigned char) cmd[0]);
                        return GP_OK; break; /* that's fine, just what we expected */
                  case DC210_COMMAND_NAK:
                        DC210_DEBUG("Sorry, but the camera seems not to understand the command 0x%02X\n", (unsigned char) cmd[0]);
                        dc210_cmd_error = DC210_NAK_ERROR;
                        break; /* anyway, send the command again */
                  default:
                        DC210_DEBUG("Strange. Unexpected response for command 0x%02X: 0x%02X\n", (unsigned char) cmd[0], response);
                        dc210_cmd_error = DC210_GARBAGE_ERROR;
                        return GP_ERROR;
                        break;
                  };
                  break;
            };
            
      };

      /* command does definitely not work */

      DC210_DEBUG("Command definitely didn't work.\n");
      
      return GP_ERROR;

};

/* appropriate actions to a command */

static int dc210_write_command_packet
(Camera * camera, char * data)
{

      unsigned char checksum;
      int i, error;
      unsigned char answer;

      /* calculating checksum */
      checksum = 0;
      for (i = 0; i < DC210_CMD_DATA_SIZE; i ++){
            checksum ^= data[i];
      };

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

            /* write the startbyte */
            dc210_write_single_char(camera, DC210_CMD_PACKET_FOLLOWING);

            /* write packet */
            gp_port_write(camera->port, data, DC210_CMD_DATA_SIZE);

            /* write checksum */
            dc210_write_single_char(camera, checksum);

            /* read answer */

            error = gp_port_read(camera->port, &answer, 1);

            if (error < 0) return GP_ERROR;

            if (answer == DC210_CORRECT_PACKET) return GP_OK;
            
            if (answer != DC210_ILLEGAL_PACKET) {
                  DC210_DEBUG("Strange answer to command packet: 0x%02X.\n", answer);
                  return GP_ERROR;
            };

      };

      DC210_DEBUG("Could not send command packet.\n");

      return GP_ERROR;

};

static int dc210_wait_for_response 
(Camera *camera, int expect_busy, GPContext *context)
{
      /* Waits for a command to finish.
         Expects either a timeout, a DC210_BUSY, 
         a DC210_COMMAND_COMPLETE or a
         DC210_PACKET_FOLLOWING; all other answers
         are considered errors */

      unsigned char response;
      int error = 0;
      int counter = 0;
      int progress_id = 0;

      if (context != NULL)
        progress_id = gp_context_progress_start (context, expect_busy, _("Waiting..."));

      while (1){

        error = dc210_read_single_char(camera, &response);
        if (error < 0){
                if (context != 0)
                    gp_context_progress_stop (context, progress_id);
              return error;
        };

        switch (response){
        case DC210_BUSY:
              /* wait a little bit longer */
              if (context != NULL && counter <= expect_busy)
                    gp_context_progress_update (context, progress_id, counter++);
              break;
        case DC210_COMMAND_COMPLETE:
        case DC210_PACKET_FOLLOWING:
              if (context != 0)
                    gp_context_progress_stop (context, progress_id);
              return response;
              break;
        default:
              if (context != 0)
                    gp_context_progress_stop (context, progress_id);
              DC210_DEBUG("Command terminated with errorcode 0x%02X.\n", response);
              return GP_ERROR;
        };
      };

};

static int dc210_read_single_block 
(Camera *camera, unsigned char * b, int blocksize) 
{

  int i, k, error;
  char cs_read, cs_computed;

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

    if (dc210_wait_for_response(camera, 0, NULL) != DC210_PACKET_FOLLOWING)
      return GP_ERROR;

    error = 1;
    for (k = 0; k < RETRIES; k++){
      if (gp_port_read(camera->port, b, blocksize) < 0){
      continue;
      };
      error = 0;
      break;
    };
  
    if (error) return GP_ERROR;

    if (dc210_read_single_char(camera, &cs_read) < 0)
      return GP_ERROR;

    cs_computed = 0;
    for (k = 0 ; k < blocksize; k++)
      cs_computed ^= b[k];
    if (cs_computed == cs_read){
      dc210_write_single_char(camera, DC210_CORRECT_PACKET);
      return GP_OK;
    };

    dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);

  };

  return GP_ERROR;

};

static int dc210_read_to_file
(Camera *camera, CameraFile * f, int blocksize, long int expectsize, GPContext *context) 
{

  int packets, k, l, fatal_error, packet_following;
  unsigned int progress_id = 0;
  unsigned char cs_read, cs_computed;
  unsigned char * b;

  int blocks = expectsize / blocksize;
  int remaining = expectsize % blocksize;

  if (NULL == (b = malloc(blocksize))) return GP_ERROR;

  if (remaining) blocks++;

  if (context != NULL)
        progress_id = gp_context_progress_start (context, blocks, _("Getting data..."));

  fatal_error = 0;
  packets = 0;

  packet_following = dc210_wait_for_response(camera, 0, NULL);
  while (DC210_PACKET_FOLLOWING == packet_following){
        fatal_error = 1;
        for (k = 0; k < RETRIES; k++){
              /* read packet */
                if (gp_port_read(camera->port, b, blocksize) < 0){
                      dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);
                    packet_following = dc210_wait_for_response(camera, 0, NULL);
                    continue;
              };
              /* read checksum */
              if (dc210_read_single_char(camera, &cs_read) == GP_ERROR){
                    free(b); 
                    return GP_ERROR;
              };
              /* test checksum */
              cs_computed = 0;
              for (l = 0 ; l < blocksize; l++)
                    cs_computed ^= b[l];
              if (cs_computed != cs_read){
                    dc210_write_single_char(camera, DC210_ILLEGAL_PACKET);
                    packet_following = dc210_wait_for_response(camera, 0, NULL);
                    continue;
              };
              /* append to file */
              if (packets == blocks - 1 && remaining)
                    gp_file_append(f, b, remaining);
              else
                    gp_file_append(f, b, blocksize);
              /* request next packet */
              dc210_write_single_char(camera, DC210_CORRECT_PACKET);
              packet_following = dc210_wait_for_response(camera, 0, NULL);
              fatal_error = 0;
              if (context != NULL)
                    gp_context_progress_update (context, progress_id, packets);
              packets++;
              break;
        };
        if (fatal_error) break;
  };

  if (packet_following < 0)
        fatal_error = 1;

  if (context != 0)
        gp_context_progress_stop (context, progress_id);

  free(b);

  if (fatal_error) return GP_ERROR;

  return GP_OK;

};

/***************************************************************************

 Working procedures

****************************************************************************/

/***** Set procedures *****/

static int dc210_set_option (Camera * camera, char command, unsigned int value, int valuesize){

      char cmd[8];
      dc210_cmd_init(cmd, command);

      switch(valuesize){
      case 0:
            break;
      case 1:
            cmd[2] = value & 0xFF;
            break;
      case 2:
            cmd[3] = value & 0xFF;
            cmd[2] = (value >> 8) & 0xFF;
            break;
      case 4:
            cmd[5] = value & 0xFF;
            cmd[4] = (value >> 8) & 0xFF;
            cmd[3] = (value >> 16) & 0xFF;
            cmd[2] = (value >> 24) & 0xFF;
            break;
      default:
            return GP_ERROR;
      };
      
      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;

      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

      return GP_OK;

};

int dc210_set_compression (Camera * camera, dc210_compression_type compression){

      return dc210_set_option(camera, DC210_SET_QUALITY, compression, 1);

};

int dc210_set_flash (Camera * camera, dc210_flash_type flash, char preflash){

      if (flash != DC210_FLASH_NONE && preflash){
            return dc210_set_option(camera, DC210_SET_FLASH, flash + 3, 1);
      }
      else
            return dc210_set_option(camera, DC210_SET_FLASH, flash, 1);

};

int dc210_set_zoom (Camera * camera, dc210_zoom_type zoom){

      return dc210_set_option(camera, DC210_SET_ZOOM, zoom, 1);
      
};

int dc210_set_file_type (Camera * camera, dc210_file_type_type file_type){

      return dc210_set_option(camera, DC210_SET_FILE_TYPE, file_type, 1);

};

int dc210_set_resolution (Camera * camera, dc210_resolution_type res){

      return dc210_set_option(camera, DC210_SET_RESOLUTION, res, 1);

};

int dc210_set_delay (Camera * camera){

      /* This function works, but I do no have the slightest idea,
         what the effect is / should be.
         There is *no* delay, when you execute this function before
         capturing. */

      return dc210_set_option(camera, DC210_SET_DELAY, 10, 4);

};

int dc210_set_exp_compensation (Camera * camera, signed int compensation){

      unsigned char param = abs(compensation);

      if (compensation < 0) param |= 0x80;

      return dc210_set_option(camera, DC210_SET_EXPOSURE, param, 1);

};

int dc210_system_time_callback (Camera * camera, CameraWidget * widget, GPContext * context){

      return dc210_set_option(camera, DC210_SET_TIME, (time(NULL) - CAMERA_SET_EPOC) << 1, 4);

};

static int dc210_format_card (Camera * camera, char * album_name, GPContext * context){

  char data[DC210_CMD_DATA_SIZE];
  char cmd[8];
  char * subst;
  unsigned char answer[16];
  unsigned char checksum_read, checksum;
  int i;

  memset (data, 0, DC210_CMD_DATA_SIZE);

  /* Make the album name acceptable - we need at least 8 characters
     which are not blank and there are no blanks allowed before the
     last character.
  */
  if (album_name != NULL && strlen(album_name) > 0){
        strncpy(data, album_name, 11);
        /* substitute blanks in the first 8 characters*/
        while (NULL != (subst = strchr(data, ' '))) *subst = '_';
        if (strlen(data) < 8) strncat(data, "________", 8 - strlen(data));
  };
  
  DC210_DEBUG("Album name is '%s'\n", data);

  dc210_cmd_init(cmd, DC210_CARD_FORMAT);

  dc210_execute_command(camera, cmd);
  dc210_write_command_packet(camera, data);
  if (dc210_wait_for_response(camera, 3, context) != DC210_PACKET_FOLLOWING) return GP_ERROR;

  gp_port_read(camera->port, answer, 16);
  gp_port_read(camera->port, &checksum_read, 1);
  checksum = 0;

  for (i = 0; i < 16; i++) checksum ^= answer[i];
  if (checksum_read != checksum) return GP_ERROR;

  DC210_DEBUG("Flash card formated.\n");

  if (dc210_write_single_char(camera, DC210_CORRECT_PACKET) == GP_ERROR) return GP_ERROR;
  if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

  gp_filesystem_reset(camera->fs);

  return GP_OK;

};

static int dc210_get_card_status (Camera * camera, dc210_card_status * card_status){

  char cmd[8];
  unsigned char answer[16];
  unsigned char checksum_read, checksum;
  int i;

  card_status->open = 0;
  card_status->program = 0;
  card_status->space = 0;

  dc210_cmd_init(cmd, DC210_CARD_STATUS);
  dc210_execute_command(camera, cmd);
  if (dc210_wait_for_response(camera, 0, NULL) != DC210_PACKET_FOLLOWING) return GP_ERROR;

  gp_port_read(camera->port, answer, 16);
  gp_port_read(camera->port, &checksum_read, 1);

  checksum = 0;
  for (i = 0; i < 16; i++) checksum ^= answer[i];

  if (checksum_read != checksum)
        DC210_DEBUG("Error reading card status.\n");
  else
        DC210_DEBUG("Card status correctly read.\n");

  if (answer[0] & 0x08) card_status->open = 1;
  DC210_DEBUG("Card status open is %d\n", card_status->open);
  card_status->program = answer[1] * 0x100 + answer[2];
  /* set the space in kb */
  card_status->space = (answer[3] * 0x1000000 + answer[4] * 0x10000 + answer[5] * 0x100 + answer[6]) / 1024;

  if (dc210_write_single_char(camera, DC210_CORRECT_PACKET) == GP_ERROR) return GP_ERROR;
  if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

  return GP_OK;

};

int dc210_format_callback(Camera * camera, CameraWidget * widget, GPContext * context){

      CameraWidget * window;
      char * album_name;

      gp_widget_get_root(widget, &window);

      gp_widget_get_child_by_label (window, _("Album name"), &widget);
      gp_widget_get_value (widget, &album_name);

      return dc210_format_card(camera, album_name, context);

};

static int dc210_check_battery (Camera *camera){

  unsigned char cmd[8];
  dc210_cmd_init(cmd, DC210_CHECK_BATTERY);
      
  if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
  if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

  return GP_OK;

};

int dc210_init_port (Camera *camera){

      /* sending a break command resets the
         speed to 9600 */
      int camera_speeds[] = {115200, 19200, 38400, 57600};
      int i, desired_speed;
      GPPortSettings settings;

      gp_port_get_settings (camera->port, &settings);
      gp_port_set_timeout (camera->port, TIMEOUT);
      settings.serial.bits     = 8;
      settings.serial.parity   = 0;
      settings.serial.stopbits = 1;

      desired_speed = settings.serial.speed;
      if (! desired_speed) desired_speed = 115200;

      DC210_DEBUG("Desired port speed is %d.\n", desired_speed);

      /* only set the speed if nothing was specified on the command line */
      if (! settings.serial.speed) settings.serial.speed = 9600;
      gp_port_set_settings (camera->port, settings);

      /* ok, run a dummy command; if the camera was off,
         this will activate it and set the speed to 9600; 
         but the command will return an error;
         It makes no sense to shorten the timout time, 
         because the camera may need up to 10 seconds (information
         of the manual) to startup */
      if (dc210_check_battery(camera) == GP_OK) return GP_OK;

      /* Fine, the last command didn't work, but we are now
         sure, the camera is working, if it is connected
         and has enough power.
         This is the time to send a break to reset the speed
         to 9600 */
      
      gp_camera_set_port_speed(camera, 9600);
      gp_port_send_break(camera->port, 300);
      GP_SYSTEM_SLEEP(300);

      /* Excellent. Now our dummy command should work */

      if (dc210_check_battery(camera) == GP_OK){
        return dc210_set_speed(camera, desired_speed);
      };

      /* My, my, this is not nice. We change the timeout
         and try other speeds as last resort */

      gp_port_set_timeout (camera->port, 100);

      for (i = 0; i < 4; i++){
            settings.serial.speed = camera_speeds[i];
            gp_port_set_settings (camera->port, settings);

            if (dc210_check_battery(camera) == GP_OK){
                  gp_port_set_timeout (camera->port, TIMEOUT);
                  return dc210_set_speed(camera, desired_speed);
            };

            DC210_DEBUG("What a pity. Speed %d does not work.\n", camera_speeds[i]);
      };

      /* reset the timeout */
      gp_port_set_timeout (camera->port, TIMEOUT);

      return GP_ERROR;

};

int dc210_set_speed (Camera *camera, int speed) {

      unsigned char cmd[8];
      GPPortSettings settings;

      dc210_cmd_init(cmd, DC210_SET_SPEED);
      
      switch (speed) {
      case 9600:
            cmd[2] = 0x96; cmd[3] = 0x00; break;
      case 19200:
            cmd[2] = 0x19; cmd[3] = 0x20; break;
      case 38400:
            cmd[2] = 0x38; cmd[3] = 0x40; break;
      case 57600:
            cmd[2] = 0x57; cmd[3] = 0x60; break;
      case 115200:
            cmd[2] = 0x11; cmd[3] = 0x52; break;
      default:
            return (GP_ERROR);
      };

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;

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

      DC210_DEBUG("Port speed set to %d.\n", speed);

      return GP_OK;
  
};

/****** Picture actions *****/

int dc210_take_picture 
(Camera * camera, GPContext * context)
{
      char cmd[8];
      dc210_cmd_init(cmd, DC210_TAKE_PICTURE);

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      switch (dc210_wait_for_response(camera, 5, context)){
        /* we allow a timeout error here and check the result via status */
        case DC210_COMMAND_COMPLETE:
        case GP_ERROR_TIMEOUT: return GP_OK; break;
        default: return GP_ERROR; break;
      };

      return GP_ERROR;

};

int dc210_delete_picture 
(Camera * camera, unsigned int picno)
{

      char cmd[8];
      unsigned int pic_offset = picno - 1;

      dc210_cmd_init(cmd, DC210_DELETE_PICTURE);
      cmd[3] = pic_offset & 0xFF;
      cmd[2] = (pic_offset >> 8) & 0xFF;

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

      return GP_OK;

};

int dc210_delete_last_picture 
(Camera * camera )
{

  dc210_status status;

  if (dc210_get_status(camera, &status) == GP_ERROR)
        return GP_ERROR;

  if (0 == status.numPicturesInCamera)
        return GP_ERROR;

  return dc210_delete_picture(camera, status.numPicturesInCamera);

};

int dc210_delete_picture_by_name 
(Camera * camera, const char * filename )
{

        char cmd[8];
      char cmd_packet[DC210_CMD_DATA_SIZE];

      dc210_cmd_init(cmd, DC210_CARD_FILE_DEL);
      dc210_cmd_packet_init(cmd_packet, filename);

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

      return GP_OK;

};

int dc210_download_last_picture 
(Camera * camera, CameraFile *file, dc210_picture_type type, GPContext *context)
{

      dc210_status status;
      dc210_picture_info picinfo;

      if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
      if (status.numPicturesInCamera == 0) return GP_ERROR;

      if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR)
            return GP_ERROR;

      if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR)
            return GP_ERROR;

      return dc210_download_picture_by_name(camera, file, picinfo.image_name, type, context);

};

int dc210_open_card
(Camera * camera)
{

      char cmd[8];
      dc210_card_status card_status;

      /* check if card is already opened */
      dc210_get_card_status(camera, &card_status);
      if (card_status.open) return GP_OK;

      dc210_cmd_init(cmd, DC210_OPEN_CARD);

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

      return GP_OK;
};

#if 0 /* This function is not used by anybody */
static int dc210_close_card
(Camera * camera)
{

      char cmd[8];
      dc210_cmd_init(cmd, DC210_CLOSE_CARD);

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

      return GP_OK;
};
#endif

int dc210_download_picture_by_name
(Camera * camera, CameraFile *file, const char *filename, dc210_picture_type type, GPContext *context)
{
  
        char cmd[8];
      char cmd_packet[DC210_CMD_DATA_SIZE];
      dc210_picture_info picinfo;

      /* prepare command */
      if (type == DC210_FULL_PICTURE){
            /* we need the file size for the progress bar */
            if (dc210_get_picture_info_by_name(camera, &picinfo, filename) == GP_ERROR)
                  return GP_ERROR;
            DC210_DEBUG("Picture size is %d\n", picinfo.picture_size);
            dc210_cmd_init(cmd, DC210_CARD_READ_FILE);
      }
      else
            dc210_cmd_init(cmd, DC210_CARD_READ_THUMB);

      if (type == DC210_RGB_THUMB) cmd[4] = 1;

      dc210_cmd_packet_init(cmd_packet, filename);

      gp_file_set_name(file, filename);

      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;

      switch (type){
      case DC210_FULL_PICTURE:
            if (picinfo.file_type == DC210_FILE_TYPE_JPEG)
                  gp_file_set_mime_type(file, GP_MIME_JPEG);
            if (dc210_read_to_file(camera, file, 
                               DC210_CARD_BLOCK_SIZE, 
                               picinfo.picture_size, context) == GP_ERROR)
                  return GP_ERROR;
            break;
      case DC210_CFA_THUMB:
            /* this thumb type is much faster to download, because it has just
               a 6th of the size of rgb data */
            if (dc210_read_to_file(camera, file, 
                               DC210_DOWNLOAD_BLOCKSIZE, 48 * 72, NULL) == GP_ERROR)
                  return GP_ERROR;
            /* convert cfa data to rgb: */
            cfa2ppm(file);
            break;
        break;
      case DC210_RGB_THUMB:
            /* if you really need nice thumbs, you can use this, but I don't think it's
               worth the 6 times longer download time */
            gp_file_set_mime_type(file, GP_MIME_PPM);
            gp_file_append(file, ppmheader, sizeof(ppmheader) - 1);
            if (dc210_read_to_file(camera, file, 
                               DC210_DOWNLOAD_BLOCKSIZE, 96 * 72 * 3, NULL) == GP_ERROR)
                  return GP_ERROR;
            break;
      };
      
      return GP_OK;
};

int dc210_capture (Camera *camera, CameraFilePath *path, GPContext *context) 
{

      dc210_status status;
      dc210_picture_info picinfo;
      int pictures_in_camera;

      /* dc210_take_picture no longer returns an error on timeout; check
         the working of the command via status */

      if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
      pictures_in_camera = status.numPicturesInCamera;

      if (dc210_take_picture(camera, context) == GP_ERROR) return GP_ERROR;
      
      if (dc210_get_status(camera, &status) == GP_ERROR) return GP_ERROR;
      if (pictures_in_camera == status.numPicturesInCamera) return GP_ERROR; 

      if (dc210_get_picture_info(camera, &picinfo, status.numPicturesInCamera) == GP_ERROR) return GP_ERROR;

      strcpy(path->folder, "/");
      strcpy(path->name, picinfo.image_name);

      return GP_OK;

};

/***** Retrieve information *****/

int dc210_get_picture_number (Camera *camera, const char * filename){

      /* This function is terrible slow if you have a lot of pictures
         in the camera; therefor it should not be used */

      dc210_status status;
      dc210_picture_info picinfo;
      int i;

      if (dc210_get_status(camera, &status) == GP_ERROR) return -1;

      for (i = 1; i <= status.numPicturesInCamera; i++){
            
            if (dc210_get_picture_info(camera, &picinfo, i) == GP_ERROR) return -1;
            
            if (strcmp(picinfo.image_name, filename) == 0){
                  return i;
            };
            
      }; 

      return -1;

};

int dc210_get_filenames (Camera *camera, CameraList *list, GPContext *context) 
{
      char cmd[8];
      CameraFile *file;
      char filename[13];
      const char * data;
      unsigned long datasize;
      int pictures, i;

      gp_file_new(&file);

      dc210_cmd_init(cmd, DC210_GET_ALBUM_FILENAMES);

      dc210_execute_command(camera, cmd);
  
      dc210_read_to_file(camera, file, DC210_DIRLIST_SIZE, 0, NULL);

      gp_file_get_data_and_size(file, &data, &datasize);

      pictures = (unsigned char) data[0] * 0x100 + (unsigned char) data[1];
      DC210_DEBUG("There are %d pictures in the camera\n", pictures);

      filename[8] = '.';
      filename[12] = '\0';
      for (i = 0; i < pictures; i++){
            strncpy(filename, data + 2 + i*20, 8);
            strncpy(filename + 9, data + 10 + i*20, 3);
            DC210_DEBUG("Adding filename %s to list\n", filename);
            gp_list_append(list, filename, NULL);
      };

      gp_file_free(file);

      return GP_OK;

};

static void dc210_picinfo_from_block (dc210_picture_info * picinfo, unsigned char * data){

      picinfo->camera_type = data[1];
      picinfo->file_type = data[2];
      picinfo->resolution = data[3];
      picinfo->compression = data[4];
      picinfo->picture_number = data[6] * 0x100 + data[7];
      picinfo->picture_size = data[8] * 0x1000000 + data[9] * 0x10000 + data[10] * 0x100 + data[11];
      picinfo->preview_size = 96 * 72 * 3 + sizeof(ppmheader);
      picinfo->picture_time = CAMERA_GET_EPOC + ((data[12] * 0x1000000 + 
                                        data[13] * 0x10000 + 
                                        data[14] * 0x100 + 
                                        data[15]) >> 1);
      picinfo->flash_used = data[16];
      picinfo->flash = data[17];
      picinfo->preflash = (data[17] > 2);
      if (picinfo->preflash) picinfo->flash -= 3;
      picinfo->zoom = data[21];
      picinfo->f_number = data[26];
      picinfo->battery = data[27];
      picinfo->exposure_time = data[28] * 0x1000000 + data[29] * 0x10000 + data[30] * 0x100 + data[31];
      strncpy(picinfo->image_name, &data[32], 12);
      picinfo->image_name[12] = 0;
      
}

int dc210_get_picture_info (Camera *camera, dc210_picture_info *picinfo, unsigned int picno) {

      char cmd[8];
      unsigned char data[DC210_PICINFO_SIZE];
      unsigned int pic_offset = picno - 1;

      dc210_cmd_init(cmd, DC210_GET_PICINFO);
      cmd[3] = pic_offset & 0xFF;
      cmd[2] = (pic_offset >> 8) & 0xFF;
          
      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_read_single_block(camera, data, DC210_PICINFO_SIZE) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
      
      dc210_picinfo_from_block(picinfo, data);
            
      return GP_OK;

};

int dc210_get_picture_info_by_name (Camera *camera, dc210_picture_info *picinfo, const char * filename) {

      char cmd[8];
      char cmd_packet[DC210_CMD_DATA_SIZE];
      unsigned char data[DC210_CARD_BLOCK_SIZE];
      
      dc210_cmd_init(cmd, DC210_CARD_GET_PICINFO);
      dc210_cmd_packet_init(cmd_packet, filename);
          
      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_write_command_packet(camera, cmd_packet) == GP_ERROR) return GP_ERROR;
      if (dc210_read_single_block(camera, data, DC210_CARD_BLOCK_SIZE) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;
      
      dc210_picinfo_from_block(picinfo, data);
            
      return GP_OK;

};

int dc210_get_status (Camera *camera, dc210_status *status) {

#ifdef DEBUG
      int i;
#endif

      char data[DC210_STATUS_SIZE];
      char cmd[8];

      /* you have to check the battery status explicitely 
         before reading the status table*/
      dc210_check_battery(camera);

      /* check the card */
      dc210_get_card_status(camera, &(status->card_status));

      dc210_cmd_init(cmd, DC210_GET_STATUS);
      
      if (dc210_execute_command(camera, cmd) == GP_ERROR) return GP_ERROR;
      if (dc210_read_single_block(camera, data, DC210_STATUS_SIZE) == GP_ERROR) return GP_ERROR;
      if (dc210_wait_for_response(camera, 0, NULL) != DC210_COMMAND_COMPLETE) return GP_ERROR;

#ifdef DEBUG
      if (firststatus){
        firststatus = 0;
      }
      else{
            for (i = 0; i < DC210_STATUS_SIZE; i++){
                  if (oldstatus[i] != data[i] && (i < 12 || i > 15)){
                        DC210_DEBUG("Statusdata differs at offset %03d (old: 0x%02X, new: 0x%02X)\n", 
                                  i, (unsigned char) oldstatus[i], (unsigned char) data[i]);
                  };
            };
      };
      memcpy(oldstatus, data, DC210_STATUS_SIZE);
#endif

      status->firmwareMajor         = data[2];
      status->firmwareMinor         = data[3];
      status->battery               = data[8];
      status->acstatus              = data[9];
      
      /* seconds since unix epoc */
      status->time = CAMERA_GET_EPOC + ((unsigned char) data[12] * 0x1000000 + 
                                (unsigned char) data[13] * 0x10000 + 
                                (unsigned char) data[14] * 0x100 + 
                                (unsigned char) data[15]) / 2;
      
      status->zoom                  = data[16];
      status->compression_type      = data[19];
      status->flash                 = data[20];
      status->exp_compensation      = data[21] & 0x7F;
      if (data[21] & 0x80) status->exp_compensation *= -1;
      status->preflash = (data[20] > 2);
      if (status->preflash) status->flash -= 3;
      status->resolution            = data[22];
      status->file_type             = data[23];
      status->totalPicturesTaken    = (unsigned char) data[25] * 0x100 + (unsigned char) data[26];
      status->totalFlashesFired     = (unsigned char) data[27] * 0x100 + (unsigned char) data[28];
      status->numPicturesInCamera   = (unsigned char) data[56] * 0x100 + (unsigned char) data[57];
      status->remainingLow          = (unsigned char) data[68] * 0x100 + (unsigned char) data[69];
      status->remainingMedium       = (unsigned char) data[70] * 0x100 + (unsigned char) data[71];
      status->remainingHigh         = (unsigned char) data[72] * 0x100 + (unsigned char) data[73];
      strncpy(status->album_name, &data[77], 11);
      status->album_name[11] = 0;

      return GP_OK;

}

/* Debugging stuff, not really needed in the driver */

#ifdef DEBUG

static int dc210_read_dummy_packet(Camera * camera){

      int i;
      signed char error;
      unsigned char answer, lastanswer, checksum;

      checksum = 0;
      lastanswer = 0;
      for ( i = 0; i < 2048; i++){
      
            error = gp_port_read(camera->port, &answer, 1);

            if (error < 0){
                  DC210_DEBUG("Packet read exhausted. Packet size: %d\n", i-1);
                  if (checksum == lastanswer)
                    DC210_DEBUG("Checksum is okay. Sending okay.\n");
                  else
                    DC210_DEBUG("Checksum is not okay. Sending correct packet anyway.\n");
                  answer = DC210_CORRECT_PACKET;
                  gp_port_write(camera->port, &answer, 1);
                  return GP_OK;
            };
            DC210_DEBUG(" Byte %03d: 0x%02X", i, answer);
            if (answer > 32)
              DC210_DEBUG(" (%c)", answer);
            DC210_DEBUG("\n");
            checksum ^= lastanswer;
            lastanswer = answer;
      };

      DC210_DEBUG("Packet too long. Sending cancel.\n");
      answer = DC210_CANCEL;
      gp_port_write(camera->port, &answer, 1);

      return GP_OK;

};

static int dc210_test_command
(Camera * camera, unsigned char cmdbyte, unsigned char *databytes){

      /* this is a debug command to test the behaviour
         of certain camera commands */
      unsigned char cmd[8];
      unsigned char answer;
      signed char error;
      int packetcount = 0;
      char dummy_cmd_packet[DC210_CMD_DATA_SIZE];

      memset (dummy_cmd_packet, 0, DC210_CMD_DATA_SIZE);

      dc210_cmd_init(cmd, cmdbyte);

      memcpy(cmd + 2, databytes, 4); 

      /* okay, write the command and wait for acknowledge */

      gp_port_write(camera->port, cmd, 8);

      error = gp_port_read(camera->port, &answer, 1);

      if (error < 0){
            DC210_DEBUG("Command 0x%02X produced port read error %d",
                   cmdbyte, error);
            return GP_OK;
      };

      switch (answer){
      case DC210_COMMAND_ACK:
            DC210_DEBUG("Okay, command 0x%02X acknowledged.\n", cmdbyte);
            break;
      case DC210_COMMAND_NAK:
            DC210_DEBUG("Sorry, command 0x%02X not acknowledged.\n", cmdbyte);
            return GP_OK;
      default:
            DC210_DEBUG("Unexpected response 0x%02X to command 0x%02X.\n", 
                   answer, cmdbyte);
            return GP_OK;
      };

 wait_finish:
      error = gp_port_read(camera->port, &answer, 1);

      if (error < 0){
            DC210_DEBUG("Command 0x%02X produced port read error %d\n",
                   cmdbyte, error);
            DC210_DEBUG("Probably the command expects a command package.\n");
            DC210_DEBUG("Sending one...\n");
            dc210_write_command_packet(camera, dummy_cmd_packet);
            goto wait_finish;
      };

      switch(answer){
      case DC210_COMMAND_COMPLETE:
            DC210_DEBUG("Okay. Command has been accepted and executed.\n");
            return GP_OK;
      case DC210_EXECUTION_ERROR:
            DC210_DEBUG("Sorry. An error occurred while executing command.\n");
            return GP_OK;
      case DC210_CORRECT_PACKET:
            DC210_DEBUG("Okay. Packet successfully received.\n");
            goto wait_finish;
      case DC210_PACKET_FOLLOWING:
            DC210_DEBUG("My, my, you got more than you bargained for. ");
            DC210_DEBUG("Awaiting packet...\n");
            dc210_read_dummy_packet(camera);
            DC210_DEBUG("Read %d packets.\n", ++packetcount);
            goto wait_finish;
      case DC210_BUSY:
            DC210_DEBUG("Camera is busy.\n");
            goto wait_finish;
      default:
            DC210_DEBUG("Unexpected response 0x%02X to command 0x%02X.\n", 
                   answer, cmdbyte);
            return GP_OK;
      };
};

int dc210_debug_callback(Camera * camera, CameraWidget * widget, GPContext * context){

      /*CameraFile *file;*/
      CameraWidget * window;
      char * s_param1, *s_param2, *s_param3;
      int param1, param2, param3;
      int value;
      unsigned char params[4];
      dc210_status status;

      memset(params, 0, 4);

      gp_widget_get_root(widget, &window);

      gp_widget_get_child_by_label (window, _("Parameter 1"), &widget);
      gp_widget_get_value (widget, &s_param1);
      param1 = atoi(s_param1);

      gp_widget_get_child_by_label (window, _("Parameter 2"), &widget);
      gp_widget_get_value (widget, &s_param2);
      param2 = atoi(s_param2);

      gp_widget_get_child_by_label (window, _("Parameter 3"), &widget);
      gp_widget_get_value (widget, &s_param3);
      param3 = atoi(s_param3);

      /* Put the stuff you want to test here */
      dc210_get_status(camera, &status);
      dc210_test_command(camera, 0x85, params);
      dc210_get_status(camera, &status);

      return GP_OK;

};

#endif

Generated by  Doxygen 1.6.0   Back to index