Logo Search packages:      
Sourcecode: libgphoto2 version File versions

casio-qv-commands.c

/* casio-qv-commands.c
 *
 * Copyright © 2001 Lutz Müller
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include "config.h"
#include "casio-qv-commands.h"

#include <stdlib.h>

#define STX 0x02
#define ETX 0x03
#define ENQ 0x05
#define ACK 0x06
#define DC2 0x12
#define NAK 0x15
#define ETB 0x17
#define UNKNOWN1 0xfe
#define UNKNOWN2 0xe0

#define CASIO_QV_RETRIES 5

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

int
QVping (Camera *camera)
{
      unsigned char c;
      int result = GP_OK, i = 0;

      /* Send ENQ and wait for ACK */
      while (1) {
            c = ENQ;
            CR (gp_port_write (camera->port, &c, 1));
            result = gp_port_read (camera->port, &c, 1);

            /* If we got ACK, everything is fine. */
            if (result >= 0) {
                  switch (c) {
                  case ACK:
                  case ENQ:
                        
                        /*
                         * According to gphoto, we need to wait
                         * for ACK. But the camera of 
                         * David Wolfskill <david@catwhisker.org>
                         * seems to return ENQ after some NAK.
                         */
                        return (GP_OK);

                  case NAK:

                        /* The camera is not yet ready. */
                        break;

                  case UNKNOWN1:
                  case UNKNOWN2:

                        /* 
                         * David Wolfskill <david@catwhisker.org>
                         * has seen those two bytes if one sends
                         * only ENQs to the camera. The camera first
                         * answers with some NAKs, then with some
                         * ACKs, and finally with UNKNOWN1 and 
                         * UNKNOWN2.
                         */
                        while (gp_port_read (camera->port, &c, 1) >= 0);
                        break;

                  default:
                        while (gp_port_read (camera->port, &c, 1) >= 0);
                        break;
                  }
            }

            if (++i < CASIO_QV_RETRIES)
                  continue;

            /* If we got an error from libgphoto2_port, pass it along */
            CR (result);

            /* Return some error code */
            return (GP_ERROR_CORRUPTED_DATA);
      }
}

static int
QVsend (Camera *camera, unsigned char *cmd, int cmd_len,
                         unsigned char *buf, int buf_len)
{
      unsigned char c;
      int checksum;
      const unsigned char *cmd_end;

      /* The camera does not insist on a ping each command, but */
      /* sometimes it hangs up without one.                     */
      CR (QVping (camera));

      /* Write the request and calculate the checksum */
      CR (gp_port_write (camera->port, cmd, cmd_len));
      for (cmd_end = cmd+cmd_len, checksum = 0; cmd < cmd_end; ++cmd)
            checksum += *cmd;

      /* Read the checksum */
      CR (gp_port_read (camera->port, &c, 1));
      if (c != (unsigned char)(~checksum))
            return (GP_ERROR_CORRUPTED_DATA);

      /* Send ACK */
      c = ACK;
      CR (gp_port_write (camera->port, &c, 1));

      /* Receive the answer */
      if (buf_len)
            CR (gp_port_read (camera->port, buf, buf_len));

      return (GP_OK);
}

static int
QVblockrecv (Camera *camera, unsigned char **buf, unsigned long int *buf_len)
{
      /* XXX - does the caller know to free *buf in case of an error? */
      unsigned char c;
      int retries, pos;

      retries = 0;
      *buf = NULL;
      *buf_len = 0;
      pos = 0;

      /* Send DC2 */
      c = DC2;
      CR (gp_port_write (camera->port, &c, 1));

      while (1) {
            unsigned char buffer[2];
            int size, i;
            int sum;
            unsigned char *new;

            /* Read STX */
            CR (gp_port_read (camera->port, &c, 1));
            if (c != STX) {
                  retries++;
                  c = NAK;
                  CR (gp_port_write (camera->port, &c, 1));
                  if (retries > CASIO_QV_RETRIES)
                        return (GP_ERROR_CORRUPTED_DATA);
                  else
                        continue;
            }

            /* Read sector size */
            CR (gp_port_read (camera->port, buffer, 2));
            size = (buffer[0] << 8) | buffer[1];
            sum = buffer[0] + buffer[1];

            /* Allocate the memory */
            new = (unsigned char*)realloc (*buf, sizeof (char) * (*buf_len + size));
            if (new == (unsigned char*)0) {
                  if (*buf != (unsigned char*)0) free(*buf);
                  return (GP_ERROR_NO_MEMORY);
            }
            *buf = new;
            *buf_len += size;

            /* Get the sector */
            CR (gp_port_read (camera->port, *buf + pos, size));
            for (i = 0; i < size; i++)
                  sum += (*buf)[i + pos];

            /* Get EOT or ETX and the checksum */
            CR (gp_port_read (camera->port, buffer, 2));
            sum += buffer[0];

            /* Verify the checksum */
            if ((unsigned char)(~sum) != buffer[1]) {
                  retries++;
                  c = NAK;
                  CR (gp_port_write (camera->port, &c, 1));
                  if (retries > CASIO_QV_RETRIES)
                        return (GP_ERROR_CORRUPTED_DATA);
                  else
                        continue;
            }     

            /* Acknowledge and prepare for next packet */
            c = ACK;
            CR (gp_port_write (camera->port, &c, 1));
            pos += size;

            /* Are we done? */
            if (buffer[0] == ETX)
                  break;            /* Yes */
            else if (buffer[0] == ETB)
                  continue;   /* No  */
            else
                  return (GP_ERROR_CORRUPTED_DATA);
      }

      return (GP_OK);
}

