From 14f3866e30b878c548a9bece246068a86d37ddd7 Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Sun, 28 Oct 2001 11:26:04 +0000 Subject: JD11 cam driver for gphoto2. git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@2826 67ed7778-7388-44ab-90cf-0a291f65f57c --- camlibs/jd11/Makefile.am | 14 ++ camlibs/jd11/decomp.c | 149 ++++++++++++++++++ camlibs/jd11/decomp.h | 5 + camlibs/jd11/jd11.c | 197 ++++++++++++++++++++++++ camlibs/jd11/jd11.html | 303 +++++++++++++++++++++++++++++++++++++ camlibs/jd11/serial.c | 381 +++++++++++++++++++++++++++++++++++++++++++++++ camlibs/jd11/serial.h | 15 ++ 7 files changed, 1064 insertions(+) create mode 100644 camlibs/jd11/Makefile.am create mode 100644 camlibs/jd11/decomp.c create mode 100644 camlibs/jd11/decomp.h create mode 100644 camlibs/jd11/jd11.c create mode 100644 camlibs/jd11/jd11.html create mode 100644 camlibs/jd11/serial.c create mode 100644 camlibs/jd11/serial.h (limited to 'camlibs/jd11') diff --git a/camlibs/jd11/Makefile.am b/camlibs/jd11/Makefile.am new file mode 100644 index 000000000..a5e88bd39 --- /dev/null +++ b/camlibs/jd11/Makefile.am @@ -0,0 +1,14 @@ +EXTRA_DIST = jd11.html + +camlibdir = $(prefix)/lib/gphoto2 +camlib_LTLIBRARIES = libgphoto2_jd11.la + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/libgphoto2 + +libgphoto2_jd11_la_SOURCES = jd11.c serial.h serial.c decomp.h decomp.c + +libgphoto2_jd11_la_LDFLAGS =\ + -avoid-version\ + -L$(shell pwd)/$(top_builddir)/libgphoto2/@dotlibs@ + +libgphoto2_jd11_la_LIBADD = -lgphoto2 diff --git a/camlibs/jd11/decomp.c b/camlibs/jd11/decomp.c new file mode 100644 index 000000000..34272e6c8 --- /dev/null +++ b/camlibs/jd11/decomp.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include "decomp.h" + +struct chain { int left,val,right; }; +struct compstate { + unsigned char curmask; + unsigned char bytebuf; + unsigned char *byteptr; + + struct chain cl[200]; + int stackstart; +}; + +/* FLOAT_QUERY: 0.860000 1.030000 1.150000. */ + +/********************************************************/ +/* The bit stage */ +/********************************************************/ +static inline int +jd11_getbit(struct compstate *cs) { + int ret; + if (cs->curmask == 0x80) + cs->bytebuf = *cs->byteptr++; + ret = cs->curmask & cs->bytebuf; + cs->curmask >>=1; + if (!cs->curmask) cs->curmask = 0x80; + return !!ret; +} + +/********************************************************/ +/* The huffman compressor stage */ +/********************************************************/ +static int +decomp_1byte(struct compstate *cs) { + int xcs = cs->stackstart; + int xbit; + + while ((cs->cl[xcs].left>=0) && (cs->cl[xcs].right>=0)) { + xbit = jd11_getbit(cs); + if (xbit) + xcs = cs->cl[xcs].left; + else + xcs = cs->cl[xcs].right; + } + return cs->cl[xcs].val; +} + +static void +build_huffmann_tree(struct compstate *cs) { + int xstack[200]; + int i,curcl=0,curstack=0; + const int df[] = { + -180,180,1000,-90,1000,90,1000,-45,1000,45,1000,-20,1000, + 20,1000,-11,1000,11,1000,-6,1000,2,1000,6,-2,1000,1000 + }; + for (i=0;icl[curcl].left = -1; + cs->cl[curcl].right = -1; + cs->cl[curcl].val = df[i]; + } else { + cs->cl[curcl].right = xstack[--curstack]; + cs->cl[curcl].left = xstack[--curstack]; + } + xstack[curstack++] = curcl++; + } + cs->stackstart = xstack[0]; +} + +#define F1 0.5 +#define F2 0.0 +#define F3 0.5 +#define F4 0.0 + +void +picture_decomp_v1(char *compressed,char *uncompressed,int width,int height) { + struct compstate cs; + unsigned char xbyte; + int i=0,curbyte=0,diff,lastval; + int *line,*lastline; + + cs.curmask = 0x80; cs.bytebuf = 0; cs.byteptr = compressed; + + build_huffmann_tree(&cs); + + line = (int*)malloc(sizeof(int)*width); + lastline= (int*)malloc(sizeof(int)*width); + curbyte=0; + memset(line,0,sizeof(line)); + memset(lastline,0,sizeof(line)); + for (i=0;i255) xbyte = 255; + if (curbyte<0) xbyte = 0; + + *uncompressed++=xbyte; + + line[i] = curbyte; + } + height--; + while (height--) { + lastval = line[0]; /* just before the copy */ + memcpy(lastline,line,width*sizeof(int)); + memset(line,0,width*sizeof(int)); + for (i=0;i255) xbyte = 255; + if (line[i]<0) xbyte = 0; + *uncompressed++=xbyte; + } + } +} + +/* Just blow up the picture from 6 bit uncompressed to 8 bit uncompressed */ +void +picture_decomp_v2(char *compressed,char *uncompressed,int width,int height) { + struct compstate cs; + int i,j; + unsigned char xbyte; + + cs.curmask = 0x80; cs.bytebuf = 0; cs.byteptr = compressed; + for (i=width*height;i--;) { + unsigned char xmask = 0x80; + xbyte = 0; + for (j=6;j--;) { + if (jd11_getbit(&cs)) + xbyte|=xmask; + xmask>>=1; + } + *uncompressed++=xbyte; + } +} diff --git a/camlibs/jd11/decomp.h b/camlibs/jd11/decomp.h new file mode 100644 index 000000000..30de7e597 --- /dev/null +++ b/camlibs/jd11/decomp.h @@ -0,0 +1,5 @@ +#ifndef _JD11_DECOMP_H +#define _JD11_DECOMP_H +extern void picture_decomp_v1(char *compressed,char *uncompressed,int width,int height); +extern void picture_decomp_v2(char *compressed,char *uncompressed,int width,int height); +#endif diff --git a/camlibs/jd11/jd11.c b/camlibs/jd11/jd11.c new file mode 100644 index 000000000..c6c93aa17 --- /dev/null +++ b/camlibs/jd11/jd11.c @@ -0,0 +1,197 @@ +/* + * Jenoptik JD11 Driver + * Copyright (C) 1999-2001 Marcus Meissner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define _(String) (String) +# define N_(String) (String) +# endif +#else +# define _(String) (String) +# define N_(String) (String) +#endif + +#include "serial.h" + +int camera_id (CameraText *id) +{ + strcpy(id->text, "JD11"); + return (GP_OK); +} + +int camera_abilities (CameraAbilitiesList *list) +{ + CameraAbilities a; + + strcpy(a.model, "Jenoptik JD11"); + a.status = GP_DRIVER_STATUS_TESTING; + a.port = GP_PORT_SERIAL; + a.speed[0] = 115200; + a.speed[1] = 0; + a.operations = GP_OPERATION_NONE ; + a.file_operations = GP_FILE_OPERATION_PREVIEW; + a.folder_operations = GP_FOLDER_OPERATION_DELETE_ALL; + + gp_abilities_list_append(list, a); + + return (GP_OK); +} + +static int file_list_func (CameraFilesystem *fs, const char *folder, + CameraList *list, void *data) +{ + Camera *camera = data; + int count, result; + + result = jd11_file_count(camera->port, &count); + if (result != GP_OK) + return result; + + gp_list_populate(list, "image%02i.pnm", count); + + return (GP_OK); +} + +static int get_file_func (CameraFilesystem *fs, const char *folder, + const char *filename, CameraFileType type, + CameraFile *file, void *user_data) +{ + Camera *camera = user_data; + int image_no, result; + char *data; + long int size; + + image_no = gp_filesystem_number(fs, folder, filename); + + if(image_no < 0) + return image_no; + + switch (type) { + /* + case GP_FILE_TYPE_RAW: + result = jd11_get_image_raw (camera->port, image_no, &data, + (int*) &size); + break; + */ + case GP_FILE_TYPE_NORMAL: + result = jd11_get_image_full (camera->port, image_no, &data, + (int*) &size); + break; + case GP_FILE_TYPE_PREVIEW: + result = jd11_get_image_preview (camera->port, image_no, + &data, (int*) &size); + break; + default: + return (GP_ERROR_NOT_SUPPORTED); + } + + if (result < 0) + return result; + + gp_file_set_name (file, filename); + gp_file_set_mime_type (file, "image/pnm"); + gp_file_set_data_and_size (file, data, size); + + return (GP_OK); +} + +static int +delete_all_func (CameraFilesystem *fs, const char* folder, void *data) +{ + Camera *camera = data; + if (strcmp (folder, "/")) + return (GP_ERROR_DIRECTORY_NOT_FOUND); + return jd11_erase_all(camera->port); +} + +static int camera_summary (Camera *camera, CameraText *summary) +{ + strcpy(summary->text, _("No summary available.")); + return (GP_OK); +} + +static int camera_manual (Camera *camera, CameraText *manual) +{ + strcpy(manual->text, + _( + "The JD11 camera works rather well with this driver.\n" + "It gets a bit confused if some data is left over on the serial line,\n" + "and will report I/O errors on startup. Just switch the camera off and\n" + "on again and it will no longer do that.\n" + "An RS232 interface @ 115 kbit is required for image transfer.\n" + "The driver allows you to get\n\n" + " - thumbnails (64x48 PGM format)\n" + " - full images (640x480 PPM format)\n" + "No color correction and no interpolation is applied as of this time.\n" + "\n\n")); + + return (GP_OK); +} + +static int camera_about (Camera *camera, CameraText *about) +{ + strcpy (about->text, + _("JD11\n" + "Marcus Meissner \n" + "Driver for the Jenoptik JD11 camera.\n" + "Protocol reverse engineered using WINE and IDA.")); + + return (GP_OK); +} + +int camera_init (Camera *camera) +{ + gp_port_settings settings; + int ret; + + /* First, set up all the function pointers */ + camera->functions->summary = camera_summary; + camera->functions->manual = camera_manual; + camera->functions->about = camera_about; + + /* Configure port */ + gp_port_set_timeout(camera->port, 1000); + gp_port_get_settings(camera->port, &settings); + settings.serial.speed = 115200; + settings.serial.bits = 8; + settings.serial.parity = 0; + settings.serial.stopbits= 1; + gp_port_set_settings(camera->port, settings); + + /* Set up the filesystem */ + gp_filesystem_set_list_funcs(camera->fs, file_list_func, NULL,camera); + gp_filesystem_set_file_funcs(camera->fs,get_file_func,NULL,camera); + gp_filesystem_set_folder_funcs(camera->fs,NULL,delete_all_func, NULL,NULL,camera); + /* test camera */ + ret = jd11_ping(camera->port); + return (ret); +} + diff --git a/camlibs/jd11/jd11.html b/camlibs/jd11/jd11.html new file mode 100644 index 000000000..34f3e4c67 --- /dev/null +++ b/camlibs/jd11/jd11.html @@ -0,0 +1,303 @@ + + + + + + Reverse Engineering the JD11 (JenCam 11) + + + +

