diff options
Diffstat (limited to 'camlibs/jd11/serial.c')
-rw-r--r-- | camlibs/jd11/serial.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/camlibs/jd11/serial.c b/camlibs/jd11/serial.c new file mode 100644 index 000000000..52f631934 --- /dev/null +++ b/camlibs/jd11/serial.c @@ -0,0 +1,549 @@ +/* + * 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/gphoto2.h> +#include <gphoto2/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; +} |