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