+Reverse Engineering the JD11 - A drama in n chapters

+ +
+

+What is the JD11?

+The JD11 is a cheap digital camera produced by JenOptik (apparenly a subsidary +of Zeiss Jena). It was at the time of writing this available for around +250 DM. +

There is software available, a windows program called FotoBee +which is a huge heap of MFC dung. It can be made to run with a small hack +under the free Windows Emulator WINE. +

WINE was crucial in reverse engineering the camera at all stages of +the project. +

+Chapter 1:The lowlevel serial protocol

+The JD11 comes with a serial cable with a DB9 connector on the computerside +and a small klinkenstecker at the camera end. So just 2 lines (RX, TX) +and GND. +

There is no documenation on the serial protocol in the inlaying documentation. +

The FotoBee.exe program uses the Windows serial communications interface, +which is fortunately implemented in WINE. By snooping the setup calls, +the serial parameters are: +

        115200 Baud, no parity, 1 stopbit, 8 bit data, no flow control
+        (neither crtscts, nor XON/XOFF)
+It also setting some large timeouts, since the camera sometimes needs like +2 seconds to think about something. +

That was rather trivial. +

+Chapter 2: The serial data transfer protocol

+The next step was to find out how the FotoBee software talks to the camera. +

 Luckily the program still uses the standard Win32 serial communication +functions for that, so I added some code to the ReadFile and +WriteFile +functions, which dumps the read/written buffer if it is writing to a serial +device. +