int
QVbattery (Camera *camera, float *battery)
{
      unsigned char cmd[6];
      unsigned char b;

      cmd[0] = 'R';
      cmd[1] = 'B';
      cmd[2] = ENQ;
      cmd[3] = 0xff;
      cmd[4] = 0xfe;
      cmd[5] = 0xe6;
      CR (QVsend (camera, cmd, 6, &b, 1));
      *battery = b / 16.;

      return (GP_OK);
}

int
QVrevision (Camera *camera, long int *revision)
{
      unsigned char cmd[2];
      unsigned char buf[4];

      cmd[0] = 'S';
      cmd[1] = 'U';
      CR (QVsend (camera, cmd, 2, buf, 4));
      *revision = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];

      return (GP_OK);
}

int
QVnumpic (Camera *camera)
{
      unsigned char cmd[2];
      unsigned char b;

      cmd[0] = 'M';
      cmd[1] = 'P';
      CR (QVsend (camera, cmd, 2, &b, 1));

      return (b);
}

int
QVpicattr (Camera *camera, int n, unsigned char *picattr)
{
      unsigned char cmd[4];
      unsigned char b;

      cmd[0] = 'D';
      cmd[1] = 'Y';
        cmd[2] = STX;
        cmd[3] = n+1;
      CR (QVsend (camera, cmd, 4, &b, 1));
      *picattr = b;

      return (GP_OK);
}

int
QVshowpic (Camera *camera, int n)
{
      unsigned char cmd[3];

      cmd[0] = 'D';
      cmd[1] = 'A';
      cmd[2] = n+1;
      CR (QVsend (camera, cmd, 3, NULL, 0));

      return (GP_OK);
}

int
QVsetpic (Camera *camera)
{
      unsigned char cmd[2];

      cmd[0] = 'D';
      cmd[1] = 'L';
      CR (QVsend (camera, cmd, 2, NULL, 0));

      return (GP_OK);
}

int
QVgetCAMpic (Camera *camera, unsigned char **data, unsigned long int *size, int fine)
{
      unsigned char cmd[2];

      cmd[0] = 'M';
      cmd[1] = fine ? 'g' : 'G';
      CR (QVsend (camera, cmd, 2, NULL, 0));
      CR (QVblockrecv (camera, data, size));

      return (GP_OK);
}

int
QVgetYCCpic (Camera *camera, unsigned char **data, unsigned long int *size)
{
      unsigned char cmd[2];

      cmd[0] = 'M';
      cmd[1] = 'K';
      CR (QVsend (camera, cmd, 2, NULL, 0));
      CR (QVblockrecv (camera, data, size));

      return (GP_OK);
}

int
QVdelete (Camera *camera, int n)
{
      unsigned char cmd[4];

      cmd[0] = 'D';
      cmd[1] = 'F';
      cmd[2] = n+1;
      cmd[3] = 0xff;
      CR (QVsend (camera, cmd, 4, NULL, 0));

      return (GP_OK);
}

int
QVprotect (Camera *camera, int n, int on)
{
      unsigned char cmd[4];

      cmd[0] = 'D';
      cmd[1] = 'Y';
      cmd[2] = on ? 1 : 0;
      cmd[3] = n+1;
      CR (QVsend (camera, cmd, 4, NULL, 0));

      return (GP_OK);
}

int
QVsize (Camera *camera, long int *size)
{
      unsigned char cmd[2];
      unsigned char buf[4];

      cmd[0] = 'E';
      cmd[1] = 'M';
      CR (QVsend (camera, cmd, 2, buf, 4));
      *size = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];

      return (GP_OK);
}

int
QVcapture (Camera *camera)
{
      unsigned char cmd[2];
      unsigned char b;

      cmd[0] = 'D';
      cmd[1] = 'R';
      CR (QVsend (camera, cmd, 2, &b, 1));

      return (GP_OK);
}

int
QVstatus (Camera *camera, char *status)
{
        unsigned char cmd[3];
        
        cmd[0] = 'D';
        cmd[1] = 'S';
        cmd[2] = STX;
        CR (QVsend (camera, cmd, 3, status, 2));

        return (GP_OK);
}

int
QVreset (Camera *camera)
{
        unsigned char cmd[2];
        
      cmd[0] = 'Q';
      cmd[1] = 'R';
      CR (QVsend (camera, cmd, 2, NULL, 0));

        return (GP_OK);
}

int
QVsetspeed (Camera *camera, int speed)
{
      unsigned char cmd[3];
        gp_port_settings settings;

      cmd[0] = 'C';
      cmd[1] = 'B';
      switch (speed) {
      case   9600: cmd[2] = 46; break;
      case  19200: cmd[2] = 22; break;
      case  38400: cmd[2] = 11; break;
      case  57600: cmd[2] =  7; break;
      case 115200: cmd[2] =  3; break;
      default: return (GP_ERROR_NOT_SUPPORTED);
      }
      CR (QVsend (camera, cmd, 3, NULL, 0));

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

      CR (QVping (camera));

      return (GP_OK);
}

Generated by  Doxygen 1.6.0   Back to index