"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"), &section);
  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"), &section);
  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"), &section);
  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"), &section);
  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"), &section);
  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"), &section);
  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 }