In general, the program sends a command down the serial line (with optional +arguments) and receives data back. Every command starts with a 0xFF +character. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandArgumentsReturnsDescription
0xff 0x08None0xff 0xf1Ping!s the camera.
0xff 0xa7NoneA packet with between 10 and 20 bytes is returned. + 3 float factors are returned, they are calculated:
+ + f1=r[1]+r[2]*0.1+r[3]*0.01;
+ f2=r[4]+r[5]*0.1+r[6]*0.01;
+ f3=r[7]+r[8]*0.1+r[9]*0.01;
+

+ Their use is still unknown to me. +
0xff 0xa4None0xff 0x01Select Index Picture to transfer, is followed by packetreading
0xff 0xa10xff picturenr0xff 0x01Selects Image picturenr to transfer. 3 Bytestreams follow (packetreading has to be called 3 times)
0xff 0xa810 bytes of data ... Set floats0xff 0x01Sets the 3 floats. Sends 10 bytes to the camera.
+ The bytestream looks: + 0xFF A B C D E F G H I
+ The floats are: A.BC D.EF G.HI
+ A...I are binary values between 0 and 9. +
0xff 0xa6NoneNo return expected.Delete all images.
0xff 0xf0NoneReturns an ASCII hexnumber (starting with two 0x66 ('f')) + Returns the size (in bytes) of the image to transfer next. This + command is issued after "select index" or "select image" + and is followed by (multiple) packet reads. +
0xff 0xf1NoneReturns 201 or less bytes + The packetreader. It is called in a loop after querying the + imagesize. If 201 bytes are read, the 201th byte is the checksum + (sum of 0-199)&0xff, otherwise there is no checksum.
+ Returns the 200 bytes read. +
0xff 0xf3NoneReturns 201 or less bytes + The packet resend command. Works exactly like the + 0xff 0xf1 packetread command, but the last packet is + retransmitted. This is useful for corrupted transmissions. +
0xff 0x72None0xff 0x71Function unknown.
0xff 0x73None0xff 0x70Function unknown
0xff 0x75None0xff70 or 0xff71 or something else.Function unknown. Returns bool?
0xff 0x78None.Some data.Appears to take a snapshot and then it should read N packets of + data. Strange. There is some text generated and printed into + a dialog. I only get back 0xff.
0xff 0x79None0xff 0xXXFunction unknown, seems to open/close the shutter in rapid succession.
0xff 0x7aNone.Some data.Unclear. GUI enables wait cursor before call and disabled it after.
0xff 0x7b0xff value.0xff 0xf1Unclear.
0xff 0xa90xff value.0xff 0xf1Set Bulb Mode. Apparently values between 1 and 9.
+

