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