Logo Search packages:      
Sourcecode: libgphoto2 version File versions

serial.c

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

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

#include <gphoto2.h>
#include <gphoto2-port.h>

#include <bayer.h>

#include "serial.h"
#include "decomp.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

#if 0
static int
dread(GPPort *port, caddr_t buf, int xsize) {
    int i;
    int ret = gp_port_read(port,buf,xsize);

    if (ret == -1) {
      perror("dread");
      return -1;
    }
    fprintf(stderr,"dread[%d]:",ret);
    for (i=0;i<ret;i++) fprintf(stderr,"%02x,",buf[i]);
    fprintf(stderr,"\n");
    return ret;
}
static int
dwrite(GPPort*port, caddr_t buf, int xsize) {
    int i;
    int ret = gp_port_write(port,buf,xsize);

    if (ret < GP_OK) {
      perror("dwrite");
      return -1;
    }
    fprintf(stderr,"dwrite[%d/%d]:",xsize,ret);
    for (i=0;i<xsize;i++) fprintf(stderr,"%02x,",buf[i]);
    fprintf(stderr,"\n");
    return ret;
}
#endif

#define READ gp_port_read
#define WRITE gp_port_write

static int _send_cmd(GPPort *port,unsigned short cmd) {
    unsigned char buf[2];
    buf[0] = cmd>>8;
    buf[1] = cmd&0xff;
    return WRITE(port,buf,2);
}

static int _read_cmd(GPPort *port,unsigned short *xcmd) {
      unsigned char buf[2];
      int   i = 0,ret;
      *xcmd = 0x4242;
      do {
            if (1==(ret=READ(port,buf,1))) {
                  if (buf[0]==0xff) {
                      if (1==READ(port,buf+1,1)) {
                        *xcmd = (buf[0] << 8)| buf[1];
                        return GP_OK;
                      }
                  }
            } else {
                return ret;
            }
      } while (i++<10);
      return GP_ERROR_IO;
}

#if 0
static void _dump_buf(unsigned char *buf,int size) {
      int i;
      fprintf(stderr,"[");
      for (i=0;i<size;i++)
            fprintf(stderr,"%02x ",buf[i]);
      fprintf(stderr,"]\n");
}
#endif


static int _send_cmd_2(GPPort *port,unsigned short cmd, unsigned short *xcmd) {
    unsigned char buf[2];
    int ret, tries = 3;
    *xcmd = 0x4242;
    while (tries--) {
      int i = 0;
      buf[0] = cmd>>8;
      buf[1] = cmd&0xff;
      ret = WRITE(port,buf,2);
      do {
            if (1==(ret=READ(port,buf,1))) {
                  if (buf[0]==0xff) {
                      if (1==READ(port,buf+1,1)) {
                        *xcmd = (buf[0] << 8)| buf[1];
                        return GP_OK;
                      }
                  }
            } else {
                return ret;
            }
      } while (i++<3);
    }
    return GP_ERROR_IO;
}

int jd11_ping(GPPort *port) {
      unsigned short xcmd;
      char  buf[1];
      int   ret,tries = 3;

      while (tries--) {
          ret = GP_ERROR_IO;
          while (1==READ(port,buf,1))
                /* drain input queue before PING */;
          ret=_send_cmd_2(port,0xff08,&xcmd);
          if ((ret>=GP_OK) && (xcmd==0xfff1))
            return GP_OK;
      }
      return ret;
}

int
jd11_get_rgb(GPPort *port,float *red, float *green, float *blue) {
      char  buf[10];
      int   ret=GP_OK,tries=0,curread=0;

      _send_cmd(port,0xffa7);
      while ((curread<10) && (tries++<30)) {
          ret=READ(port,buf+curread,sizeof(buf)-curread);
          if (ret < 0)
            continue;
          if (ret == 0)
            break;
          curread+=ret;
      }
      if(curread<10) {
          fprintf(stderr,"%d returned bytes on float query.\n",ret);
          return GP_ERROR_IO;
      }
      /*_dump_buf(buf,10);*/
      *green      = buf[1]+buf[2]*0.1+buf[3]*0.01;
      *red  = buf[4]+buf[5]*0.1+buf[6]*0.01;
      *blue = buf[7]+buf[8]*0.1+buf[9]*0.01;
      return GP_OK;
}