+Following commands can be used on toplevel: +

    +
  • PING +
  • FLOAT FACTORS +
  • SELECT INDEX +
  • SELECT IMAGE +
  • ... +
+For reading the INDEX picture following sequence appears: +
    +
  • SELECT INDEX +
  • IMAGE SIZE +
  • READ PACKET until packets exhausted. +
+For reading the IMAGE picture following sequence appears: +
    +
  • SELECT IMAGE n +
  • Do 3 times: +
      +
    • IMAGE SIZE +
    • READ PACKET until packets exhausted. +
    +
+Thats all we needed to know about the serial commands. + +

Chapter 3: The image compression, stage 1

+ +Judging from other cameras it is easy to suspect the camera uses the JPEG +format. It does not unfortunately. + +

Chapter 3.1: The format of the index picture

+Casting a closer look at the raw data of the index picture shows a a stream +of 8 bit values. Some experimentation later it turns out to a stream of +64x48 grayscale pictures, upside down. +Using:
+	rawtopgm <index 64 (sizeof_index/64) |pnmflip -tb > index.ppm
+
+we can convert it into a .PPM and convert it further using standard UNIX tools. +

+ +The size of the index picture also tells us the number of pictures that are +currently stored in the camera. Just divide the size of the indeximage by 64*48. + +

Chapter 3.2: The low quality compressed image format

