1 /****************************************************************/
2 /* library.c - Gphoto2 library for accessing the Panasonic */
3 /* Coolshot KXL-600A & KXL-601A digital cameras. */
4 /* */
5 /* Copyright 2001 Chris Pinkham */
6 /* */
7 /* Author: Chris Pinkham <cpinkham@infi.net> */
8 /* */
9 /* This library is free software; you can redistribute it */
10 /* and/or modify it under the terms of the GNU Library General */
11 /* Public License as published by the Free Software Foundation; */
12 /* either version 2 of the License, or (at your option) any */
13 /* later version. */
14 /* */
15 /* This library is distributed in the hope that it will be */
16 /* useful, but WITHOUT ANY WARRANTY; without even the implied */
17 /* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
18 /* PURPOSE. See the GNU Library General Public License for */
19 /* more details. */
20 /* */
21 /* You should have received a copy of the GNU Library General */
22 /* Public License along with this library; if not, write to the */
23 /* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,*/
24 /* Boston, MA 02110-1301 USA */
25 /****************************************************************/
26
27 #define _POSIX_C_SOURCE___ 199309L
28 #define _DEFAULT_SOURCE
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <gphoto2/gphoto2.h>
35 #include <time.h>
36 #include "library.h"
37
38 #ifdef ENABLE_NLS
39 # include <libintl.h>
40 # undef _
41 # define _(String) dgettext (GETTEXT_PACKAGE, String)
42 # ifdef gettext_noop
43 # define N_(String) gettext_noop (String)
44 # else
45 # define N_(String) (String)
46 # endif
47 #else
48 # define textdomain(String) (String)
49 # define gettext(String) (String)
50 # define dgettext(Domain,Message) (Message)
51 # define dcgettext(Domain,Message,Type) (Message)
52 # define bindtextdomain(Domain,Directory) (Domain)
53 # define _(String) (String)
54 # define N_(String) (String)
55 #endif
56
57 #define GP_MODULE "coolshot"
58
59 #define COOL_SLEEP 10000
60
61 #define RETRIES 10
62
63 #define COOLSHOT_DONE 0x00
64 #define COOLSHOT_PKT 0x01
65 #define COOLSHOT_ENQ 0x05
66 #define COOLSHOT_ACK 0x06
67 #define COOLSHOT_NAK 0x15
68
69
70 static int coolshot_ack (Camera *camera);
71 #if 0
72 static int coolshot_nak (Camera *camera);
73 #endif
74 static int coolshot_sp (Camera *camera);
75 static int coolshot_fs( Camera *camera, int number );
76 static int coolshot_write_packet (Camera *camera, char *packet);
77 static int coolshot_read_packet (Camera *camera, char *packet);
78 static int coolshot_check_checksum( char *packet, int length );
79 static int coolshot_download_image( Camera *camera, CameraFile *file,
80 char *buf, int *len, int thumbnail, GPContext *context );
81
82 static int packet_size = 500;
83
84 /* ??set mode?? */
coolshot_sm(Camera * camera)85 int coolshot_sm( Camera *camera ) {
86 char buf[16];
87
88 GP_DEBUG ("* coolshot_sm");
89
90 memset( buf, 0, sizeof( buf ));
91
92 buf[0] = COOLSHOT_PKT;
93 buf[2] = 'S';
94 buf[3] = 'M';
95 buf[4] = 0x01;
96 buf[15] = 0x02;
97
98 coolshot_write_packet( camera, buf );
99
100 /* read ACK */
101 coolshot_read_packet( camera, buf );
102
103 /* read data */
104 coolshot_read_packet( camera, buf );
105
106 /* send ACK */
107 coolshot_ack( camera );
108
109 packet_size = 128;
110
111 return( GP_OK );
112 }
113
114 /* ?set baud? */
coolshot_sb(Camera * camera,int speed)115 int coolshot_sb( Camera *camera, int speed ) {
116 char buf[16];
117 gp_port_settings settings;
118
119 GP_DEBUG ("* coolshot_sb");
120 GP_DEBUG ("*** speed: %i", speed);
121
122 memset( buf, 0, sizeof( buf ));
123
124 buf[0] = COOLSHOT_PKT;
125 buf[2] = 'S';
126 buf[3] = 'B';
127 buf[4] = 0x01;
128 buf[15] = 0x02;
129
130 gp_port_get_settings (camera->port, &settings);
131
132 switch (speed) {
133 case 9600:
134 buf[4] = '1';
135 settings.serial.speed = 9600;
136 break;
137 case -1:
138 case 19200:
139 buf[4] = '2';
140 settings.serial.speed = 19200;
141 break;
142 case 28800:
143 buf[4] = '3';
144 settings.serial.speed = 28800;
145 break;
146 case 38400:
147 buf[4] = '4';
148 settings.serial.speed = 38400;
149 break;
150 case 57600:
151 buf[4] = '5';
152 settings.serial.speed = 57600;
153 break;
154 case 0: /* Default speed */
155 case 115200:
156 buf[4] = '6';
157 settings.serial.speed = 115200;
158 break;
159 default:
160 return (GP_ERROR_IO_SERIAL_SPEED);
161 }
162
163 coolshot_enq( camera );
164
165 /* set speed */
166 coolshot_write_packet( camera, buf );
167
168 /* read ack */
169 coolshot_read_packet( camera, buf );
170
171 /* read OK */
172 coolshot_read_packet( camera, buf );
173
174 /* ack the OK */
175 coolshot_ack( camera );
176
177 CHECK (gp_port_set_settings (camera->port, settings));
178
179 usleep(10 * 1000);
180 return (GP_OK);
181 }
182
183 static
coolshot_fs(Camera * camera,int number)184 int coolshot_fs( Camera *camera, int number ) {
185 char buf[16];
186
187 GP_DEBUG ("* coolshot_fs");
188
189 memset( buf, 0, sizeof( buf ));
190
191 buf[0] = COOLSHOT_PKT;
192 buf[2] = 'F';
193 buf[3] = 'S';
194 buf[7] = number;
195 buf[15] = 0x02;
196
197 coolshot_enq( camera );
198
199 coolshot_write_packet( camera, buf );
200
201 /* read ACK */
202 coolshot_read_packet( camera, buf );
203
204 /* read data */
205 coolshot_read_packet( camera, buf );
206
207 /* send ACK */
208 coolshot_ack( camera );
209 return( GP_OK );
210 }
211
212 static
coolshot_sp(Camera * camera)213 int coolshot_sp( Camera *camera ) {
214 char buf[16];
215
216 GP_DEBUG ("* coolshot_sp");
217
218 memset( buf, 0, sizeof( buf ));
219
220 buf[0] = COOLSHOT_PKT;
221 buf[2] = 'S';
222 buf[3] = 'P';
223 buf[4] = 0x02;
224 buf[15] = 0x02;
225
226 coolshot_enq( camera );
227
228 coolshot_write_packet( camera, buf );
229
230 /* read ACK */
231 coolshot_read_packet( camera, buf );
232
233 packet_size = 500;
234
235 return( GP_OK );
236 }
237
coolshot_file_count(Camera * camera)238 int coolshot_file_count (Camera *camera) {
239 char buf[16];
240 int count = 0;
241
242 GP_DEBUG ("* coolshot_file_count");
243
244 memset( buf, 0, sizeof( buf ));
245
246 buf[0] = COOLSHOT_PKT;
247 buf[2] = 'R';
248 buf[3] = 'N';
249 buf[5] = 0x01;
250 buf[15] = 0x02;
251
252 coolshot_enq( camera );
253
254 /* request count */
255 coolshot_write_packet( camera, buf );
256
257 /* read ack */
258 coolshot_read_packet( camera, buf );
259
260 /* read data packet */
261 coolshot_read_packet( camera, buf );
262
263 count = buf[7];
264
265 usleep( COOL_SLEEP );
266 coolshot_ack( camera );
267
268 return( count );
269 }
270
coolshot_request_image(Camera * camera,CameraFile * file,char * buf,int * len,int number,GPContext * context)271 int coolshot_request_image( Camera *camera, CameraFile *file,
272 char *buf, int *len, int number, GPContext *context ) {
273 char packet[16];
274
275 GP_DEBUG ("* coolshot_request_image");
276
277 memset( packet, 0, sizeof( packet ));
278
279 packet[0] = COOLSHOT_PKT;
280 packet[2] = 'R';
281 packet[3] = 'D';
282 packet[7] = number;
283 packet[15] = 0x02;
284
285 /* fixme */
286 coolshot_fs( camera, number );
287 coolshot_sp( camera );
288
289 coolshot_enq( camera );
290
291 /* request image */
292 coolshot_write_packet( camera, packet );
293
294 /* read ack */
295 coolshot_read_packet( camera, packet );
296
297 /* read OK */
298 coolshot_read_packet( camera, packet );
299
300 /* read data */
301 coolshot_download_image( camera, file, buf, len, 0, context );
302
303 return( GP_OK );
304 }
305
coolshot_request_thumbnail(Camera * camera,CameraFile * file,char * buf,int * len,int number,GPContext * context)306 int coolshot_request_thumbnail( Camera *camera, CameraFile *file,
307 char *buf, int *len, int number, GPContext *context ) {
308 char packet[16];
309
310 GP_DEBUG ("* coolshot_request_thumbnail");
311
312 memset( packet, 0, sizeof( packet ));
313
314 packet[0] = COOLSHOT_PKT;
315 packet[2] = 'R';
316 packet[3] = 'M';
317 packet[7] = number;
318 packet[15] = 0x02;
319
320 /* fixme */
321 coolshot_fs( camera, number );
322 /*
323 coolshot_sp( camera );
324 */
325
326 coolshot_enq( camera );
327
328 /* request image */
329 coolshot_write_packet( camera, packet );
330
331 /* read ack */
332 coolshot_read_packet( camera, packet );
333
334 /* read OK */
335 coolshot_read_packet( camera, packet );
336
337 /* read data */
338 coolshot_download_image( camera, file, buf, len, 1, context );
339
340 return( GP_OK );
341 }
342
343 static
coolshot_check_checksum(char * packet,int length)344 int coolshot_check_checksum( char *packet, int length ) {
345 int checksum = 0;
346 int p_csum = 0;
347 int x;
348 unsigned char *ptr;
349
350 ptr = (unsigned char *)packet + 2;
351 for( x = 2; x < (length - 4 ); x++ ) {
352 checksum += *(ptr++);
353 /* checksum += (unsigned char)packet[x]; */
354 }
355 checksum &= 0xffff; /* 16 bit checksum */
356
357 p_csum = (unsigned char)packet[length - 4];
358 p_csum = p_csum << 8;
359 p_csum += (unsigned char)packet[length - 3];
360
361 if ( checksum == p_csum ) {
362 return( GP_OK );
363 } else {
364 return( GP_ERROR );
365 }
366 }
367
coolshot_download_image(Camera * camera,CameraFile * file,char * buf,int * len,int thumbnail,GPContext * context)368 int coolshot_download_image( Camera *camera, CameraFile *file,
369 char *buf, int *len, int thumbnail, GPContext *context ) {
370 char packet[1024];
371 int data_len;
372 int bytes_read = 0;
373 int last_good = 0;
374 unsigned int id;
375
376 GP_DEBUG ("* coolshot_download_image");
377
378 memset( packet, 0, sizeof( packet ));
379
380 packet[2] = '0';
381 packet[3] = '0';
382
383 coolshot_ack( camera );
384
385 coolshot_read_packet( camera, packet );
386
387 data_len = (unsigned char)packet[6] * 256;
388 data_len += (unsigned char)packet[7];
389
390 /* fixme, get rid of hardcoded length */
391 if ( coolshot_check_checksum( packet, 8 + packet_size + 4 ) == GP_OK ) {
392 coolshot_ack( camera );
393 last_good = 1;
394 } else {
395 /*
396 coolshot_nak( camera );
397 */
398 last_good = 0;
399 }
400
401 id = gp_context_progress_start (context, thumbnail ? 1800 : 80000,
402 _("Downloading image..."));
403 while( strncmp( packet + 2, "DT", 2 ) == 0 ) {
404 /* process packet */
405 if ( last_good ) {
406 data_len = (unsigned char)packet[6] * 256;
407 data_len += (unsigned char)packet[7];
408
409 memcpy( buf + bytes_read, packet + 8, data_len );
410
411 bytes_read += data_len;
412 }
413
414 gp_context_progress_update (context, id, bytes_read);
415 /* fixme, add ability to cancel download */
416
417 coolshot_read_packet( camera, packet );
418
419 data_len = (unsigned char)packet[6] * 256;
420 data_len += (unsigned char)packet[7];
421
422 /* fixme, get rid of hardcoded length */
423 if ( coolshot_check_checksum( packet, 8 + packet_size + 4 ) == GP_OK) {
424 coolshot_ack( camera );
425 last_good = 1;
426 } else {
427 /*
428 coolshot_nak( camera );
429 */
430 last_good = 0;
431 }
432 }
433 gp_context_progress_stop (context, id);
434
435 coolshot_ack( camera );
436
437 *len = bytes_read;
438
439 return( GP_OK );
440 }
441
442 static
coolshot_write_packet(Camera * camera,char * packet)443 int coolshot_write_packet (Camera *camera, char *packet) {
444 int x, ret, r, checksum=0, length;
445
446 GP_DEBUG ("* coolshot_write_packet");
447
448 if ( packet[0] == COOLSHOT_PKT ) {
449 /* fixme */
450 length = 16;
451
452 for ( x = 2 ; x < 12; x++ ) {
453 checksum += (unsigned char)packet[x];
454 }
455
456 packet[length - 4] = (checksum >> 8 ) & 0xff;
457 packet[length - 3] = checksum & 0xff;
458
459 } else if (( packet[0] == COOLSHOT_ENQ ) ||
460 ( packet[0] == COOLSHOT_ACK ) ||
461 ( packet[0] == COOLSHOT_NAK )) {
462 length = 1;
463 } else {
464 length = 0;
465 /* fixme */
466 return( -1 );
467 }
468
469 for (r = 0; r < RETRIES; r++) {
470 ret = gp_port_write (camera->port, packet, length);
471 if (ret == GP_ERROR_TIMEOUT)
472 continue;
473
474 return (ret);
475 }
476
477 return (GP_ERROR_TIMEOUT);
478 }
479
480 static
coolshot_read_packet(Camera * camera,char * packet)481 int coolshot_read_packet (Camera *camera, char *packet) {
482 int r = 0, x = 0, ret, done, length=0;
483 int blocksize, bytes_read;
484
485 GP_DEBUG ("* coolshot_read_packet");
486
487 read_packet_again:
488 packet[0] = 0;
489
490 if (r > 0)
491 GP_DEBUG ("* reading again...");
492
493 done = 0;
494
495 blocksize = 1;
496
497 for (r = 0; r < RETRIES; r++) {
498
499 bytes_read = gp_port_read (camera->port, packet, blocksize);
500 if (bytes_read == GP_ERROR_TIMEOUT)
501 continue;
502 if (bytes_read < 0)
503 return (bytes_read);
504
505 if ( packet[0] == COOLSHOT_ENQ ) {
506 usleep( COOL_SLEEP );
507 coolshot_ack( camera );
508 coolshot_read_packet( camera, packet );
509 return( GP_OK );
510 }
511
512 if (( packet[0] == COOLSHOT_ACK ) ||
513 ( packet[0] == COOLSHOT_DONE )) {
514 return( GP_OK );
515 }
516
517 if ( packet[0] != COOLSHOT_PKT ) {
518 return( GP_ERROR );
519 }
520
521 bytes_read = gp_port_read (camera->port, packet + 1, 3 );
522 if (bytes_read == GP_ERROR_TIMEOUT)
523 continue;
524 if (bytes_read < 0)
525 return (bytes_read);
526
527 /* Determine the packet type */
528 if (( strncmp( packet + 2, "OK", 2 ) == 0 ) ||
529 ( strncmp( packet + 2, "DE", 2 ) == 0 ) ||
530 ( strncmp( packet + 2, "SB", 2 ) == 0 )) {
531 /* normal 16-byte packet, so read the other 12 bytes */
532 ret = gp_port_read (camera->port, packet + 4, 12 );
533 if (ret == GP_ERROR_TIMEOUT) {
534 /* fixme */
535 /*
536 coolshot_nak (camera);
537 */
538 goto read_packet_again;
539 }
540
541 if (ret < 0)
542 return (ret);
543
544 return( GP_OK );
545 } else if ( strncmp( packet + 2, "DT", 2 ) == 0 ) {
546 /* read in packet number and length */
547 ret = gp_port_read (camera->port, packet + 4, 4 );
548 /* fixme, error detection */
549
550 length = (unsigned char)packet[6] * 256;
551 length += (unsigned char)packet[7];
552
553 if (( packet_size == 128 ) ||
554 ( length == 128 )) {
555 length = 128;
556 } else {
557 length = 500;
558 }
559 length += 4;
560
561 ret = gp_port_read (camera->port, packet + 8, length );
562 /* fixme, error detection */
563
564 x = 0;
565 while(( ret == GP_ERROR_TIMEOUT ) &&
566 ( x < RETRIES )) {
567 x++;
568 ret = gp_port_read (camera->port, packet + 8, length );
569 }
570
571 return( GP_OK );
572 }
573
574 if (done) break;
575 }
576
577 return (GP_ERROR_TIMEOUT);
578 }
579
580 static
coolshot_ack(Camera * camera)581 int coolshot_ack (Camera *camera)
582 {
583 int ret, r = 0;
584 char buf[16];
585
586 GP_DEBUG ("* coolshot_ack");
587
588 buf[0] = COOLSHOT_ACK;
589
590 for (r = 0; r < RETRIES; r++) {
591
592 ret = coolshot_write_packet (camera, buf);
593 if (ret == GP_ERROR_TIMEOUT)
594 continue;
595 if (ret == GP_OK)
596 return (ret);
597 }
598 return (GP_ERROR_TIMEOUT);
599 }
600
601 #if 0
602 static
603 int coolshot_nak (Camera *camera)
604 {
605 int ret, r = 0;
606 char buf[16];
607
608 GP_DEBUG ("* coolshot_nak");
609
610 buf[0] = COOLSHOT_NAK;
611
612 for (r = 0; r < RETRIES; r++) {
613
614 ret = coolshot_write_packet (camera, buf);
615 if (ret == GP_ERROR_TIMEOUT)
616 continue;
617 if (ret == GP_OK)
618 return (ret);
619 }
620 return (GP_ERROR_TIMEOUT);
621 }
622 #endif
623
coolshot_enq(Camera * camera)624 int coolshot_enq (Camera *camera)
625 {
626 int ret, r = 0;
627 char buf[16];
628
629 GP_DEBUG ("* coolshot_enq");
630
631 buf[0] = COOLSHOT_ENQ;
632
633 for (r = 0; r < RETRIES; r++) {
634
635 ret = coolshot_write_packet (camera, buf);
636 if (ret == GP_ERROR_TIMEOUT)
637 continue;
638 if (ret != GP_OK)
639 return (ret);
640
641 ret = coolshot_read_packet (camera, buf);
642 if (ret == GP_ERROR_TIMEOUT)
643 continue;
644 if (ret != GP_OK)
645 return (ret);
646
647 if (buf[0] == COOLSHOT_ACK)
648 return (GP_OK);
649 else
650 return (GP_ERROR_CORRUPTED_DATA);
651
652 }
653 return (GP_ERROR_TIMEOUT);
654 }
655
656
657 #define WIDTH 40
658 #define HEIGHT 30
659
660 #define Y_ADJ 25
661
662 #define RIND(x, y, w) (((w)*(HEIGHT))+((y/2)*(WIDTH/2))+(x/2))
663 #define BIND(x, y, w) (((w)*(HEIGHT))+((WIDTH/4)*(HEIGHT))+((y/2)*(WIDTH/2))+(x/2))
664
coolshot_build_thumbnail(char * data,int * size)665 int coolshot_build_thumbnail (char *data, int *size)
666 {
667 char thumbnail[32768];
668 char *ptr;
669 unsigned char *udata = (unsigned char *)data;
670 char *src;
671 int length;
672 int x, y;
673 int loop;
674 int Y, U, V;
675
676
677 ptr = thumbnail;
678
679 src = data;
680 x = y = 0;
681
682 for( loop = 0; loop < *size; loop++ ) {
683 if ( x == WIDTH ) {
684 x = 0;
685 y++;
686 }
687
688 if ( y < HEIGHT ) {
689 /*
690 from imagemagick
691 Y = 0.299000*R+0.587000*G+0.114000*B
692 Cb= -0.168736*R-0.331264*G+0.500000*B
693 Cr= 0.500000*R-0.418688*G-0.081316*B
694
695 R = Y +1.402000*Cr
696 G = Y-0.344136*Cb-0.714136*Cr
697 B = Y+1.772000*Cb
698 */
699
700 Y = *src + Y_ADJ;
701 U = udata[RIND(x,y,WIDTH)] - 128;
702 V = udata[BIND(x,y,WIDTH)] - 128;
703
704 ptr[0] = Y + ( 1.402000 * V );
705 ptr[1] = Y - ( 0.344136 * U ) - ( 0.714136 * V );
706 ptr[2] = Y + ( 1.772000 * U );
707 ptr += 3;
708
709 x++;
710 src++;
711 }
712 }
713
714 /* copy the header */
715 sprintf( data,
716 "P6\n"
717 "# CREATOR: gphoto2, panasonic coolshot library\n"
718 "%d %d\n"
719 "255\n", 80, 60 );
720
721 length = strlen( data );
722
723 /* copy the image doubling both height and width */
724 ptr = data + length;
725 for( y = 0; y < HEIGHT; y++ ) {
726 src = thumbnail + (y * WIDTH * 3);
727 for( x = 0; x < WIDTH ; x++, src += 3 ) {
728 ptr[0] = src[0]; ptr[1] = src[1]; ptr[2] = src[2]; ptr += 3;
729 ptr[0] = src[0]; ptr[1] = src[1]; ptr[2] = src[2]; ptr += 3;
730 }
731 src = thumbnail + (y * WIDTH * 3);
732 for( x = 0; x < WIDTH ; x++, src += 3 ) {
733 ptr[0] = src[0]; ptr[1] = src[1]; ptr[2] = src[2]; ptr += 3;
734 ptr[0] = src[0]; ptr[1] = src[1]; ptr[2] = src[2]; ptr += 3;
735 }
736 }
737
738 length += WIDTH * HEIGHT * 3 * 4;
739
740 *size = length;
741
742 return( GP_OK );
743 }
744
745
746