int
jd11_set_rgb(GPPort *port,float red, float green, float blue) {
      unsigned char     buf[20];

      _send_cmd(port,0xffa7);
      buf[0] = 0xff;
      buf[1] = (int)green;
      buf[2] = ((int)(green*10))%10;
      buf[3] = ((int)(green*100))%10;
      buf[4] = (int)red;
      buf[5] = ((int)(red*10))%10;
      buf[6] = ((int)(red*100))%10;
      buf[7] = (int)blue;
      buf[8] = ((int)(blue*10))%10;
      buf[9] = ((int)(blue*100))%10;
      /*_dump_buf(buf,10);*/
      return WRITE(port,buf,10);
}

int
jd11_select_index(GPPort *port) {   /* select index */
      unsigned short xcmd;
      int ret;

      ret = _send_cmd_2(port,0xffa4,&xcmd);
      if (ret < GP_OK)
          return ret;
      if (xcmd!=0xff01)
          return GP_ERROR_IO;
      return GP_OK;
}

int
jd11_select_image(GPPort *port,int nr) {  /* select image <nr> */
      unsigned short xcmd;

      _send_cmd(port,0xffa1);
      _send_cmd(port,0xff00|nr);
      _read_cmd(port,&xcmd);
      if (xcmd != 0xff01)
          return GP_ERROR_IO;
      return GP_OK;
}

int
jd11_set_bulb_exposure(GPPort *port,int i) {
      unsigned short xcmd;

      if ((i<1) || (i>9))
          return GP_ERROR_BAD_PARAMETERS;

      _send_cmd(port,0xffa9);
      _send_cmd(port,0xff00|i);
      _read_cmd(port,&xcmd);
      return GP_OK;
}

#if 0
static void jd11_TestADC(GPPort *port) {
      unsigned short xcmd;

      _send_cmd(port,0xff75);
      _read_cmd(port,&xcmd);
      fprintf(stderr,"TestADC: done, xcmd=%x\n",xcmd);
}
static void cmd_TestDRAM(GPPort *port) {
      unsigned short xcmd;

      _send_cmd(port,0xff72);
      _read_cmd(port,&xcmd);
      fprintf(stderr,"TestDRAM: done.\n");
}

/* doesn't actually flash */
static void cmd_TestFLASH(GPPort *port) {
      unsigned short xcmd;

      _send_cmd(port,0xff73);
      _read_cmd(port,&xcmd);
      fprintf(stderr,"TestFLASH: xcmd = %x.\n",xcmd);
}

/* some kind of selftest  ... shuts the shutters, beeps... only stops by 
 * powercycle. */
static void cmd_79(GPPort *port) {
      unsigned short xcmd;

      _send_cmd(port,0xff79);
      _read_cmd(port,&xcmd);
      fprintf(stderr,"79: done, xcmd =%x\n",xcmd);
}
#endif


static int
jd11_imgsize(GPPort *port) {
      char  buf[20];
      int   ret;
      int   i=0,curread=0;

      _send_cmd(port,0xfff0);
      do {
            ret=READ(port,&buf[curread],10-curread);
            if (ret>0)
                curread+=ret;
            usleep(1000);
      } while ((i++<20) && (curread<10));
      /*_dump_buf(buf,curread);*/
      if (!curread) /* We get 0 bytes return for 0 images. */
          return 0;
      ret=strtol(&buf[2],NULL,16);
      return ret;
}

static int
getpacket(GPPort *port,unsigned char *buf, int expect) {
        int curread = 0, csum = 0;
      int tries = 0;
      if (expect == 200)
          expect++;
      while (tries++<5) {
            int i=0,ret;

            do {
                  ret=READ(port,buf+curread,expect-curread);
                  if (ret>0) {
                        curread+=ret;
                        i=0;
                        continue;
                  }
                  usleep(100);
            } while ((i++<2) && (curread<expect));
            if (curread!=expect) {
                if (!curread)
                  return 0;
                _send_cmd(port,0xfff3);
                curread = csum = 0;
                continue;
            }
            /*printf("curread is %d\n",curread);*/
            /*printf("PACKET:");_dump_buf(buf,curread);*/
            for (i=0;i<curread-1;i++)
                  csum+=buf[i];
            if (buf[curread-1]==(csum&0xff) || (curread!=201))
                  return curread-1;
            fprintf(stderr,"BAD CHECKSUM %x vs %x, trying resend...\n",buf[curread-1],csum&0xff);
            _send_cmd(port,0xfff3);
            curread = csum = 0;
            /*return curread-1;*/
      }
      fprintf(stderr,"Giving up after 5 tries.\n");
      return 0;
}

