1 /* sonydscf1.c
2  *
3  * Copyright (C) M. Adam Kendall <joker@penguinpub.com>
4  * Copyright (C) 2002 Bart van Leeuwen <bart@netage.nl>
5  *
6  * Based on the chotplay CLI interface from Ken-ichi Hayashi 1996,1997
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA  02110-1301  USA
22  */
23 
24 #include "config.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 
30 #include <gphoto2/gphoto2.h>
31 
32 #ifdef ENABLE_NLS
33 #  include <libintl.h>
34 #  undef _
35 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
36 #  ifdef gettext_noop
37 #    define N_(String) gettext_noop (String)
38 #  else
39 #    define N_(String) (String)
40 #  endif
41 #else
42 #  define _(String) (String)
43 #  define N_(String) (String)
44 #endif
45 
46 #include "command.h"
47 #include "pmp.h"
48 
49 #define JPEG 0
50 #define JPEG_T 1
51 #define PMP 2
52 #define PMX 3
53 
54 #define PMF_MAXSIZ 3*1024
55 
56 #define MAX_PICTURE_NUM 200
57 static unsigned char  picture_index[MAX_PICTURE_NUM];
58 static unsigned short picture_thumbnail_index[MAX_PICTURE_NUM];
59 static unsigned char  picture_protect[MAX_PICTURE_NUM];
60 static unsigned char  picture_rotate[MAX_PICTURE_NUM];
61 
62 static int
make_jpeg_comment(unsigned char * buf,unsigned char * jpeg_comment)63 make_jpeg_comment(unsigned char *buf, unsigned char *jpeg_comment)
64 {
65   int i, cur = 0;
66   int reso, shutter;
67 
68   struct resolution {
69     int reso_val;
70     char *reso_conv;
71   } reso_tab[] = {
72     {PMP_FIN, "fine"},
73     {PMP_STD, "standard"},
74     {PMP_ECM, "economy"},
75     {0,       "unknown"},
76   };
77 
78   struct sh_speed {
79     int spd_val;
80     char *spd_conv;
81   } sh_speed_tab[] = {
82     {0x0123, "1/7.5"},
83     {0x0187, "1/15"},
84     {0x01eb, "1/30"},
85     {0x024f, "1/60"},
86     {0x0298, "1/100"},
87     {0x031d, "1/250"},
88     {0x0381, "1/500"},
89     {0x03e5, "1/1000"},
90     {0,      "unknown"},
91   };
92 
93   jpeg_comment[0] = 0xff;
94   jpeg_comment[1] = 0xd8;
95   jpeg_comment[2] = 0xff;
96   jpeg_comment[3] = 0xfe;
97 
98   /* resolution */
99   reso = *(buf+PMP_RESOLUTION);
100 
101   i = 0;
102   while (1) {
103     if ((reso == reso_tab[i].reso_val) || (reso_tab[i].reso_val == 0)) {
104       cur = 6 + sprintf((char*)&jpeg_comment[6], "Resolution: %s\n",
105                           reso_tab[i].reso_conv);
106       break;
107     }
108     i++;
109   }
110 
111   /* shutter speed */
112   shutter = (buf[PMP_SPEED]<<8)|buf[PMP_SPEED+1];
113 
114   i = 0;
115   while (1) {
116     if ((shutter == sh_speed_tab[i].spd_val) ||
117         (sh_speed_tab[i].spd_val == 0)) {
118       cur = cur + sprintf((char*)&jpeg_comment[cur], "Shutter-speed: %s\n",
119                           sh_speed_tab[i].spd_conv);
120       break;
121     }
122     i++;
123   }
124 
125   /* PMP comment */
126   if (*(buf+PMP_COMMENT)) {
127     cur = cur + sprintf((char*)&jpeg_comment[cur], "Comment: %s\n",
128                         (char *)(buf+PMP_COMMENT));
129   }
130 
131   /* taken date */
132   if (*(buf+PMP_TAKE_YEAR) == 0xff) {
133     cur = cur + sprintf((char*)&jpeg_comment[cur],
134                         "Date-Taken: ----/--/-- --:--:--\n");
135   }
136   else {
137     cur = cur + sprintf((char*)&jpeg_comment[cur],
138                         "Date-Taken: %d/%02d/%02d %02d:%02d:%02d\n",
139     2000+(*(buf+PMP_TAKE_YEAR)), *(buf+PMP_TAKE_MONTH),
140     *(buf+PMP_TAKE_DATE), *(buf+PMP_TAKE_HOUR), *(buf+PMP_TAKE_MINUTE),
141     *(buf+PMP_TAKE_SECOND));
142   }
143 
144   /* edited date */
145   if (*(buf+PMP_EDIT_YEAR) == 0xff) {
146     cur = cur + sprintf((char*)&jpeg_comment[cur],
147                         "Date-Edited: ----/--/-- --:--:--\n");
148   }
149   else {
150     cur = cur + sprintf((char*)&jpeg_comment[cur],
151                         "Date-Edited: %d/%02d/%02d %02d:%02d:%02d\n",
152     2000+(*(buf+PMP_EDIT_YEAR)), *(buf+PMP_EDIT_MONTH),
153     *(buf+PMP_EDIT_DATE), *(buf+PMP_EDIT_HOUR), *(buf+PMP_EDIT_MINUTE),
154     *(buf+PMP_EDIT_SECOND));
155   }
156 
157   /* use flash? */
158   if (*(buf+PMP_FLASH) != 0) {
159     cur = cur + sprintf((char*)&jpeg_comment[cur], "Flash: on\n");
160   }
161 
162   /* insert total jpeg comment length */
163   jpeg_comment[4] = (unsigned char)((cur - 4) >> 8);
164   jpeg_comment[5] = (unsigned char)(cur - 4);
165 
166   return cur;
167 }
168 
169 static int
get_picture_information(GPPort * port,int * pmx_num,int outit)170 get_picture_information(GPPort *port,int *pmx_num, int outit)
171 {
172   unsigned char buforg[PMF_MAXSIZ];
173   char name[64];
174   int i, n;
175   int j, k;
176   char *buf = (char *) &buforg;
177 
178   strcpy(name, "/PIC_CAM/PIC00000/PIC_INF.PMF");
179   F1ok(port);
180   F1getdata(port, name, (unsigned char *)buf);
181 
182   n = buf[26] * 256 + buf[27]; /* how many files */
183   *pmx_num = buf[31];  /* ??? */
184 
185   if(n ==10)
186      buf++;
187 
188   k = 0;
189   for(i = 0 ; i < (int) *pmx_num ; i++){
190     for(j = 0 ; j < buforg[0x20 + 4 * i + 3]; j++){
191       picture_thumbnail_index[k] = (j << 8) | buforg[0x20 + 4 * i] ;
192       k++;
193     }
194   }
195   for(i = 0 ; i < n ; i++){
196     picture_index[i] = buf[0x420 + 0x10 * i + 3];
197     picture_rotate[i] = buf[0x420 + 0x10 * i + 5];
198     picture_protect[i] = buf[0x420 + 0x10 * i + 14];
199   }
200 
201   if(outit == 2){
202       fprintf(stdout," No:Internal name:Thumbnail name(Nth):Rotate:Protect\n");
203     for(i = 0 ; i < n ; i++){
204       fprintf(stdout,"%03d:", i + 1);
205       fprintf(stdout," PSN%05d.PMP:", picture_index[i]);
206       fprintf(stdout,"PIDX%03d.PMX(%02d)    :",
207               0xff & picture_thumbnail_index[i],
208               0xff & (picture_thumbnail_index[i] >> 8));
209       switch(picture_rotate[i]){
210       case 0x00:
211         fprintf(stdout,"     0:");
212         break;
213       case 0x04:
214         fprintf(stdout,"   270:");
215         break;
216       case 0x08:
217         fprintf(stdout,"   180:");
218         break;
219       case 0x0c:
220         fprintf(stdout,"    90:");
221         break;
222       default:
223         fprintf(stdout,"   ???:");
224         break;
225       }
226       if(picture_protect[i])
227         fprintf(stdout,"on");
228       else
229         fprintf(stdout,"off");
230       fprintf(stdout,"\n");
231     }
232   }
233   return(n);
234 }
235 
236 static int
get_file(GPPort * port,char * name,CameraFile * file,int format,GPContext * context)237 get_file(GPPort *port, char *name, CameraFile *file, int format, GPContext *context)
238 {
239   unsigned long filelen;
240   unsigned long total = 0;
241   long len,jpegcommentlen;
242   unsigned char buf[0x400];
243   unsigned char jpeg_comment[256];
244   int ret, id;
245 
246   F1ok(port);
247   F1status(port);
248 
249   filelen = F1finfo(port,name);
250   if(filelen == 0)
251     return GP_ERROR;
252 
253   if(F1fopen(port,name) != 0)
254     return GP_ERROR_IO;
255 
256   if(format != JPEG)
257     return GP_ERROR;
258 
259   len = F1fread(port, buf, 126);
260   if( len < 126){
261     F1fclose(port);
262     return GP_ERROR_IO_READ;
263   }
264   jpegcommentlen = make_jpeg_comment(buf, jpeg_comment);
265   ret = gp_file_append (file, (char *)jpeg_comment, jpegcommentlen);
266   if (ret < GP_OK) return ret;
267 
268   total = 126;
269   id = gp_context_progress_start (context, filelen,
270                                     _("Downloading data..."));
271   ret = GP_OK;
272   while((len = F1fread(port, buf, 0x0400)) != 0){
273     if(len < 0)
274       return GP_ERROR_IO_READ;
275     total = total + len;
276     gp_file_append (file, (char *)buf, len);
277     gp_context_progress_update (context, id, total);
278     if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
279 	ret = GP_ERROR_CANCEL;
280         break;
281     }
282   }
283   gp_context_progress_stop (context, id);
284   F1fclose(port);
285   return ret;
286 }
287 
288 static long
get_thumbnail(GPPort * port,char * name,CameraFile * file,int format,int n)289 get_thumbnail(GPPort *port,char *name, CameraFile *file, int format, int n)
290 {
291   unsigned long filelen;
292   unsigned long total = 0;
293   long len;
294   int i;
295   unsigned char buf[0x1000];
296   unsigned char *p;
297 
298   p = buf;
299 
300   F1ok(port);
301   F1status(port);
302 
303   filelen = F1finfo(port,name);
304   if(filelen == 0)
305     return GP_ERROR_IO;
306 
307   if(F1fopen(port,name) != 0)
308     return GP_ERROR_IO;
309 
310   for( i = 0 ; i < n ; i++)
311     len = F1fseek(port, 0x1000, 1);
312 
313   while((len = F1fread(port, p, 0x0400)) != 0){
314     if(len < 0){
315       F1fclose(port);
316       return GP_ERROR_IO_READ;
317     }
318     total = total + len;
319     p = p + len;
320     if(total >= 0x1000)
321       break;
322   }
323   F1fclose(port);
324 
325   filelen = buf[12] * 0x1000000 + buf[13] * 0x10000 +
326     buf[14] * 0x100 + buf[15];
327 
328   return gp_file_append (file, (char *)&buf[256], filelen);
329 }
330 
331 #if 0
332 static void
333 get_date_info(GPPort *port, char *name, char *outfilename ,char *newfilename)
334 {
335   char *p, *q;
336   int year = 0;
337   int month = 0;
338   int date = 0;
339   int hour = 0;
340   int minute = 0;
341   int second = 0;
342   unsigned char buf[128];
343 
344   F1ok(port);
345   F1status(port);
346 
347   (void) F1finfo(port, name);
348   if(F1fopen(port, name) ==0){
349     if(F1fread(port, buf, 126) == 126){
350       if(*(buf+PMP_TAKE_YEAR) != 0xff){
351         year = (int) *(buf+PMP_TAKE_YEAR);
352         month = (int) *(buf+PMP_TAKE_MONTH);
353         date = (int) *(buf+PMP_TAKE_DATE);
354         hour = (int) *(buf+PMP_TAKE_HOUR);
355         minute = (int) *(buf+PMP_TAKE_MINUTE);
356         second = (int) *(buf+PMP_TAKE_SECOND);
357       }
358     }
359     F1fclose(port);
360   }
361 
362   p = outfilename;
363   q = newfilename;
364   while(*p){
365     if(*p == '%'){
366       p++;
367       switch(*p){
368       case '%':
369         *q = '%';
370         break;
371       case 'H':
372         q = q + sprintf(q, "%02d", hour);
373         break;
374       case 'M':
375         q = q + sprintf(q, "%02d", minute);
376         break;
377        case 'S':
378         q = q + sprintf(q, "%02d", second);
379         break;
380       case 'T':
381 #ifdef BINARYFILEMODE
382         q = q + sprintf(q, "%02d%02d%02d", hour, minute, date);
383 #else
384         q = q + sprintf(q, "%02d:%02d:%02d", hour, minute, date);
385 #endif
386         break;
387       case 'y':
388         q = q + sprintf(q, "%02d", year);
389         break;
390       case 'm':
391         q = q + sprintf(q, "%02d", month);
392         break;
393       case 'd':
394         q = q + sprintf(q, "%02d", date);
395         break;
396       case 'D':
397 #ifdef BINARYFILEMODE
398         q = q + sprintf(q, "%02d%02d%02d", year, month, date);
399 #else
400         q = q + sprintf(q, "%02d_%02d_%02d", year, month, date);
401 #endif
402         break;
403       default:
404         q = q + sprintf(q, "%%%c", *p);
405         break;
406       }
407       p++;
408     }else
409       *q++ = *p++;
410   }
411   *q = 0;
412 
413 }
414 #endif
415 
416 static int
get_picture(GPPort * port,int n,CameraFile * file,int format,int ignore,int all_pic_num,GPContext * context)417 get_picture(GPPort *port, int n, CameraFile *file, int format, int ignore, int all_pic_num,
418 GPContext *context)
419 {
420   long  len;
421   char name[64];
422   char name2[64];
423   int i;
424 
425   fprintf(stderr,"all_pic_num 1 %d\n", all_pic_num);
426   all_pic_num = get_picture_information(port,&i,0);
427   fprintf(stderr,"all_pic_num 2 %d\n", all_pic_num);
428 
429 
430 retry:
431 
432   if (all_pic_num < n) {
433     fprintf(stderr, "picture number %d is too large. %d\n",all_pic_num,n);
434     return(GP_ERROR);
435    }
436 
437   switch(format){
438   case PMX:
439     sprintf(name, "/PIC_CAM/PIC00000/PIDX%03d.PMX", n - 1);
440     break;
441   case JPEG_T:
442     sprintf(name, "/PIC_CAM/PIC00000/PIDX%03d.PMX",
443             (picture_thumbnail_index[n] & 0xff));
444     break;
445   case JPEG:
446   case PMP:
447   default:
448     if(ignore)
449       sprintf(name, "/PIC_CAM/PIC00000/PSN%05d.PMP", n);
450     else
451       sprintf(name, "/PIC_CAM/PIC00000/PSN%05d.PMP", picture_index[n]);
452     break;
453   }
454   if(ignore)
455     sprintf(name2, "/PIC_CAM/PIC00000/PSN%05d.PMP", n );
456   else
457     sprintf(name2, "/PIC_CAM/PIC00000/PSN%05d.PMP", picture_index[n]);
458 
459   /* printf("name %s, name2 %s, %d\n",name,name2,n); */
460 
461   if(0)
462     switch(format){
463     case PMX:
464       fprintf(stdout, "pidx%03d.pmx: ", n -1 );
465       break;
466     case JPEG_T:
467       fprintf(stderr, "Thumbnail %03d: ", n);
468       break;
469     case PMP:
470     case JPEG:
471     default:
472       fprintf(stdout, "Picture %03d: ", n);
473       break;
474     }
475 
476   if(format == JPEG_T)
477     len = get_thumbnail(port, name, file, format,
478                         0xff & (picture_thumbnail_index[n] >> 8));
479   else
480     len = get_file(port, name, file, format, context);
481   if(len < GP_OK )
482     goto retry;
483 
484   return(len);
485 }
486 
camera_id(CameraText * id)487 int camera_id (CameraText *id) {
488         strcpy(id->text, "sonydscf1-bvl");
489         return (GP_OK);
490 }
491 
camera_abilities(CameraAbilitiesList * list)492 int camera_abilities (CameraAbilitiesList *list) {
493         CameraAbilities a;
494 
495 	memset (&a, 0, sizeof(a));
496         strcpy(a.model, "Sony:DSC-F1");
497 	a.status = GP_DRIVER_STATUS_EXPERIMENTAL;
498         a.port	= GP_PORT_SERIAL;
499         a.speed[0] = 9600;
500         a.speed[1] = 19200;
501         a.speed[2] = 38400;
502         a.operations        =  GP_OPERATION_NONE;
503         a.file_operations   =  GP_FILE_OPERATION_DELETE;
504         a.folder_operations =  GP_FOLDER_OPERATION_NONE;
505         return gp_abilities_list_append(list, a);
506 }
507 
camera_exit(Camera * camera,GPContext * context)508 static int camera_exit (Camera *camera, GPContext *context) {
509         if(F1ok(camera->port))
510            return(GP_ERROR);
511         return (F1fclose(camera->port));
512 }
513 
get_file_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileType type,CameraFile * file,void * user_data,GPContext * context)514 static int get_file_func (CameraFilesystem *fs, const char *folder,
515 			  const char *filename, CameraFileType type,
516 			  CameraFile *file, void *user_data, GPContext *context)
517 {
518 	Camera *camera = user_data;
519         int num;
520 
521         gp_log (GP_LOG_DEBUG, "sonyf1/get_file_func","folder: %s, file: %s", folder, filename);
522 
523         if(!F1ok(camera->port))
524            return (GP_ERROR);
525 
526 	gp_file_set_mime_type (file, GP_MIME_JPEG);
527 
528         /* Retrieve the number of the photo on the camera */
529 	num = gp_filesystem_number(camera->fs, "/", filename, context);
530 	if (num < GP_OK)
531 		return num;
532 
533 	switch (type) {
534 	case GP_FILE_TYPE_NORMAL:
535 		return get_picture (camera->port, num, file, JPEG, 0, F1howmany(camera->port), context);
536 	case GP_FILE_TYPE_PREVIEW:
537 		return get_picture (camera->port, num, file, JPEG_T, TRUE, F1howmany(camera->port), context);
538 	default:
539 		return (GP_ERROR_NOT_SUPPORTED);
540 	}
541         return GP_OK;
542 }
543 
544 static int
delete_file_func(CameraFilesystem * fs,const char * folder,const char * filename,void * data,GPContext * context)545 delete_file_func (CameraFilesystem *fs, const char *folder,
546 	     const char *filename, void *data,
547 	     GPContext *context)
548 {
549 	Camera *camera = data;
550 	int max, num;
551 
552 	gp_log (GP_LOG_DEBUG, "sonydscf1/delete_file_func", "%s / %s", folder, filename);
553 	num = gp_filesystem_number(camera->fs, "/", filename, context);
554 	if (num<GP_OK)
555 		return num;
556 	max = gp_filesystem_count(camera->fs,folder, context);
557 	if (max<GP_OK)
558 		return max;
559 	gp_log (GP_LOG_DEBUG, "sonydscf1/delete_file_func", "file nr %d", num);
560 	if(!F1ok(camera->port))
561 		return GP_ERROR;
562 	if(picture_protect[num] != 0x00){
563 		gp_log (GP_LOG_ERROR, "sonydscf1/delete_file_func", "picture %d is protected.", num);
564 		return GP_ERROR;
565 	}
566 	return F1deletepicture(camera->port, picture_index[num]);
567 }
568 
569 static int
camera_summary(Camera * camera,CameraText * summary,GPContext * context)570 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
571 {
572         int i;
573 
574         if(!F1ok(camera->port))
575            return (GP_ERROR);
576         get_picture_information(camera->port,&i,2);
577         return (F1newstatus(camera->port, 1, summary->text));
578 }
579 
camera_about(Camera * camera,CameraText * about,GPContext * context)580 static int camera_about (Camera *camera, CameraText *about, GPContext *context)
581 {
582         strcpy(about->text,
583 _("Sony DSC-F1 Digital Camera Support\nM. Adam Kendall <joker@penguinpub.com>\nBased on the chotplay CLI interface from\nKen-ichi Hayashi\nGphoto2 port by Bart van Leeuwen <bart@netage.nl>"));
584 
585         return (GP_OK);
586 }
587 
file_list_func(CameraFilesystem * fs,const char * folder,CameraList * list,void * data,GPContext * context)588 static int file_list_func (CameraFilesystem *fs, const char *folder,
589 			   CameraList *list, void *data, GPContext *context)
590 {
591 	Camera *camera = data;
592         F1ok(camera->port);
593         /*if(F1ok(camera->port))
594            return(GP_ERROR);*/
595         /* Populate the list */
596         return gp_list_populate(list, "PSN%05i.jpg", F1howmany(camera->port));
597 }
598 
599 static CameraFilesystemFuncs fsfuncs = {
600 	.file_list_func = file_list_func,
601 	.get_file_func = get_file_func,
602 	.del_file_func = delete_file_func,
603 };
604 
camera_init(Camera * camera,GPContext * context)605 int camera_init (Camera *camera, GPContext *context) {
606         GPPortSettings settings;
607 
608         camera->functions->exit         = camera_exit;
609         camera->functions->summary      = camera_summary;
610         camera->functions->about        = camera_about;
611 
612 	/* Configure the port */
613         gp_port_set_timeout (camera->port, 5000);
614 	gp_port_get_settings (camera->port, &settings);
615         settings.serial.bits    = 8;
616         settings.serial.parity  = 0;
617         settings.serial.stopbits= 1;
618         gp_port_set_settings (camera->port, settings);
619 
620 	/* Set up the filesystem */
621 	return gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
622 }
623 
624