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

library.c

/****************************************************
 * kodak dc3200 digital camera driver library       *
 * for gphoto2                                      *
 *                                                  *
 * author: donn morrison - dmorriso@gulf.uvic.ca    *
 * date: dec 2000 - jan 2002                        *
 * license: gpl                                     *
 * version: 1.6                                     *
 *                                                  *
 ****************************************************/

#include "config.h"
#include "library.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <termios.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "dc3200.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 _(String) (String)
#  define N_(String) (String)
#endif

/*
 * FIXME: Use properly sized integer types. The dc3200 code used lots
 *        of u_char, u_long, u_int, which may be wrong on non-32bit systems.
 */

/* #define DEBUG */

/*
 * dc3200_set_speed
 *
 * handshakes a baud rate with the camera
 *
 */
int dc3200_set_speed(Camera *camera, int baudrate)
{
      int baudcode = C9600;
      unsigned char resp[INI_PACKET_LEN], msg[INI_PACKET_LEN];
      int resp_len = INI_PACKET_LEN, msg_len = INI_PACKET_LEN;

      msg[0] = 0xAF;
      msg[1] = 0x00;

      switch(baudrate) {
      case 9600:
            baudcode = C9600;
            break;
      case 19200:
            baudcode = C19200;
            break;
      case 38400:
            baudcode = C38400;
            break;
      case 57600:
            baudcode = C57600;
            break;
      case 115200:
            baudcode = C115200;
            break;
      default:
            printf("unsupported baudrate: %d.\n", baudrate);
            return GP_ERROR;
      }

      msg[2] = baudcode;

      /* send our preferred baud rate */
      if(dc3200_send_command(camera, msg, msg_len, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;
      /* the camera responds with our preferred baud rate or its
       * maximum baud rate, whichever is lowest
       */

      /* compile a confirmation packet */
      msg[0] = 0x9F;
      msg[1] = 0x00;
      if(resp_len == 2) {
            msg_len = 2;
      } else {
            /* calculate reply baud handshake */
            msg[2] = (resp[2] + 1) / 2;
            msg_len = INI_PACKET_LEN;
      }

      if(dc3200_send_command(camera, msg, msg_len, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;

      if(resp_len == 2) {
            /* set the handshaked baudrate
             * supports only 9600
             */
            return C9600;
      } else if(resp[1] == 0x01) {
            /* set the handshaked baudrate */
            return (resp[2]*2) - 1;
      } else {
            /* unknown baud */
            return GP_ERROR;
      }

      return GP_ERROR;
}

/*
 * dc3200_setup
 *
 * sends two commands essential for survival
 *
 */
int dc3200_setup(Camera *camera)
{
      /*
       * some strange commands that must be
       * completed after initialization and
       * before any camera access
       *
       * version info? ...
       *
       */

      unsigned char cmd1[5] = {0x01, 0, 0x01, 0x00, 0x0F};
      unsigned char cmd2[8] = {0x01, 0, 0x80, 0x00, 0x01, 0x81, 0x00, 0x03};

      unsigned char ack[ACK_PACKET_LEN], resp[DEF_PACKET_LEN];
      int ack_len = ACK_PACKET_LEN, resp_len = DEF_PACKET_LEN;

      cmd1[1] = dc3200_calc_seqnum(camera);
      cmd2[1] = dc3200_calc_seqnum(camera);

      if(dc3200_send_command(camera, cmd1, sizeof(cmd1), ack, &ack_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_check_ack(camera, ack, ack_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_recv_response(camera, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_send_ack(camera, resp[1]) == GP_ERROR)
            return GP_ERROR;

      if(dc3200_send_command(camera, cmd2, sizeof(cmd2), ack, &ack_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_check_ack(camera, ack, ack_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_recv_response(camera, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;
      if(dc3200_send_ack(camera, resp[1]) == GP_ERROR)
            return GP_ERROR;

      /* set the cmd sequence number */
      camera->pl->cmd_seqnum = 0;
      camera->pl->rec_seqnum = 0;

      return GP_OK;
}


/*
 * dc3200_get_data
 *
 * retrieves data from the camera as either file
 * data or file/folder list data
 *
 */

      /* command to retrieve directory listing
      unsigned char list_pkt[DEF_PACKET_LEN] = {0x01, dc3200_calc_seqnum(camera), 0x80, 0x00, 0x20, 0x03, 26 + strlen(filename),
                                          0xc1, 0x50, 0x00, 0x00, 0x00, 0x00, 19 + strlen(filename),
                                          0x04, 0x01, 0x00, 0x01, 0x00, 0x01, 0x60, 0x01, 0x00, 0x01, 0x00, 0x05,
                                          0x00, 0x00, 0x00, 2 + strlen(filename), 0x01};
      */
      /* command to get the picture
      unsigned char get_pkt[DEF_PACKET_LEN] = {0x01, calc_seqnum(), 0x80, 0x00, 0x20, 0x03, 26 + strlen(filename),
                              0xC1, 0x50, 0x00, 0x00, 0x00, 0x00, 19 + strlen(filename),
                                          0x04, 0x01, 0x00, 0x01, 0x01, 0x04, 0x60, 0x10, 0x00, 0x01, 0x00, 0x05,
                                          0x00, 0x00, 0x00, 2 + strlen(filename), 0x01};
      */

int dc3200_get_data(Camera *camera, unsigned char **data, unsigned long *data_len, int command, const char *folder, const char *filename)
{
      unsigned char ack[ACK_PACKET_LEN], resp[DEF_PACKET_LEN];
      int ack_len = ACK_PACKET_LEN, resp_len = DEF_PACKET_LEN;
      unsigned long num_left = 0;
      unsigned long total = 0;
      int data_start_pos = 0;
      unsigned char *ptr_data = NULL;
      unsigned int pid = 0;

      /* command bytes */
      unsigned char cb1=0x00,cb2=0x00,cb3=0x00;

      /* packet parts */
      unsigned char pkt_hdr[7];
      unsigned char pkt_typ[7];
      unsigned char pkt_cmd[12];
      unsigned char pkt_len[5];

      unsigned char *packet;
      int packet_len;
      char *file = NULL;
      char *ptr = NULL;

      if(folder) {
            if(filename) {
                  file = malloc(strlen(folder) + strlen(filename) + 2);
                  if(!file)
                        return GP_ERROR;

                  /* concatenate the folder + filename */
                  strncpy(file, folder, strlen(folder));
                  file[strlen(folder)] = 0;
                  /* append the filename */
                  if(folder[strlen(folder)-1] != '\\')
                  strcat(file, "\\");
                  strncat(file, filename, strlen(filename));

            } else {
                  file = malloc(strlen(folder) + 2);
                  if(!file)
                        return GP_ERROR;

                  strncpy(file, folder, strlen(folder));
                  file[strlen(folder)] = 0;
            }
      } else {
            return GP_ERROR;
      }

      /* change all /'s to \'s */
      while((ptr = strchr(file, '/'))) {
            ptr[0] = '\\';
      }

      /* there should not be a trailing '\', except for root folder */
      if(strlen(file) > 1 && file[strlen(file)-1] == '\\')
            file[strlen(file)-1] = 0;

      switch (command) {
      case CMD_GET_PREVIEW:
            cb1 = 0x02; cb2 = 0x70; cb3 = 0x11;
            break;
      case CMD_GET_FILE:
            cb1 = 0x01; cb2 = 0x60; cb3 = 0x10;
            break;
      case CMD_LIST_FILES:
            cb1 = 0x01; cb2 = 0x60; cb3 = 0x01;
            break;
      }

      camera->pl->cmd_seqnum++;

      pkt_hdr[0] = 0x01;
      pkt_hdr[1] = dc3200_calc_seqnum(camera);
      pkt_hdr[2] = 0x80; pkt_hdr[3] = 0x00; pkt_hdr[4] = 0x20; pkt_hdr[5] = 0x03;
      pkt_hdr[6] = 26 + strlen(file);

      pkt_typ[0] = 0xC1;
      pkt_typ[1] = 0x50;
      pkt_typ[2] = 0x00; pkt_typ[3] = 0x00; pkt_typ[4] = 0x00; pkt_typ[5] = 0x00;
      pkt_typ[6] = 19 + strlen(file);

      pkt_cmd[0]  = 0x04; pkt_cmd[1]  =  cb1; /* cmd */
      pkt_cmd[2]  = 0x00; pkt_cmd[3]  = 0x01;   /* ??? */
      pkt_cmd[4]  = (camera->pl->cmd_seqnum >> 8) & 0xff; pkt_cmd[5]  = camera->pl->cmd_seqnum & 0xff; /* SEQ */
      pkt_cmd[6]  =  cb2; pkt_cmd[7]  =  cb3;   /* cmd */
      pkt_cmd[8]  = 0x00; pkt_cmd[9]  = 0x01;   /* ??? */
      pkt_cmd[10] = 0x00; pkt_cmd[11] = 0x05;   /* ??? */

      pkt_len[0] = 0x00; pkt_len[1] = 0x00; pkt_len[2] = 0x00;
      pkt_len[3] = strlen(file) + 2;
      pkt_len[4] = 0x01;

      packet_len = sizeof(pkt_hdr) + sizeof(pkt_typ) + sizeof(pkt_cmd) + sizeof(pkt_len) + strlen(file) + 2;
      packet = malloc(packet_len);
      if(!packet) {
            free(file);
            return GP_ERROR;
      }

      /* clear packet */
      memset(packet, 0, packet_len);

      /* copy pkt parts into packet */
      memcpy(packet, pkt_hdr, sizeof(pkt_hdr));
      memcpy(packet + sizeof(pkt_hdr), pkt_typ, sizeof(pkt_typ));
      memcpy(packet + sizeof(pkt_hdr) + sizeof(pkt_typ), pkt_cmd, sizeof(pkt_cmd));
      memcpy(packet + sizeof(pkt_hdr) + sizeof(pkt_typ) + sizeof(pkt_cmd), pkt_len, sizeof(pkt_len));
      memcpy(packet + sizeof(pkt_hdr) + sizeof(pkt_typ) + sizeof(pkt_cmd) + sizeof(pkt_len), file, strlen(file));

      free(file);

      /* send the command to list files */
      if(dc3200_send_command(camera, packet, packet_len, ack, &ack_len) == GP_ERROR){
            free(packet);
            return GP_ERROR;
      }

      free(packet);

      do {
            resp_len = DEF_PACKET_LEN;
            if(dc3200_recv_response(camera, resp, &resp_len) == GP_ERROR) {
                  return GP_ERROR;
            }

            if(dc3200_send_ack(camera, resp[1]) == GP_ERROR) {
                  return GP_ERROR;
            }

            if(resp[1] == camera->pl->rec_seqnum)
                  continue;

            camera->pl->rec_seqnum = resp[1];

            /*
             * we decide what action to take based on
             * the number of packets we are expecting
             *
             * resp[7] holds this info
             *
             */
            switch(resp[7]) {
            case 0xC1:
                  /*
                   * SINGLE PACKET
                   */

                  /* get the total list length from the data header */
                  *data_len = bytes_to_l(resp[26], resp[27], resp[28], resp[29]);
                  num_left = 0;
                  data_start_pos = 31;
                  *data_len -= 1;

                  /* allocate a buffer to store all this data */
                  *data = malloc(*data_len);
                  if(*data == NULL) {
                        return GP_ERROR;
                  }

                  ptr_data = *data;

                  /* copy this portion of the data */
                  memcpy(ptr_data, resp + data_start_pos, resp_len - data_start_pos);
                  /* incr the buff ptr */
                  ptr_data += resp_len - data_start_pos;
                  break;

            case 0x41:
                  /*
                   * MULTIPACKET, START
                   */

                  /* get the total list length from the data header */
                  *data_len = bytes_to_l(resp[34], resp[35], resp[36], resp[37]);
                  num_left = bytes_to_l(resp[12], resp[13], resp[14], resp[15]);
                  total = num_left;
                  data_start_pos = 39;
                  *data_len -= 1;

                  /* allocate a buffer to store all this data */
                  *data = malloc(*data_len);
                  if(*data == NULL) {
                        return GP_ERROR;
                  }

                  ptr_data = *data;

                  /* copy this portion of the data */
                  memcpy(ptr_data, resp + data_start_pos, resp_len - data_start_pos);
                  /* incr the data ptr */
                  ptr_data += resp_len - data_start_pos;

                  /* update gphoto2 frontend */
                  if(command == CMD_GET_FILE || command == CMD_GET_PREVIEW)
                  {
                        pid = gp_context_progress_start(camera->pl->context,(int)*data_len,"%s", filename);
                        gp_context_progress_update(camera->pl->context, pid, ptr_data - *data);
                        if(gp_context_cancel(camera->pl->context) == GP_CONTEXT_FEEDBACK_CANCEL) {
                              free(*data);
                              dc3200_cancel_get_data(camera);
                              return GP_ERROR_CANCEL;
                        }
                  }
                  break;
            case 0x01:
                  /*
                   * MULTIPACKET, MIDDLE
                   */
                  /* calculate the number of packets remaining */
                  num_left = bytes_to_l(resp[12], resp[13], resp[14], resp[15]);
                  data_start_pos = 16;

                  if(*data == NULL) {
                        return GP_ERROR;
                  }

                  /* copy this portion of the data */
                  memcpy(ptr_data, resp + data_start_pos, resp_len - data_start_pos);
                  /* incr the buff ptr */
                  ptr_data += resp_len - data_start_pos;

                  /* update gphoto2 frontend */
                  if(command == CMD_GET_FILE || command == CMD_GET_PREVIEW)
                  {
                        gp_context_progress_update(camera->pl->context, pid, ptr_data - *data);
                        if(gp_context_cancel(camera->pl->context) == GP_CONTEXT_FEEDBACK_CANCEL) {
                              free(*data);
                              dc3200_cancel_get_data(camera);
                              return GP_ERROR_CANCEL;
                        }
                  }
                  break;
            case 0x81:
                  /*
                   * MULTIPACKET, END
                   */
                  /* calculate the number of packets remaining */
                  num_left = bytes_to_l(resp[12], resp[13], resp[14], resp[15]);
                  data_start_pos = 16;

                  if(*data == NULL) {
                        return GP_ERROR;
                  }

                  /* copy this portion of the data */
                  memcpy(ptr_data, resp + data_start_pos, resp_len - data_start_pos);
                  /* incr the buff ptr */
                  ptr_data += resp_len - data_start_pos;

                  /* update gphoto2 frontend */
                  if(command == CMD_GET_FILE || command == CMD_GET_PREVIEW)
                  {
                        gp_context_progress_update(camera->pl->context, pid, ptr_data - *data);
                        if(gp_context_cancel(camera->pl->context) == GP_CONTEXT_FEEDBACK_CANCEL) {
                              free(*data);
                              dc3200_cancel_get_data(camera);
                              return GP_ERROR_CANCEL;
                        }
                  }
                  break;
            default:
                  return GP_ERROR;
            }
      } while(num_left > 1);

      if(pid != 0 && (command == CMD_GET_FILE || command == CMD_GET_PREVIEW))
            gp_context_progress_stop(camera->pl->context, pid);

      return GP_OK;
}

/*
 * dc3200_cancel_get_data
 *
 * stops a get data command
 *
 */
int dc3200_cancel_get_data(Camera *camera)
{
      unsigned char pkt[20] = {0x01, 0, 0x80, 0x00, 0x20, 0x03, 0x0d, 0xc1, 0x50, 0xc0,
            0x00, 0x00, 0x00, 0x06, 0x04, 0x01, 0x00, 0x01, 0, 0};
      unsigned char ack[ACK_PACKET_LEN], resp[DEF_PACKET_LEN];
      int ack_len = ACK_PACKET_LEN, resp_len = DEF_PACKET_LEN;
      struct timeval timeout;
      timeout.tv_sec = 0;
      timeout.tv_usec = 1000;

      pkt[1] = dc3200_calc_seqnum(camera);
      pkt[18] = (camera->pl->cmd_seqnum >> 8) & 0xff;
      pkt[19] = camera->pl->cmd_seqnum & 0xff;

      /* wait a bit ... */
      select(0, 0, 0, 0, &timeout);

      /* clear the buffer */
      dc3200_clear_read_buffer(camera);

      if(dc3200_send_command(camera, (unsigned char *)pkt, 20, ack, &ack_len) == GP_ERROR)
            return GP_ERROR;

      if(dc3200_recv_response(camera, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;
      else
            dc3200_send_ack(camera, resp[1]);

      resp_len = DEF_PACKET_LEN;
      if(dc3200_recv_response(camera, resp, &resp_len) == GP_ERROR)
            return GP_ERROR;
      else
            dc3200_send_ack(camera, resp[1]);

      return GP_OK;
}

/*
 * dc3200_send_command
 *
 * if cmd == NULL || cmd_len == 0, send_command waits for a response
 * otherwise, it sends a command and waits for an acknowledgement
 *
 */
int dc3200_send_command(Camera *camera, unsigned char *cmd, int cmd_len, unsigned char *ack, int *ack_len)
{
      int sends, reads;
      int buff_len = *ack_len;
      int received = 0;
      unsigned char *buff = NULL;

      buff = malloc(sizeof(unsigned char) * *ack_len);
      if(buff == NULL) {
            return GP_ERROR;
      }

      sends = SEND_RETRIES;

      while(sends > 0) {
            reads = READ_RETRIES;
            /* check that we are acutally sending a command
             * and not just waiting for data
             */
            if(cmd != NULL && cmd_len > 0) {
                  /* clear the read buffer */
                  dc3200_clear_read_buffer(camera);

                  /* send the command */
                  dc3200_send_packet(camera, cmd, cmd_len);
            }

            /* wait for response */
            while(reads > 0) {
                  if(dc3200_recv_packet(camera, buff, &buff_len) != GP_ERROR) {
                        received = 1;
                        break;
                  }
                  reads--;
            }

            if(received) {
                  if(buff_len > *ack_len) {
                        /* buffer size too small */
                        free(buff);
                        return GP_ERROR;
                  }

                  /* sukksess */
                  *ack_len = buff_len;
                  memcpy(ack, buff, buff_len);
                  free(buff);
                  return GP_OK;
            } else {
                  sends--;
            }
      }

      /* send failed */
      free(buff);
      return GP_ERROR;
}

/*
 * dc3200_recv_response
 *
 * receives a response from a previous command
 *
 */
int dc3200_recv_response(Camera *camera, unsigned char *resp, int *resp_len)
{
      return dc3200_send_command(camera, NULL, 0, resp, resp_len);
}

/*
 * dc3200_send_ack
 *
 * sends an ack packet
 *
 */
int dc3200_send_ack(Camera *camera, int seqnum)
{
      unsigned char ack[ACK_PACKET_LEN];
      ack[0] = 0x01;
      ack[1] = seqnum + 16;

      return dc3200_send_packet(camera, ack, sizeof(ack));
}

/*
 * dc3200_check_ack
 *
 * checks an ack packet (well ok not really)
 *
 */
int dc3200_check_ack(Camera *camera, unsigned char *ack, int ack_len)
{
      return GP_OK;
}

/*
 * dc3200_send_packet
 *
 * compiles a packet from data and sends it
 *
 */
int dc3200_send_packet(Camera *camera, unsigned char *data, int data_len)
{
      int res;

      int buff_len = data_len;
      unsigned char *buff = NULL;

      buff = malloc(sizeof(unsigned char) * buff_len);
      if(!buff)
            return GP_ERROR;

      memcpy(buff, data, buff_len);

      /* compile this into a packet */
      res = dc3200_compile_packet(camera, &buff, &buff_len);
      if(res == GP_ERROR)
            return res;

#ifdef DEBUG
      dump_buffer(buff, buff_len, "s", 16);
#endif
      res = gp_port_write(camera->port, buff, data_len + 3);
      free(buff);
      return res;
}

/*
 * dc3200_recv_packet
 *
 * waits for a packet to arrive, checks it, and returns it
 *
 */
int dc3200_recv_packet(Camera *camera, unsigned char *data, int *data_len)
{
      int complete = 0;
      int num_read = 0, res = 0, fails = 0;

      /* allocate storage for size, checksum, and EOP */
      unsigned char *buff = NULL;

      buff = malloc(sizeof(unsigned char) * (*data_len + 3));
      if(buff == NULL) {
            return GP_ERROR;
      }

      memset(buff, 0, *data_len + 3);

      /*
       * - read data until we get an 0xFF
       * - process packet
       *
       */

      res = gp_port_read(camera->port, &buff[num_read], 1);

      while(res >= 0 && fails < READ_RETRIES) {
            if(res == 0) {
                  /* read nothing */
                  fails++;
            } else {
                  /* reset # of fails */
                  fails = 0;
                  num_read++;
                  if(buff[num_read-1] == 0xFF) {
                        complete = 1;
                        break;
                  }
                  if(num_read == *data_len + 3) {
                        /* we've reached the buffer limit */
                        complete = 0;
                        break;
                  }
            }
            res = gp_port_read(camera->port, &buff[num_read], 1);
      }

      if(!complete) {
            /* packet incomplete */
            return GP_ERROR;
      }

#ifdef DEBUG
      dump_buffer(buff, num_read, "r", 16);
#endif

      if(dc3200_process_packet(camera, buff, &num_read) == GP_ERROR) {
            return GP_ERROR;
      }

      /* save the last successful packet received time */
      time(&(camera->pl->last));

      memcpy(data, buff, *data_len);

      /* return with new packet size */
      *data_len = num_read;

      free(buff);
      return GP_OK;
}

/*
 * dc3200_compile_packet
 *
 * changes 0xFF -> 0xFE 0x01
 *         0xFE -> 0xFE 0x00
 * adds packet length, checksum, and EOP (0xFF)
 *
 */
int dc3200_compile_packet(Camera *camera, unsigned char **data, int *data_len)
{
      int count, i, j;
      unsigned char *new_data = NULL;
      unsigned char *tmp_ptr  = NULL;

      /* realloc + 2 for len and checksum */
      *data_len += 2;

      tmp_ptr = (unsigned char*)realloc(*data, *data_len);
      if(tmp_ptr == NULL)
            return GP_ERROR;

      *data = tmp_ptr;

      /* add length, checksum */
      (*data)[*data_len - 2] = *data_len - 2;
      (*data)[*data_len - 1] = dc3200_calc_checksum(camera, *data, *data_len - 1);

      /* this is a hack to fix the 0xFF/0xFE problem.
       * we adjust a "don't care" byte so the checksum
       * is not 0xFF or 0xFE
       */
      if((*data)[*data_len - 1] >= 0xFE) {
            if(*data_len > 19) {
                  (*data)[19] += 2;
                  (*data)[*data_len - 1] = dc3200_calc_checksum(camera, *data, *data_len - 1);
                  printf("adjusting checksum to %02x\n", (*data)[*data_len - 1]);
            }
      }

      /* count number of 0xfe's and 0xff's */
      count = 0;
      for(i=0;i<*data_len; i++) {
            if((*data)[i] == 0xFE || (*data)[i] == 0xFF)
                  count++;
      }

      new_data = (unsigned char*)malloc(*data_len + count + 3); /* 3 for length, checksum, EOP */
      if(!new_data)
            return GP_ERROR;

      j = 0;
      for(i=0;i<*data_len; i++) {
            if((*data)[i] == 0xFE || (*data)[i] == 0xFF) {
                  printf("(*data)[i]        == %02x\n", (*data)[i]);
                  printf("(*data)[i] - 0xFE == %02x\n", (*data)[i] - 0xFE);
                  new_data[j++] = 0xFE;
                  new_data[j++] = (*data)[i] - 0xFE;
            } else {
                  new_data[j++] = (*data)[i];
            }
      }

      /* adjust the new packet count */
      *data_len += count + 1;

      new_data[*data_len - 1] = 0xFF;

      /* free the old packet data */
      free(*data);

      /* set the ptr */
      *data = new_data;

      return GP_OK;
}

/*
 * dc3200_process_packet
 *
 * changes 0xFE 0x01 -> 0xFF
 *         0xFE 0x00 -> 0xFE
 * checks & removes packet length, checksum, EOP (0xFF)
 *
 */
int dc3200_process_packet(Camera *camera, unsigned char *data, int *data_len)
{
      int count = 0, i;
      int length, checksum;
      unsigned char *buff;

      if(data == NULL || *data_len < 1) {
            return GP_ERROR;
      }

      /* allocate a new buffer */
      buff = (unsigned char*)malloc(sizeof(unsigned char) * *data_len);
      if(!buff)
            return GP_ERROR;

      /* change 0xFE 0x00 | 0x01 -> 0xFF | 0xFE */
      for(i=0; i<*data_len; i++) {
            if(data[i] == 0xFE) {
                  if(i<*data_len-1) { /* so we don't run out of array bounds */
                        if(data[i+1] == 0x00) {
                              buff[count] = 0xFE;
                              /* advance i so we don't pick up the trailing byte */
                              i++;
                              /* incr count */
                              count++;
                        } else if(data[i+1] == 0x01) {
                              buff[count] = 0xFF;
                              i++;
                              count++;
                        }
                  } else {
                        /* we've found an 0xFE but there is no trailing byte */
                        free(buff);
                        return GP_ERROR;
                  }
            } else {
                  buff[count] = data[i];
                  count++;
            }
      }

      /* copy over the old buffer */
      memcpy(data, buff, count);

      length = data[count - 3];
      checksum = data[count - 2];

      /* make sure its a valid packet */
      if(length != count - 3 || checksum != dc3200_calc_checksum(camera, data, count - 2)) {
            printf("%02x=%02x %02x=%02x\n", length, count - 3, checksum, dc3200_calc_checksum(camera, data, count - 2));
            free(buff);
            return GP_ERROR;
      }

      /* adjust packet size, strip length, checksum, EOP */
      *data_len = count - 3;

      free(buff);
      return GP_OK;
}

/*
 * dc3200_calc_checksum
 *
 * calculates the checksum for a byte array
 *
 */
int dc3200_calc_checksum(Camera *camera, unsigned char * buffer, int len)
{
      int sum = 0, i;

      for(i=0; i<len; i++) {
            sum += buffer[i];
      }

      sum = -sum + 0xFF;
      if(sum < 0) sum = sum & 0xFF;

      return sum;
}

/*
 * dc3200_calc_seqnum
 *
 * calculates the seqnum for a packet
 *
 */
int dc3200_calc_seqnum(Camera *camera)
{
      if(camera->pl->pkt_seqnum >= 0x1F || camera->pl->pkt_seqnum < 0x10) {
            camera->pl->pkt_seqnum = 0x10;
            return camera->pl->pkt_seqnum;
      } else {
            camera->pl->pkt_seqnum++;
            return camera->pl->pkt_seqnum;
      }
}

/*
 * dc3200_keep_alive
 *
 * sends and receives a ping packet to keep the
 * camera awake
 *
 */
int dc3200_keep_alive(Camera *camera)
{
      unsigned char ka[ACK_PACKET_LEN]; /* keepalive */
      unsigned char ak[ACK_PACKET_LEN]; /* keepalive ack */
      int ak_len = ACK_PACKET_LEN;

      ka[0] = 0xCF;
      ka[1] = 0x01;

      /* send keep alive packet */
      if(dc3200_send_command(camera, ka, sizeof(ka), ak, &ak_len) == GP_ERROR) {
            return GP_ERROR;
      }

      /* check the ack (should be same packet) */
      if(memcmp(ak,ka,ak_len) == 0) {
            return GP_OK;
      }

      return GP_ERROR;
}

/*
 * dc3200_clear_read_buffer
 *
 * clears data in the read buffer by reading it out
 *
 * there is definitely a better way to accomplish this...
 *
 */
int dc3200_clear_read_buffer(Camera *camera)
{
      unsigned char byte;
      int count = 0;

      gp_port_set_timeout(camera->port, 0);

      while(gp_port_read(camera->port, &byte, 1) > 0)
            count++;

      if(count > 0)
            printf("cleared %d bytes from read buffer\n", count);

      gp_port_set_timeout(camera->port, TIMEOUT);

      return GP_OK;
}

/*
 * dump_buffer
 *
 * displays a byte array nicely formatted in hex format
 *
 */
int dump_buffer(unsigned char * buffer, int len, char * title, int bytesperline)
{
      char spacer[80];
      int i;

      memset(spacer, 0, sizeof(spacer));
      memset(spacer, ' ', strlen(title)+2);

      printf("%s: ", title);

      for(i=0; i<len; i++) {
            if(i%bytesperline==0 && i > 0) {
                  printf("\n%s", spacer);
            }
            printf("%02x ", buffer[i]);
      }

      printf("\n");

      printf("%s: ", title);

      for(i=0; i<len; i++) {
            if(i%bytesperline==0 && i > 0) {
                  printf("\n%s", spacer);
            }
            if(buffer[i] >= 0x20 && buffer[i] < 0x7F) {
                  printf("%c", buffer[i]);
            } else {
                  printf(".");
            }
      }

      printf("\n");

      return GP_OK;
}

unsigned long bytes_to_l(int a, int b, int c, int d)
{
      unsigned long res = a;
      res = res << 24 | b << 16 | c << 8 | d;
      return res;
}

Generated by  Doxygen 1.6.0   Back to index