int
jd11_erase_all(GPPort *port) {
      return _send_cmd(port,0xffa6);
}

/* This function reads all thumbnails at once and initializes the whole
 * camera filesystem. This can be done, because finding out how much 
 * pictures are on the camera is done by reading the whole preview picture
 * stream anyway.
 * And since the file infos are static mostly, why not just set them too at
 * the same time.
 */
int
jd11_index_reader(GPPort *port, CameraFilesystem *fs, GPContext *context) {
    int           i, id, count, xsize, curread=0, ret=0;
    char    *indexbuf;

    ret = jd11_select_index(port);
    if (ret != GP_OK)
      return ret;
    xsize = jd11_imgsize(port);
    if (!xsize) { /* shortcut, no reading needed */
      return GP_OK;
    }
    count = xsize/(64*48);
    xsize = count * (64*48);
    indexbuf = malloc(xsize);
    if (!indexbuf) return GP_ERROR_NO_MEMORY;
    id = gp_context_progress_start (context, xsize,
                            _("Downloading thumbnail..."));
    _send_cmd(port,0xfff1);
    while (curread < xsize) {
          int readsize = xsize-curread;
          if (readsize>200) readsize = 200;
          ret=getpacket(port,indexbuf+curread,readsize);
          if (ret==0)
                break;
          curread+=ret;
          if (ret<200)
                break;
          gp_context_progress_update (context, id, curread);
          if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
            /* What to do...Just free the stuff we allocated for now.*/
            free(indexbuf);
            return GP_ERROR_CANCEL;
          }
          _send_cmd(port,0xfff1);
    }
    gp_context_progress_stop (context, id);
    for (i=0;i<count;i++) {
      CameraFile  *file;
      char        *src, fn[20];
      unsigned char thumb[64*48];
      int y;
      CameraFileInfo    info;
      
      ret = gp_file_new(&file);
      if (ret!=GP_OK)
          return ret;
      sprintf(fn,"image%02i.pgm",i);
      gp_file_set_type (file, GP_FILE_TYPE_PREVIEW);
      gp_file_set_name(file, fn);
      gp_file_set_mime_type(file, GP_MIME_PGM);
      gp_file_append(file, THUMBHEADER, strlen(THUMBHEADER));
      src = indexbuf+(i*64*48);
      for (y=0;y<48;y++) {
          int x,off = 64*y;
          for (x=0;x<64;x++)
            thumb[47*64-off+(63-x)] = src[off+x];
      }
      ret = gp_file_append(file,thumb,sizeof(thumb));
      if (ret != GP_OK) return ret;
      ret = gp_filesystem_append(fs, "/", fn, context);
      if (ret != GP_OK) return ret;
      ret = gp_filesystem_set_file_noop(fs, "/", file, context);
      if (ret != GP_OK) return ret;

      /* we also get the fs info for free, so just set it */
      info.file.fields = GP_FILE_INFO_TYPE | GP_FILE_INFO_NAME | 
                  GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
                  GP_FILE_INFO_SIZE;
      strcpy(info.file.type,GP_MIME_PNM);
      strcpy(info.file.name,fn);
      info.file.width         = 640;
      info.file.height  = 480;
      info.file.size          = 640*480*3+strlen(IMGHEADER);
      info.preview.fields = GP_FILE_INFO_TYPE |
                  GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
                  GP_FILE_INFO_SIZE;
      strcpy(info.preview.type,GP_MIME_PGM);
      info.preview.width      = 64;
      info.preview.height     = 48;
      info.preview.size = 64*48+strlen(THUMBHEADER);
      ret = gp_filesystem_set_info_noop(fs, "/", info, context);
    }
    free(indexbuf);
    return GP_OK;
}