+ The camera has two modes to store pictures, either in low or + high quality. This is marked by the letters "L" and "H" on the + cameras LCD. Default is the low quality format.

+ It is still unclear to me how to detect high/low quality formats, + except with the size of the returned image. + +

+At first look the data returned from the camera looks like junknoise. So I had +to peek into the diassembly, which shows a slightly inefficient huffman decompressor, with following bitpatterns: + + + + + + + + + + + + + + + + +
BitsValue
00 -2
01 6
10 2
110 6
1110 11
1111 0 -11
1111 10 20
1111 110 -20
1111 1110 45
1111 1111 0 -45
1111 1111 10 90
1111 1111 110 -90
1111 1111 1110 180
1111 1111 1111 0 -180
+The result of this decompression run is 320*480 bytes for the first image, +and 320*240 for the second and third image. But these are not the pixel values, +these are differences! +
+So I had another look. Pixels are 8bit unsigned values and computed like this: +

    +
  • In the first row of the image: pixel[i] = lastpixel+decompressed_diff;
    + The first pixel is based on 0. +
  • In all other rows (starting lastvalue is pixel[0] of the previous line): +
      +
    • newpixelvalue = lastvalue + decompressed_diff;
      +
    • lastvalue = newpixelvalue*0.5 + pixel_lastline[i+1]*0.5; +
      +    		0 X 0
      +		X N 0
      +    
      + The 'X' pixels influence the 'N' pixel (together with the uncompressed diff) +
    +
+Tada. We now have 3 uncompressed images. To view each of them we can use: +
+	rawtopgm 320 480 <image0 | pnmflip -tb > image0.ppm
+	rawtopgm 320 240 <image1 | pnmflip -tb > image1.ppm
+	rawtopgm 320 240 <image2 | pnmflip -tb > image2.ppm
+
+where image0 is the first image read, and image1,image2 the next two images.

+Both give pretty grayscale pictures, but are not yet in color. + +

Chapter 3.2: The high quality compressed image format

+The high quality format uses a very different compression.

+It just compacts all 8bit values to 6bit by shortening out the 2 least +significant bits. +So we just restore them (AAAA AABB BBBB CCCC CCDD DDDD -> AAAAAA00, BBBBBB00, +CCCCCC00, DDDDDD00) and get the same grayscale images as with the lowquality +compression. + +

Chapter 3.3: Getting colors

+I am still working on that. They are not RGB. +
+

Download

