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