1 /* pdc320.c
2  *
3  * Copyright 2001 Lutz Mueller
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., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  */
20 
21 /* Originally written by Peter Desnoyers <pjd@fred.cambridge.ma.us>,
22  * and adapted for gphoto2 by
23  * Nathan Stenzel <nathanstenzel@users.sourceforge.net> and
24  * Lutz Mueller <lutz@users.sourceforge.net>
25  *
26  * Maintained by Nathan Stenzel <nathanstenzel@users.sourceforge.net>
27  *
28  * Original windows drivers available at:
29  *	http://www.polaroid.com/service/software/index.html
30  */
31 
32 #define _DEFAULT_SOURCE
33 
34 #include "config.h"
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include <gphoto2/gphoto2-library.h>
41 #include <gphoto2/gphoto2-port-log.h>
42 
43 #include "pdc320.h"
44 
45 #ifdef ENABLE_NLS
46 #  include <libintl.h>
47 #  undef _
48 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
49 #  ifdef gettext_noop
50 #    define N_(String) gettext_noop (String)
51 #  else
52 #    define N_(String) (String)
53 #  endif
54 #else
55 #  define textdomain(String) (String)
56 #  define gettext(String) (String)
57 #  define dgettext(Domain,Message) (Message)
58 #  define dcgettext(Domain,Message,Type) (Message)
59 #  define bindtextdomain(Domain,Directory) (Domain)
60 #  define _(String) (String)
61 #  define N_(String) (String)
62 #endif
63 
64 #define GP_MODULE "pdc320"
65 
66 /*******************************************************************************/
67 /* NOTICE: There is a 16x8 block of pixels after the image data.               */
68 /* All of them are about the same and I believe they are for image correction. */
69 /*******************************************************************************/
70 
71 /* Notes on what needs work:
72  * 	Make a better header that could correct color problems....
73  *		or manage to decode, color correct, and save the image.
74  * The quantization tables are incorrect for the PDC320.
75  */
76 
77 /*
78  * For the PDC640SE, the init sequence is INIT,ID,ENDINIT,STATE,NUM,SIZE,PIC.
79  *
80  * During handshake, if the first read byte is not 6 then it is not good. Read
81  * the number of bytes mentioned +2 ("FE FF"?)and then INIT and try SIZE
82  * again (this is a loop).
83  *
84  * It is possible that the PDC320 might do a similar handshaking sequence at
85  * that same point.
86  */
87 
88 typedef enum {
89 	PDC320,
90 	PDC640SE
91 } PDCModel;
92 
93 struct _CameraPrivateLibrary {
94 	PDCModel model;
95 };
96 
97 static int
pdc320_escape(const unsigned char * inbuf,int inbuflen,unsigned char * outbuf)98 pdc320_escape(
99 	const unsigned char *inbuf, int inbuflen,
100 	unsigned char *outbuf
101 ) {
102 	int i,j;
103 
104 	j = 0;
105 	for (i=0;i<inbuflen;i++) {
106 		switch (inbuf[i]) {
107 		case 0xe3:
108 			outbuf[j++] = 0xe5;outbuf[j++] = 3;
109 			break;
110 		case 0xe4:
111 			outbuf[j++] = 0xe5;outbuf[j++] = 2;
112 			break;
113 		case 0xe5:
114 			outbuf[j++] = 0xe5;outbuf[j++] = 1;
115 			break;
116 		case 0xe6:
117 			outbuf[j++] = 0xe5;outbuf[j++] = 0;
118 			break;
119 		default:outbuf[j++] = inbuf[i];
120 			break;
121 		}
122 	}
123 	return j;
124 }
125 
126 static int
pdc320_calc_checksum(const unsigned char * buf,int buflen)127 pdc320_calc_checksum(const unsigned char *buf, int buflen) {
128 	int checksum, j;
129 
130 	checksum = 0;
131 	j = 0;
132 	for (j=0;j<buflen/2;j++) {
133 		checksum += buf[j*2];
134 		checksum += buf[j*2+1]<<8;
135 	}
136 	if (buflen & 1)
137 		checksum += buf[buflen-1];
138 
139 	while (checksum > 0xffff) {
140 		checksum =
141 			(checksum & 0xffff) +
142 			((checksum >> 16) & 0xffff);
143 	}
144 	return 0xffff-checksum; /* neg checksum actually */
145 }
146 
147 static int
pdc320_command(GPPort * port,const unsigned char * cmd,int cmdlen)148 pdc320_command(
149 	GPPort *port,
150 	const unsigned char *cmd, int cmdlen
151 ) {
152 	unsigned char csum[2];
153 	int checksum, off, ret;
154 	unsigned char *newcmd;
155 
156 	checksum = pdc320_calc_checksum (cmd, cmdlen);
157 	csum[0] = checksum & 0xff;
158 	csum[1] = (checksum >> 8) & 0xff;
159 	/* 4 times 0xe6, checksum and command, both might be escaped */
160 	newcmd = malloc (2*(sizeof(csum)+cmdlen)+4);
161 	if (!newcmd)
162 		return GP_ERROR_NO_MEMORY;
163 	memset (newcmd, 0xe6, 4); off = 4;
164 	off += pdc320_escape (cmd, cmdlen, newcmd + off);
165 	off += pdc320_escape (csum, 2, newcmd + off);
166 	ret = gp_port_write (port, (char *)newcmd, off);
167 	free(newcmd);
168 	return ret;
169 }
170 
171 static int
pdc320_simple_command(GPPort * port,const unsigned char cmd)172 pdc320_simple_command (GPPort *port, const unsigned char cmd) {
173 	return pdc320_command(port, &cmd, 1);
174 }
175 
176 static int
pdc320_simple_reply(GPPort * port,const unsigned char expcode,unsigned int replysize,unsigned char * reply)177 pdc320_simple_reply (GPPort *port, const unsigned char expcode,
178 	unsigned int replysize, unsigned char *reply
179 ) {
180 	unsigned char csum[2];
181 	int calccsum;
182 
183 	CR (gp_port_read (port, (char *)reply, 1));
184 	if (reply[0] != expcode) {
185 		GP_DEBUG("*** reply got 0x%02x, expected 0x%02x\n",
186 			reply[0], expcode
187 		);
188 		return GP_ERROR;
189 	}
190 	CR (gp_port_read (port, (char *)reply+1, replysize-1));
191 	CR (gp_port_read (port, (char *)csum, 2));
192 	calccsum = pdc320_calc_checksum (reply, replysize);
193 	if (calccsum != ((csum[1] << 8) | csum[0])) {
194 		GP_DEBUG("csum %x vs %x\n",calccsum,((csum[0]<<8)|csum[1]));
195 		return GP_ERROR;
196 	}
197 	return GP_OK;
198 }
199 
200 static int
pdc320_simple_command_reply(GPPort * port,const unsigned char cmd,const unsigned char expcode,unsigned int replysize,unsigned char * reply)201 pdc320_simple_command_reply (GPPort *port,
202 	const unsigned char cmd, const unsigned char expcode,
203 	unsigned int replysize, unsigned char *reply
204 ) {
205 	CR (pdc320_simple_command (port, cmd));
206 	CR (pdc320_simple_reply (port, expcode, replysize, reply));
207 	return GP_OK;
208 }
209 
210 static int
pdc320_init(GPPort * port)211 pdc320_init (GPPort *port)
212 {
213 	unsigned char buf[32];
214 	unsigned char e6[4];
215 	int i;
216 
217 	GP_DEBUG ("*** PDC320_INIT ***");
218 
219 	/* The initial command is prefixed by 4 raw E6. */
220 	memset(e6,0xe6,sizeof(e6));
221 	CR (gp_port_write (port, (char *)e6, sizeof (e6) ));
222 
223 	GP_DEBUG ("*** PDC320_INIT ***");
224 	CR (pdc320_simple_command_reply (port, PDC320_INIT, 5, 1, buf));
225 	GP_DEBUG ("*** PDC320_ID ***");
226 	CR (pdc320_simple_command_reply (port, PDC320_ID, 0, 12, buf));
227 	GP_DEBUG ("*** PDC320_STATE ***");
228 	CR (pdc320_simple_command_reply (port, PDC320_STATE, 2, 22, buf));
229 
230 	for (i=0;i<9;i++) {
231 		GP_DEBUG ("%d: %d (0x%x)",i,((buf[2+i*2]<<8)|buf[2+2*i+1]), ((buf[2+i*2]<<8)|buf[2+2*i+1]));
232 	}
233 	GP_DEBUG ("*** PDC320_ENDINIT ***");
234 	return pdc320_simple_command_reply (port, PDC320_ENDINIT, 9, 1, buf);
235 }
236 
237 static int
pdc320_num(GPPort * port)238 pdc320_num (GPPort *port)
239 {
240 	unsigned char buf[2];
241 
242 	GP_DEBUG ("*** PDC320_NUM ***");
243 	CR (pdc320_simple_command_reply (port, PDC320_NUM, 3, 2, buf));
244 	GP_DEBUG ("The camera contains %i files.", buf[1]);
245 	return buf[1];
246 }
247 
248 static int
pdc320_delete(GPPort * port)249 pdc320_delete (GPPort *port)
250 {
251 	unsigned char buf[1];
252 
253 	GP_DEBUG ("*** PDC320_DELETE ***");
254 	return pdc320_simple_command_reply(port, PDC320_DEL, 8, 1, buf);
255 }
256 
257 static int
pdc320_size(Camera * camera,int n)258 pdc320_size (Camera *camera, int n)
259 {
260 	int size;
261 	unsigned char buf[5];
262 	unsigned char cmd[2];
263 
264 	GP_DEBUG ("*** PDC320_SIZE ***");
265 	cmd[0] = PDC320_SIZE;
266 	cmd[1] = n;
267 	CR (pdc320_command (camera->port, cmd, sizeof (cmd)));
268 	CR (pdc320_simple_reply (camera->port, 6, 5, buf));
269 	size = (buf[1] << 24) + (buf[2] << 16) + (buf[3] << 8) + buf[4];
270 	GP_DEBUG ("Image %i has size %i.", n, size);
271 	return (size);
272 }
273 
274 /* Unclear. */
275 static int
pdc320_0c(Camera * camera,int n)276 pdc320_0c (Camera *camera, int n)
277 {
278 	int size, i;
279 	unsigned char buf[3], *xbuf;
280 	unsigned char cmd[2];
281 
282 	cmd[0] = 0x0c;
283 	cmd[1] = n;		/* n is from 1 on up */
284 
285 	/* Write the command */
286 	GP_DEBUG ("*** PDC320_0c ***");
287 	CR (pdc320_command (camera->port, cmd, sizeof (cmd)));
288 	CR (gp_port_read (camera->port, (char *)buf, 3));
289 	if (buf[0] != 7)
290 		return GP_ERROR;
291 	size = (buf[1] << 8) | buf[2];
292 	xbuf = malloc (size);
293 	CR (gp_port_read (camera->port, (char *)xbuf, size));
294 	for (i=0; i<size; i++) {
295 		GP_DEBUG ("buf[%d]=0x%02x", i, xbuf[i]);
296 	}
297 	CR (gp_port_read (camera->port, (char *)buf, 2));
298 	/* checksum is calculated from both, but i am not clear how. */
299 	free (xbuf);
300 	return GP_OK;
301 }
302 
303 static int
pdc320_pic(Camera * camera,int n,unsigned char ** data,int * size)304 pdc320_pic (Camera *camera, int n, unsigned char **data, int *size)
305 {
306 	unsigned char cmd[2];
307 	unsigned char buf[2048];
308 	int remaining, f1, f2, i, len;
309 	int chunksize=2000;
310 
311 	/* Get the size of the picture and allocate the memory */
312 	GP_DEBUG ("Checking size of image %i...", n);
313 	CR (*size = pdc320_size (camera, n));
314 	*data = malloc (sizeof (char) * (*size));
315 	if (!*data)
316 		return (GP_ERROR_NO_MEMORY);
317 
318 	cmd[0] = PDC320_PIC;
319 	cmd[1] = n;
320 
321 	CR_FREE (pdc320_command (camera->port, cmd, sizeof (cmd)), *data);
322 	switch (camera->pl->model) {
323 	case PDC640SE:
324 		chunksize = 528;
325 		break;
326 	case PDC320:
327 		chunksize = 2000;
328 		break;
329 	}
330 
331 	len = *size;
332 	for (i = 0; i < *size; i += chunksize) {
333 
334 		/* How many bytes do we read in this round? */
335 		remaining = *size - i;
336 		len = (remaining > chunksize) ? chunksize : remaining;
337 
338 		/* Read the frame number */
339 		usleep (10000);
340 		CR_FREE (gp_port_read (camera->port, (char *)buf, 5), *data);
341 		f1 = (buf[1] << 8) + buf[2];
342 		f2 = (buf[3] << 8) + buf[4];
343 		GP_DEBUG ("Reading frame %d "
344 				 "(%d)...", f1, f2);
345 
346 		/* Read the actual data */
347 		usleep(1000);
348 		CR_FREE (gp_port_read (camera->port, (char *)*data + i, len), *data);
349 
350 		/* Read the checksum */
351 		CR_FREE (gp_port_read (camera->port, (char *)buf, 2), *data);
352 	}
353 
354 	return (GP_OK);
355 }
356 
357 int
camera_id(CameraText * id)358 camera_id (CameraText *id)
359 {
360 	strcpy (id->text, "Polaroid DC320");
361 
362 	return (GP_OK);
363 }
364 
365 int
camera_abilities(CameraAbilitiesList * list)366 camera_abilities (CameraAbilitiesList *list)
367 {
368 	int i;
369 	CameraAbilities a;
370 
371 	for (i = 0; models[i].model; i++) {
372 		memset(&a, 0, sizeof(a));
373 		strcpy (a.model, models[i].model);
374 		a.status		= GP_DRIVER_STATUS_EXPERIMENTAL;
375 		a.port			= GP_PORT_SERIAL;
376 		a.speed[0]		= 115200;
377 		a.speed[1]		= 0;
378 		a.operations		= GP_OPERATION_NONE;
379 		a.file_operations	= GP_FILE_OPERATION_NONE;
380 		a.folder_operations	= GP_FOLDER_OPERATION_DELETE_ALL;
381 		CR (gp_abilities_list_append (list, a));
382 	}
383 	return (GP_OK);
384 }
385 
386 static int
get_file_func(CameraFilesystem * fs,const char * folder,const char * filename,CameraFileType type,CameraFile * file,void * user_data,GPContext * context)387 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
388 	       CameraFileType type, CameraFile *file, void *user_data,
389 	       GPContext *context)
390 {
391 	Camera *camera = user_data;
392 	jpeg *myjpeg;
393 	chunk *tempchunk;
394 	int r, n, size, width, height;
395 	unsigned char *data;
396 
397 	if ((type != GP_FILE_TYPE_RAW) && (type != GP_FILE_TYPE_NORMAL))
398 		return (GP_ERROR_NOT_SUPPORTED);
399 
400 	/*
401 	 * Get the number of the picture from the filesystem and increment
402 	 * since we need a range starting with 1.
403 	 */
404 	GP_DEBUG ("Getting number from fs...");
405 	CR (n = gp_filesystem_number (camera->fs, folder, filename, context));
406 	n++;
407 
408 	/* Get the file */
409 	GP_DEBUG ("Getting file %i...", n);
410 	CR (pdc320_pic (camera, n, &data, &size));
411 	r = pdc320_0c (camera, n);
412 	if (r < GP_OK) {
413 		free (data);
414 		return r;
415 	}
416 
417 	/* Post-processing */
418 	switch (type) {
419 	case GP_FILE_TYPE_RAW:
420 		CR (gp_file_set_data_and_size (file, (char *)data, size));
421 		CR (gp_file_set_mime_type (file, GP_MIME_RAW));
422 		break;
423 	case GP_FILE_TYPE_NORMAL:
424 	default:
425 		GP_DEBUG ("Using Nathan Stenzel's experimental jpeg.c\n");
426 		GP_DEBUG ("About to make jpeg header\n");
427 		width = data[4]*256 + data[5];
428 		height = data[2]*256 + data[3];
429 		GP_DEBUG ("Width=%i\tHeight=%i\n", width, height);
430 		myjpeg = gpi_jpeg_header(width,height/2, 0x11,0x11,0x21, 1,0,0, &chrominance, &luminance,
431 		    0,0,0, gpi_jpeg_chunk_new_filled(HUFF_00),
432 		    gpi_jpeg_chunk_new_filled(HUFF_10), NULL, NULL);
433 		GP_DEBUG ("Turning the picture data into a chunk data type\n");
434 		tempchunk = gpi_jpeg_chunk_new(size);
435 		tempchunk->data = data;
436 		GP_DEBUG ("Adding the picture data to the jpeg structure\n");
437 		gpi_jpeg_add_marker(myjpeg, tempchunk, 6, size-1);
438 		GP_DEBUG ("Writing the jpeg file\n");
439 		gpi_jpeg_write(file, filename, myjpeg);
440 		GP_DEBUG ("Cleaning up the mess\n");
441 		gpi_jpeg_destroy(myjpeg);
442 		free (tempchunk);
443 		break;
444     	}
445 	return (GP_OK);
446 }
447 
448 static int
delete_all_func(CameraFilesystem * fs,const char * folder,void * data,GPContext * context)449 delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
450 		 GPContext *context)
451 {
452 	Camera *camera = data;
453 
454 	CR (pdc320_delete (camera->port));
455 	return (GP_OK);
456 }
457 
458 static int
camera_about(Camera * camera,CameraText * about,GPContext * context)459 camera_about (Camera *camera, CameraText *about, GPContext *context)
460 {
461 	strcpy (about->text, _("Download program for several Polaroid cameras. "
462 		"Originally written by Peter Desnoyers "
463 		"<pjd@fred.cambridge.ma.us>, and adapted for gphoto2 by "
464 		"Nathan Stenzel <nathanstenzel@users.sourceforge.net> and "
465 		"Lutz Mueller <lutz@users.sf.net>.\n"
466 		"Polaroid 640SE testing was done by Michael Golden "
467 		"<naugrim@juno.com>."));
468 	return (GP_OK);
469 }
470 
471 static int
file_list_func(CameraFilesystem * fs,const char * folder,CameraList * list,void * data,GPContext * context)472 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
473 		void *data, GPContext *context)
474 {
475 	int n;
476 	Camera *camera = data;
477 
478 	/* Fill the list */
479 	CR (n = pdc320_num (camera->port));
480 	gp_list_populate (list, "PDC320%04i.jpg", n);
481 	return (GP_OK);
482 }
483 
484 static int
camera_summary(Camera * camera,CameraText * summary,GPContext * context)485 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
486 {
487 	char buf[12];
488 
489 	GP_DEBUG ("*** PDC320_ID ***");
490 	CR (pdc320_simple_command_reply (camera->port, PDC320_ID, 0, 12, (unsigned char *)buf));
491 	sprintf (summary->text, _("Model: %x, %x, %x, %x"), buf[8],buf[9],buf[10],buf[11]);
492 	return (GP_OK);
493 }
494 
495 static int
camera_exit(Camera * camera,GPContext * context)496 camera_exit (Camera *camera, GPContext *context)
497 {
498 	if (!camera)
499 		return (GP_ERROR_BAD_PARAMETERS);
500 
501 	if (camera->pl) {
502 		free (camera->pl);
503 		camera->pl = NULL;
504 	}
505 
506 	return (GP_OK);
507 }
508 
509 static CameraFilesystemFuncs fsfuncs = {
510 	.file_list_func = file_list_func,
511 	.get_file_func = get_file_func,
512 	.delete_all_func = delete_all_func
513 };
514 
515 int
camera_init(Camera * camera,GPContext * context)516 camera_init (Camera *camera, GPContext *context)
517 {
518 	GPPortSettings settings;
519 	CameraAbilities abilities;
520 	int result;
521 
522         /* First, set up all the function pointers */
523 	camera->functions->exit		= camera_exit;
524         camera->functions->about        = camera_about;
525 	camera->functions->summary      = camera_summary;
526 
527 	/* Now, tell the filesystem where to get lists and info */
528 	gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
529 
530 	camera->pl = malloc (sizeof (CameraPrivateLibrary));
531 	if (!camera->pl)
532 		return (GP_ERROR_NO_MEMORY);
533 
534 	/* What model are we talking to? */
535 	gp_camera_get_abilities (camera, &abilities);
536 	if (	!strcmp (abilities.model, "Polaroid:Fun! 320") ||
537 		!strcmp (abilities.model, "Polaroid Fun! 320")
538 	)
539 		camera->pl->model = PDC320;
540 	else if (!strcmp (abilities.model, "Polaroid:640SE") ||
541 		 !strcmp (abilities.model, "Polaroid 640SE")
542 	)
543 		camera->pl->model = PDC640SE;
544 	else {
545 		free (camera->pl);
546 		camera->pl = NULL;
547 		return (GP_ERROR_MODEL_NOT_FOUND);
548 	}
549 
550 	/* Open the port and check if the camera is there */
551 	gp_port_get_settings (camera->port, &settings);
552 	if (!settings.serial.speed)
553 		settings.serial.speed = 115200;
554 	gp_port_set_settings (camera->port, settings);
555 	gp_port_set_timeout (camera->port, 30000);
556 
557 	/* Check if the camera is really there */
558 	result = pdc320_init (camera->port);
559 	if (result < 0) {
560 		free (camera->pl);
561 		camera->pl = NULL;
562 		return (result);
563 	}
564 	return (GP_OK);
565 }
566