"Fossies" - the Fresh Open Source Software Archive 
Member "libgphoto2-2.5.27/camlibs/docupen/docupen.c" (21 Feb 2021, 22333 Bytes) of package /linux/privat/libgphoto2-2.5.27.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "docupen.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.5.26_vs_2.5.27.
1 /* docupen.c
2 * Docupen camera driver (camlib).
3 *
4 * Copyright 2020 Ondrej Zary <ondrej@zary.sk>
5 * based on Docupen tools by Florian Heinz <fh@cronon-ag.de>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
21 */
22 #include "config.h"
23
24 #include <gphoto2/gphoto2-library.h>
25 #include <gphoto2/gphoto2-result.h>
26 #include <gphoto2-endian.h>
27
28 #include "docupen.h"
29
30 #ifdef ENABLE_NLS
31 # include <libintl.h>
32 # undef _
33 # define _(String) dgettext (GETTEXT_PACKAGE, String)
34 # ifdef gettext_noop
35 # define N_(String) gettext_noop (String)
36 # else
37 # define N_(String) (String)
38 # endif
39 #else
40 # define _(String) (String)
41 # define N_(String) (String)
42 #endif
43
44 #if 0
45 static const struct {
46 char *model;
47 int usb_vendor;
48 int usb_product;
49 } models[] = {
50 { "Planon DocuPen RC800", 0x18dd, 0x1000 },
51 { NULL, 0, 0 }
52 };
53 #endif
54
55 #define DP_ACK 0xD1
56 #define DP_CMD_LEN 8
57
58 static char cmd_query[] = { 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a };
59 static char cmd_inquiry[] = { 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a };
60 static char cmd_turnoff[] = { 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a };
61 static char cmd_del_all[] = { 0x7a, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x1a };
62 static char cmd_get_profile[] = { 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1a }; /* length = 0x400 */
63 static char cmd_set_profile[] = { 0x59, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1a }; /* length = 0x400 */
64
65 #define RAW_HEADER_SERIAL_OFFSET 0x4e
66 static char raw_header[] = {
67 /* 0 */ 0x53, 0x53, 0x08, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xc0, /* SS._..........@. */
68 /* 10 */ 0x12, 0x00, 0x20, 0x48, 0x88, 0x00, 0x00, 0x68, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* .. H...h........ */
69 /* 20 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ................ */
70 /* 30 */ 0x0d, 0x0d, 0x0c, 0x0d, 0x0d, 0x0d, 0x0c, 0x0e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........g....... */
71 /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, /* ..............12 */
72 /* 50 */ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 /* 34567890......P */
73 };
74
75 bool dp_cmd(GPPort *port, const char *cmd)
76 {
77 unsigned char reply[64];
78
79 if (gp_port_write(port, cmd, DP_CMD_LEN) != DP_CMD_LEN) {
80 GP_LOG_E("command write failed");
81 return false;
82 }
83 int ret = gp_port_read(port, (void *)reply, sizeof(reply));
84 if (ret < 1 || reply[0] != DP_ACK) {
85 GP_LOG_E("command failed: ret=%d reply[0]=%02hhx", ret, reply[0]);
86 return false;
87 }
88 return true;
89 }
90
91 static bool inquiry_read(Camera *camera)
92 {
93 if (gp_port_read(camera->port, (void *)&camera->pl->info, 4) != 4) { /* read header */
94 GP_LOG_E("error reading info header");
95 return false;
96 }
97 /* FIXME: len is 8bit unsigned, so can be at most 255 ... sizeof(struct dp_info) is currently over 256
98 * so this is alwas false ... It is harmless and likely ok, but weird. -Marcus 20200831 */
99 if (camera->pl->info.len > sizeof(struct dp_info)) {
100 GP_LOG_E("camera info too long: %d bytes", camera->pl->info.len);
101 return false;
102 }
103 int ret = gp_port_read(camera->port, (void *)&camera->pl->info + 4, camera->pl->info.len - 4);
104 if (ret != camera->pl->info.len - 4) {
105 GP_LOG_E("camera info length error: expected %d bytes, got %d", camera->pl->info.len - 4, ret);
106 return false;
107 }
108
109 return true;
110 }
111
112
113 int camera_exit (Camera *camera, GPContext *context);
114 int
115 camera_exit (Camera *camera, GPContext *context)
116 {
117 if (camera->pl) {
118 if (camera->pl->cache)
119 fclose(camera->pl->cache);
120 free(camera->pl->cache_file);
121 free(camera->pl->lut);
122 free(camera->pl);
123 camera->pl = NULL;
124 }
125 dp_cmd(camera->port, cmd_turnoff);
126 return GP_OK;
127 }
128
129
130 static bool dp_get_profile(Camera *camera)
131 {
132 if (!camera->pl->profile)
133 camera->pl->profile = malloc(PROFILE_LEN);
134 if (!camera->pl->profile)
135 return false;
136
137 dp_cmd(camera->port, cmd_get_profile);
138 if (gp_port_read(camera->port, camera->pl->profile, PROFILE_LEN) != PROFILE_LEN)
139 return false;
140
141 return true;
142 }
143
144 static bool dp_set_profile(Camera *camera)
145 {
146 if (!camera->pl->profile)
147 return false;
148
149 dp_cmd(camera->port, cmd_set_profile);
150 if (gp_port_write(camera->port, camera->pl->profile, PROFILE_LEN) != PROFILE_LEN)
151 return false;
152
153 return true;
154 }
155
156
157 int camera_config_get (Camera *camera, CameraWidget **window, GPContext *context);
158 int
159 camera_config_get (Camera *camera, CameraWidget **window, GPContext *context)
160 {
161 CameraWidget *section, *widget;
162
163 if (!dp_get_profile(camera))
164 return GP_ERROR;
165
166 gp_widget_new (GP_WIDGET_WINDOW, _("Scanner Profile Configuration"), window);
167
168 gp_widget_new (GP_WIDGET_SECTION, _("Mono mode"), §ion);
169 gp_widget_append (*window, section);
170
171 gp_widget_new (GP_WIDGET_RADIO, _("Depth"), &widget);
172 gp_widget_append (section, widget);
173 gp_widget_add_choice (widget, _("Mono (b/w)"));
174 gp_widget_add_choice (widget, _("Grey (4bpp)"));
175 gp_widget_add_choice (widget, _("Grey (8bpp)"));
176 switch(camera->pl->profile[0x80]) {
177 case 0x00: gp_widget_set_value (widget, _("Mono (b/w)")); break;
178 case 0x01: gp_widget_set_value (widget, _("Grey (4bpp)")); break;
179 case 0x02: gp_widget_set_value (widget, _("Grey (8bpp)")); break;
180 }
181
182 gp_widget_new (GP_WIDGET_RADIO, _("Lo Resolution"), &widget);
183 gp_widget_append (section, widget);
184 gp_widget_add_choice (widget, _("100 DPI"));
185 gp_widget_add_choice (widget, _("200 DPI"));
186 switch(camera->pl->profile[0x81]) {
187 case RES_100DPI: gp_widget_set_value (widget, _("100 DPI")); break;
188 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
189 }
190
191 gp_widget_new (GP_WIDGET_RADIO, _("Hi Resolution"), &widget);
192 gp_widget_append (section, widget);
193 gp_widget_add_choice (widget, _("200 DPI"));
194 gp_widget_add_choice (widget, _("400 DPI"));
195 switch(camera->pl->profile[0x82]) {
196 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
197 case RES_400DPI: gp_widget_set_value (widget, _("400 DPI")); break;
198 }
199
200 gp_widget_new (GP_WIDGET_SECTION, _("Color Document mode"), §ion);
201 gp_widget_append (*window, section);
202
203 gp_widget_new (GP_WIDGET_RADIO, _("Depth"), &widget);
204 gp_widget_append (section, widget);
205 gp_widget_add_choice (widget, _("NQ (12bpp)"));
206 switch(camera->pl->profile[0x83]) {
207 case 0x04: gp_widget_set_value (widget, _("NQ (12bpp)")); break;
208 }
209
210 gp_widget_new (GP_WIDGET_RADIO, _("Lo Resolution"), &widget);
211 gp_widget_append (section, widget);
212 gp_widget_add_choice (widget, _("100 DPI"));
213 gp_widget_add_choice (widget, _("200 DPI"));
214 switch(camera->pl->profile[0x84]) {
215 case RES_100DPI: gp_widget_set_value (widget, _("100 DPI")); break;
216 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
217 }
218
219 gp_widget_new (GP_WIDGET_RADIO, _("Hi Resolution"), &widget);
220 gp_widget_append (section, widget);
221 gp_widget_add_choice (widget, _("200 DPI"));
222 gp_widget_add_choice (widget, _("400 DPI"));
223 switch(camera->pl->profile[0x85]) {
224 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
225 case RES_400DPI: gp_widget_set_value (widget, _("400 DPI")); break;
226 }
227
228 gp_widget_new (GP_WIDGET_SECTION, _("Color Photo mode"), §ion);
229 gp_widget_append (*window, section);
230
231 gp_widget_new (GP_WIDGET_RADIO, _("Depth"), &widget);
232 gp_widget_append (section, widget);
233 gp_widget_add_choice (widget, _("HQ (24bpp)"));
234 switch(camera->pl->profile[0x86]) {
235 case 0x08: gp_widget_set_value (widget, _("HQ (24bpp)")); break;
236 }
237
238 gp_widget_new (GP_WIDGET_RADIO, _("Lo Resolution"), &widget);
239 gp_widget_append (section, widget);
240 gp_widget_add_choice (widget, _("100 DPI"));
241 gp_widget_add_choice (widget, _("200 DPI"));
242 switch(camera->pl->profile[0x87]) {
243 case RES_100DPI: gp_widget_set_value (widget, _("100 DPI")); break;
244 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
245 }
246
247 gp_widget_new (GP_WIDGET_RADIO, _("Hi Resolution"), &widget);
248 gp_widget_append (section, widget);
249 gp_widget_add_choice (widget, _("200 DPI"));
250 gp_widget_add_choice (widget, _("400 DPI"));
251 switch(camera->pl->profile[0x88]) {
252 case RES_200DPI: gp_widget_set_value (widget, _("200 DPI")); break;
253 case RES_400DPI: gp_widget_set_value (widget, _("400 DPI")); break;
254 }
255
256 return GP_OK;
257 }
258
259
260 int camera_config_set (Camera *camera, CameraWidget *window, GPContext *context);
261 int
262 camera_config_set (Camera *camera, CameraWidget *window, GPContext *context)
263 {
264 CameraWidget *section, *widget;
265 char *value;
266
267 gp_widget_get_child_by_label (window, _("Mono mode"), §ion);
268 gp_widget_get_child_by_label (section, _("Depth"), &widget);
269 if (gp_widget_changed (widget)) {
270 gp_widget_get_value (widget, &value);
271 gp_widget_set_changed (widget, 0);
272 if (!strcmp(value, _("Mono (b/w)")))
273 camera->pl->profile[0x80] = 0x00;
274 else if (!strcmp(value, _("Grey (4bpp)")))
275 camera->pl->profile[0x80] = 0x01;
276 else if (!strcmp(value, _("Grey (8bpp)")))
277 camera->pl->profile[0x80] = 0x02;
278 }
279
280 gp_widget_get_child_by_label (section, _("Lo Resolution"), &widget);
281 if (gp_widget_changed (widget)) {
282 gp_widget_get_value (widget, &value);
283 gp_widget_set_changed (widget, 0);
284 if (!strcmp(value, _("100 DPI")))
285 camera->pl->profile[0x81] = RES_100DPI;
286 else if (!strcmp(value, _("200 DPI")))
287 camera->pl->profile[0x81] = RES_200DPI;;
288 }
289
290 gp_widget_get_child_by_label (section, _("Hi Resolution"), &widget);
291 if (gp_widget_changed (widget)) {
292 gp_widget_get_value (widget, &value);
293 gp_widget_set_changed (widget, 0);
294 if (!strcmp(value, _("200 DPI")))
295 camera->pl->profile[0x82] = RES_200DPI;
296 else if (!strcmp(value, _("400 DPI")))
297 camera->pl->profile[0x82] = RES_400DPI;;
298 }
299
300 gp_widget_get_child_by_label (window, _("Color Document mode"), §ion);
301 gp_widget_get_child_by_label (section, _("Depth"), &widget);
302 if (gp_widget_changed (widget)) {
303 gp_widget_get_value (widget, &value);
304 gp_widget_set_changed (widget, 0);
305 if (!strcmp(value, _("NQ (12bpp)")))
306 camera->pl->profile[0x83] = 0x04;
307 }
308
309 gp_widget_get_child_by_label (section, _("Lo Resolution"), &widget);
310 if (gp_widget_changed (widget)) {
311 gp_widget_get_value (widget, &value);
312 gp_widget_set_changed (widget, 0);
313 if (!strcmp(value, _("100 DPI")))
314 camera->pl->profile[0x84] = RES_100DPI;
315 else if (!strcmp(value, _("200 DPI")))
316 camera->pl->profile[0x84] = RES_200DPI;;
317 }
318
319 gp_widget_get_child_by_label (section, _("Hi Resolution"), &widget);
320 if (gp_widget_changed (widget)) {
321 gp_widget_get_value (widget, &value);
322 gp_widget_set_changed (widget, 0);
323 if (!strcmp(value, _("200 DPI")))
324 camera->pl->profile[0x85] = RES_200DPI;
325 else if (!strcmp(value, _("400 DPI")))
326 camera->pl->profile[0x85] = RES_400DPI;;
327 }
328
329 gp_widget_get_child_by_label (window, _("Color Photo mode"), §ion);
330 gp_widget_get_child_by_label (section, _("Depth"), &widget);
331 if (gp_widget_changed (widget)) {
332 gp_widget_get_value (widget, &value);
333 gp_widget_set_changed (widget, 0);
334 if (!strcmp(value, _("HQ (24bpp)")))
335 camera->pl->profile[0x86] = 0x08;
336 }
337
338 gp_widget_get_child_by_label (section, _("Lo Resolution"), &widget);
339 if (gp_widget_changed (widget)) {
340 gp_widget_get_value (widget, &value);
341 gp_widget_set_changed (widget, 0);
342 if (!strcmp(value, _("100 DPI")))
343 camera->pl->profile[0x87] = RES_100DPI;
344 else if (!strcmp(value, _("200 DPI")))
345 camera->pl->profile[0x87] = RES_200DPI;;
346 }
347
348 gp_widget_get_child_by_label (section, _("Hi Resolution"), &widget);
349 if (gp_widget_changed (widget)) {
350 gp_widget_get_value (widget, &value);
351 gp_widget_set_changed (widget, 0);
352 if (!strcmp(value, _("200 DPI")))
353 camera->pl->profile[0x88] = RES_200DPI;
354 else if (!strcmp(value, _("400 DPI")))
355 camera->pl->profile[0x88] = RES_400DPI;;
356 }
357
358 if (!dp_set_profile(camera))
359 return GP_ERROR;
360
361 return GP_OK;
362 }
363
364
365 int
366 camera_summary (Camera *camera, CameraText *summary, GPContext *context);
367 int
368 camera_summary (Camera *camera, CameraText *summary, GPContext *context)
369 {
370 sprintf(summary->text, "Scanner model: DocuPen RC800\n"
371 "Images in memory: %d\n"
372 "Used bytes in memory: %d\n"
373 "Internal Flash ID: %04x\n"
374 "Memory size: %d\n"
375 "Calibration values: %d %d %d %d %d %d %d %d",
376 le32toh(camera->pl->info.pagestored),
377 le32toh(camera->pl->info.datacountbyte),
378 le16toh(camera->pl->info.flashmemid),
379 le32toh(camera->pl->info.flashmemmax),
380 camera->pl->info.calibvalue[0],
381 camera->pl->info.calibvalue[1],
382 camera->pl->info.calibvalue[2],
383 camera->pl->info.calibvalue[3],
384 camera->pl->info.calibvalue[4],
385 camera->pl->info.calibvalue[5],
386 camera->pl->info.calibvalue[6],
387 camera->pl->info.calibvalue[7]
388 );
389 return GP_OK;
390 }
391
392
393 int
394 camera_manual (Camera *camera, CameraText *manual, GPContext *context);
395 int
396 camera_manual (Camera *camera, CameraText *manual, GPContext *context)
397 {
398 strcpy(manual->text,
399 _(
400 "Docupen scanner can't download/erase individual images, only everything\n"
401 "at once. To work-around this, a cache file is created where a copy of the\n"
402 "scanner's memory is stored. The cache fill is trigerred by downloading any\n"
403 "image - so downloading the first image will take long time if the cache is\n"
404 "empty or not valid. The cache is invalidated automatically when the amount\n"
405 "of used memory reported by the scanner does not match cache size.\n"
406 "The cache file is located at ~/.cache/docupen-SERIAL_NO.bin\n"
407 "\n"
408 "The scanner has a very short auto-power-off timeout - only 8 seconds - and\n"
409 "it's effective even when connected by USB. You need to turn it on before\n"
410 "each gphoto2 operation. In some situations, you might need to prevent it\n"
411 "from turning off by repeatedly pressing any of the buttons."
412 ));
413
414 return GP_OK;
415 }
416
417
418 int
419 camera_about (Camera *camera, CameraText *about, GPContext *context);
420 int
421 camera_about (Camera *camera, CameraText *about, GPContext *context)
422 {
423 strcpy (about->text, _("DocuPen RC800 scanner library\n"
424 "Copyright 2020 Ondrej Zary <ondrej@zary.sk>\n"
425 "based on Docupen tools by Florian Heinz <fh@cronon-ag.de>"
426 ));
427
428 return GP_OK;
429 }
430
431
432 int
433 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
434 CameraFileType type, CameraFile *file, void *data,
435 GPContext *context);
436 int
437 get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
438 CameraFileType type, CameraFile *file, void *data,
439 GPContext *context)
440 {
441 Camera *camera = data;
442 struct dp_imagehdr header;
443 size_t ret;
444 char *file_data;
445 gdImagePtr img;
446 void *gdout;
447 int gdsize;
448 int nr = gp_filesystem_number(fs, folder, filename, context);
449 if (nr < 0)
450 return nr;
451 nr++; /* libgphoto2 file numbering is 0-based, docupen 1-based */
452
453 if (!dp_init_cache(camera)) {
454 GP_LOG_E("error initializing cache");
455 return GP_ERROR;
456 }
457
458 /* find the file in cache */
459 fseek(camera->pl->cache, 0, SEEK_SET);
460 do {
461 ret = fread(&header, 1, sizeof(header), camera->pl->cache);
462 if (ret < sizeof(header)) {
463 GP_LOG_E("error reading image header");
464 return GP_ERROR;
465 }
466 if (le16toh(header.magic) != DP_MAGIC) {
467 GP_LOG_E("invalid magic number in image header: 0x%04x", le16toh(header.magic));
468 return GP_ERROR;
469 }
470 if (le16toh(header.nr) == nr) /* found */
471 break;
472 fseek(camera->pl->cache, le32toh(header.payloadlen), SEEK_CUR);
473 } while (1);
474
475 file_data = malloc(le32toh(header.payloadlen));
476 if (!file_data)
477 return GP_ERROR_NO_MEMORY;
478
479 ret = fread(file_data, 1, le32toh(header.payloadlen), camera->pl->cache);
480 if (ret < le32toh(header.payloadlen)) {
481 perror("fread");
482 GP_LOG_E("error reading image data");
483 free(file_data);
484 return GP_ERROR;
485 }
486 switch (type) {
487 case GP_FILE_TYPE_PREVIEW:
488 case GP_FILE_TYPE_NORMAL:
489 switch (le16toh(header.type)) {
490 case TYPE_MONO:
491 img = dp_get_image_mono(&header, file_data);
492 break;
493 case TYPE_GREY4:
494 case TYPE_GREY8:
495 img = dp_get_image_grey(&header, file_data, camera->pl->lut);
496 break;
497 case TYPE_COLOR12:
498 case TYPE_COLOR24:
499 img = dp_get_image_color(&header, file_data, camera->pl->lut);
500 break;
501 default:
502 GP_LOG_E("invalid image type 0x%x", le16toh(header.type));
503 free(file_data);
504 return GP_ERROR;
505 }
506 if (!img) {
507 free(file_data);
508 return GP_ERROR_NO_MEMORY;
509 }
510 gdout = gdImagePngPtr(img, &gdsize);
511 gdImageDestroy(img);
512 free(file_data);
513 if (!gdout) {
514 GP_LOG_E("image conversion error");
515 return GP_ERROR;
516 }
517 file_data = malloc(gdsize);
518 memcpy(file_data, gdout, gdsize);
519 gdFree(gdout);
520 gp_file_set_mime_type (file, GP_MIME_PNG);
521 gp_file_set_data_and_size (file, file_data, gdsize);
522 break;
523 case GP_FILE_TYPE_RAW:
524 gp_file_set_mime_type(file, GP_MIME_RAW);
525 memcpy(raw_header + RAW_HEADER_SERIAL_OFFSET, camera->pl->info.serialno, sizeof(camera->pl->info.serialno));
526 gp_file_append(file, (void *)&raw_header, sizeof(raw_header));
527 gp_file_append(file, (void *)&header, sizeof(header));
528 gp_file_append(file, file_data, le32toh(header.payloadlen));
529 free(file_data);
530 gp_file_adjust_name_for_mime_type(file);
531 break;
532 default:
533 free(file_data);
534 return GP_ERROR_NOT_SUPPORTED;
535 }
536
537 return GP_OK;
538 }
539
540
541 int
542 delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
543 GPContext *context);
544 int
545 delete_all_func (CameraFilesystem *fs, const char *folder, void *data,
546 GPContext *context)
547 {
548 Camera *camera = data;
549 unsigned char status;
550
551 if (!dp_cmd(camera->port, cmd_del_all)) {
552 GP_LOG_E("delete all command failed");
553 return GP_ERROR_CAMERA_ERROR;
554 }
555
556 do
557 gp_port_read(camera->port, (void *)&status, 1);
558 while (status == DP_ACK);
559
560 if (status != 0) {
561 GP_LOG_E("erase failed");
562 return GP_ERROR_CAMERA_ERROR;
563 }
564
565 if (!inquiry_read(camera)) {
566 GP_LOG_E("error reading inquiry after erase");
567 return GP_ERROR_CAMERA_ERROR;
568 }
569
570 dp_delete_cache(camera);
571
572 return GP_OK;
573 }
574
575
576 int
577 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
578 void *data, GPContext *context);
579 int
580 file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
581 void *data, GPContext *context)
582 {
583 Camera *camera = data;
584 return gp_list_populate(list, "docupen%03i.png", le32toh(camera->pl->info.pagestored));
585 }
586
587
588 int
589 storage_info_func (CameraFilesystem *fs,
590 CameraStorageInformation **storageinformations,
591 int *nrofstorageinformations, void *data,
592 GPContext *context);
593 int
594 storage_info_func (CameraFilesystem *fs,
595 CameraStorageInformation **storageinformations,
596 int *nrofstorageinformations, void *data,
597 GPContext *context)
598 {
599 Camera *camera = data;
600 CameraStorageInformation *sinfo;
601
602 sinfo = malloc(sizeof(CameraStorageInformation));
603 if (!sinfo)
604 return GP_ERROR_NO_MEMORY;
605
606 *storageinformations = sinfo;
607 *nrofstorageinformations = 1;
608
609 sinfo->fields = GP_STORAGEINFO_BASE;
610 strcpy(sinfo->basedir, "/");
611 sinfo->fields |= GP_STORAGEINFO_ACCESS;
612 sinfo->access = GP_STORAGEINFO_AC_READONLY_WITH_DELETE;
613 sinfo->fields |= GP_STORAGEINFO_STORAGETYPE;
614 sinfo->type = GP_STORAGEINFO_ST_REMOVABLE_RAM;
615 sinfo->fields |= GP_STORAGEINFO_FILESYSTEMTYPE;
616 sinfo->fstype = GP_STORAGEINFO_FST_GENERICFLAT;
617 sinfo->fields |= GP_STORAGEINFO_MAXCAPACITY;
618 sinfo->capacitykbytes = le32toh(camera->pl->info.flashmemmax) / 1024;
619 sinfo->fields |= GP_STORAGEINFO_FREESPACEKBYTES;
620 sinfo->freekbytes = (le32toh(camera->pl->info.flashmemmax) - le32toh(camera->pl->info.datacountbyte)) / 1024;
621
622 return GP_OK;
623 }
624
625
626 int
627 camera_id (CameraText *id)
628 {
629 strcpy(id->text, "docupen");
630
631 return GP_OK;
632 }
633
634
635 int
636 camera_abilities (CameraAbilitiesList *list)
637 {
638 CameraAbilities a;
639
640 memset(&a, 0, sizeof(a));
641 strcpy(a.model, "Planon DocuPen RC800");
642 a.status = GP_DRIVER_STATUS_EXPERIMENTAL;
643 a.port = GP_PORT_USB;
644 a.usb_vendor = 0x18dd;
645 a.usb_product = 0x1000;
646 a.speed[0] = 0;
647 a.operations = GP_OPERATION_CONFIG;
648 a.file_operations = GP_FILE_OPERATION_RAW;
649 a.folder_operations = GP_FOLDER_OPERATION_DELETE_ALL;
650
651 gp_abilities_list_append(list, a);
652
653 return GP_OK;
654 }
655
656 CameraFilesystemFuncs fsfuncs = {
657 .file_list_func = file_list_func,
658 .get_file_func = get_file_func,
659 .delete_all_func = delete_all_func,
660 .storage_info_func = storage_info_func
661 };
662
663 int
664 camera_init (Camera *camera, GPContext *context)
665 {
666 char buf[64];
667
668 camera->functions->exit = camera_exit;
669 camera->functions->get_config = camera_config_get;
670 camera->functions->set_config = camera_config_set;
671 camera->functions->summary = camera_summary;
672 camera->functions->manual = camera_manual;
673 camera->functions->about = camera_about;
674
675 gp_filesystem_set_funcs(camera->fs, &fsfuncs, camera);
676
677 camera->pl = calloc(1, sizeof(CameraPrivateLibrary));
678 if (!camera->pl)
679 return GP_ERROR_NO_MEMORY;
680
681 if (!dp_cmd(camera->port, cmd_query)) {
682 GP_LOG_E("query failed");
683 camera_exit(camera, context);
684 return GP_ERROR_CAMERA_ERROR;
685 }
686 gp_port_read(camera->port, buf, sizeof(buf)); /* read and ingore */
687
688 if (!dp_cmd(camera->port, cmd_inquiry)) {
689 GP_LOG_E("inquiry failed");
690 camera_exit(camera, context);
691 return GP_ERROR_CAMERA_ERROR;
692 }
693 if (!inquiry_read(camera)) {
694 GP_LOG_E("error reading inquiry reply");
695 camera_exit(camera, context);
696 return GP_ERROR_CAMERA_ERROR;
697 }
698
699 return GP_OK;
700 }