Source code upload
[framework/connectivity/libgphoto2.git] / camlibs / jd11 / serial.c
1 /*
2  * Jenopt JD11 Camera Driver
3  * Copyright © 1999-2001 Marcus Meissner <marcus@jet.franken.de> 
4  * 
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, 
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details. 
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 #include "config.h"
21
22 #include <stdio.h>
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27
28 #include <gphoto2/gphoto2.h>
29 #include <gphoto2/gphoto2-port.h>
30
31 #include <bayer.h>
32
33 #include "serial.h"
34 #include "decomp.h"
35
36 #ifdef ENABLE_NLS
37 #  include <libintl.h>
38 #  undef _
39 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
40 #  ifdef gettext_noop
41 #    define N_(String) gettext_noop (String)
42 #  else
43 #    define N_(String) (String)
44 #  endif
45 #else
46 #  define textdomain(String) (String)
47 #  define gettext(String) (String)
48 #  define dgettext(Domain,Message) (Message)
49 #  define dcgettext(Domain,Message,Type) (Message)
50 #  define bindtextdomain(Domain,Directory) (Domain)
51 #  define _(String) (String)
52 #  define N_(String) (String)
53 #endif
54
55 #if 0
56 static int
57 dread(GPPort *port, caddr_t buf, int xsize) {
58     int i;
59     int ret = gp_port_read(port,buf,xsize);
60
61     if (ret == -1) {
62         perror("dread");
63         return -1;
64     }
65     fprintf(stderr,"dread[%d]:",ret);
66     for (i=0;i<ret;i++) fprintf(stderr,"%02x,",buf[i]);
67     fprintf(stderr,"\n");
68     return ret;
69 }
70 static int
71 dwrite(GPPort*port, caddr_t buf, int xsize) {
72     int i;
73     int ret = gp_port_write(port,buf,xsize);
74
75     if (ret < GP_OK) {
76         perror("dwrite");
77         return -1;
78     }
79     fprintf(stderr,"dwrite[%d/%d]:",xsize,ret);
80     for (i=0;i<xsize;i++) fprintf(stderr,"%02x,",buf[i]);
81     fprintf(stderr,"\n");
82     return ret;
83 }
84 #endif
85
86 #define READ(port,buf,len) gp_port_read(port,(char*)(buf),len)
87 #define WRITE(port,buf,len) gp_port_write(port,(char*)(buf),len)
88
89 static int _send_cmd(GPPort *port,unsigned short cmd) {
90     unsigned char buf[2];
91     buf[0] = cmd>>8;
92     buf[1] = cmd&0xff;
93     return WRITE(port,buf,2);
94 }
95
96 static int _read_cmd(GPPort *port,unsigned short *xcmd) {
97         unsigned char buf[2];
98         int     i = 0,ret;
99         *xcmd = 0x4242;
100         do {
101                 if (1==(ret=READ(port,buf,1))) {
102                         if (buf[0]==0xff) {
103                             if (1==READ(port,buf+1,1)) {
104                                 *xcmd = (buf[0] << 8)| buf[1];
105                                 return GP_OK;
106                             }
107                         }
108                 } else {
109                     return ret;
110                 }
111         } while (i++<10);
112         return GP_ERROR_IO;
113 }
114
115 #if 0
116 static void _dump_buf(unsigned char *buf,int size) {
117         int i;
118         fprintf(stderr,"[");
119         for (i=0;i<size;i++)
120                 fprintf(stderr,"%02x ",buf[i]);
121         fprintf(stderr,"]\n");
122 }
123 #endif
124
125
126 static int _send_cmd_2(GPPort *port,unsigned short cmd, unsigned short *xcmd) {
127     unsigned char buf[2];
128     int ret, tries = 3;
129     *xcmd = 0x4242;
130     while (tries--) {
131         int i = 0;
132         buf[0] = cmd>>8;
133         buf[1] = cmd&0xff;
134         ret = WRITE(port,buf,2);
135         do {
136                 if (1==(ret=READ(port,buf,1))) {
137                         if (buf[0]==0xff) {
138                             if (1==READ(port,buf+1,1)) {
139                                 *xcmd = (buf[0] << 8)| buf[1];
140                                 return GP_OK;
141                             }
142                         }
143                 } else {
144                     return ret;
145                 }
146         } while (i++<3);
147     }
148     return GP_ERROR_IO;
149 }
150
151 int jd11_ping(GPPort *port) {
152         unsigned short xcmd;
153         char    buf[1];
154         int     ret,tries = 3;
155
156         while (tries--) {
157             ret = GP_ERROR_IO;
158             while (1==READ(port,buf,1))
159                     /* drain input queue before PING */;
160             ret=_send_cmd_2(port,0xff08,&xcmd);
161             if ((ret>=GP_OK) && (xcmd==0xfff1))
162                 return GP_OK;
163         }
164         return ret;
165 }
166
167 int
168 jd11_get_rgb(GPPort *port,float *red, float *green, float *blue) {
169         char    buf[10];
170         int     ret=GP_OK,tries=0,curread=0;
171
172         _send_cmd(port,0xffa7);
173         while ((curread<10) && (tries++<30)) {
174             ret=READ(port,buf+curread,sizeof(buf)-curread);
175             if (ret < 0)
176                 continue;
177             if (ret == 0)
178                 break;
179             curread+=ret;
180         }
181         if(curread<10) {
182             fprintf(stderr,"%d returned bytes on float query.\n",ret);
183             return GP_ERROR_IO;
184         }
185         /*_dump_buf(buf,10);*/
186         *green  = buf[1]+buf[2]*0.1+buf[3]*0.01;
187         *red    = buf[4]+buf[5]*0.1+buf[6]*0.01;
188         *blue   = buf[7]+buf[8]*0.1+buf[9]*0.01;
189         return GP_OK;
190 }
191
192 int
193 jd11_set_rgb(GPPort *port,float red, float green, float blue) {
194         unsigned char   buf[20];
195
196         _send_cmd(port,0xffa7);
197         buf[0] = 0xff;
198         buf[1] = (int)green;
199         buf[2] = ((int)(green*10))%10;
200         buf[3] = ((int)(green*100))%10;
201         buf[4] = (int)red;
202         buf[5] = ((int)(red*10))%10;
203         buf[6] = ((int)(red*100))%10;
204         buf[7] = (int)blue;
205         buf[8] = ((int)(blue*10))%10;
206         buf[9] = ((int)(blue*100))%10;
207         /*_dump_buf(buf,10);*/
208         return WRITE(port,buf,10);
209 }
210
211 int
212 jd11_select_index(GPPort *port) {       /* select index */
213         unsigned short xcmd;
214         int ret;
215
216         ret = _send_cmd_2(port,0xffa4,&xcmd);
217         if (ret < GP_OK)
218             return ret;
219         if (xcmd!=0xff01)
220             return GP_ERROR_IO;
221         return GP_OK;
222 }
223
224 int
225 jd11_select_image(GPPort *port,int nr) {        /* select image <nr> */
226         unsigned short xcmd;
227
228         _send_cmd(port,0xffa1);
229         _send_cmd(port,0xff00|nr);
230         _read_cmd(port,&xcmd);
231         if (xcmd != 0xff01)
232             return GP_ERROR_IO;
233         return GP_OK;
234 }
235
236 int
237 jd11_set_bulb_exposure(GPPort *port,int i) {
238         unsigned short xcmd;
239
240         if ((i<1) || (i>9))
241             return GP_ERROR_BAD_PARAMETERS;
242
243         _send_cmd(port,0xffa9);
244         _send_cmd(port,0xff00|i);
245         _read_cmd(port,&xcmd);
246         return GP_OK;
247 }
248
249 #if 0
250 static void jd11_TestADC(GPPort *port) {
251         unsigned short xcmd;
252
253         _send_cmd(port,0xff75);
254         _read_cmd(port,&xcmd);
255         fprintf(stderr,"TestADC: done, xcmd=%x\n",xcmd);
256 }
257 static void cmd_TestDRAM(GPPort *port) {
258         unsigned short xcmd;
259
260         _send_cmd(port,0xff72);
261         _read_cmd(port,&xcmd);
262         fprintf(stderr,"TestDRAM: done.\n");
263 }
264
265 /* doesn't actually flash */
266 static void cmd_TestFLASH(GPPort *port) {
267         unsigned short xcmd;
268
269         _send_cmd(port,0xff73);
270         _read_cmd(port,&xcmd);
271         fprintf(stderr,"TestFLASH: xcmd = %x.\n",xcmd);
272 }
273
274 /* some kind of selftest  ... shuts the shutters, beeps... only stops by 
275  * powercycle. */
276 static void cmd_79(GPPort *port) {
277         unsigned short xcmd;
278
279         _send_cmd(port,0xff79);
280         _read_cmd(port,&xcmd);
281         fprintf(stderr,"79: done, xcmd =%x\n",xcmd);
282 }
283 #endif
284
285
286 static int
287 jd11_imgsize(GPPort *port) {
288         char    buf[20];
289         int     ret;
290         int     i=0,curread=0;
291
292         _send_cmd(port,0xfff0);
293         do {
294                 ret=READ(port,&buf[curread],10-curread);
295                 if (ret>0)
296                     curread+=ret;
297                 usleep(1000);
298         } while ((i++<20) && (curread<10));
299         /*_dump_buf(buf,curread);*/
300         if (!curread) /* We get 0 bytes return for 0 images. */
301             return 0;
302         ret=strtol(&buf[2],NULL,16);
303         return ret;
304 }
305
306 static int
307 getpacket(GPPort *port,unsigned char *buf, int expect) {
308         int curread = 0, csum = 0;
309         int tries = 0;
310         if (expect == 200)
311             expect++;
312         while (tries++<5) {
313                 int i=0,ret;
314
315                 do {
316                         ret=READ(port,buf+curread,expect-curread);
317                         if (ret>0) {
318                                 curread+=ret;
319                                 i=0;
320                                 continue;
321                         }
322                         usleep(100);
323                 } while ((i++<2) && (curread<expect));
324                 if (curread!=expect) {
325                     if (!curread)
326                         return 0;
327                     _send_cmd(port,0xfff3);
328                     curread = csum = 0;
329                     continue;
330                 }
331                 /*printf("curread is %d\n",curread);*/
332                 /*printf("PACKET:");_dump_buf(buf,curread);*/
333                 for (i=0;i<curread-1;i++)
334                         csum+=buf[i];
335                 if (buf[curread-1]==(csum&0xff) || (curread!=201))
336                         return curread-1;
337                 fprintf(stderr,"BAD CHECKSUM %x vs %x, trying resend...\n",buf[curread-1],csum&0xff);
338                 _send_cmd(port,0xfff3);
339                 curread = csum = 0;
340                 /*return curread-1;*/
341         }
342         fprintf(stderr,"Giving up after 5 tries.\n");
343         return 0;
344 }
345
346 int
347 jd11_erase_all(GPPort *port) {
348         return _send_cmd(port,0xffa6);
349 }
350
351 /* This function reads all thumbnails at once and initializes the whole
352  * camera filesystem. This can be done, because finding out how much 
353  * pictures are on the camera is done by reading the whole preview picture
354  * stream anyway.
355  * And since the file infos are static mostly, why not just set them too at
356  * the same time.
357  */
358 int
359 jd11_index_reader(GPPort *port, CameraFilesystem *fs, GPContext *context) {
360     int         i, id, count, xsize, curread=0, ret=0;
361     unsigned char       *indexbuf;
362
363     ret = jd11_select_index(port);
364     if (ret != GP_OK)
365         return ret;
366     xsize = jd11_imgsize(port);
367     if (!xsize) { /* shortcut, no reading needed */
368         return GP_OK;
369     }
370     count = xsize/(64*48);
371     xsize = count * (64*48);
372     indexbuf = malloc(xsize);
373     if (!indexbuf) return GP_ERROR_NO_MEMORY;
374     id = gp_context_progress_start (context, xsize,
375                                     _("Downloading thumbnail..."));
376     _send_cmd(port,0xfff1);
377     while (curread < xsize) {
378             int readsize = xsize-curread;
379             if (readsize>200) readsize = 200;
380             ret=getpacket(port,indexbuf+curread,readsize);
381             if (ret==0)
382                     break;
383             curread+=ret;
384             if (ret<200)
385                     break;
386             gp_context_progress_update (context, id, curread);
387             if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
388                 /* What to do...Just free the stuff we allocated for now.*/
389                 free(indexbuf);
390                 return GP_ERROR_CANCEL;
391             }
392             _send_cmd(port,0xfff1);
393     }
394     gp_context_progress_stop (context, id);
395     for (i=0;i<count;i++) {
396         CameraFile      *file;
397         char            fn[20];
398         unsigned char *src;
399         unsigned char thumb[64*48];
400         int y;
401         CameraFileInfo  info;
402         
403         ret = gp_file_new(&file);
404         if (ret!=GP_OK) {
405             free(indexbuf);
406             return ret;
407         }
408         sprintf(fn,"image%02i.pgm",i);
409         gp_file_set_type (file, GP_FILE_TYPE_PREVIEW);
410         gp_file_set_name(file, fn);
411         gp_file_set_mime_type(file, GP_MIME_PGM);
412         gp_file_append(file, THUMBHEADER, strlen(THUMBHEADER));
413         src = indexbuf+(i*64*48);
414         for (y=0;y<48;y++) {
415             int x,off = 64*y;
416             for (x=0;x<64;x++)
417                 thumb[47*64-off+(63-x)] = src[off+x];
418         }
419         ret = gp_file_append(file,(char*)thumb,sizeof(thumb));
420         if (ret != GP_OK) {
421                 gp_file_free (file);
422                 return ret;
423         }
424         ret = gp_filesystem_append(fs, "/", fn, context);
425         if (ret != GP_OK) {
426                 /* should perhaps remove the entry again */
427                 gp_file_free (file);
428                 return ret;
429         }
430         ret = gp_filesystem_set_file_noop(fs, "/", file, context);
431         if (ret != GP_OK) return ret;
432
433         /* we also get the fs info for free, so just set it */
434         info.file.fields = GP_FILE_INFO_TYPE | GP_FILE_INFO_NAME | 
435                         GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
436                         GP_FILE_INFO_SIZE;
437         strcpy(info.file.type,GP_MIME_PNM);
438         strcpy(info.file.name,fn);
439         info.file.width         = 640;
440         info.file.height        = 480;
441         info.file.size          = 640*480*3+strlen(IMGHEADER);
442         info.preview.fields = GP_FILE_INFO_TYPE |
443                         GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT | 
444                         GP_FILE_INFO_SIZE;
445         strcpy(info.preview.type,GP_MIME_PGM);
446         info.preview.width      = 64;
447         info.preview.height     = 48;
448         info.preview.size       = 64*48+strlen(THUMBHEADER);
449         ret = gp_filesystem_set_info_noop(fs, "/", info, context);
450     }
451     free(indexbuf);
452     return GP_OK;
453 }
454
455 static int
456 serial_image_reader(Camera *camera,CameraFile *file,int nr,unsigned char ***imagebufs,int *sizes, GPContext *context) {
457     int picnum,curread,ret=0;
458     GPPort *port = camera->port;
459     unsigned int id;
460
461     jd11_select_image(port,nr);
462     *imagebufs = (unsigned char**)malloc(3*sizeof(char**));
463     for (picnum=0;picnum<3;picnum++) {
464         curread=0;
465         sizes[picnum] = jd11_imgsize(port);
466         (*imagebufs)[picnum]=(unsigned char*)malloc(sizes[picnum]+400);
467         _send_cmd(port,0xfff1);
468         id = gp_context_progress_start (context, sizes[picnum],
469                         _("Downloading data..."));
470         while (curread<sizes[picnum]) {
471             int readsize = sizes[picnum]-curread;
472             if (readsize > 200) readsize = 200;
473             ret=getpacket(port,(*imagebufs)[picnum]+curread,readsize);
474             if (ret==0)
475                 break;
476             curread+=ret;
477             if (ret<200)
478                 break;
479             gp_context_progress_update (context, id, curread);
480             if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
481                 int j;
482                 /* What to do ... Just free the stuff we allocated for now. */
483                 for (j=0;j<picnum;j++)
484                     free((*imagebufs)[picnum]);
485                 free(*imagebufs);
486                 return GP_ERROR_CANCEL;
487             }
488             _send_cmd(port,0xfff1);
489         }
490         gp_context_progress_stop (context, id);
491     }
492     return GP_OK;
493 }
494
495
496 int
497 jd11_get_image_full(
498     Camera *camera, CameraFile*file, int nr, int raw, GPContext *context
499 ) {
500     unsigned char       *s,*uncomp[3],**imagebufs;
501     int                 ret,sizes[3];
502     unsigned char       *data;
503     int                 h;
504
505     ret = serial_image_reader(camera,file,nr,&imagebufs,sizes, context);
506     if (ret!=GP_OK)
507         return ret;
508     uncomp[0] = malloc(320*480);
509     uncomp[1] = malloc(320*480/2);
510     uncomp[2] = malloc(320*480/2);
511     if (sizes[0]!=115200) {
512             picture_decomp_v1(imagebufs[0],uncomp[0],320,480);
513             picture_decomp_v1(imagebufs[1],uncomp[1],320,480/2);
514             picture_decomp_v1(imagebufs[2],uncomp[2],320,480/2);
515     } else {
516             picture_decomp_v2(imagebufs[0],uncomp[0],320,480);
517             picture_decomp_v2(imagebufs[1],uncomp[1],320,480/2);
518             picture_decomp_v2(imagebufs[2],uncomp[2],320,480/2);
519     }
520     gp_file_append(file, IMGHEADER, strlen(IMGHEADER));
521     data = malloc(640*480*3);
522     if (!raw) {
523         unsigned char *bayerpre;
524         s = bayerpre = malloc(640*480);
525         /* note that picture is upside down and left<->right mirrored */
526         for (h=480;h--;) {
527             int w;
528             for (w=320;w--;) {
529                 if (h&1) {
530                     /* G B G B G B G B G */
531                     *s++ = uncomp[2][(h/2)*320+w];
532                     *s++ = uncomp[0][h*320+w];
533                 } else {
534                     /* R G R G R G R G R */
535                     *s++ = uncomp[0][h*320+w];
536                     *s++ = uncomp[1][(h/2)*320+w];
537                 }
538             }
539         }
540         gp_bayer_decode(bayerpre,640,480,data,BAYER_TILE_RGGB);
541         free(bayerpre);
542     } else {
543         s=data;
544         for (h=480;h--;) { /* upside down */
545             int w;
546             for (w=640;w--;) { /* right to left */
547                 /* and images are in green red blue */
548                 *s++=uncomp[1][(h/2)*320+(w/2)];
549                 *s++=uncomp[0][h*320+(w/2)];
550                 *s++=uncomp[2][(h/2)*320+(w/2)];
551             }
552         }
553     }
554     free(uncomp[0]);free(uncomp[1]);free(uncomp[2]);
555     free(imagebufs[0]);free(imagebufs[1]);free(imagebufs[2]);free(imagebufs);
556     gp_file_append(file, (char*)data, 640*480*3);
557     free(data);
558     return GP_OK;
559 }