static int
serial_image_reader(Camera *camera,CameraFile *file,int nr,unsigned char ***imagebufs,int *sizes, GPContext *context) {
    int     picnum,curread,ret=0;
    GPPort *port = camera->port;
    unsigned int id;

    jd11_select_image(port,nr);
    *imagebufs = (unsigned char**)malloc(3*sizeof(char**));
    for (picnum=0;picnum<3;picnum++) {
      curread=0;
      sizes[picnum] = jd11_imgsize(port);
      (*imagebufs)[picnum]=(unsigned char*)malloc(sizes[picnum]+400);
      _send_cmd(port,0xfff1);
      id = gp_context_progress_start (context, sizes[picnum],
                  _("Downloading data..."));
      while (curread<sizes[picnum]) {
          int readsize = sizes[picnum]-curread;
          if (readsize > 200) readsize = 200;
          ret=getpacket(port,(*imagebufs)[picnum]+curread,readsize);
          if (ret==0)
            break;
          curread+=ret;
          if (ret<200)
            break;
          gp_context_progress_update (context, id, curread);
          if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
            int j;
            /* What to do ... Just free the stuff we allocated for now. */
            for (j=0;j<picnum;j++)
                free((*imagebufs)[picnum]);
            free(*imagebufs);
            return GP_ERROR_CANCEL;
          }
          _send_cmd(port,0xfff1);
      }
      gp_context_progress_stop (context, id);
    }
    return GP_OK;
}


int
jd11_get_image_full(
    Camera *camera, CameraFile*file, int nr, int raw, GPContext *context
) {
    unsigned char *s,*uncomp[3],**imagebufs;
    int                 ret,sizes[3];
    char          *data;
    int           h;

    ret = serial_image_reader(camera,file,nr,&imagebufs,sizes, context);
    if (ret!=GP_OK)
      return ret;
    uncomp[0] = malloc(320*480);
    uncomp[1] = malloc(320*480/2);
    uncomp[2] = malloc(320*480/2);
    if (sizes[0]!=115200) {
          picture_decomp_v1(imagebufs[0],uncomp[0],320,480);
          picture_decomp_v1(imagebufs[1],uncomp[1],320,480/2);
          picture_decomp_v1(imagebufs[2],uncomp[2],320,480/2);
    } else {
          picture_decomp_v2(imagebufs[0],uncomp[0],320,480);
          picture_decomp_v2(imagebufs[1],uncomp[1],320,480/2);
          picture_decomp_v2(imagebufs[2],uncomp[2],320,480/2);
    }
    gp_file_append(file, IMGHEADER, strlen(IMGHEADER));
    data = malloc(640*480*3);
    if (!raw) {
      unsigned char *bayerpre;
      s = bayerpre = malloc(640*480);
      /* note that picture is upside down and left<->right mirrored */
      for (h=480;h--;) {
          int w;
          for (w=320;w--;) {
            if (h&1) {
                /* G B G B G B G B G */
                *s++ = uncomp[2][(h/2)*320+w];
                *s++ = uncomp[0][h*320+w];
            } else {
                /* R G R G R G R G R */
                *s++ = uncomp[0][h*320+w];
                *s++ = uncomp[1][(h/2)*320+w];
            }
          }
      }
      gp_bayer_decode(bayerpre,640,480,data,BAYER_TILE_RGGB);
      free(bayerpre);
    } else {
      s=data;
      for (h=480;h--;) { /* upside down */
          int w;
          for (w=640;w--;) { /* right to left */
            /* and images are in green red blue */
            *s++=uncomp[1][(h/2)*320+(w/2)];
            *s++=uncomp[0][h*320+(w/2)];
            *s++=uncomp[2][(h/2)*320+(w/2)];
          }
      }
    }
    free(uncomp[0]);free(uncomp[1]);free(uncomp[2]);
    free(imagebufs[0]);free(imagebufs[1]);free(imagebufs[2]);free(imagebufs);
    gp_file_append(file, data, 640*480*3);
    free(data);
    return GP_OK;
}

Generated by  Doxygen 1.6.0   Back to index