+The package is available as .tar.gz file: jd11-1.0.tar.gz. + + diff --git a/camlibs/jd11/serial.c b/camlibs/jd11/serial.c new file mode 100644 index 000000000..7a5ee6a88 --- /dev/null +++ b/camlibs/jd11/serial.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include + +#include +#include + +#include "serial.h" +#include "decomp.h" + +#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>8; + buf[1] = cmd&0xff; + res = WRITE(port,buf,2); + if (res!=2) + return GP_ERROR_IO; + return GP_OK; +} + +static void _read_cmd(GPPort *port,unsigned short *xcmd) { + unsigned char buf[2]; + int i = 0; + *xcmd = 0x4242; + do { + if (2==READ(port,buf,2)) { + if (buf[0]==0xff) + break; + continue; + } + /*usleep(100);*/ i=10; + } while (i++<10); + *xcmd = (buf[0]<<8)|buf[1]; +} + +#if 0 +static void _dump_buf(unsigned char *buf,int size) { + int i; + fprintf(stderr,"["); + for (i=0;i */ + 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; +} + +#if 0 +static void cmd_75(GPPort *port) { + unsigned short xcmd; + + _send_cmd(port,0xff75); + _read_cmd(port,&xcmd); + fprintf(stderr,"75: done, xcmd=%x\n",xcmd); +} +static void cmd_72(GPPort *port) { + unsigned short xcmd; + + _send_cmd(port,0xff72); + _read_cmd(port,&xcmd); + assert(xcmd==0xff01); /* this seems to be the OK value or Go Ahead */ + fprintf(stderr,"72: done.\n"); +} +static void cmd_73(GPPort *port) { + unsigned short xcmd; + + _send_cmd(port,0xff73); + _read_cmd(port,&xcmd); + fprintf(stderr,"73: 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,ret);*/ + ret=strtol(&buf[2],NULL,16); + /*fprintf(stderr,"IMGSIZE: %d (%d images)\n",ret,ret/64/48);*/ + 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 xsize/(64*48)) { + fprintf(stderr,"ERROR: nr %d is larger than %d\n",nr,xsize/64/48); + return GP_ERROR_BAD_PARAMETERS; + } + xsize = (xsize / (64*48)) * (64*48); + indexbuf = malloc(xsize+400); + if (!indexbuf) return GP_ERROR_NO_MEMORY; + _send_cmd(port,0xfff1); + while (1) { + int readsize = xsize-curread; + if (readsize>200) readsize = 200; + ret=getpacket(port,indexbuf+curread,readsize); + if (ret==0) + break; + curread+=ret; + packets++; + if (ret<200) + break; + _send_cmd(port,0xfff1); + } + strcpy(header,"P5\n# gPhoto2 JD11 thumbnail image\n64 48 255\n"); + *size = 64*48+strlen(header); + *data = malloc(*size); + if (!*data) return GP_ERROR_NO_MEMORY; + strcpy(*data,header); + src = indexbuf+(nr*64*48); + dst = (*data)+strlen(header); + + for (y=0;y<48;y++) { + int x,off = 64*y; + for (x=0;x<64;x++) + dst[47*64-off+(63-x)] = src[off+x]; + } + free(indexbuf); + return GP_OK; +} + +int +jd11_file_count(GPPort *port,int *count) { + int xsize,packets=0,curread=0,ret=0; + char tmpbuf[202]; + + jd11_select_index(port); + xsize = jd11_imgsize(port); xsize = (xsize / (64*48)) * (64*48); + _send_cmd(port,0xfff1); + while (curread <= xsize) { + int readsize = xsize-curread; + if (readsize>200) readsize = 200; + ret=getpacket(port,tmpbuf,readsize); + if (ret==0) + break; + curread+=ret; + packets++; + if (ret<200) + break; + _send_cmd(port,0xfff1); + } + *count = curread/64/48+1; + return GP_OK; +} + +static int +serial_image_reader(GPPort *port,int nr,unsigned char ***imagebufs,int *sizes) { + int picnum,packets,curread,ret=0; + + jd11_select_image(port,nr); + *imagebufs = (unsigned char**)malloc(3*sizeof(char**)); + for (picnum=0;picnum<3;picnum++) { + packets=0; + curread=0; + sizes[picnum] = jd11_imgsize(port); + (*imagebufs)[picnum]=(unsigned char*)malloc(sizes[picnum]+400); + _send_cmd(port,0xfff1); + while (curread 200) readsize = 200; + ret=getpacket(port,(*imagebufs)[picnum]+curread,readsize); + if (ret==0) + break; + curread+=ret; + packets++; + if (ret<200) + break; + _send_cmd(port,0xfff1); + } + } + return GP_OK; +} + + +int +jd11_get_image_full(GPPort *port,int nr, char **data, int *size) { + unsigned char *s,*uncomp[3],**imagebufs; + int ret,sizes[3]; + char header[200]; + int h; + + ret = serial_image_reader(port,nr,&imagebufs,sizes); + 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); + } + + strcpy(header,"P6\n# gPhoto2 JD11 thumbnail image\n640 480 255\n"); + *size = 640*480*3+strlen(header); + *data = malloc(*size); + strcpy(*data,header); + s=(*data)+strlen(header); + 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); + return GP_OK; +} diff --git a/camlibs/jd11/serial.h b/camlibs/jd11/serial.h new file mode 100644 index 000000000..ce5dab6d0 --- /dev/null +++ b/camlibs/jd11/serial.h @@ -0,0 +1,15 @@ +#ifndef _JD11_SERIAL_H +#define _JD11_SERIAL_H + +#include +#include + +extern int jd11_file_count(GPPort *port, int *count); +extern int jd11_get_image_preview(GPPort *port,int nr, char **data, int *size); +extern int jd11_get_image_full(GPPort *port,int nr, char **data, int *size); +extern int jd11_erase_all(GPPort *port); +extern int jd11_ping(GPPort *port); +extern int jd11_float_query(GPPort *port); +extern int jd11_select_index(GPPort *port); +extern int jd11_select_image(GPPort *port, int nr); +#endif -- cgit v1.2.1