Merge branch 'master' into 159-canon-mf113w-not-working

# Conflicts solved:
#	backend/pixma/pixma.h
merge-requests/244/head
Rolf Bensch 2020-06-06 13:46:30 +02:00
commit fe118fda01
154 zmienionych plików z 17627 dodań i 13161 usunięć

Wyświetl plik

@ -1,12 +1,12 @@
# .gitlab-ci.yml -- to test some source code build scenarios
# Copyright (C) 2016-2019 Olaf Meeuwissen
# Copyright (C) 2016-2020 Olaf Meeuwissen
#
# License: GPL-3.0+
variables:
REGISTRY_HUB: "registry.gitlab.com/sane-project/ci-envs"
CONFIGURE_MINI: "--enable-silent-rules"
CONFIGURE_FULL: "--with-usb --enable-avahi --enable-pnm-backend --with-libcurl --with-poppler-glib"
CONFIGURE_FULL: "--with-usb --with-usb-record-replay --with-avahi --enable-pnm-backend --with-libcurl --with-poppler-glib"
stages:
- tarball
@ -76,18 +76,25 @@ debian-10-full:
- doc/sanei-html
expire_in: 1 day
fedora-31-clang:
image: $REGISTRY_HUB:fedora-31-clang
fedora-32-clang:
image: $REGISTRY_HUB:fedora-32-clang
variables:
CONFIGURE_OPTS: "$CONFIGURE_MINI $CONFIGURE_FULL"
<<: *compile_definition
alpine-3.11-musl:
image: $REGISTRY_HUB:alpine-3.11-musl
alpine-3.12-musl:
image: $REGISTRY_HUB:alpine-3.12-musl
variables:
CONFIGURE_OPTS: "$CONFIGURE_MINI $CONFIGURE_FULL"
<<: *compile_definition
ubuntu-16.04-lts:
image: $REGISTRY_HUB:ubuntu-xenial-dist
variables:
CONFIGURE_OPTS: "$CONFIGURE_MINI $CONFIGURE_FULL"
MAKE_FLAGS: "CFLAGS=-Werror CXXFLAGS=-Werror"
<<: *compile_definition
# This snapshot stage job makes sure that the source tarball has all
# it needs to rebuild itself, install everything built and cleans up
# without leaving any droppings behind when uninstalling. The build

Wyświetl plik

@ -13,6 +13,7 @@ Backends:
Mitsuru Okaniwa, Ulrich Deiters
canon630u: Nathan Rutman
canon_dr: m. allan noah (*)
canon_lide70: Juergen Ernst, pimvantend (*)
canon_pp: Matthew Duggan, Simon Krix
cardscan: m. allan noah (*)
coolscan: Didier Carlier, Andreas Rick

Wyświetl plik

@ -25,6 +25,7 @@ $ make install
- libcurl4-gnutls-dev or similar
- libxml2-dev or similar
- libsnmp-dev or similar
- libpoppler-glib-dev or similar
2.2. Get the latest SANE backend from git:
You can download "daily git snapshot" from here:

33
NEWS
Wyświetl plik

@ -2,6 +2,10 @@
## New with the next release
### Backends
- adds an `canon_lide70` backend
### Documentation
- removes the SANE Standard. This is now maintained as a separate
@ -11,6 +15,35 @@
### Build
- removes the `--with-api-spec` option from `configure`
- replaces the `--enable-avahi` option with an `--with-avahi` that
defaults to enabling if possible. If the option is given and the
required support is not available, `configure` will exit with an
error.
## New with 1.0.30 (released 2020-05-17)
This release fixes several security related issues and a build issue.
### Backends
- `epson2`: fixes CVE-2020-12867 (GHSL-2020-075) and several memory
management issues found while addressing that CVE
- `epsonds`: addresses out-of-bound memory access issues to fix
CVE-2020-12862 (GHSL-2020-082) and CVE-2020-12863 (GHSL-2020-083),
addresses a buffer overflow fixing CVE-2020-12865 (GHSL-2020-084)
and disables network autodiscovery to mitigate CVE-2020-12866
(GHSL-2020-079), CVE-2020-12861 (GHSL-2020-080) and CVE-2020-12864
(GHSL-2020-081). Note that this backend does not support network
scanners to begin with.
- `magicolor`: fixes a floating point exception and uninitialized data
read
- fixes an overflow in `sanei_tcp_read()`
### Build
- fixes a build issue where linker flags would become link time
dependencies (#239)
## New with 1.0.29 (released 2020-02-02)

2
README
Wyświetl plik

@ -57,6 +57,8 @@ installed.
- libgphoto2 (>=2.0): For the gphoto2 backend.
- a C++11 compliant C++ compiler for the genesys backend.
If you got the source straight from the git repository, as opposed to
a source tarball, you will need a few more utilities. These utilities
should normally *not* be needed for source archives downloaded from

Wyświetl plik

@ -613,7 +613,7 @@ for be in ${BACKENDS}; do
;;
escl)
if test "x${enable_avahi}" != "xyes"; then
if test "x${with_avahi}" != "xyes"; then
echo "*** $be backend requires AVAHI library - $DISABLE_MSG"
backend_supported="no"
fi
@ -629,7 +629,14 @@ for be in ${BACKENDS}; do
if test "x${sane_cv_use_libjpeg}" != "xyes"; then
echo "*** $be backend currently requires JPEG library - $DISABLE_MSG"
backend_supported="no"
else
if test "x${ac_cv_func_jpeg_crop_scanline}" != "xyes" \
|| test "x${ac_cv_func_jpeg_skip_scanlines}" != "xyes"; then
echo "*** $be backend requires a newer JPEG library - $DISABLE_MSG"
backend_supported="no"
fi
fi
;;
gphoto2)

Wyświetl plik

@ -65,6 +65,7 @@ EXTRA_DIST += saned.conf.in
BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \
artec_eplus48u.conf avision.conf bh.conf \
canon630u.conf canon.conf canon_dr.conf \
canon_lide70.conf \
canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \
coolscan.conf dc210.conf dc240.conf dc25.conf \
dell1600n_net.conf dmc.conf epjitsu.conf epson2.conf \
@ -157,6 +158,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \
libapple.la libartec.la libartec_eplus48u.la \
libas6e.la libavision.la libbh.la \
libcanon.la libcanon630u.la libcanon_dr.la \
libcanon_lide70.la \
libcanon_pp.la libcardscan.la libcoolscan.la \
libcoolscan2.la libcoolscan3.la libdc25.la \
libdc210.la libdc240.la libdell1600n_net.la \
@ -190,6 +192,7 @@ be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \
libsane-apple.la libsane-artec.la libsane-artec_eplus48u.la \
libsane-as6e.la libsane-avision.la libsane-bh.la \
libsane-canon.la libsane-canon630u.la libsane-canon_dr.la \
libsane-canon_lide70.la \
libsane-canon_pp.la libsane-cardscan.la libsane-coolscan.la \
libsane-coolscan2.la libsane-coolscan3.la libsane-dc25.la \
libsane-dc210.la libsane-dc240.la libsane-dell1600n_net.la \
@ -344,6 +347,17 @@ libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += canon_dr.conf.in
libcanon_lide70_la_SOURCES = canon_lide70.c
libcanon_lide70_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_lide70
nodist_libsane_canon_lide70_la_SOURCES = canon_lide70-s.c
libsane_canon_lide70_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_lide70
libsane_canon_lide70_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_lide70_la_LIBADD = $(COMMON_LIBS) libcanon_lide70.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += canon_lide70.conf.in
# TODO: Why are this distributed but not compiled?
EXTRA_DIST += canon_lide70-common.c
libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h
libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp
@ -514,11 +528,9 @@ libsane_fujitsu_la_LIBADD = $(COMMON_LIBS) libfujitsu.la ../sanei/sanei_init_deb
EXTRA_DIST += fujitsu.conf.in
libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/buffer.h genesys/buffer.cpp \
genesys/calibration.h \
genesys/command_set.h \
genesys/command_set_common.h genesys/command_set_common.cpp \
genesys/conv.h genesys/conv.cpp \
genesys/device.h genesys/device.cpp \
genesys/enums.h genesys/enums.cpp \
genesys/error.h genesys/error.cpp \
@ -526,6 +538,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/gl646.cpp genesys/gl646.h genesys/gl646_registers.h \
genesys/gl124.cpp genesys/gl124.h genesys/gl124_registers.h \
genesys/gl841.cpp genesys/gl841.h genesys/gl841_registers.h \
genesys/gl842.cpp genesys/gl842.h genesys/gl842_registers.h \
genesys/gl843.cpp genesys/gl843.h genesys/gl843_registers.h \
genesys/gl846.cpp genesys/gl846.h genesys/gl846_registers.h \
genesys/gl847.cpp genesys/gl847.h genesys/gl847_registers.h \
@ -546,6 +559,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/status.h genesys/status.cpp \
genesys/tables_frontend.cpp \
genesys/tables_gpo.cpp \
genesys/tables_memory_layout.cpp \
genesys/tables_model.cpp \
genesys/tables_motor.cpp \
genesys/tables_sensor.cpp \
@ -554,6 +568,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/test_usb_device.h genesys/test_usb_device.cpp \
genesys/usb_device.h genesys/usb_device.cpp \
genesys/low.cpp genesys/low.h \
genesys/value_filter.h \
genesys/utilities.h
libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys
@ -561,7 +576,10 @@ libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys
nodist_libsane_genesys_la_SOURCES = genesys-s.cpp
libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys
libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS)
libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la \
../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \
../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo \
$(MATH_LIB) $(TIFF_LIBS) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += genesys.conf.in
libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h
@ -695,10 +713,10 @@ libsane_kodak_la_LIBADD = $(COMMON_LIBS) libkodak.la ../sanei/sanei_init_debug.l
EXTRA_DIST += kodak.conf.in
libkodakaio_la_SOURCES = kodakaio.c kodakaio.h
libkodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio
libkodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=kodakaio
nodist_libsane_kodakaio_la_SOURCES = kodakaio-s.c
libsane_kodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio
libsane_kodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=kodakaio
libsane_kodakaio_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_kodakaio_la_LIBADD = $(COMMON_LIBS) libkodakaio.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(USB_LIBS) $(SOCKET_LIBS) $(AVAHI_LIBS) $(MATH_LIB) $(RESMGR_LIBS)
EXTRA_DIST += kodakaio.conf.in
@ -917,12 +935,12 @@ libpixma_la_SOURCES = pixma/pixma.c \
pixma/pixma_bjnp.h \
pixma/pixma_bjnp_private.h \
pixma/pixma_rename.h
libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma
libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) $(XML_CFLAGS) -DBACKEND_NAME=pixma
nodist_libsane_pixma_la_SOURCES = pixma-s.c
libsane_pixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma
libsane_pixma_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(XML_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += pixma.conf.in
# included in pixma.c
EXTRA_DIST += pixma/pixma_sane_options.c pixma/pixma_sane_options.h

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,960 @@
/* sane - Scanner Access Now Easy.
BACKEND canon_lide70
Copyright (C) 2019 Juergen Ernst and pimvantend.
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
This file implements a SANE backend for the Canon CanoScan LiDE 70 */
#define BUILD 0
#define MM_IN_INCH 25.4
#include "../include/sane/config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "../include/sane/sane.h"
#include "../include/sane/sanei.h"
#include "../include/sane/saneopts.h"
#include "../include/sane/sanei_config.h"
#include "../include/sane/sanei_usb.h"
#define BACKEND_NAME canon_lide70
#define CANONUSB_CONFIG_FILE "canon_lide70.conf"
#include "../include/sane/sanei_backend.h"
typedef enum
{
opt_num_opts = 0,
opt_mode_group,
opt_threshold,
opt_mode,
opt_resolution,
opt_non_blocking,
opt_geometry_group,
opt_tl_x,
opt_tl_y,
opt_br_x,
opt_br_y,
/* must come last: */
num_options
}
canon_opts;
#include "canon_lide70-common.c"
static size_t
max_string_size (const SANE_String_Const strings[])
{
size_t size, max_size = 0;
SANE_Int i;
for (i = 0; strings[i]; ++i)
{
size = strlen (strings[i]) + 1;
if (size > max_size)
max_size = size;
}
return max_size;
}
static SANE_String_Const mode_list[] = {
SANE_VALUE_SCAN_MODE_COLOR,
SANE_VALUE_SCAN_MODE_GRAY,
SANE_VALUE_SCAN_MODE_LINEART,
0
};
static SANE_Fixed init_tl_x = SANE_FIX (0.0);
static SANE_Fixed init_tl_y = SANE_FIX (0.0);
static SANE_Fixed init_br_x = SANE_FIX (80.0);
static SANE_Fixed init_br_y = SANE_FIX (100.0);
static SANE_Int init_threshold = 75;
static SANE_Int init_resolution = 600;
static SANE_String init_mode = SANE_VALUE_SCAN_MODE_COLOR;
static SANE_Int init_graymode = 0;
static SANE_Bool init_non_blocking = SANE_FALSE;
/*-----------------------------------------------------------------*/
/*
Scan range
*/
static const SANE_Range widthRange = {
0, /* minimum */
SANE_FIX (CANON_MAX_WIDTH * MM_IN_INCH / 600), /* maximum */
0 /* quantization */
};
static const SANE_Range heightRange = {
0, /* minimum */
/* SANE_FIX (CANON_MAX_HEIGHT * MM_IN_INCH / 600 - TOP_EDGE ), maximum */
SANE_FIX (297.0),
0 /* quantization */
};
static const SANE_Range threshold_range = {
0,
100,
1
};
static SANE_Int resolution_list[] = { 5,
75,
150,
300,
600,
1200
};
typedef struct Canon_Device
{
struct Canon_Device *next;
SANE_String name;
SANE_Device sane;
}
Canon_Device;
/* Canon_Scanner is the type used for the sane handle */
typedef struct Canon_Scanner
{
struct Canon_Scanner *next;
Canon_Device *device;
CANON_Handle scan;
}
Canon_Scanner;
static int num_devices = 0;
static const SANE_Device **devlist = NULL;
static Canon_Device *first_dev = NULL;
static Canon_Scanner *first_handle = NULL;
/*-----------------------------------------------------------------*/
static SANE_Status
attach_scanner (const char *devicename, Canon_Device ** devp)
{
CANON_Handle scan;
Canon_Device *dev;
SANE_Status status;
DBG (3, "attach_scanner: %s\n", devicename);
for (dev = first_dev; dev; dev = dev->next)
{
if (strcmp (dev->sane.name, devicename) == 0)
{
if (devp)
*devp = dev;
return SANE_STATUS_GOOD;
}
}
dev = malloc (sizeof (*dev));
if (!dev)
return SANE_STATUS_NO_MEM;
memset (dev, '\0', sizeof (Canon_Device)); /* clear structure */
DBG (4, "attach_scanner: opening %s\n", devicename);
status = CANON_open_device (&scan, devicename);
if (status != SANE_STATUS_GOOD)
{
DBG (1, "ERROR: attach_scanner: opening %s failed\n", devicename);
free (dev);
return status;
}
dev->name = strdup (devicename);
dev->sane.name = dev->name;
dev->sane.vendor = "CANON";
dev->sane.model = CANON_get_device_name (&scan);
dev->sane.type = "flatbed scanner";
CANON_close_device (&scan);
++num_devices;
dev->next = first_dev;
first_dev = dev;
if (devp)
*devp = dev;
return SANE_STATUS_GOOD;
}
/* callback function for sanei_usb_attach_matching_devices */
static SANE_Status
attach_one (const char *name)
{
attach_scanner (name, 0);
return SANE_STATUS_GOOD;
}
/* Find our devices */
SANE_Status
sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
{
char config_line[PATH_MAX];
size_t len;
FILE *fp;
DBG_INIT ();
#if 0
DBG_LEVEL = 10;
#endif
DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
DBG (1, "sane_init: SANE Canon LiDE70 backend version %d.%d.%d from %s\n",
V_MAJOR, V_MINOR, BUILD, PACKAGE_STRING);
if (version_code)
*version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BUILD);
sanei_usb_init ();
fp = sanei_config_open (CANONUSB_CONFIG_FILE);
if (!fp)
{
/* no config-file: try these */
attach_scanner ("/dev/scanner", 0);
attach_scanner ("/dev/usbscanner", 0);
attach_scanner ("/dev/usb/scanner", 0);
return SANE_STATUS_GOOD;
}
DBG (3, "reading configure file %s\n", CANONUSB_CONFIG_FILE);
while (sanei_config_read (config_line, sizeof (config_line), fp))
{
if (config_line[0] == '#')
continue; /* ignore line comments */
len = strlen (config_line);
if (!len)
continue; /* ignore empty lines */
DBG (4, "attach_matching_devices(%s)\n", config_line);
sanei_usb_attach_matching_devices (config_line, attach_one);
}
DBG (4, "finished reading configure file\n");
fclose (fp);
return SANE_STATUS_GOOD;
}
void
sane_exit (void)
{
Canon_Device *dev, *next;
DBG (3, "sane_exit\n");
for (dev = first_dev; dev; dev = next)
{
next = dev->next;
free (dev->name);
free (dev);
}
if (devlist)
free (devlist);
return;
}
SANE_Status
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
{
Canon_Device *dev;
int i;
DBG (3, "sane_get_devices(local_only = %d)\n", local_only);
if (devlist)
free (devlist);
devlist = malloc ((num_devices + 1) * sizeof (devlist[0]));
if (!devlist)
return SANE_STATUS_NO_MEM;
i = 0;
for (dev = first_dev; i < num_devices; dev = dev->next)
devlist[i++] = &dev->sane;
devlist[i++] = 0;
*device_list = devlist;
return SANE_STATUS_GOOD;
}
static SANE_Status
init_options (CANON_Handle * chndl)
{
SANE_Option_Descriptor *od;
DBG (2, "begin init_options: chndl=%p\n", (void *) chndl);
/* opt_num_opts */
od = &chndl->opt[opt_num_opts];
od->name = "";
od->title = SANE_TITLE_NUM_OPTIONS;
od->desc = SANE_DESC_NUM_OPTIONS;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_NONE;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_num_opts].w = num_options;
DBG (2, "val[opt_num_opts]: %d\n", chndl->val[opt_num_opts].w);
/* opt_mode_group */
od = &chndl->opt[opt_mode_group];
od->name = "";
od->title = SANE_I18N ("Scan Mode");
od->desc = "";
od->type = SANE_TYPE_GROUP;
od->unit = SANE_UNIT_NONE;
od->size = 0;
od->cap = 0;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_mode_group].w = 0;
/* opt_mode */
od = &chndl->opt[opt_mode];
od->name = SANE_NAME_SCAN_MODE;
od->title = SANE_TITLE_SCAN_MODE;
od->desc = SANE_DESC_SCAN_MODE;
od->type = SANE_TYPE_STRING;
od->unit = SANE_UNIT_NONE;
od->size = max_string_size (mode_list);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_STRING_LIST;
od->constraint.string_list = mode_list;
chndl->val[opt_mode].s = malloc (od->size);
if (!chndl->val[opt_mode].s)
return SANE_STATUS_NO_MEM;
strcpy (chndl->val[opt_mode].s, init_mode);
chndl->graymode = init_graymode;
/* opt_threshold */
od = &chndl->opt[opt_threshold];
od->name = SANE_NAME_THRESHOLD;
od->title = SANE_TITLE_THRESHOLD;
od->desc = SANE_DESC_THRESHOLD;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_PERCENT;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &threshold_range;
chndl->val[opt_threshold].w = init_threshold;
/* opt_resolution */
od = &chndl->opt[opt_resolution];
od->name = SANE_NAME_SCAN_RESOLUTION;
od->title = SANE_TITLE_SCAN_RESOLUTION;
od->desc = SANE_DESC_SCAN_RESOLUTION;
od->type = SANE_TYPE_INT;
od->unit = SANE_UNIT_DPI;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_WORD_LIST;
od->constraint.word_list = resolution_list;
chndl->val[opt_resolution].w = init_resolution;
/* opt_non_blocking */
od = &chndl->opt[opt_non_blocking];
od->name = "non-blocking";
od->title = SANE_I18N ("Use non-blocking IO");
od->desc = SANE_I18N ("Use non-blocking IO for sane_read() if supported "
"by the frontend.");
od->type = SANE_TYPE_BOOL;
od->unit = SANE_UNIT_NONE;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_INACTIVE;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_non_blocking].w = init_non_blocking;
/* opt_geometry_group */
od = &chndl->opt[opt_geometry_group];
od->name = "";
od->title = SANE_I18N ("Geometry");
od->desc = "";
od->type = SANE_TYPE_GROUP;
od->unit = SANE_UNIT_NONE;
od->size = 0;
od->cap = 0;
od->constraint_type = SANE_CONSTRAINT_NONE;
od->constraint.range = 0;
chndl->val[opt_geometry_group].w = 0;
/* opt_tl_x */
od = &chndl->opt[opt_tl_x];
od->name = SANE_NAME_SCAN_TL_X;
od->title = SANE_TITLE_SCAN_TL_X;
od->desc = SANE_DESC_SCAN_TL_X;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &widthRange;
chndl->val[opt_tl_x].w = init_tl_x;
/* opt_tl_y */
od = &chndl->opt[opt_tl_y];
od->name = SANE_NAME_SCAN_TL_Y;
od->title = SANE_TITLE_SCAN_TL_Y;
od->desc = SANE_DESC_SCAN_TL_Y;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &heightRange;
chndl->val[opt_tl_y].w = init_tl_y;
/* opt_br_x */
od = &chndl->opt[opt_br_x];
od->name = SANE_NAME_SCAN_BR_X;
od->title = SANE_TITLE_SCAN_BR_X;
od->desc = SANE_DESC_SCAN_BR_X;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &widthRange;
chndl->val[opt_br_x].w = init_br_x;
/* opt_br_y */
od = &chndl->opt[opt_br_y];
od->name = SANE_NAME_SCAN_BR_Y;
od->title = SANE_TITLE_SCAN_BR_Y;
od->desc = SANE_DESC_SCAN_BR_Y;
od->type = SANE_TYPE_FIXED;
od->unit = SANE_UNIT_MM;
od->size = sizeof (SANE_Word);
od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
od->constraint_type = SANE_CONSTRAINT_RANGE;
od->constraint.range = &heightRange;
chndl->val[opt_br_y].w = init_br_y;
DBG (2, "end init_options: chndl=%p\n", (void *) chndl);
return SANE_STATUS_GOOD;
}
SANE_Status
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
{
Canon_Device *dev;
SANE_Status status;
Canon_Scanner *scanner;
DBG (3, "sane_open\n");
if (devicename[0]) /* search for devicename */
{
DBG (4, "sane_open: devicename=%s\n", devicename);
for (dev = first_dev; dev; dev = dev->next)
if (strcmp (dev->sane.name, devicename) == 0)
break;
if (!dev)
{
status = attach_scanner (devicename, &dev);
if (status != SANE_STATUS_GOOD)
return status;
}
}
else
{
DBG (2, "sane_open: no devicename, opening first device\n");
dev = first_dev;
}
if (!dev)
return SANE_STATUS_INVAL;
scanner = malloc (sizeof (*scanner));
if (!scanner)
return SANE_STATUS_NO_MEM;
memset (scanner, 0, sizeof (*scanner));
scanner->device = dev;
status = CANON_open_device (&scanner->scan, dev->sane.name);
if (status != SANE_STATUS_GOOD)
{
free (scanner);
return status;
}
status = init_options (&scanner->scan);
*handle = scanner;
/* insert newly opened handle into list of open handles: */
scanner->next = first_handle;
first_handle = scanner;
return status;
}
static void
print_options (CANON_Handle * chndl)
{
SANE_Option_Descriptor *od;
SANE_Word option_number;
SANE_Char caps[1024];
for (option_number = 0; option_number < num_options; option_number++)
{
od = &chndl->opt[option_number];
DBG (50, "-----> number: %d\n", option_number);
DBG (50, " name: `%s'\n", od->name);
DBG (50, " title: `%s'\n", od->title);
DBG (50, " description: `%s'\n", od->desc);
DBG (50, " type: %s\n",
od->type == SANE_TYPE_BOOL ? "SANE_TYPE_BOOL" :
od->type == SANE_TYPE_INT ? "SANE_TYPE_INT" :
od->type == SANE_TYPE_FIXED ? "SANE_TYPE_FIXED" :
od->type == SANE_TYPE_STRING ? "SANE_TYPE_STRING" :
od->type == SANE_TYPE_BUTTON ? "SANE_TYPE_BUTTON" :
od->type == SANE_TYPE_GROUP ? "SANE_TYPE_GROUP" : "unknown");
DBG (50, " unit: %s\n",
od->unit == SANE_UNIT_NONE ? "SANE_UNIT_NONE" :
od->unit == SANE_UNIT_PIXEL ? "SANE_UNIT_PIXEL" :
od->unit == SANE_UNIT_BIT ? "SANE_UNIT_BIT" :
od->unit == SANE_UNIT_MM ? "SANE_UNIT_MM" :
od->unit == SANE_UNIT_DPI ? "SANE_UNIT_DPI" :
od->unit == SANE_UNIT_PERCENT ? "SANE_UNIT_PERCENT" :
od->unit == SANE_UNIT_MICROSECOND ? "SANE_UNIT_MICROSECOND" :
"unknown");
DBG (50, " size: %d\n", od->size);
caps[0] = '\0';
if (od->cap & SANE_CAP_SOFT_SELECT)
strcat (caps, "SANE_CAP_SOFT_SELECT ");
if (od->cap & SANE_CAP_HARD_SELECT)
strcat (caps, "SANE_CAP_HARD_SELECT ");
if (od->cap & SANE_CAP_SOFT_DETECT)
strcat (caps, "SANE_CAP_SOFT_DETECT ");
if (od->cap & SANE_CAP_EMULATED)
strcat (caps, "SANE_CAP_EMULATED ");
if (od->cap & SANE_CAP_AUTOMATIC)
strcat (caps, "SANE_CAP_AUTOMATIC ");
if (od->cap & SANE_CAP_INACTIVE)
strcat (caps, "SANE_CAP_INACTIVE ");
if (od->cap & SANE_CAP_ADVANCED)
strcat (caps, "SANE_CAP_ADVANCED ");
DBG (50, " capabilities: %s\n", caps);
DBG (50, "constraint type: %s\n",
od->constraint_type == SANE_CONSTRAINT_NONE ?
"SANE_CONSTRAINT_NONE" :
od->constraint_type == SANE_CONSTRAINT_RANGE ?
"SANE_CONSTRAINT_RANGE" :
od->constraint_type == SANE_CONSTRAINT_WORD_LIST ?
"SANE_CONSTRAINT_WORD_LIST" :
od->constraint_type == SANE_CONSTRAINT_STRING_LIST ?
"SANE_CONSTRAINT_STRING_LIST" : "unknown");
if (od->type == SANE_TYPE_INT)
DBG (50, " value: %d\n", chndl->val[option_number].w);
else if (od->type == SANE_TYPE_FIXED)
DBG (50, " value: %f\n",
SANE_UNFIX (chndl->val[option_number].w));
else if (od->type == SANE_TYPE_STRING)
DBG (50, " value: %s\n", chndl->val[option_number].s);
}
}
void
sane_close (SANE_Handle handle)
{
Canon_Scanner *prev, *scanner;
SANE_Status res;
DBG (3, "sane_close\n");
scanner = handle;
print_options (&scanner->scan);
if (!first_handle)
{
DBG (1, "ERROR: sane_close: no handles opened\n");
return;
}
/* remove handle from list of open handles: */
prev = NULL;
for (scanner = first_handle; scanner; scanner = scanner->next)
{
if (scanner == handle)
break;
prev = scanner;
}
if (!scanner)
{
DBG (1, "ERROR: sane_close: invalid handle %p\n", handle);
return; /* oops, not a handle we know about */
}
if (prev)
prev->next = scanner->next;
else
first_handle = scanner->next;
res = CANON_close_device (&scanner->scan);
DBG (3, "CANON_close_device returned: %d\n", res);
free (scanner);
}
const SANE_Option_Descriptor *
sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
DBG (4, "sane_get_option_descriptor: handle=%p, option = %d\n",
(void *) handle, option);
if (option < 0 || option >= num_options)
{
DBG (3, "sane_get_option_descriptor: option < 0 || "
"option > num_options\n");
return 0;
}
return &chndl->opt[option];
}
SANE_Status
sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
void *value, SANE_Int * info)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
SANE_Int myinfo = 0;
SANE_Status status;
DBG (4, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
(void *) handle, option, action, (void *) value, (void *) info);
if (option < 0 || option >= num_options)
{
DBG (1, "sane_control_option: option < 0 || option > num_options\n");
return SANE_STATUS_INVAL;
}
if (!SANE_OPTION_IS_ACTIVE (chndl->opt[option].cap))
{
DBG (1, "sane_control_option: option is inactive\n");
return SANE_STATUS_INVAL;
}
if (chndl->opt[option].type == SANE_TYPE_GROUP)
{
DBG (1, "sane_control_option: option is a group\n");
return SANE_STATUS_INVAL;
}
switch (action)
{
case SANE_ACTION_SET_VALUE:
if (!SANE_OPTION_IS_SETTABLE (chndl->opt[option].cap))
{
DBG (1, "sane_control_option: option is not setable\n");
return SANE_STATUS_INVAL;
}
status = sanei_constrain_value (&chndl->opt[option], value, &myinfo);
if (status != SANE_STATUS_GOOD)
{
DBG (3, "sane_control_option: sanei_constrain_value returned %s\n",
sane_strstatus (status));
return status;
}
switch (option)
{
case opt_tl_x: /* Fixed with parameter reloading */
case opt_tl_y:
case opt_br_x:
case opt_br_y:
if (chndl->val[option].w == *(SANE_Fixed *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Fixed *) value;
myinfo |= SANE_INFO_RELOAD_PARAMS;
DBG (4, "sane_control_option: set option %d (%s) to %.0f %s\n",
option, chndl->opt[option].name,
SANE_UNFIX (*(SANE_Fixed *) value),
chndl->opt[option].unit == SANE_UNIT_MM ? "mm" : "dpi");
break;
case opt_non_blocking:
if (chndl->val[option].w == *(SANE_Bool *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Bool *) value;
DBG (4, "sane_control_option: set option %d (%s) to %s\n",
option, chndl->opt[option].name,
*(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
break;
case opt_resolution:
case opt_threshold:
if (chndl->val[option].w == *(SANE_Int *) value)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
chndl->val[option].w = *(SANE_Int *) value;
myinfo |= SANE_INFO_RELOAD_PARAMS;
myinfo |= SANE_INFO_RELOAD_OPTIONS;
DBG (4, "sane_control_option: set option %d (%s) to %d\n",
option, chndl->opt[option].name, *(SANE_Int *) value);
break;
case opt_mode:
if (strcmp (chndl->val[option].s, value) == 0)
{
DBG (4, "sane_control_option: option %d (%s) not changed\n",
option, chndl->opt[option].name);
break;
}
strcpy (chndl->val[option].s, (SANE_String) value);
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) ==
0)
{
chndl->opt[opt_threshold].cap &= ~SANE_CAP_INACTIVE;
chndl->graymode = 2;
}
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0)
{
chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
chndl->graymode = 0;
}
if (strcmp (chndl->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0)
{
chndl->opt[opt_threshold].cap |= SANE_CAP_INACTIVE;
chndl->graymode = 1;
}
myinfo |= SANE_INFO_RELOAD_PARAMS;
myinfo |= SANE_INFO_RELOAD_OPTIONS;
DBG (4, "sane_control_option: set option %d (%s) to %s\n",
option, chndl->opt[option].name, (SANE_String) value);
break;
default:
DBG (1, "sane_control_option: trying to set unexpected option\n");
return SANE_STATUS_INVAL;
}
break;
case SANE_ACTION_GET_VALUE:
switch (option)
{
case opt_num_opts:
*(SANE_Word *) value = num_options;
DBG (4, "sane_control_option: get option 0, value = %d\n",
num_options);
break;
case opt_tl_x: /* Fixed options */
case opt_tl_y:
case opt_br_x:
case opt_br_y:
{
*(SANE_Fixed *) value = chndl->val[option].w;
DBG (4,
"sane_control_option: get option %d (%s), value=%.1f %s\n",
option, chndl->opt[option].name,
SANE_UNFIX (*(SANE_Fixed *) value),
chndl->opt[option].unit ==
SANE_UNIT_MM ? "mm" : SANE_UNIT_DPI ? "dpi" : "");
break;
}
case opt_non_blocking:
*(SANE_Bool *) value = chndl->val[option].w;
DBG (4,
"sane_control_option: get option %d (%s), value=%s\n",
option, chndl->opt[option].name,
*(SANE_Bool *) value == SANE_TRUE ? "true" : "false");
break;
case opt_mode: /* String (list) options */
strcpy (value, chndl->val[option].s);
DBG (4, "sane_control_option: get option %d (%s), value=`%s'\n",
option, chndl->opt[option].name, (SANE_String) value);
break;
case opt_resolution:
case opt_threshold:
*(SANE_Int *) value = chndl->val[option].w;
DBG (4, "sane_control_option: get option %d (%s), value=%d\n",
option, chndl->opt[option].name, *(SANE_Int *) value);
break;
default:
DBG (1, "sane_control_option: trying to get unexpected option\n");
return SANE_STATUS_INVAL;
}
break;
default:
DBG (1, "sane_control_option: trying unexpected action %d\n", action);
return SANE_STATUS_INVAL;
}
if (info)
*info = myinfo;
return SANE_STATUS_GOOD;
}
SANE_Status
sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
{
Canon_Scanner *hndl = handle; /* Eliminate compiler warning */
CANON_Handle *chndl = &hndl->scan;
int rc = SANE_STATUS_GOOD;
int w = SANE_UNFIX (chndl->val[opt_br_x].w -
chndl->val[opt_tl_x].w) / MM_IN_INCH *
chndl->val[opt_resolution].w;
int h =
SANE_UNFIX (chndl->val[opt_br_y].w -
chndl->val[opt_tl_y].w) / MM_IN_INCH *
chndl->val[opt_resolution].w;
DBG (3, "sane_get_parameters\n");
chndl->params.depth = 8;
chndl->params.last_frame = SANE_TRUE;
chndl->params.pixels_per_line = w;
chndl->params.lines = h;
if (chndl->graymode == 1)
{
chndl->params.format = SANE_FRAME_GRAY;
chndl->params.bytes_per_line = w;
}
else if (chndl->graymode == 2)
{
chndl->params.format = SANE_FRAME_GRAY;
w /= 8;
if ((chndl->params.pixels_per_line % 8) != 0)
w++;
chndl->params.bytes_per_line = w;
chndl->params.depth = 1;
}
else
{
chndl->params.format = SANE_FRAME_RGB;
chndl->params.bytes_per_line = w * 3;
}
*params = chndl->params;
DBG (1, "%d\n", chndl->params.format);
return rc;
}
SANE_Status
sane_start (SANE_Handle handle)
{
Canon_Scanner *scanner = handle;
CANON_Handle *chndl = &scanner->scan;
SANE_Status res;
DBG (3, "sane_start\n");
res = sane_get_parameters (handle, &chndl->params);
res = CANON_set_scan_parameters (&scanner->scan);
if (res != SANE_STATUS_GOOD)
return res;
return CANON_start_scan (&scanner->scan);
}
SANE_Status
sane_read (SANE_Handle handle, SANE_Byte * data,
SANE_Int max_length, SANE_Int * length)
{
Canon_Scanner *scanner = handle;
return CANON_read (&scanner->scan, data, max_length, length);
}
void
sane_cancel (SANE_Handle handle)
{
DBG (3, "sane_cancel: handle = %p\n", handle);
DBG (3, "sane_cancel: cancelling is unsupported in this backend\n");
}
SANE_Status
sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
{
DBG (3, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
non_blocking);
if (non_blocking != SANE_FALSE)
return SANE_STATUS_UNSUPPORTED;
return SANE_STATUS_GOOD;
}
SANE_Status
sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
{
handle = handle; /* silence gcc */
fd = fd; /* silence gcc */
return SANE_STATUS_UNSUPPORTED;
}

Wyświetl plik

@ -0,0 +1,8 @@
# Options for the canon_lide70 backend
# Autodetect the Canon CanoScan LiDE 70
usb 0x04a9 0x2225
# device list for non-linux-systems (enable if autodetect fails):
#/dev/scanner
#/dev/usb/scanner0

Wyświetl plik

@ -19,6 +19,7 @@ bh
canon
canon630u
canon_dr
canon_lide70
#canon_pp
cardscan
coolscan

Wyświetl plik

@ -512,59 +512,65 @@ DMCInitOptions(DMC_Camera *c)
static SANE_Status
DMCSetMode(DMC_Camera *c, int mode)
{
switch(mode) {
switch (mode)
{
case IMAGE_MFI:
c->tl_x_range.min = 0;
c->tl_x_range.max = c->tl_x_range.max;
c->tl_y_range.min = 0;
c->tl_y_range.max = c->tl_y_range.max;
c->br_x_range.min = 800;
c->br_x_range.max = c->br_x_range.max;
c->br_y_range.min = 599;
c->br_y_range.max = c->br_y_range.max;
break;
c->tl_x_range.min = 0;
c->tl_x_range.max = 800;
c->tl_y_range.min = 0;
c->tl_y_range.max = 599;
c->br_x_range.min = c->tl_x_range.min;
c->br_x_range.max = c->tl_x_range.max;
c->br_y_range.min = c->tl_y_range.min;
c->br_y_range.max = c->tl_y_range.max;
break;
case IMAGE_VIEWFINDER:
c->tl_x_range.min = 0;
c->tl_x_range.max = c->tl_x_range.max;
c->tl_y_range.min = 0;
c->tl_y_range.max = c->tl_y_range.max;
c->br_x_range.min = 269;
c->br_x_range.max = c->br_x_range.max;
c->br_y_range.min = 200;
c->br_y_range.max = c->br_y_range.max;
break;
c->tl_x_range.min = 0;
c->tl_x_range.max = 269;
c->tl_y_range.min = 0;
c->tl_y_range.max = 200;
c->br_x_range.min = c->tl_x_range.min;
c->br_x_range.max = c->tl_x_range.max;
c->br_y_range.min = c->tl_y_range.min;
c->br_y_range.max = c->tl_y_range.max;
break;
case IMAGE_RAW:
c->tl_x_range.min = 0;
c->tl_x_range.max = c->tl_x_range.max;
c->tl_y_range.min = 0;
c->tl_y_range.max = c->tl_y_range.max;
c->br_x_range.min = 1598;
c->br_x_range.max = c->br_x_range.max;
c->br_y_range.min = 599;
c->br_y_range.max = c->br_y_range.max;
break;
c->tl_x_range.min = 0;
c->tl_x_range.max = 1598;
c->tl_y_range.min = 0;
c->tl_y_range.max = 599;
c->br_x_range.min = c->tl_x_range.min;
c->br_x_range.max = c->tl_x_range.max;
c->br_y_range.min = c->tl_y_range.min;
c->br_y_range.max = c->tl_y_range.max;
break;
case IMAGE_THUMB:
c->tl_x_range.min = 0;
c->tl_x_range.max = c->tl_x_range.max;
c->tl_y_range.min = 0;
c->tl_y_range.max = c->tl_y_range.max;
c->br_x_range.min = 79;
c->br_x_range.max = c->br_x_range.max;
c->br_y_range.min = 59;
c->br_y_range.max = c->br_y_range.max;
break;
c->tl_x_range.min = 0;
c->tl_x_range.max = 79;
c->tl_y_range.min = 0;
c->tl_y_range.max = 59;
c->br_x_range.min = c->tl_x_range.min;
c->br_x_range.max = c->tl_x_range.max;
c->br_y_range.min = c->tl_y_range.min;
c->br_y_range.max = c->tl_y_range.max;
break;
case IMAGE_SUPER_RES:
c->tl_x_range.min = 0;
c->tl_x_range.max = c->tl_x_range.max;
c->tl_y_range.min = 0;
c->tl_y_range.max = c->tl_y_range.max;
c->br_x_range.min = 1598;
c->br_x_range.max = c->br_x_range.max;
c->br_y_range.min = 1199;
c->br_y_range.max = c->br_y_range.max;
break;
c->tl_x_range.min = 0;
c->tl_x_range.max = 1598;
c->tl_y_range.min = 0;
c->tl_y_range.max = 1199;
c->br_x_range.min = c->tl_x_range.min;
c->br_x_range.max = c->tl_x_range.max;
c->br_y_range.min = c->tl_y_range.min;
c->br_y_range.max = c->tl_y_range.max;
break;
default:
return SANE_STATUS_INVAL;
return SANE_STATUS_INVAL;
}
c->imageMode = mode;
c->val[OPT_TL_X].w = c->tl_x_range.min;

Wyświetl plik

@ -32,11 +32,12 @@
#include "sane/sanei_debug.h"
static int
static ssize_t
sanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
SANE_Status *status)
{
int ready, read = -1;
int ready;
ssize_t read = -1;
fd_set readable;
struct timeval tv;
@ -62,111 +63,136 @@ sanei_epson_net_read_raw(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
return read;
}
int
static ssize_t
sanei_epson_net_read_buf(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
SANE_Status * status)
{
ssize_t read = 0;
DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n",
__func__, (u_long) wanted, s->netptr, (u_long) s->netlen);
if ((size_t) wanted > s->netlen) {
*status = SANE_STATUS_IO_ERROR;
wanted = s->netlen;
}
memcpy(buf, s->netptr, wanted);
read = wanted;
s->netptr += read;
s->netlen -= read;
if (s->netlen == 0) {
DBG(23, "%s: freeing %p\n", __func__, s->netbuf);
free(s->netbuf);
s->netbuf = s->netptr = NULL;
s->netlen = 0;
}
return read;
}
ssize_t
sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted,
SANE_Status * status)
{
ssize_t size;
ssize_t read = 0;
unsigned char header[12];
/* read from buffer, if available */
if (s->netptr != s->netbuf) {
DBG(23, "reading %lu from buffer at %p, %lu available\n",
(u_long) wanted, s->netptr, (u_long) s->netlen);
memcpy(buf, s->netptr, wanted);
read = wanted;
s->netlen -= wanted;
if (s->netlen == 0) {
DBG(23, "%s: freeing %p\n", __func__, s->netbuf);
free(s->netbuf);
s->netbuf = s->netptr = NULL;
s->netlen = 0;
}
return read;
}
/* receive net header */
size = sanei_epson_net_read_raw(s, header, 12, status);
if (size != 12) {
if (wanted < 0) {
*status = SANE_STATUS_INVAL;
return 0;
}
size_t size;
ssize_t read = 0;
unsigned char header[12];
/* read from remainder of buffer */
if (s->netptr) {
return sanei_epson_net_read_buf(s, buf, wanted, status);
}
/* receive net header */
read = sanei_epson_net_read_raw(s, header, 12, status);
if (read != 12) {
return 0;
}
/* validate header */
if (header[0] != 'I' || header[1] != 'S') {
DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]);
*status = SANE_STATUS_IO_ERROR;
return 0;
}
/* parse payload size */
size = be32atoh(&header[6]);
DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
(u_long) wanted, (u_long) size);
*status = SANE_STATUS_GOOD;
if (size == wanted) {
if (!s->netbuf) {
DBG(15, "%s: direct read\n", __func__);
DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
(u_long) wanted, (u_long) size);
DBG(15, "%s: full read\n", __func__);
read = sanei_epson_net_read_raw(s, buf, size, status);
if (s->netbuf) {
free(s->netbuf);
s->netbuf = NULL;
s->netlen = 0;
if ((size_t) wanted > size) {
wanted = size;
}
if (read < 0) {
return 0;
}
/* } else if (wanted < size && s->netlen == size) { */
read = sanei_epson_net_read_raw(s, buf, wanted, status);
} else {
DBG(23, "%s: partial read\n", __func__);
DBG(15, "%s: buffered read\n", __func__);
DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__,
(u_long) s->netlen, (u_long) size);
read = sanei_epson_net_read_raw(s, s->netbuf, size, status);
if (read != size) {
return 0;
if (s->netlen > size) {
s->netlen = size;
}
s->netlen = size - wanted;
s->netptr += wanted;
read = wanted;
/* fill buffer */
read = sanei_epson_net_read_raw(s, s->netbuf, s->netlen, status);
s->netptr = s->netbuf;
s->netlen = (read > 0 ? read : 0);
DBG(23, "0,4 %02x %02x\n", s->netbuf[0], s->netbuf[4]);
DBG(23, "storing %lu to buffer at %p, next read at %p, %lu bytes left\n",
(u_long) size, s->netbuf, s->netptr, (u_long) s->netlen);
memcpy(buf, s->netbuf, wanted);
/* copy wanted part */
read = sanei_epson_net_read_buf(s, buf, wanted, status);
}
return read;
}
int
size_t
sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *buf,
size_t buf_size, size_t reply_len, SANE_Status *status)
{
unsigned char *h1, *h2, *payload;
unsigned char *packet = malloc(12 + 8 + buf_size);
/* XXX check allocation failure */
if (!packet) {
*status = SANE_STATUS_NO_MEM;
return 0;
}
h1 = packet;
h2 = packet + 12;
payload = packet + 12 + 8;
if (reply_len) {
s->netbuf = s->netptr = malloc(reply_len);
if (s->netbuf) {
DBG(23, "%s, freeing %p, %ld bytes unprocessed\n",
__func__, s->netbuf, (u_long) s->netlen);
free(s->netbuf);
s->netbuf = s->netptr = NULL;
s->netlen = 0;
}
s->netbuf = malloc(reply_len);
if (!s->netbuf) {
free(packet);
*status = SANE_STATUS_NO_MEM;
return 0;
}
s->netlen = reply_len;
DBG(24, "allocated %lu bytes at %p\n",
(u_long) reply_len, s->netbuf);
DBG(24, "%s: allocated %lu bytes at %p\n", __func__,
(u_long) s->netlen, s->netbuf);
}
DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n",

Wyświetl plik

@ -4,9 +4,9 @@
#include <sys/types.h>
#include "../include/sane/sane.h"
extern int sanei_epson_net_read(struct Epson_Scanner *s, unsigned char *buf, ssize_t buf_size,
extern ssize_t sanei_epson_net_read(struct Epson_Scanner *s, unsigned char *buf, ssize_t buf_size,
SANE_Status *status);
extern int sanei_epson_net_write(struct Epson_Scanner *s, unsigned int cmd, const unsigned char *buf,
extern size_t sanei_epson_net_write(struct Epson_Scanner *s, unsigned int cmd, const unsigned char *buf,
size_t buf_size, size_t reply_len,
SANE_Status *status);
extern SANE_Status sanei_epson_net_lock(struct Epson_Scanner *s);

Wyświetl plik

@ -117,7 +117,7 @@ esci2_check_header(const char *cmd, const char *buf, unsigned int *more)
return 0;
}
err = sscanf(&buf[5], "%x#", more);
err = sscanf(&buf[5], "%7x#", more);
if (err != 1) {
DBG(1, "cannot decode length from header\n");
return 0;
@ -193,6 +193,8 @@ static SANE_Status esci2_cmd(epsonds_scanner* s,
ssize_t read = eds_recv(s, pbuf, more, &status);
if (read != more) {
free(pbuf);
return SANE_STATUS_IO_ERROR;
}
/* parse the received data block */
@ -255,18 +257,20 @@ static int decode_value(char *buf, int len)
}
/* h000 */
static char *decode_binary(char *buf)
static char *decode_binary(char *buf, int len)
{
char tmp[6];
int hl;
memcpy(tmp, buf, 4);
tmp[4] = '\0';
len -= 4;
if (buf[0] != 'h')
return NULL;
hl = strtol(tmp + 1, NULL, 16);
if (hl > len) hl = len;
if (hl) {
char *v = malloc(hl + 1);
@ -279,9 +283,9 @@ static char *decode_binary(char *buf)
return NULL;
}
static char *decode_string(char *buf)
static char *decode_string(char *buf, int len)
{
char *p, *s = decode_binary(buf);
char *p, *s = decode_binary(buf, len);
if (s == NULL)
return NULL;
@ -326,20 +330,20 @@ static SANE_Status info_cb(void *userdata, char *token, int len)
if (strncmp("PRD", token, 3) == 0) {
free(s->hw->model);
s->hw->model = decode_string(value);
s->hw->model = decode_string(value, len);
s->hw->sane.model = s->hw->model;
DBG(1, " product: %s\n", s->hw->model);
/* we will free the string later */
}
if (strncmp("VER", token, 3) == 0) {
char *v = decode_string(value);
char *v = decode_string(value, len);
DBG(1, " version: %s\n", v);
free(v);
}
if (strncmp("S/N", token, 3) == 0) {
char *v = decode_string(value);
char *v = decode_string(value, len);
DBG(1, " serial: %s\n", v);
free(v);
}
@ -876,6 +880,11 @@ esci2_img(struct epsonds_scanner *s, SANE_Int *length)
return parse_status;
}
/* more data than was accounted for in s->buf */
if (more > s->bsz) {
return SANE_STATUS_IO_ERROR;
}
/* ALWAYS read image data */
if (s->hw->connection == SANE_EPSONDS_NET) {
epsonds_net_request_read(s, more);

Wyświetl plik

@ -47,6 +47,8 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "sane/saneopts.h"
@ -1230,16 +1232,18 @@ sane_start(SANE_Handle handle)
if (s->line_buffer == NULL)
return SANE_STATUS_NO_MEM;
/* ring buffer for front page, twice bsz */
/* transfer buffer size, bsz */
/* XXX read value from scanner */
status = eds_ring_init(&s->front, (65536 * 4) * 2);
s->bsz = (65536 * 4);
/* ring buffer for front page */
status = eds_ring_init(&s->front, s->bsz * 2);
if (status != SANE_STATUS_GOOD) {
return status;
}
/* transfer buffer, bsz */
/* XXX read value from scanner */
s->buf = realloc(s->buf, 65536 * 4);
/* transfer buffer */
s->buf = realloc(s->buf, s->bsz);
if (s->buf == NULL)
return SANE_STATUS_NO_MEM;

Wyświetl plik

@ -10,7 +10,7 @@ usb
# e.g.:
# usb 0x4b8 0x14c
# Network
# Network (not yet supported!)
#
# net 192.168.1.123
net autodiscovery
#net autodiscovery

Wyświetl plik

@ -160,6 +160,7 @@ struct epsonds_scanner
Option_Value val[NUM_OPTIONS];
SANE_Parameters params;
size_t bsz; /* transfer buffer size */
SANE_Byte *buf, *line_buffer;
ring_buffer *current, front, back;

Wyświetl plik

@ -8,6 +8,12 @@
# -> put your device ip instead of '123.456.789.10'.
# -> put the port that you use instead of '88'.
# For example, the lines below are for one device, but if you have several devices to use, you can duplicate the lines below as many times as you have devices.
# You can also configure a device on a single line starting with 'device'
# by writing a complete URL and an optional model name.
#device http://123.456.789.10:8080 OptionalModel1
#device https://123.456.789.10:443 "Optional Model 2"
#device unix:/run/proxy.sock:http://123.456.789.10:80
#[device]

Plik diff jest za duży Load Diff

Wyświetl plik

@ -64,6 +64,14 @@
#define ESCL_CONFIG_FILE "escl.conf"
enum {
PLATEN = 0,
ADFSIMPLEX,
ADFDUPLEX
};
typedef struct {
int p1_0;
int p2_0;
@ -83,9 +91,11 @@ typedef struct ESCL_Device {
int port_nb;
char *ip_address;
char *type;
SANE_Bool https;
char *unix_socket;
} ESCL_Device;
typedef struct capabilities
typedef struct capst
{
int height;
int width;
@ -105,6 +115,7 @@ typedef struct capabilities
int ContentTypesSize;
SANE_String_Const *DocumentFormats;
int DocumentFormatsSize;
int format_ext;
SANE_Int *SupportedResolutions;
int SupportedResolutionsSize;
SANE_String_Const *SupportedIntents;
@ -115,11 +126,21 @@ typedef struct capabilities
int RiskyRightMargin;
int RiskyTopMargin;
int RiskyBottomMargin;
int duplex;
} caps_t;
typedef struct capabilities
{
caps_t caps[3];
int source;
SANE_String_Const *Sources;
int SourcesSize;
FILE *tmp;
unsigned char *img_data;
long img_size;
long img_read;
int format_ext;
size_t real_read;
SANE_Bool work;
} capabilities_t;
typedef struct {
@ -149,6 +170,9 @@ enum
OPT_TL_Y,
OPT_BR_X,
OPT_BR_Y,
OPT_SCAN_SOURCE,
NUM_OPTIONS
};
@ -158,13 +182,19 @@ enum
ESCL_Device *escl_devices(SANE_Status *status);
SANE_Status escl_device_add(int port_nb, const char *model_name,
char *ip_address, char *type);
SANE_Status escl_status(SANE_String_Const name);
capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, SANE_String_Const name,
SANE_Status escl_status(const ESCL_Device *device,
int source,
const char* jobId,
SANE_Status *job);
capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, const ESCL_Device *device,
SANE_Status *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name,
SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device,
char *result);
void escl_scanner(SANE_String_Const name, char *result);
void escl_scanner(const ESCL_Device *device, char *result);
typedef void CURL;
void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path);
unsigned char *escl_crop_surface(capabilities_t *scanner, unsigned char *surface,
int w, int h, int bps, int *width, int *height);

Wyświetl plik

@ -141,7 +141,7 @@ memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp)
char *str = realloc(mem->memory, mem->size + realsize + 1);
if (str == NULL) {
fprintf(stderr, "not enough memory (realloc returned NULL)\n");
DBG(10, "not enough memory (realloc returned NULL)\n");
return (0);
}
mem->memory = str;
@ -179,56 +179,61 @@ find_nodes_c(xmlNode *node)
* \return 0
*/
static int
find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner)
find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner, int type)
{
const char *name = (const char *)node->name;
if (strcmp(name, "ColorMode") == 0)
scanner->ColorModes = char_to_array(scanner->ColorModes, &scanner->ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1);
if (strcmp(name, "ColorMode") == 0) {
const char *color = (SANE_String_Const)xmlNodeGetContent(node);
if (type == PLATEN || strcmp(color, "BlackAndWhite1"))
scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, &scanner->caps[type].ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1);
}
else if (strcmp(name, "ContentType") == 0)
scanner->ContentTypes = char_to_array(scanner->ContentTypes, &scanner->ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
scanner->caps[type].ContentTypes = char_to_array(scanner->caps[type].ContentTypes, &scanner->caps[type].ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
else if (strcmp(name, "DocumentFormat") == 0)
{
int i = 0;
scanner->DocumentFormats = char_to_array(scanner->DocumentFormats, &scanner->DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
for(; i < scanner->DocumentFormatsSize; i++)
SANE_Bool have_jpeg = SANE_FALSE, have_png = SANE_FALSE, have_tiff = SANE_FALSE, have_pdf = SANE_FALSE;
scanner->caps[type].DocumentFormats = char_to_array(scanner->caps[type].DocumentFormats, &scanner->caps[type].DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
for(; i < scanner->caps[type].DocumentFormatsSize; i++)
{
if (scanner->default_format == NULL && !strcmp(scanner->DocumentFormats[i], "image/jpeg"))
if (!strcmp(scanner->caps[type].DocumentFormats[i], "image/jpeg"))
{
scanner->default_format = strdup("image/jpeg");
have_jpeg = SANE_TRUE;
}
#if(defined HAVE_LIBPNG)
else if(!strcmp(scanner->DocumentFormats[i], "image/png") && (scanner->default_format == NULL || strcmp(scanner->default_format, "image/tiff")))
else if(!strcmp(scanner->caps[type].DocumentFormats[i], "image/png"))
{
if (scanner->default_format)
free(scanner->default_format);
scanner->default_format = strdup("image/png");
have_png = SANE_TRUE;
}
#endif
#if(defined HAVE_TIFFIO_H)
else if(!strcmp(scanner->DocumentFormats[i], "image/tiff"))
else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "image/tiff"))
{
if (scanner->default_format)
free(scanner->default_format);
scanner->default_format = strdup("image/tiff");
have_tiff = SANE_TRUE;
}
#endif
#if(defined HAVE_POPPLER_GLIB)
else if(!strcmp(scanner->DocumentFormats[i], "application/pdf"))
else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "application/pdf"))
{
if (scanner->default_format)
free(scanner->default_format);
scanner->default_format = strdup("application/pdf");
have_pdf = SANE_TRUE;
}
#endif
}
fprintf(stderr, "Capability : [%s]\n", scanner->default_format);
if (have_pdf)
scanner->caps[type].default_format = strdup("application/pdf");
else if (have_tiff)
scanner->caps[type].default_format = strdup("image/tiff");
else if (have_png)
scanner->caps[type].default_format = strdup("image/png");
else if (have_jpeg)
scanner->caps[type].default_format = strdup("image/jpeg");
}
else if (strcmp(name, "DocumentFormatExt") == 0)
scanner->format_ext = 1;
scanner->caps[type].format_ext = 1;
else if (strcmp(name, "Intent") == 0)
scanner->SupportedIntents = char_to_array(scanner->SupportedIntents, &scanner->SupportedIntentsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
scanner->caps[type].SupportedIntents = char_to_array(scanner->caps[type].SupportedIntents, &scanner->caps[type].SupportedIntentsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
else if (strcmp(name, "XResolution") == 0)
scanner->SupportedResolutions = int_to_array(scanner->SupportedResolutions, &scanner->SupportedResolutionsSize, atoi((const char *)xmlNodeGetContent(node)));
scanner->caps[type].SupportedResolutions = int_to_array(scanner->caps[type].SupportedResolutions, &scanner->caps[type].SupportedResolutionsSize, atoi((const char *)xmlNodeGetContent(node)));
return (0);
}
@ -242,39 +247,39 @@ find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner)
* \return 0
*/
static int
find_value_of_int_variables(xmlNode *node, capabilities_t *scanner)
find_value_of_int_variables(xmlNode *node, capabilities_t *scanner, int type)
{
int MaxWidth = 0;
int MaxHeight = 0;
const char *name = (const char *)node->name;
if (strcmp(name, "MinWidth") == 0)
scanner->MinWidth = atoi((const char*)xmlNodeGetContent(node));
scanner->caps[type].MinWidth = atoi((const char*)xmlNodeGetContent(node));
else if (strcmp(name, "MaxWidth") == 0) {
MaxWidth = atoi((const char*)xmlNodeGetContent(node));
if (scanner->MaxWidth == 0 || MaxWidth < scanner->MaxWidth)
scanner->MaxWidth = atoi((const char *)xmlNodeGetContent(node));
if (scanner->caps[type].MaxWidth == 0 || MaxWidth < scanner->caps[type].MaxWidth)
scanner->caps[type].MaxWidth = atoi((const char *)xmlNodeGetContent(node));
}
else if (strcmp(name, "MinHeight") == 0)
scanner->MinHeight = atoi((const char*)xmlNodeGetContent(node));
scanner->caps[type].MinHeight = atoi((const char*)xmlNodeGetContent(node));
else if (strcmp(name, "MaxHeight") == 0) {
MaxHeight = atoi((const char*)xmlNodeGetContent(node));
if (scanner->MaxHeight == 0 || MaxHeight < scanner->MaxHeight)
scanner->MaxHeight = atoi((const char *)xmlNodeGetContent(node));
if (scanner->caps[type].MaxHeight == 0 || MaxHeight < scanner->caps[type].MaxHeight)
scanner->caps[type].MaxHeight = atoi((const char *)xmlNodeGetContent(node));
}
else if (strcmp(name, "MaxScanRegions") == 0)
scanner->MaxScanRegions = atoi((const char *)xmlNodeGetContent(node));
scanner->caps[type].MaxScanRegions = atoi((const char *)xmlNodeGetContent(node));
else if (strcmp(name, "MaxOpticalXResolution") == 0)
scanner->MaxOpticalXResolution = atoi((const char *)xmlNodeGetContent(node));
scanner->caps[type].MaxOpticalXResolution = atoi((const char *)xmlNodeGetContent(node));
else if (strcmp(name, "RiskyLeftMargin") == 0)
scanner->RiskyLeftMargin = atoi((const char *)xmlNodeGetContent(node));
scanner->caps[type].RiskyLeftMargin = atoi((const char *)xmlNodeGetContent(node));
else if (strcmp(name, "RiskyRightMargin") == 0)
scanner->RiskyRightMargin = atoi((const char *)xmlNodeGetContent(node));
scanner->caps[type].RiskyRightMargin = atoi((const char *)xmlNodeGetContent(node));
else if (strcmp(name, "RiskyTopMargin") == 0)
scanner->RiskyTopMargin = atoi((const char *)xmlNodeGetContent(node));
scanner->caps[type].RiskyTopMargin = atoi((const char *)xmlNodeGetContent(node));
else if (strcmp(name, "RiskyBottomMargin") == 0)
scanner->RiskyBottomMargin = atoi((const char *)xmlNodeGetContent(node));
find_valor_of_array_variables(node, scanner);
scanner->caps[type].RiskyBottomMargin = atoi((const char *)xmlNodeGetContent(node));
find_valor_of_array_variables(node, scanner, type);
return (0);
}
@ -287,7 +292,7 @@ find_value_of_int_variables(xmlNode *node, capabilities_t *scanner)
* \return 0
*/
static int
find_true_variables(xmlNode *node, capabilities_t *scanner)
find_true_variables(xmlNode *node, capabilities_t *scanner, int type)
{
const char *name = (const char *)node->name;
if (strcmp(name, "MinWidth") == 0 ||
@ -306,7 +311,7 @@ find_true_variables(xmlNode *node, capabilities_t *scanner)
strcmp(name, "RiskyTopMargin") == 0 ||
strcmp(name, "RiskyBottomMargin") == 0 ||
strcmp(name, "DocumentFormatExt") == 0)
find_value_of_int_variables(node, scanner);
find_value_of_int_variables(node, scanner, type);
return (0);
}
@ -317,21 +322,67 @@ find_true_variables(xmlNode *node, capabilities_t *scanner)
* \return 0
*/
static int
print_xml_c(xmlNode *node, capabilities_t *scanner)
print_xml_c(xmlNode *node, capabilities_t *scanner, int type)
{
while (node) {
if (node->type == XML_ELEMENT_NODE) {
if (find_nodes_c(node))
find_true_variables(node, scanner);
if (find_nodes_c(node) && type != -1)
find_true_variables(node, scanner, type);
}
print_xml_c(node->children, scanner);
if (!strcmp((const char *)node->name, "PlatenInputCaps")) {
scanner->Sources[PLATEN] = (SANE_String_Const)strdup(SANE_I18N ("Flatbed"));
scanner->SourcesSize++;
scanner->source = PLATEN;
print_xml_c(node->children, scanner, PLATEN);
scanner->caps[PLATEN].duplex = 0;
}
else if (!strcmp((const char *)node->name, "AdfSimplexInputCaps")) {
scanner->Sources[ADFSIMPLEX] = (SANE_String_Const)strdup(SANE_I18N("ADF"));
scanner->SourcesSize++;
if (scanner->source == -1) scanner->source = ADFSIMPLEX;
print_xml_c(node->children, scanner, ADFSIMPLEX);
scanner->caps[ADFSIMPLEX].duplex = 0;
}
else if (!strcmp((const char *)node->name, "AdfDuplexInputCaps")) {
scanner->Sources[ADFDUPLEX] = (SANE_String_Const)strdup(SANE_I18N ("ADF Duplex"));
scanner->SourcesSize++;
if (scanner->source == -1) scanner->source = ADFDUPLEX;
print_xml_c(node->children, scanner, ADFDUPLEX);
scanner->caps[ADFDUPLEX].duplex = 1;
}
else
print_xml_c(node->children, scanner, type);
node = node->next;
}
return (0);
}
static void
_reduce_color_modes(capabilities_t *scanner)
{
int type = 0;
for (type = 0; type < 3; type++) {
if (scanner->caps[type].ColorModesSize) {
if (scanner->caps[type].default_format &&
strcmp(scanner->caps[type].default_format, "application/pdf")) {
if (scanner->caps[type].ColorModesSize == 3) {
free(scanner->caps[type].ColorModes);
scanner->caps[type].ColorModes = NULL;
scanner->caps[type].ColorModesSize = 0;
scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
&scanner->caps[type].ColorModesSize,
(SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0);
scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
&scanner->caps[type].ColorModesSize,
(SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0);
}
}
}
}
}
/**
* \fn capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status)
* \fn capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status)
* \brief Function that finally recovers all the capabilities of the scanner, using curl.
* This function is called in the 'sane_open' function and it's the equivalent of
* the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerCapabilities".
@ -339,18 +390,18 @@ print_xml_c(xmlNode *node, capabilities_t *scanner)
* \return scanner (the structure that stocks all the capabilities elements)
*/
capabilities_t *
escl_capabilities(SANE_String_Const name, SANE_Status *status)
escl_capabilities(const ESCL_Device *device, SANE_Status *status)
{
capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t));
CURL *curl_handle = NULL;
struct cap *var = NULL;
xmlDoc *data = NULL;
xmlNode *node = NULL;
int i = 0;
const char *scanner_capabilities = "/eSCL/ScannerCapabilities";
char tmp[PATH_MAX] = { 0 };
*status = SANE_STATUS_GOOD;
if (name == NULL)
if (device == NULL)
*status = SANE_STATUS_NO_MEM;
var = (struct cap *)calloc(1, sizeof(struct cap));
if (var == NULL)
@ -358,32 +409,41 @@ escl_capabilities(SANE_String_Const name, SANE_Status *status)
var->memory = malloc(1);
var->size = 0;
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_capabilities);
DBG( 1, "Get Capabilities : %s\n", tmp);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scanner_capabilities);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
DBG( 1, "The scanner didn't respond.\n");
CURLcode res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res));
*status = SANE_STATUS_INVAL;
goto clean_data;
}
DBG( 10, "XML Capabilities[\n%s\n]\n", var->memory);
data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0);
if (data == NULL)
if (data == NULL) {
*status = SANE_STATUS_NO_MEM;
goto clean_data;
}
node = xmlDocGetRootElement(data);
if (node == NULL)
if (node == NULL) {
*status = SANE_STATUS_NO_MEM;
print_xml_c(node, scanner);
goto clean;
}
scanner->source = 0;
scanner->Sources = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * 4);
for (i = 0; i < 4; i++)
scanner->Sources[i] = NULL;
print_xml_c(node, scanner, -1);
_reduce_color_modes(scanner);
clean:
xmlFreeDoc(data);
clean_data:
xmlCleanupParser();
xmlMemoryDump();
curl_easy_cleanup(curl_handle);
free(var->memory);
if (var)
free(var->memory);
free(var);
return (scanner);
}

Wyświetl plik

@ -37,6 +37,7 @@ escl_crop_surface(capabilities_t *scanner,
int *width,
int *height)
{
double ratio = 1.0;
int x_off = 0, x = 0;
int real_w = 0;
int y_off = 0, y = 0;
@ -44,24 +45,31 @@ escl_crop_surface(capabilities_t *scanner,
unsigned char *surface_crop = NULL;
DBG( 1, "Escl Image Crop\n");
if (w < (int)scanner->width)
scanner->width = w;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
ratio = (double)w / (double)scanner->caps[scanner->source].width;
scanner->caps[scanner->source].width = w;
if (scanner->caps[scanner->source].pos_x < 0)
scanner->caps[scanner->source].pos_x = 0;
if (scanner->caps[scanner->source].pos_x &&
(scanner->caps[scanner->source].width >
scanner->caps[scanner->source].pos_x))
x_off = (int)((double)scanner->caps[scanner->source].pos_x * ratio);
real_w = scanner->caps[scanner->source].width - x_off;
if (h < (int)scanner->height)
scanner->height = h;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
scanner->caps[scanner->source].height = h;
if (scanner->caps[scanner->source].pos_y &&
(scanner->caps[scanner->source].height >
scanner->caps[scanner->source].pos_y))
y_off = (int)((double)scanner->caps[scanner->source].pos_y * ratio);
real_h = scanner->caps[scanner->source].height - y_off;
DBG( 1, "Escl Image Crop [%dx%d|%dx%d]\n", scanner->caps[scanner->source].pos_x, scanner->caps[scanner->source].pos_y,
scanner->caps[scanner->source].width, scanner->caps[scanner->source].height);
x_off = scanner->pos_x;
real_w = scanner->width - x_off;
y_off = scanner->pos_y;
real_h = scanner->height - y_off;
*width = real_w;
*height = real_h;
if (x_off > 0 || real_w < scanner->width ||
y_off > 0 || real_h < scanner->height) {
DBG( 1, "Escl Image Crop [%dx%d]\n", *width, *height);
if (x_off > 0 || real_w < scanner->caps[scanner->source].width ||
y_off > 0 || real_h < scanner->caps[scanner->source].height) {
surface_crop = (unsigned char *)malloc (sizeof (unsigned char) * real_w
* real_h * bps);
if(!surface_crop) {
@ -74,7 +82,12 @@ escl_crop_surface(capabilities_t *scanner,
{
for (x = 0; x < real_w; x++)
{
surface_crop[y * real_w + x] = surface[(y + y_off) * w + x + x_off];
surface_crop[(y * real_w * bps) + (x * bps)] =
surface[((y + y_off) * w * bps) + ((x + x_off) * bps)];
surface_crop[(y * real_w * bps) + (x * bps) + 1] =
surface[((y + y_off) * w * bps) + ((x + x_off) * bps) + 1];
surface_crop[(y * real_w * bps) + (x * bps) + 2] =
surface[((y + y_off) * w * bps) + ((x + x_off) * bps) + 2];
}
}
free(surface);

Wyświetl plik

@ -120,7 +120,6 @@ jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx)
if (cinfo->src == NULL) {
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
src = (my_source_mgr *) cinfo->src;
}
src = (my_source_mgr *) cinfo->src;
src->pub.init_source = init_source;
@ -193,20 +192,39 @@ get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps)
cinfo.out_color_space = JCS_RGB;
cinfo.quantize_colors = FALSE;
jpeg_calc_output_dimensions(&cinfo);
if (cinfo.output_width < (unsigned int)scanner->width)
scanner->width = cinfo.output_width;
if (scanner->pos_x < 0)
scanner->pos_x = 0;
if (cinfo.output_width < (unsigned int)scanner->caps[scanner->source].width)
scanner->caps[scanner->source].width = cinfo.output_width;
if (scanner->caps[scanner->source].pos_x < 0)
scanner->caps[scanner->source].pos_x = 0;
if (cinfo.output_height < (unsigned int)scanner->height)
scanner->height = cinfo.output_height;
if (scanner->pos_y < 0)
scanner->pos_y = 0;
x_off = scanner->pos_x;
w = scanner->width - x_off;
y_off = scanner->pos_y;
h = scanner->height - y_off;
if (cinfo.output_height < (unsigned int)scanner->caps[scanner->source].height)
scanner->caps[scanner->source].height = cinfo.output_height;
if (scanner->caps[scanner->source].pos_y < 0)
scanner->caps[scanner->source].pos_y = 0;
DBG(10, "1-JPEF Geometry [%dx%d|%dx%d]\n",
scanner->caps[scanner->source].pos_x,
scanner->caps[scanner->source].pos_y,
scanner->caps[scanner->source].width,
scanner->caps[scanner->source].height);
x_off = scanner->caps[scanner->source].pos_x;
if (x_off > (unsigned int)scanner->caps[scanner->source].width) {
w = scanner->caps[scanner->source].width;
x_off = 0;
}
else
w = scanner->caps[scanner->source].width - x_off;
y_off = scanner->caps[scanner->source].pos_y;
if(y_off > (unsigned int)scanner->caps[scanner->source].height) {
h = scanner->caps[scanner->source].height;
y_off = 0;
}
else
h = scanner->caps[scanner->source].height - y_off;
DBG(10, "2-JPEF Geometry [%dx%d|%dx%d]\n",
x_off,
y_off,
w,
h);
surface = malloc(w * h * cinfo.output_components);
if (surface == NULL) {
jpeg_destroy_decompress(&cinfo);
@ -224,7 +242,7 @@ get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps)
if (y_off > 0)
jpeg_skip_scanlines(&cinfo, y_off);
pos = 0;
while (cinfo.output_scanline < (unsigned int)scanner->height) {
while (cinfo.output_scanline < (unsigned int)scanner->caps[scanner->source].height) {
rowptr[0] = (JSAMPROW)surface + (lineSize * pos); // ..cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
pos++;

Wyświetl plik

@ -68,18 +68,11 @@ static const char settings[] =
" <scan:ColorMode>%s</scan:ColorMode>" \
" <scan:XResolution>%d</scan:XResolution>" \
" <scan:YResolution>%d</scan:YResolution>" \
" <pwg:InputSource>Platen</pwg:InputSource>" \
" <pwg:InputSource>%s</pwg:InputSource>" \
" <scan:InputSource>%s</scan:InputSource>" \
"%s" \
"</scan:ScanSettings>";
static char formatExtJPEG[] =
" <scan:DocumentFormatExt>image/jpeg</scan:DocumentFormatExt>";
static char formatExtPNG[] =
" <scan:DocumentFormatExt>image/png</scan:DocumentFormatExt>";
static char formatExtTIFF[] =
" <scan:DocumentFormatExt>image/tiff</scan:DocumentFormatExt>";
/**
* \fn static size_t download_callback(void *str, size_t size, size_t nmemb, void *userp)
* \brief Callback function that stocks in memory the content of the 'job'. Example below :
@ -122,7 +115,7 @@ download_callback(void *str, size_t size, size_t nmemb, void *userp)
}
/**
* \fn char *escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
* \fn char *escl_newjob (capabilities_t *scanner, const ESCL_Device *device, SANE_Status *status)
* \brief Function that, using curl, uploads the data (composed by the scanner capabilities) to the
* server to download the 'job' and recover the 'new job' (char *result), in LOCATION.
* This function is called in the 'sane_start' function and it's the equivalent of the
@ -131,22 +124,23 @@ download_callback(void *str, size_t size, size_t nmemb, void *userp)
* \return result (the 'new job', situated in LOCATION)
*/
char *
escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
escl_newjob (capabilities_t *scanner, const ESCL_Device *device, SANE_Status *status)
{
CURL *curl_handle = NULL;
int off_x = 0, off_y = 0;
struct uploading *upload = NULL;
struct downloading *download = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
char cap_data[PATH_MAX] = { 0 };
char job_cmd[PATH_MAX] = { 0 };
char *location = NULL;
char *result = NULL;
char *temporary = NULL;
char *f_ext = "";
char *format_ext = NULL;
char duplex_mode[1024] = { 0 };
*status = SANE_STATUS_GOOD;
if (name == NULL || scanner == NULL) {
if (device == NULL || scanner == NULL) {
*status = SANE_STATUS_NO_MEM;
DBG( 1, "Create NewJob : the name or the scan are invalid.\n");
return (NULL);
@ -165,43 +159,55 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
return (NULL);
}
curl_handle = curl_easy_init();
if (scanner->format_ext == 1)
if (scanner->caps[scanner->source].format_ext == 1)
{
if (!strcmp(scanner->default_format, "image/jpeg"))
format_ext = formatExtJPEG;
else if (!strcmp(scanner->default_format, "image/png"))
format_ext = formatExtPNG;
else if (!strcmp(scanner->default_format, "image/tiff"))
format_ext = formatExtTIFF;
else
format_ext = f_ext;
char f_ext_tmp[1024];
snprintf(f_ext_tmp, sizeof(f_ext_tmp),
" <scan:DocumentFormatExt>%s</scan:DocumentFormatExt>",
scanner->caps[scanner->source].default_format);
format_ext = f_ext_tmp;
}
else
format_ext = f_ext;
DBG( 1, "Create NewJob : %s\n", scanner->default_format);
if(scanner->source > PLATEN && scanner->Sources[ADFDUPLEX]) {
snprintf(duplex_mode, sizeof(duplex_mode),
" <scan:Duplex>%s</scan:Duplex>",
scanner->source == ADFDUPLEX ? "true" : "false");
}
DBG( 1, "Create NewJob : %s\n", scanner->caps[scanner->source].default_format);
if (scanner->caps[scanner->source].pos_x > scanner->caps[scanner->source].width)
off_x = (scanner->caps[scanner->source].pos_x > scanner->caps[scanner->source].width) / 2;
if (scanner->caps[scanner->source].pos_y > scanner->caps[scanner->source].height)
off_y = (scanner->caps[scanner->source].pos_y > scanner->caps[scanner->source].height) / 2;
if (curl_handle != NULL) {
snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0, scanner->default_format,
format_ext,
scanner->default_color, scanner->default_resolution, scanner->default_resolution);
char *source = (scanner->source == PLATEN ? "Platen" : "Feeder");
snprintf(cap_data, sizeof(cap_data), settings,
scanner->caps[scanner->source].height,
scanner->caps[scanner->source].width,
off_x,
off_y,
scanner->caps[scanner->source].default_format,
format_ext,
scanner->caps[scanner->source].default_color,
scanner->caps[scanner->source].default_resolution,
scanner->caps[scanner->source].default_resolution,
source,
source,
duplex_mode[0] == 0 ? "" : duplex_mode);
DBG( 1, "Create NewJob : %s\n", cap_data);
upload->read_data = strdup(cap_data);
upload->size = strlen(cap_data);
download->memory = malloc(1);
download->size = 0;
strcpy(job_cmd, name);
strcat(job_cmd, scan_jobs);
curl_easy_setopt(curl_handle, CURLOPT_URL, job_cmd);
if (strncmp(name, "https", 5) == 0) {
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scan_jobs);
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, upload->read_data);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, upload->size);
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, download_callback);
curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)download);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
DBG( 1, "Create NewJob : the scanner responded incorrectly.\n");
CURLcode res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
DBG( 1, "Create NewJob : the scanner responded incorrectly: %s\n", curl_easy_strerror(res));
*status = SANE_STATUS_INVAL;
}
else {
@ -221,14 +227,21 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
}
}
if (result == NULL) {
DBG( 1, "Error : Create NewJob, no location\n");
*status = SANE_STATUS_INVAL;
DBG( 1, "Error : Create NewJob, no location: %s\n", download->memory);
*status = SANE_STATUS_INVAL;
}
free(download->memory);
}
else {
DBG( 1, "Create NewJob : The creation of the failed job\n");
*status = SANE_STATUS_INVAL;
DBG( 1, "Create NewJob : The creation of the failed job: %s\n", download->memory);
// If "409 Conflict" appear it means that there is no paper in feeder
if (strstr(download->memory, "409 Conflict") != NULL)
*status = SANE_STATUS_NO_DOCS;
// If "503 Service Unavailable" appear, it means that device is busy (scanning in progress)
else if (strstr(download->memory, "503 Service Unavailable") != NULL)
*status = SANE_STATUS_DEVICE_BUSY;
else
*status = SANE_STATUS_INVAL;
}
}
else {

Wyświetl plik

@ -140,8 +140,8 @@ get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps)
}
poppler_page_get_size (page, &dw, &dh);
dw = (double)scanner->default_resolution * dw / 72.0;
dh = (double)scanner->default_resolution * dh / 72.0;
dw = (double)scanner->caps[scanner->source].default_resolution * dw / 72.0;
dh = (double)scanner->caps[scanner->source].default_resolution * dh / 72.0;
w = (int)ceil(dw);
h = (int)ceil(dh);
cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
@ -157,8 +157,8 @@ get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps)
status = SANE_STATUS_INVAL;
goto free_surface;
}
cairo_scale (cr, (double)scanner->default_resolution / 72.0,
(double)scanner->default_resolution / 72.0);
cairo_scale (cr, (double)scanner->caps[scanner->source].default_resolution / 72.0,
(double)scanner->caps[scanner->source].default_resolution / 72.0);
cairo_save (cr);
poppler_page_render (page, cr);
cairo_restore (cr);

Wyświetl plik

@ -31,13 +31,22 @@
#include <curl/curl.h>
static size_t
write_callback(void __sane_unused__*str,
size_t __sane_unused__ size,
size_t nmemb,
void __sane_unused__ *userp)
{
return nmemb;
}
/**
* \fn void escl_scanner(SANE_String_Const name, char *result)
* \fn void escl_scanner(const ESCL_Device *device, char *result)
* \brief Function that resets the scanner after each scan, using curl.
* This function is called in the 'sane_cancel' function.
*/
void
escl_scanner(SANE_String_Const name, char *result)
escl_scanner(const ESCL_Device *device, char *result)
{
CURL *curl_handle = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
@ -46,30 +55,25 @@ escl_scanner(SANE_String_Const name, char *result)
int i = 0;
long answer = 0;
if (name == NULL || result == NULL)
if (device == NULL || result == NULL)
return;
CURL_CALL:
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
strcpy(scan_cmd, name);
strcat(scan_cmd, scan_jobs);
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
DBG( 1, "Reset Job : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s",
scan_jobs, result, scanner_start);
escl_curl_url(curl_handle, device, scan_cmd);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
if (curl_easy_perform(curl_handle) == CURLE_OK) {
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &answer);
if (i < 3 && answer == 503) {
curl_easy_cleanup(curl_handle);
i++;
goto CURL_CALL;
}
i++;
if (i >= 15) return;
}
curl_easy_cleanup(curl_handle);
if (SANE_STATUS_GOOD != escl_status(device,
PLATEN,
NULL,
NULL))
goto CURL_CALL;
}
}

Wyświetl plik

@ -43,13 +43,14 @@
static size_t
write_callback(void *str, size_t size, size_t nmemb, void *userp)
{
size_t to_write = fwrite(str, size, nmemb, (FILE *)userp);
capabilities_t *scanner = (capabilities_t *)userp;
size_t to_write = fwrite(str, size, nmemb, scanner->tmp);
scanner->real_read += to_write;
return (to_write);
}
/**
* \fn SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result)
* \fn SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result)
* \brief Function that, after recovering the 'new job', scans the image writed in the
* temporary file, using curl.
* This function is called in the 'sane_start' function and it's the equivalent of
@ -58,7 +59,7 @@ write_callback(void *str, size_t size, size_t nmemb, void *userp)
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char *result)
escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result)
{
CURL *curl_handle = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
@ -66,34 +67,41 @@ escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char
char scan_cmd[PATH_MAX] = { 0 };
SANE_Status status = SANE_STATUS_GOOD;
if (name == NULL)
if (device == NULL)
return (SANE_STATUS_NO_MEM);
scanner->real_read = 0;
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
strcpy(scan_cmd, name);
strcat(scan_cmd, scan_jobs);
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
DBG( 1, "Scan : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s",
scan_jobs, result, scanner_start);
escl_curl_url(curl_handle, device, scan_cmd);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = tmpfile();
if (scanner->tmp != NULL) {
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, scanner->tmp);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, scanner);
CURLcode res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
DBG( 1, "Unable to scan: %s\n", curl_easy_strerror(res));
fclose(scanner->tmp);
scanner->tmp = NULL;
status = SANE_STATUS_INVAL;
goto cleanup;
}
else
curl_easy_cleanup(curl_handle);
fseek(scanner->tmp, 0, SEEK_SET);
}
else
status = SANE_STATUS_NO_MEM;
cleanup:
curl_easy_cleanup(curl_handle);
}
DBG(10, "eSCL scan : [%s]\treal read (%ld)\n", sane_strstatus(status), scanner->real_read);
if (scanner->real_read == 0)
{
fclose(scanner->tmp);
scanner->tmp = NULL;
return SANE_STATUS_NO_DOCS;
}
return (status);
}

Wyświetl plik

@ -83,34 +83,105 @@ find_nodes_s(xmlNode *node)
return (1);
}
/**
* \fn static void print_xml_s(xmlNode *node, SANE_Status *status)
* \brief Function that browses the xml file, node by node.
* If the node 'State' is found, we are expecting to found in this node the 'Idle'
* content (if the scanner is ready to use) and then 'status' = SANE_STATUS_GOOD.
* Otherwise, this means that the scanner isn't ready to use.
*/
static void
print_xml_s(xmlNode *node, SANE_Status *status)
print_xml_job_status(xmlNode *node,
SANE_Status *job,
int *image)
{
int x = 0;
while (node) {
if (node->type == XML_ELEMENT_NODE) {
if (find_nodes_s(node)) {
if (strcmp((const char *)node->name, "State") == 0)
x = 1;
if (strcmp((const char *)node->name, "JobState") == 0) {
const char *state = (const char *)xmlNodeGetContent(node);
if (!strcmp(state, "Processing")) {
*job = SANE_STATUS_DEVICE_BUSY;
DBG(10, "jobId Processing SANE_STATUS_DEVICE_BUSY\n");
}
else if (!strcmp(state, "Completed")) {
*job = SANE_STATUS_GOOD;
DBG(10, "jobId Completed SANE_STATUS_GOOD\n");
}
else if (strcmp((const char *)node->name, "ImagesToTransfer") == 0) {
const char *state = (const char *)xmlNodeGetContent(node);
*image = atoi(state);
}
}
}
if (x == 1 && strcmp((const char *)xmlNodeGetContent(node), "Idle") == 0)
*status = SANE_STATUS_GOOD;
}
print_xml_s(node->children, status);
print_xml_job_status(node->children, job, image);
node = node->next;
}
}
static void
print_xml_platen_and_adf_status(xmlNode *node,
SANE_Status *platen,
SANE_Status *adf,
const char* jobId,
SANE_Status *job,
int *image)
{
while (node) {
if (node->type == XML_ELEMENT_NODE) {
if (find_nodes_s(node)) {
if (strcmp((const char *)node->name, "State") == 0) {
DBG(10, "State\t");
const char *state = (const char *)xmlNodeGetContent(node);
if (!strcmp(state, "Idle")) {
DBG(10, "Idle SANE_STATUS_GOOD\n");
*platen = SANE_STATUS_GOOD;
} else if (!strcmp(state, "Processing")) {
DBG(10, "Processing SANE_STATUS_DEVICE_BUSY\n");
*platen = SANE_STATUS_DEVICE_BUSY;
} else {
DBG(10, "%s SANE_STATUS_UNSUPPORTED\n", state);
*platen = SANE_STATUS_UNSUPPORTED;
}
}
// Thank's Alexander Pevzner (pzz@apevzner.com)
else if (adf && strcmp((const char *)node->name, "AdfState") == 0) {
const char *state = (const char *)xmlNodeGetContent(node);
if (!strcmp(state, "ScannerAdfLoaded")){
DBG(10, "ScannerAdfLoaded SANE_STATUS_GOOD\n");
*adf = SANE_STATUS_GOOD;
} else if (!strcmp(state, "ScannerAdfJam")) {
DBG(10, "ScannerAdfJam SANE_STATUS_JAMMED\n");
*adf = SANE_STATUS_JAMMED;
} else if (!strcmp(state, "ScannerAdfDoorOpen")) {
DBG(10, "ScannerAdfDoorOpen SANE_STATUS_COVER_OPEN\n");
*adf = SANE_STATUS_COVER_OPEN;
} else if (!strcmp(state, "ScannerAdfProcessing")) {
/* Kyocera version */
DBG(10, "ScannerAdfProcessing SANE_STATUS_NO_DOC\n");
*adf = SANE_STATUS_NO_DOCS;
} else if (!strcmp(state, "ScannerAdfEmpty")) {
DBG(10, "ScannerAdfEmpty SANE_STATUS_NO_DOCS\n");
/* Cannon TR4500, EPSON XP-7100 */
*adf = SANE_STATUS_NO_DOCS;
} else {
DBG(10, "%s SANE_STATUS_NO_DOCS\n", state);
*adf = SANE_STATUS_UNSUPPORTED;
}
}
else if (jobId && job && strcmp((const char *)node->name, "JobUri") == 0) {
if (strstr((const char *)xmlNodeGetContent(node), jobId)) {
print_xml_job_status(node, job, image);
}
}
}
}
print_xml_platen_and_adf_status(node->children,
platen,
adf,
jobId,
job,
image);
node = node->next;
}
}
/**
* \fn SANE_Status escl_status(SANE_String_Const name)
* \fn SANE_Status escl_status(const ESCL_Device *device)
* \brief Function that finally recovers the scanner status ('Idle', or not), using curl.
* This function is called in the 'sane_open' function and it's the equivalent of
* the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerStatus".
@ -118,40 +189,45 @@ print_xml_s(xmlNode *node, SANE_Status *status)
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_status(SANE_String_Const name)
escl_status(const ESCL_Device *device,
int source,
const char* jobId,
SANE_Status *job)
{
SANE_Status status;
SANE_Status status = SANE_STATUS_DEVICE_BUSY;
SANE_Status platen= SANE_STATUS_DEVICE_BUSY;
SANE_Status adf= SANE_STATUS_DEVICE_BUSY;
CURL *curl_handle = NULL;
struct idle *var = NULL;
xmlDoc *data = NULL;
xmlNode *node = NULL;
const char *scanner_status = "/eSCL/ScannerStatus";
char tmp[PATH_MAX] = { 0 };
int image = -1;
int pass = 0;
reload:
if (name == NULL)
if (device == NULL)
return (SANE_STATUS_NO_MEM);
status = SANE_STATUS_DEVICE_BUSY;
platen= SANE_STATUS_DEVICE_BUSY;
adf= SANE_STATUS_DEVICE_BUSY;
var = (struct idle*)calloc(1, sizeof(struct idle));
if (var == NULL)
return (SANE_STATUS_NO_MEM);
var->memory = malloc(1);
var->size = 0;
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
DBG( 1, "Get Status : %s.\n", tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {
DBG( 1, "The scanner didn't respond.\n");
CURLcode res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res));
status = SANE_STATUS_INVAL;
goto clean_data;
}
DBG( 10, "eSCL : Status : %s.\n", var->memory);
data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0);
if (data == NULL) {
status = SANE_STATUS_NO_MEM;
@ -162,8 +238,18 @@ escl_status(SANE_String_Const name)
status = SANE_STATUS_NO_MEM;
goto clean;
}
status = SANE_STATUS_DEVICE_BUSY;
print_xml_s(node, &status);
/* Decode Job status */
// Thank's Alexander Pevzner (pzz@apevzner.com)
print_xml_platen_and_adf_status(node, &platen, &adf, jobId, job, &image);
if (platen != SANE_STATUS_GOOD &&
platen != SANE_STATUS_UNSUPPORTED) {
status = platen;
} else if (source == PLATEN) {
status = platen;
} else {
status = adf;
}
DBG (10, "STATUS : %s\n", sane_strstatus(status));
clean:
xmlFreeDoc(data);
clean_data:
@ -172,5 +258,14 @@ clean_data:
curl_easy_cleanup(curl_handle);
free(var->memory);
free(var);
if (pass == 0 &&
source != PLATEN &&
image == 0 &&
(status == SANE_STATUS_GOOD ||
status == SANE_STATUS_UNSUPPORTED ||
status == SANE_STATUS_DEVICE_BUSY)) {
pass = 1;
goto reload;
}
return (status);
}

Wyświetl plik

@ -124,15 +124,24 @@ usb 0x03f0 0x4605
# Plustek OpticBook 3600
usb 0x07b3 0x0900
# Plustek OpticFilm 7200
usb 0x07b3 0x0807
# Plustek OpticFilm 7200i
usb 0x07b3 0x0c04
# Plustek OpticFilm 7300
usb 0x07b3 0x0c12
# Plustek OpticFilm 7400
usb 0x07b3 0x0c3a
# Plustek OpticFilm 7500i
usb 0x07b3 0x0c13
# Plustek OpticFilm 8200i
usb 0x07b3 0x130d
# Primax Electronics, Ltd Xerox 2400 Onetouch
usb 0x0461 0x038b

Wyświetl plik

@ -1,102 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#include "buffer.h"
#include <cstring>
#include <stdexcept>
namespace genesys {
void Genesys_Buffer::alloc(std::size_t size)
{
buffer_.resize(size);
avail_ = 0;
pos_ = 0;
}
void Genesys_Buffer::clear()
{
buffer_.clear();
avail_ = 0;
pos_ = 0;
}
void Genesys_Buffer::reset()
{
avail_ = 0;
pos_ = 0;
}
std::uint8_t* Genesys_Buffer::get_write_pos(std::size_t size)
{
if (avail_ + size > buffer_.size())
return nullptr;
if (pos_ + avail_ + size > buffer_.size())
{
std::memmove(buffer_.data(), buffer_.data() + pos_, avail_);
pos_ = 0;
}
return buffer_.data() + pos_ + avail_;
}
std::uint8_t* Genesys_Buffer::get_read_pos()
{
return buffer_.data() + pos_;
}
void Genesys_Buffer::produce(std::size_t size)
{
if (size > buffer_.size() - avail_)
throw std::runtime_error("buffer size exceeded");
avail_ += size;
}
void Genesys_Buffer::consume(std::size_t size)
{
if (size > avail_)
throw std::runtime_error("no more data in buffer");
avail_ -= size;
pos_ += size;
}
} // namespace genesys

Wyświetl plik

@ -1,89 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#ifndef BACKEND_GENESYS_BUFFER_H
#define BACKEND_GENESYS_BUFFER_H
#include <vector>
#include <cstddef>
#include <cstdint>
namespace genesys {
/* A FIFO buffer. Note, that this is _not_ a ringbuffer.
if we need a block which does not fit at the end of our available data,
we move the available data to the beginning.
*/
struct Genesys_Buffer
{
Genesys_Buffer() = default;
std::size_t size() const { return buffer_.size(); }
std::size_t avail() const { return avail_; }
std::size_t pos() const { return pos_; }
// TODO: refactor code that uses this function to no longer use it
void set_pos(std::size_t pos) { pos_ = pos; }
void alloc(std::size_t size);
void clear();
void reset();
std::uint8_t* get_write_pos(std::size_t size);
std::uint8_t* get_read_pos(); // TODO: mark as const
void produce(std::size_t size);
void consume(std::size_t size);
private:
std::vector<std::uint8_t> buffer_;
// current position in read buffer
std::size_t pos_ = 0;
// data bytes currently in buffer
std::size_t avail_ = 0;
};
} // namespace genesys
#endif // BACKEND_GENESYS_BUFFER_H

Wyświetl plik

@ -67,13 +67,10 @@ public:
virtual void init(Genesys_Device* dev) const = 0;
virtual void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const = 0;
Genesys_Register_Set* regs) const = 0;
virtual void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
virtual void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
/** Set up registers for a scan. Similar to init_regs_for_scan except that the session is
already computed from the session
@ -133,9 +130,6 @@ public:
/// eject document from scanner
virtual void eject_document(Genesys_Device* dev) const = 0;
/// move scanning head to transparency adapter
virtual void move_to_ta(Genesys_Device* dev) const = 0;
/// write shading data calibration to ASIC
virtual void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
std::uint8_t* data, int size) const = 0;

Wyświetl plik

@ -24,6 +24,7 @@
#include "command_set_common.h"
#include "low.h"
#include "value_filter.h"
namespace genesys {
@ -83,6 +84,7 @@ void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
// turning off the lamp
LampSettings settings[] = {
{ ModelId::CANON_4400F, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::CANON_5600F, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::CANON_8400F, ScanMethod::TRANSPARENCY, {
{ 0xa6, 0x34, 0xf4 },
}, {
@ -113,6 +115,7 @@ void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
{ 0x6c, 0x00, 0x80 },
}
},
{ ModelId::PLUSTEK_OPTICFILM_7200, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa8, 0x07, 0x07 },
@ -121,6 +124,7 @@ void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
}
},
{ ModelId::PLUSTEK_OPTICFILM_7300, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7400, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa8, 0x07, 0x07 },
@ -128,6 +132,13 @@ void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
{ 0xa8, 0x00, 0x07 },
}
},
{ ModelId::PLUSTEK_OPTICFILM_8200I, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_8200I, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa8, 0x04, 0x04 },
}, {
{ 0xa8, 0x00, 0x04 },
}
},
};
for (const auto& setting : settings) {
@ -150,7 +161,7 @@ void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set&
struct MotorSettings {
ModelId model_id;
ResolutionFilter resolutions;
ValueFilterAny<unsigned> resolutions;
GenesysRegisterSettingSet regs_primary_and_secondary;
GenesysRegisterSettingSet regs_primary;
GenesysRegisterSettingSet regs_secondary;
@ -187,7 +198,7 @@ void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set&
{ 0xa6, 0x01, 0x41 },
}
},
{ ModelId::HP_SCANJET_G4050, ResolutionFilter::ANY, {
{ ModelId::HP_SCANJET_G4050, VALUE_FILTER_ANY, {
{ 0x6b, 0x81, 0x81 }, // set MULTFILM and GPOADF
{ 0x6c, 0x00, 0x40 }, // note that reverse change is not applied on off
// 0xa6 register 0x08 bit likely sets motor power. No move at all without that one
@ -200,9 +211,12 @@ void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set&
{ 0xa9, 0x00, 0x10 }, // note that 0x20 bit is not reset
}, {}
},
{ ModelId::PLUSTEK_OPTICFILM_7200I, ResolutionFilter::ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7300, ResolutionFilter::ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, ResolutionFilter::ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7200, VALUE_FILTER_ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7200I, VALUE_FILTER_ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7300, VALUE_FILTER_ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7400, VALUE_FILTER_ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_7500I, VALUE_FILTER_ANY, {}, {}, {} },
{ ModelId::PLUSTEK_OPTICFILM_8200I, VALUE_FILTER_ANY, {}, {}, {} },
};
for (const auto& setting : settings) {

Wyświetl plik

@ -1,238 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2005, 2006 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#define DEBUG_DECLARE_ONLY
#include "conv.h"
#include "sane/sanei_magic.h"
namespace genesys {
/**
* uses the threshold/threshold_curve to control software binarization
* This code was taken from the epjistsu backend by m. allan noah
* @param dev device set up for the scan
* @param src pointer to raw data
* @param dst pointer where to store result
* @param width width of the processed line
* */
void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width)
{
DBG_HELPER(dbg);
int j, windowX, sum = 0;
int thresh;
int offset, addCol, dropCol;
unsigned char mask;
int x;
std::uint8_t min, max;
/* normalize line */
min = 255;
max = 0;
for (x = 0; x < width; x++)
{
if (src[x] > max)
{
max = src[x];
}
if (src[x] < min)
{
min = src[x];
}
}
/* safeguard against dark or white areas */
if(min>80)
min=0;
if(max<80)
max=255;
for (x = 0; x < width; x++)
{
src[x] = ((src[x] - min) * 255) / (max - min);
}
/* ~1mm works best, but the window needs to have odd # of pixels */
windowX = (6 * dev->settings.xres) / 150;
if (!(windowX % 2))
windowX++;
/* second, prefill the sliding sum */
for (j = 0; j < windowX; j++)
sum += src[j];
/* third, walk the input buffer, update the sliding sum, */
/* determine threshold, output bits */
for (j = 0; j < width; j++)
{
/* output image location */
offset = j % 8;
mask = 0x80 >> offset;
thresh = dev->settings.threshold;
/* move sum/update threshold only if there is a curve */
if (dev->settings.threshold_curve)
{
addCol = j + windowX / 2;
dropCol = addCol - windowX;
if (dropCol >= 0 && addCol < width)
{
sum -= src[dropCol];
sum += src[addCol];
}
thresh = dev->lineart_lut[sum / windowX];
}
/* use average to lookup threshold */
if (src[j] > thresh)
*dst &= ~mask; /* white */
else
*dst |= mask; /* black */
if (offset == 7)
dst++;
}
}
/**
* software lineart using data from a 8 bit gray scan. We assume true gray
* or monochrome scan as input.
*/
void genesys_gray_lineart(Genesys_Device* dev,
std::uint8_t* src_data, std::uint8_t* dst_data,
std::size_t pixels, std::size_t lines, std::uint8_t threshold)
{
DBG_HELPER(dbg);
std::size_t y;
DBG(DBG_io2, "%s: converting %zu lines of %zu pixels\n", __func__, lines, pixels);
DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold);
for (y = 0; y < lines; y++)
{
binarize_line (dev, src_data + y * pixels, dst_data, pixels);
dst_data += pixels / 8;
}
}
/** Look in image for likely left/right/bottom paper edges, then crop image.
*/
void genesys_crop(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
Genesys_Device *dev = s->dev;
int top = 0;
int bottom = 0;
int left = 0;
int right = 0;
// first find edges if any
TIE(sanei_magic_findEdges(&s->params, dev->img_buffer.data(),
dev->settings.xres, dev->settings.yres,
&top, &bottom, &left, &right));
DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left,
right);
// now crop the image
TIE(sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right));
/* update counters to new image size */
dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines;
}
/** Look in image for likely upper and left paper edges, then rotate
* image so that upper left corner of paper is upper left of image.
*/
void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor)
{
DBG_HELPER(dbg);
Genesys_Device *dev = s->dev;
int x = 0, y = 0, bg;
double slope = 0;
bg=0;
if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1)
{
bg=0xff;
}
TIE(sanei_magic_findSkew(&s->params, dev->img_buffer.data(),
sensor.optical_res, sensor.optical_res,
&x, &y, &slope));
DBG(DBG_info, "%s: slope=%f => %f\n", __func__, slope, slope * 180 / M_PI);
// rotate image slope is in [-PI/2,PI/2]. Positive values rotate trigonometric direction wise
TIE(sanei_magic_rotate(&s->params, dev->img_buffer.data(),
x, y, slope, bg));
}
/** remove lone dots
*/
void genesys_despeck(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
TIE(sanei_magic_despeck(&s->params, s->dev->img_buffer.data(), s->despeck));
}
/** Look if image needs rotation and apply it
* */
void genesys_derotate(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
int angle = 0;
TIE(sanei_magic_findTurn(&s->params, s->dev->img_buffer.data(),
s->resolution, s->resolution, &angle));
// apply rotation angle found
TIE(sanei_magic_turn(&s->params, s->dev->img_buffer.data(), angle));
// update counters to new image size
s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines;
}
} // namespace genesys

Wyświetl plik

@ -1,69 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#ifndef BACKEND_GENESYS_CONV_H
#define BACKEND_GENESYS_CONV_H
#include "device.h"
#include "sensor.h"
#include "genesys.h"
namespace genesys {
void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width);
void genesys_gray_lineart(Genesys_Device* dev,
std::uint8_t* src_data, std::uint8_t* dst_data,
std::size_t pixels, size_t lines, std::uint8_t threshold);
void genesys_crop(Genesys_Scanner* s);
void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor);
void genesys_despeck(Genesys_Scanner* s);
void genesys_derotate(Genesys_Scanner* s);
} // namespace genesys
#endif // BACKEND_GENESYS_CONV_H

Wyświetl plik

@ -102,10 +102,6 @@ Genesys_Device::~Genesys_Device()
void Genesys_Device::clear()
{
read_buffer.clear();
binarize_buffer.clear();
local_buffer.clear();
calib_file.clear();
calibration_cache.clear();
@ -114,9 +110,9 @@ void Genesys_Device::clear()
dark_average_data.clear();
}
ImagePipelineNodeBytesSource& Genesys_Device::get_pipeline_source()
ImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source()
{
return static_cast<ImagePipelineNodeBytesSource&>(pipeline.front());
return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front());
}
bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const
@ -227,8 +223,12 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< " initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n'
<< " settings: " << format_indent_braced_list(4, dev.settings) << '\n'
<< " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n'
<< " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n'
<< " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
<< " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n';
if (!dev.memory_layout.regs.empty()) {
out << " memory_layout.regs: "
<< format_indent_braced_list(4, dev.memory_layout.regs) << '\n';
}
out << " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
<< " motor: " << format_indent_braced_list(4, dev.motor) << '\n'
<< " control[0..6]: " << std::hex
<< static_cast<unsigned>(dev.control[0]) << ' '
@ -254,24 +254,26 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< " read_active: " << dev.read_active << '\n'
<< " parking: " << dev.parking << '\n'
<< " document: " << dev.document << '\n'
<< " read_buffer.size(): " << dev.read_buffer.size() << '\n'
<< " binarize_buffer.size(): " << dev.binarize_buffer.size() << '\n'
<< " local_buffer.size(): " << dev.local_buffer.size() << '\n'
<< " oe_buffer.size(): " << dev.oe_buffer.size() << '\n'
<< " total_bytes_read: " << dev.total_bytes_read << '\n'
<< " total_bytes_to_read: " << dev.total_bytes_to_read << '\n'
<< " session: " << format_indent_braced_list(4, dev.session) << '\n'
<< " lineart_lut: (not printed)\n"
<< " calibration_cache: (not printed)\n"
<< " line_count: " << dev.line_count << '\n'
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n'
<< " buffer_image: " << dev.buffer_image << '\n'
<< " img_buffer.size(): " << dev.img_buffer.size() << '\n'
<< '}';
return out;
}
void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs)
{
GenesysRegisterSettingSet backup;
for (const auto& reg : regs) {
dev.interface->write_register(reg.address, reg.value);
}
}
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
{
apply_reg_settings_to_device_with_backup(dev, regs);

Wyświetl plik

@ -46,7 +46,6 @@
#include "calibration.h"
#include "command_set.h"
#include "buffer.h"
#include "enums.h"
#include "image_pipeline.h"
#include "motor.h"
@ -78,6 +77,17 @@ struct Genesys_Gpo
GenesysRegisterSettingSet regs;
};
struct MemoryLayout
{
// This is used on GL845, GL846, GL847 and GL124 which have special registers to define the
// memory layout
MemoryLayout() = default;
ValueFilter<ModelId> models;
GenesysRegisterSettingSet regs;
};
struct MethodResolutions
{
std::vector<ScanMethod> methods;
@ -89,6 +99,16 @@ struct MethodResolutions
return *std::min_element(resolutions_x.begin(), resolutions_x.end());
}
unsigned get_nearest_resolution_x(unsigned resolution) const
{
return *std::min_element(resolutions_x.begin(), resolutions_x.end(),
[&](unsigned lhs, unsigned rhs)
{
return std::abs(static_cast<int>(lhs) - static_cast<int>(resolution)) <
std::abs(static_cast<int>(rhs) - static_cast<int>(resolution));
});
}
unsigned get_min_resolution_y() const
{
return *std::min_element(resolutions_y.begin(), resolutions_y.end());
@ -186,7 +206,7 @@ struct Genesys_Model
// Amount of feeding needed to eject document after finishing scanning in mm
float eject_feed = 0;
// Line-distance correction (in pixel at optical_ydpi) for CCD scanners
// Line-distance correction (in pixel at motor base_ydpi) for CCD scanners
SANE_Int ld_shift_r = 0;
SANE_Int ld_shift_g = 0;
SANE_Int ld_shift_b = 0;
@ -244,8 +264,8 @@ struct Genesys_Device
// frees commonly used data
void clear();
SANE_Word vendorId = 0; /**< USB vendor identifier */
SANE_Word productId = 0; /**< USB product identifier */
std::uint16_t vendorId = 0; // USB vendor identifier
std::uint16_t productId = 0; // USB product identifier
// USB mode:
// 0: not set
@ -262,7 +282,7 @@ struct Genesys_Device
// acquiring the positions of the black and white strips and the actual scan area
bool ignore_offsets = false;
Genesys_Model *model = nullptr;
const Genesys_Model* model = nullptr;
// pointers to low level functions
std::unique_ptr<CommandSet> cmd_set;
@ -272,6 +292,7 @@ struct Genesys_Device
Genesys_Settings settings;
Genesys_Frontend frontend, frontend_initial;
Genesys_Gpo gpo;
MemoryLayout memory_layout;
Genesys_Motor motor;
std::uint8_t control[6] = {};
@ -296,13 +317,6 @@ struct Genesys_Device
// for sheetfed scanner's, is TRUE when there is a document in the scanner
bool document = false;
Genesys_Buffer read_buffer;
// buffer for digital lineart from gray data
Genesys_Buffer binarize_buffer;
// local buffer for gray data during dynamix lineart
Genesys_Buffer local_buffer;
// total bytes read sent to frontend
size_t total_bytes_read = 0;
// total bytes read to be sent to frontend
@ -311,9 +325,6 @@ struct Genesys_Device
// contains computed data for the current setup
ScanSession session;
// look up table used in dynamic rasterization
unsigned char lineart_lut[256] = {};
Calibration calibration_cache;
// number of scan lines used during scan
@ -322,22 +333,13 @@ struct Genesys_Device
// array describing the order of the sub-segments of the sensor
std::vector<unsigned> segment_order;
// buffer to handle even/odd data
Genesys_Buffer oe_buffer = {};
// stores information about how the input image should be processed
ImagePipelineStack pipeline;
// an buffer that allows reading from `pipeline` in chunks of any size
ImageBuffer pipeline_buffer;
// when true the scanned picture is first buffered to allow software image enhancements
bool buffer_image = false;
// image buffer where the scanned picture is stored
std::vector<std::uint8_t> img_buffer;
ImagePipelineNodeBytesSource& get_pipeline_source();
ImagePipelineNodeBufferedCallableSource& get_pipeline_source();
std::unique_ptr<ScannerInterface> interface;
@ -365,6 +367,8 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev);
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs);
void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs);
GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs);

Wyświetl plik

@ -109,6 +109,243 @@ std::ostream& operator<<(std::ostream& out, ColorFilter mode)
return out;
}
std::ostream& operator<<(std::ostream& out, ModelId id)
{
switch (id) {
case ModelId::UNKNOWN: out << "UNKNOWN"; break;
case ModelId::CANON_4400F: out << "CANON_4400F"; break;
case ModelId::CANON_5600F: out << "CANON_5600F"; break;
case ModelId::CANON_8400F: out << "CANON_8400F"; break;
case ModelId::CANON_8600F: out << "CANON_8600F"; break;
case ModelId::CANON_IMAGE_FORMULA_101: out << "CANON_IMAGE_FORMULA_101"; break;
case ModelId::CANON_LIDE_50: out << "CANON_LIDE_50"; break;
case ModelId::CANON_LIDE_60: out << "CANON_LIDE_60"; break;
case ModelId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case ModelId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
case ModelId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case ModelId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case ModelId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
case ModelId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
case ModelId::CANON_LIDE_220: out << "CANON_LIDE_220"; break;
case ModelId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
case ModelId::DCT_DOCKETPORT_487: out << "DCT_DOCKETPORT_487"; break;
case ModelId::HP_SCANJET_2300C: out << "HP_SCANJET_2300C"; break;
case ModelId::HP_SCANJET_2400C: out << "HP_SCANJET_2400C"; break;
case ModelId::HP_SCANJET_3670: out << "HP_SCANJET_3670"; break;
case ModelId::HP_SCANJET_4850C: out << "HP_SCANJET_4850C"; break;
case ModelId::HP_SCANJET_G4010: out << "HP_SCANJET_G4010"; break;
case ModelId::HP_SCANJET_G4050: out << "HP_SCANJET_G4050"; break;
case ModelId::HP_SCANJET_N6310: out << "HP_SCANJET_N6310"; break;
case ModelId::MEDION_MD5345: out << "MEDION_MD5345"; break;
case ModelId::PANASONIC_KV_SS080: out << "PANASONIC_KV_SS080"; break;
case ModelId::PENTAX_DSMOBILE_600: out << "PENTAX_DSMOBILE_600"; break;
case ModelId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
case ModelId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
case ModelId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
case ModelId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
case ModelId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
case ModelId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
case ModelId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
case ModelId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
case ModelId::PLUSTEK_OPTICPRO_ST12: out << "PLUSTEK_OPTICPRO_ST12"; break;
case ModelId::PLUSTEK_OPTICPRO_ST24: out << "PLUSTEK_OPTICPRO_ST24"; break;
case ModelId::SYSCAN_DOCKETPORT_465: out << "SYSCAN_DOCKETPORT_465"; break;
case ModelId::SYSCAN_DOCKETPORT_467: out << "SYSCAN_DOCKETPORT_467"; break;
case ModelId::SYSCAN_DOCKETPORT_485: out << "SYSCAN_DOCKETPORT_485"; break;
case ModelId::SYSCAN_DOCKETPORT_665: out << "SYSCAN_DOCKETPORT_665"; break;
case ModelId::SYSCAN_DOCKETPORT_685: out << "SYSCAN_DOCKETPORT_685"; break;
case ModelId::UMAX_ASTRA_4500: out << "UMAX_ASTRA_4500"; break;
case ModelId::VISIONEER_7100: out << "VISIONEER_7100"; break;
case ModelId::VISIONEER_ROADWARRIOR: out << "VISIONEER_ROADWARRIOR"; break;
case ModelId::VISIONEER_STROBE_XP100_REVISION3:
out << "VISIONEER_STROBE_XP100_REVISION3"; break;
case ModelId::VISIONEER_STROBE_XP200: out << "VISIONEER_STROBE_XP200"; break;
case ModelId::VISIONEER_STROBE_XP300: out << "VISIONEER_STROBE_XP300"; break;
case ModelId::XEROX_2400: out << "XEROX_2400"; break;
case ModelId::XEROX_TRAVELSCANNER_100: out << "XEROX_TRAVELSCANNER_100"; break;
default:
out << static_cast<unsigned>(id); break;
}
return out;
}
std::ostream& operator<<(std::ostream& out, SensorId id)
{
switch (id) {
case SensorId::CCD_5345: out << "CCD_5345"; break;
case SensorId::CCD_CANON_4400F: out << "CCD_CANON_4400F"; break;
case SensorId::CCD_CANON_5600F: out << "CCD_CANON_5600F"; break;
case SensorId::CCD_CANON_8400F: out << "CCD_CANON_8400F"; break;
case SensorId::CCD_CANON_8600F: out << "CCD_CANON_8600F"; break;
case SensorId::CCD_DP665: out << "CCD_DP665"; break;
case SensorId::CCD_DP685: out << "CCD_DP685"; break;
case SensorId::CCD_DSMOBILE600: out << "CCD_DSMOBILE600"; break;
case SensorId::CCD_DOCKETPORT_487: out << "CCD_DOCKETPORT_487"; break;
case SensorId::CCD_G4050: out << "CCD_G4050"; break;
case SensorId::CCD_HP2300: out << "CCD_HP2300"; break;
case SensorId::CCD_HP2400: out << "CCD_HP2400"; break;
case SensorId::CCD_HP3670: out << "CCD_HP3670"; break;
case SensorId::CCD_HP_N6310: out << "CCD_HP_N6310"; break;
case SensorId::CCD_HP_4850C: out << "CCD_HP_4850C"; break;
case SensorId::CCD_IMG101: out << "CCD_IMG101"; break;
case SensorId::CCD_KVSS080: out << "CCD_KVSS080"; break;
case SensorId::CCD_PLUSTEK_OPTICBOOK_3800: out << "CCD_PLUSTEK_OPTICBOOK_3800"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_7200: out << "CCD_PLUSTEK_OPTICFILM_7200"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_7200I: out << "CCD_PLUSTEK_OPTICFILM_7200I"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_7300: out << "CCD_PLUSTEK_OPTICFILM_7300"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_7400: out << "CCD_PLUSTEK_OPTICFILM_7400"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_7500I: out << "CCD_PLUSTEK_OPTICFILM_7500I"; break;
case SensorId::CCD_PLUSTEK_OPTICFILM_8200I: out << "CCD_PLUSTEK_OPTICFILM_8200I"; break;
case SensorId::CCD_PLUSTEK_OPTICPRO_3600: out << "CCD_PLUSTEK_OPTICPRO_3600"; break;
case SensorId::CCD_ROADWARRIOR: out << "CCD_ROADWARRIOR"; break;
case SensorId::CCD_ST12: out << "CCD_ST12"; break;
case SensorId::CCD_ST24: out << "CCD_ST24"; break;
case SensorId::CCD_UMAX: out << "CCD_UMAX"; break;
case SensorId::CCD_XP300: out << "CCD_XP300"; break;
case SensorId::CIS_CANON_LIDE_35: out << "CIS_CANON_LIDE_35"; break;
case SensorId::CIS_CANON_LIDE_60: out << "CIS_CANON_LIDE_60"; break;
case SensorId::CIS_CANON_LIDE_80: out << "CIS_CANON_LIDE_80"; break;
case SensorId::CIS_CANON_LIDE_100: out << "CIS_CANON_LIDE_100"; break;
case SensorId::CIS_CANON_LIDE_110: out << "CIS_CANON_LIDE_110"; break;
case SensorId::CIS_CANON_LIDE_120: out << "CIS_CANON_LIDE_120"; break;
case SensorId::CIS_CANON_LIDE_200: out << "CIS_CANON_LIDE_200"; break;
case SensorId::CIS_CANON_LIDE_210: out << "CIS_CANON_LIDE_210"; break;
case SensorId::CIS_CANON_LIDE_220: out << "CIS_CANON_LIDE_220"; break;
case SensorId::CIS_CANON_LIDE_700F: out << "CIS_CANON_LIDE_700F"; break;
case SensorId::CIS_XP200: out << "CIS_XP200"; break;
default:
out << static_cast<unsigned>(id); break;
}
return out;
}
std::ostream& operator<<(std::ostream& out, AdcId id)
{
switch (id) {
case AdcId::UNKNOWN: out << "UNKNOWN"; break;
case AdcId::AD_XP200: out << "AD_XP200"; break;
case AdcId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
case AdcId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case AdcId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case AdcId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case AdcId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
case AdcId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
case AdcId::CANON_4400F: out << "CANON_4400F"; break;
case AdcId::CANON_5600F: out << "CANON_5600F"; break;
case AdcId::CANON_8400F: out << "CANON_8400F"; break;
case AdcId::CANON_8600F: out << "CANON_8600F"; break;
case AdcId::G4050: out << "G4050"; break;
case AdcId::IMG101: out << "IMG101"; break;
case AdcId::KVSS080: out << "KVSS080"; break;
case AdcId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
case AdcId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
case AdcId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
case AdcId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
case AdcId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
case AdcId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
case AdcId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
case AdcId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
case AdcId::WOLFSON_5345: out << "WOLFSON_5345"; break;
case AdcId::WOLFSON_DSM600: out << "WOLFSON_DSM600"; break;
case AdcId::WOLFSON_HP2300: out << "WOLFSON_HP2300"; break;
case AdcId::WOLFSON_HP2400: out << "WOLFSON_HP2400"; break;
case AdcId::WOLFSON_HP3670: out << "WOLFSON_HP3670"; break;
case AdcId::WOLFSON_ST12: out << "WOLFSON_ST12"; break;
case AdcId::WOLFSON_ST24: out << "WOLFSON_ST24"; break;
case AdcId::WOLFSON_UMAX: out << "WOLFSON_UMAX"; break;
case AdcId::WOLFSON_XP300: out << "WOLFSON_XP300"; break;
default:
out << static_cast<unsigned>(id); break;
}
return out;
}
std::ostream& operator<<(std::ostream& out, GpioId id)
{
switch (id) {
case GpioId::UNKNOWN: out << "UNKNOWN"; break;
case GpioId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
case GpioId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case GpioId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case GpioId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case GpioId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
case GpioId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
case GpioId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
case GpioId::CANON_4400F: out << "CANON_4400F"; break;
case GpioId::CANON_5600F: out << "CANON_5600F"; break;
case GpioId::CANON_8400F: out << "CANON_8400F"; break;
case GpioId::CANON_8600F: out << "CANON_8600F"; break;
case GpioId::DP665: out << "DP665"; break;
case GpioId::DP685: out << "DP685"; break;
case GpioId::G4050: out << "G4050"; break;
case GpioId::HP2300: out << "HP2300"; break;
case GpioId::HP2400: out << "HP2400"; break;
case GpioId::HP3670: out << "HP3670"; break;
case GpioId::HP_N6310: out << "HP_N6310"; break;
case GpioId::IMG101: out << "IMG101"; break;
case GpioId::KVSS080: out << "KVSS080"; break;
case GpioId::MD_5345: out << "MD_5345"; break;
case GpioId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
case GpioId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
case GpioId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
case GpioId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
case GpioId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
case GpioId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
case GpioId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
case GpioId::ST12: out << "ST12"; break;
case GpioId::ST24: out << "ST24"; break;
case GpioId::UMAX: out << "UMAX"; break;
case GpioId::XP200: out << "XP200"; break;
case GpioId::XP300: out << "XP300"; break;
default: out << static_cast<unsigned>(id); break;
}
return out;
}
std::ostream& operator<<(std::ostream& out, MotorId id)
{
switch (id) {
case MotorId::UNKNOWN: out << "UNKNOWN"; break;
case MotorId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
case MotorId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
case MotorId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
case MotorId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
case MotorId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
case MotorId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
case MotorId::CANON_LIDE_60: out << "CANON_LIDE_60"; break;
case MotorId::CANON_LIDE_700: out << "CANON_LIDE_700"; break;
case MotorId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case MotorId::CANON_4400F: out << "CANON_4400F"; break;
case MotorId::CANON_5600F: out << "CANON_5600F"; break;
case MotorId::CANON_8400F: out << "CANON_8400F"; break;
case MotorId::CANON_8600F: out << "CANON_8600F"; break;
case MotorId::DP665: out << "DP665"; break;
case MotorId::DSMOBILE_600: out << "DSMOBILE_600"; break;
case MotorId::G4050: out << "G4050"; break;
case MotorId::HP2300: out << "HP2300"; break;
case MotorId::HP2400: out << "HP2400"; break;
case MotorId::HP3670: out << "HP3670"; break;
case MotorId::IMG101: out << "IMG101"; break;
case MotorId::KVSS080: out << "KVSS080"; break;
case MotorId::MD_5345: out << "MD_5345"; break;
case MotorId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
case MotorId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
case MotorId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
case MotorId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
case MotorId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
case MotorId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
case MotorId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
case MotorId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
case MotorId::ROADWARRIOR: out << "ROADWARRIOR"; break;
case MotorId::ST24: out << "ST24"; break;
case MotorId::UMAX: out << "UMAX"; break;
case MotorId::XP200: out << "XP200"; break;
case MotorId::XP300: out << "XP300"; break;
default: out << static_cast<unsigned>(id); break;
}
return out;
}
std::ostream& operator<<(std::ostream& out, StepType type)
{
switch (type) {

Wyświetl plik

@ -201,9 +201,12 @@ enum class ModelId : unsigned
PANASONIC_KV_SS080,
PENTAX_DSMOBILE_600,
PLUSTEK_OPTICBOOK_3800,
PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
PLUSTEK_OPTICPRO_ST12,
PLUSTEK_OPTICPRO_ST24,
@ -222,16 +225,33 @@ enum class ModelId : unsigned
XEROX_TRAVELSCANNER_100,
};
inline void serialize(std::istream& str, ModelId& x)
{
unsigned value;
serialize(str, value);
x = static_cast<ModelId>(value);
}
inline void serialize(std::ostream& str, ModelId& x)
{
unsigned value = static_cast<unsigned>(x);
serialize(str, value);
}
std::ostream& operator<<(std::ostream& out, ModelId id);
enum class SensorId : unsigned
{
UNKNOWN = 0,
CCD_5345,
CCD_CANON_4400F,
CCD_CANON_5600F,
CCD_CANON_8400F,
CCD_CANON_8600F,
CCD_DP665,
CCD_DP685,
CCD_DSMOBILE600,
CCD_DOCKETPORT_487,
CCD_G4050,
CCD_HP2300,
CCD_HP2400,
@ -241,9 +261,12 @@ enum class SensorId : unsigned
CCD_IMG101,
CCD_KVSS080,
CCD_PLUSTEK_OPTICBOOK_3800,
CCD_PLUSTEK_OPTICFILM_7200,
CCD_PLUSTEK_OPTICFILM_7200I,
CCD_PLUSTEK_OPTICFILM_7300,
CCD_PLUSTEK_OPTICFILM_7400,
CCD_PLUSTEK_OPTICFILM_7500I,
CCD_PLUSTEK_OPTICFILM_8200I,
CCD_PLUSTEK_OPTICPRO_3600,
CCD_ROADWARRIOR,
CCD_ST12, // SONY ILX548: 5340 Pixel ???
@ -251,6 +274,7 @@ enum class SensorId : unsigned
CCD_UMAX,
CCD_XP300,
CIS_CANON_LIDE_35,
CIS_CANON_LIDE_60,
CIS_CANON_LIDE_80,
CIS_CANON_LIDE_100,
CIS_CANON_LIDE_110,
@ -275,6 +299,8 @@ inline void serialize(std::ostream& str, SensorId& x)
serialize(str, value);
}
std::ostream& operator<<(std::ostream& out, SensorId id);
enum class AdcId : unsigned
{
@ -287,15 +313,19 @@ enum class AdcId : unsigned
CANON_LIDE_200,
CANON_LIDE_700F,
CANON_4400F,
CANON_5600F,
CANON_8400F,
CANON_8600F,
G4050,
IMG101,
KVSS080,
PLUSTEK_OPTICBOOK_3800,
PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
WOLFSON_5345,
WOLFSON_DSM600,
@ -321,6 +351,8 @@ inline void serialize(std::ostream& str, AdcId& x)
serialize(str, value);
}
std::ostream& operator<<(std::ostream& out, AdcId id);
enum class GpioId : unsigned
{
UNKNOWN = 0,
@ -332,6 +364,7 @@ enum class GpioId : unsigned
CANON_LIDE_210,
CANON_LIDE_700F,
CANON_4400F,
CANON_5600F,
CANON_8400F,
CANON_8600F,
DP665,
@ -345,9 +378,12 @@ enum class GpioId : unsigned
KVSS080,
MD_5345,
PLUSTEK_OPTICBOOK_3800,
PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
ST12,
ST24,
@ -356,6 +392,8 @@ enum class GpioId : unsigned
XP300,
};
std::ostream& operator<<(std::ostream& out, GpioId id);
enum class MotorId : unsigned
{
UNKNOWN = 0,
@ -365,9 +403,11 @@ enum class MotorId : unsigned
CANON_LIDE_200,
CANON_LIDE_210,
CANON_LIDE_35,
CANON_LIDE_60,
CANON_LIDE_700,
CANON_LIDE_80,
CANON_4400F,
CANON_5600F,
CANON_8400F,
CANON_8600F,
DP665,
@ -380,9 +420,12 @@ enum class MotorId : unsigned
KVSS080,
MD_5345,
PLUSTEK_OPTICBOOK_3800,
PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
ROADWARRIOR,
ST24,
@ -391,6 +434,8 @@ enum class MotorId : unsigned
XP300,
};
std::ostream& operator<<(std::ostream& out, MotorId id);
enum class StepType : unsigned
{
FULL = 0,
@ -423,6 +468,7 @@ enum class AsicType : unsigned
UNKNOWN = 0,
GL646,
GL841,
GL842,
GL843,
GL845,
GL846,
@ -442,15 +488,25 @@ enum class ModelFlag : unsigned
// use 14-bit gamma table instead of 12-bit
GAMMA_14BIT = 1 << 1,
// skip lamp warmup (genesys_warmup())
SKIP_WARMUP = 1 << 4,
// perform lamp warmup
WARMUP = 1 << 4,
// repark head and check for lock by moving without scanning
REPARK = 1 << 7,
// whether to disable offset and gain calibration
DISABLE_ADC_CALIBRATION = 1 << 5,
// whether to disable exposure calibration (this currently is only done on CIS
// scanners)
DISABLE_EXPOSURE_CALIBRATION = 1 << 6,
// whether to disable shading calibration completely
DISABLE_SHADING_CALIBRATION = 1 << 7,
// do dark calibration
DARK_CALIBRATION = 1 << 8,
// host-side calibration uses a complete scan
HOST_SIDE_CALIBRATION_COMPLETE_SCAN = 1 << 9,
// whether scanner must wait for the head while parking
MUST_WAIT = 1 << 10,
@ -460,23 +516,23 @@ enum class ModelFlag : unsigned
// allow custom gamma tables
CUSTOM_GAMMA = 1 << 13,
// skip calibration completely, this is needed for sheet-fed scanners
NO_CALIBRATION = 1 << 14,
// the scanner uses multi-segment sensors that must be handled during calibration
SIS_SENSOR = 1 << 16,
// the head must be reparked between shading scans
SHADING_REPARK = 1 << 18,
// the scanner always uses maximum hwdpi to setup the sensor
FULL_HWDPI_MODE = 1 << 19,
// the scanner outputs inverted pixel data
INVERT_PIXEL_DATA = 1 << 19,
// the scanner outputs 16-bit data that is byte-inverted
INVERTED_16BIT_DATA = 1 << 20,
SWAP_16BIT_DATA = 1 << 20,
// the scanner has transparency, but it's implemented using only one motor
UTA_NO_SECONDARY_MOTOR = 1 << 21
UTA_NO_SECONDARY_MOTOR = 1 << 21,
// the scanner has transparency, but it's implemented using only one lamp
TA_NO_SECONDARY_LAMP = 1 << 22,
};
inline ModelFlag operator|(ModelFlag left, ModelFlag right)
@ -522,8 +578,10 @@ enum class ScanFlag : unsigned
FEEDING = 1 << 8,
USE_XPA = 1 << 9,
ENABLE_LEDADD = 1 << 10,
USE_XCORRECTION = 1 << 11,
REVERSE = 1 << 12,
// the scanner should return head to home position automatically after scan.
AUTO_GO_HOME = 1 << 13,
};
inline ScanFlag operator|(ScanFlag left, ScanFlag right)
@ -563,39 +621,6 @@ inline void serialize(std::ostream& str, ScanFlag& x)
std::ostream& operator<<(std::ostream& out, ScanFlag flags);
enum class MotorFlag : unsigned
{
NONE = 0,
AUTO_GO_HOME = 1 << 0,
DISABLE_BUFFER_FULL_MOVE = 1 << 2,
FEED = 1 << 3,
USE_XPA = 1 << 4,
REVERSE = 1 << 5,
};
inline MotorFlag operator|(MotorFlag left, MotorFlag right)
{
return static_cast<MotorFlag>(static_cast<unsigned>(left) | static_cast<unsigned>(right));
}
inline MotorFlag& operator|=(MotorFlag& left, MotorFlag right)
{
left = left | right;
return left;
}
inline MotorFlag operator&(MotorFlag left, MotorFlag right)
{
return static_cast<MotorFlag>(static_cast<unsigned>(left) & static_cast<unsigned>(right));
}
inline bool has_flag(MotorFlag flags, MotorFlag which)
{
return (flags & which) == which;
}
enum class Direction : unsigned
{
FORWARD = 0,

Wyświetl plik

@ -45,6 +45,7 @@
#include "error.h"
#include <cstdarg>
#include <cstdlib>
namespace genesys {
@ -212,4 +213,32 @@ void DebugMessageHelper::vlog(unsigned level, const char* format, ...)
DBG(level, "%s: %s\n", func_, msg.c_str());
}
enum class LogImageDataStatus
{
NOT_SET,
ENABLED,
DISABLED
};
static LogImageDataStatus s_log_image_data_setting = LogImageDataStatus::NOT_SET;
LogImageDataStatus dbg_read_log_image_data_setting()
{
auto* setting = std::getenv("SANE_DEBUG_GENESYS_IMAGE");
if (!setting)
return LogImageDataStatus::DISABLED;
auto setting_int = std::strtol(setting, nullptr, 10);
if (setting_int == 0)
return LogImageDataStatus::DISABLED;
return LogImageDataStatus::ENABLED;
}
bool dbg_log_image_data()
{
if (s_log_image_data_setting == LogImageDataStatus::NOT_SET) {
s_log_image_data_setting = dbg_read_log_image_data_setting();
}
return s_log_image_data_setting == LogImageDataStatus::ENABLED;
}
} // namespace genesys

Wyświetl plik

@ -137,7 +137,6 @@ private:
unsigned num_exceptions_on_enter_ = 0;
};
#if defined(__GNUC__) || defined(__clang__)
#define GENESYS_CURRENT_FUNCTION __PRETTY_FUNCTION__
#elif defined(__FUNCSIG__)
@ -149,6 +148,8 @@ private:
#define DBG_HELPER(var) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION)
#define DBG_HELPER_ARGS(var, ...) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION, __VA_ARGS__)
bool dbg_log_image_data();
template<class F>
SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function)
{
@ -171,6 +172,27 @@ SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function)
}
}
template<class F>
SANE_Status wrap_exceptions_to_status_code_return(const char* func, F&& function)
{
try {
return function();
} catch (const SaneException& exc) {
DBG(DBG_error, "%s: got error: %s\n", func, exc.what());
return exc.status();
} catch (const std::bad_alloc& exc) {
(void) exc;
DBG(DBG_error, "%s: failed to allocate memory\n", func);
return SANE_STATUS_NO_MEM;
} catch (const std::exception& exc) {
DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what());
return SANE_STATUS_INVAL;
} catch (...) {
DBG(DBG_error, "%s: got unknown uncaught exception\n", func);
return SANE_STATUS_INVAL;
}
}
template<class F>
void catch_all_exceptions(const char* func, F&& function)
{

Wyświetl plik

@ -46,9 +46,6 @@
namespace genesys {
// buffer.h
struct Genesys_Buffer;
// calibration.h
struct Genesys_Calibration_Cache;
@ -74,7 +71,6 @@ class Image;
// image_buffer.h
class ImageBuffer;
class ImageBufferGenesysUsb;
// image_pipeline.h
class ImagePipelineNode;
@ -86,7 +82,7 @@ struct Pixel;
struct RawPixel;
// low.h
struct Genesys_USB_Device_Entry;
struct UsbDeviceEntry;
// motor.h
struct Genesys_Motor;
@ -111,8 +107,6 @@ class ScannerInterfaceUsb;
class TestScannerInterface;
// sensor.h
class ScanMethodFilter;
class ResolutionFilter;
struct GenesysFrontendLayout;
struct Genesys_Frontend;
struct SensorExposure;
@ -123,6 +117,10 @@ struct Genesys_Settings;
struct SetupParams;
struct ScanSession;
// value_filter.h
template<class T> class ValueFilter;
template<class T> class ValueFilterAny;
// test_usb_device.h
class TestUsbDevice;

Wyświetl plik

@ -107,21 +107,12 @@ enum Genesys_Option
OPT_GAMMA_VECTOR_R,
OPT_GAMMA_VECTOR_G,
OPT_GAMMA_VECTOR_B,
OPT_SWDESKEW,
OPT_SWCROP,
OPT_SWDESPECK,
OPT_DESPECK,
OPT_SWSKIP,
OPT_SWDEROTATE,
OPT_BRIGHTNESS,
OPT_CONTRAST,
OPT_EXTRAS_GROUP,
OPT_LAMP_OFF_TIME,
OPT_LAMP_OFF,
OPT_THRESHOLD,
OPT_THRESHOLD_CURVE,
OPT_DISABLE_INTERPOLATION,
OPT_COLOR_FILTER,
OPT_CALIBRATION_FILE,
OPT_EXPIRATION_TIME,
@ -213,18 +204,9 @@ struct Genesys_Scanner
// Option values
SANE_Word bit_depth = 0;
SANE_Word resolution = 0;
bool preview = false;
SANE_Word threshold = 0;
SANE_Word threshold_curve = 0;
bool disable_interpolation = false;
bool preview = false; // TODO: currently not used
bool lamp_off = false;
SANE_Word lamp_off_time = 0;
bool swdeskew = false;
bool swcrop = false;
bool swdespeck = false;
bool swderotate = false;
SANE_Word swskip = 0;
SANE_Word despeck = 0;
SANE_Word contrast = 0;
SANE_Word brightness = 0;
SANE_Word expiration_time = 0;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -50,68 +50,6 @@
namespace genesys {
namespace gl124 {
typedef struct
{
uint8_t r31;
uint8_t r32;
uint8_t r33;
uint8_t r34;
uint8_t r35;
uint8_t r36;
uint8_t r38;
} Gpio_layout;
/** @brief gpio layout
* describes initial gpio settings for a given model
* registers 0x31 to 0x38
*/
static Gpio_layout gpios[]={
/* LiDE 110 */
{ /* 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38 */
0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00
},
/* LiDE 210 */
{
0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00
},
/* LiDE 120 */
{
0x9f, 0x53, 0x01, 0x80, 0x5f, 0x01, 0x00
},
};
typedef struct
{
uint8_t rd0;
uint8_t rd1;
uint8_t rd2;
uint8_t re0;
uint8_t re1;
uint8_t re2;
uint8_t re3;
uint8_t re4;
uint8_t re5;
uint8_t re6;
uint8_t re7;
} Memory_layout;
static Memory_layout layouts[]={
/* LIDE 110, 120 */
{ /* 0xd0 0xd1 0xd2 */
0x0a, 0x15, 0x20,
/* 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 */
0x00, 0xac, 0x08, 0x55, 0x08, 0x56, 0x0f, 0xff
},
/* LIDE 210, 220 */
{
0x0a, 0x1f, 0x34,
0x01, 0x24, 0x08, 0x91, 0x08, 0x92, 0x0f, 0xff
}
};
static void gl124_send_slope_table(Genesys_Device* dev, int table_nr,
const std::vector<uint16_t>& slope_table, int steps);
class CommandSetGl124 : public CommandSetCommon
{
public:
@ -122,15 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -171,8 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -54,388 +54,6 @@
namespace genesys {
namespace gl646 {
static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set, int dpi);
/**
* sets up the scanner for a scan, registers, gamma tables, shading tables
* and slope tables, based on the parameter struct.
* @param dev device to set up
* @param regs registers to set up
* @param settings settings of the scan
* @param split true if move before scan has to be done
* @param xcorrection true if scanner's X geometry must be taken into account to
* compute X, ie add left margins
* @param ycorrection true if scanner's Y geometry must be taken into account to
* compute Y, ie add top margins
*/
static ScanSession setup_for_scan(Genesys_Device* device,
const Genesys_Sensor& sensor,
Genesys_Register_Set*regs,
Genesys_Settings settings,
bool split,
bool xcorrection,
bool ycorrection,
bool reverse);
/**
* Does a simple move of the given distance by doing a scan at lowest resolution
* shading correction. Memory for data is allocated in this function
* and must be freed by caller.
* @param dev device of the scanner
* @param distance distance to move in MM
*/
static void simple_move(Genesys_Device* dev, SANE_Int distance);
/**
* Does a simple scan of the area given by the settings. Scanned data
* it put in an allocated area which must be freed by the caller.
* and slope tables, based on the parameter struct. There is no shading
* correction while gamma correction is active.
* @param dev device to set up
* @param settings settings of the scan
* @param move flag to enable scanhead to move
* @param forward flag to tell movement direction
* @param shading flag to tell if shading correction should be done
* @param data pointer that will point to the scanned data
*/
static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Settings settings, bool move, bool forward,
bool shading, std::vector<uint8_t>& data, const char* test_identifier);
/**
* Send the stop scan command
* */
static void end_scan_impl(Genesys_Device* dev, Genesys_Register_Set* reg, bool check_stop,
bool eject);
/**
* writes control data to an area behind the last motor table.
*/
static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution);
/**
* initialize scanner's registers at SANE init time
*/
static void gl646_init_regs (Genesys_Device * dev);
/**
* master motor settings table entry
*/
typedef struct
{
/* key */
MotorId motor_id;
unsigned dpi;
unsigned channels;
/* settings */
StepType steptype;
bool fastmod; // fast scanning
bool fastfed; // fast fed slope tables
SANE_Int mtrpwm;
MotorSlope slope1;
MotorSlope slope2;
SANE_Int fwdbwd; /* forward/backward steps */
} Motor_Master;
/**
* master motor settings, for a given motor and dpi,
* it gives steps and speed informations
*/
static Motor_Master motor_master[] = {
/* HP3670 motor settings */
{MotorId::HP3670, 50, 3, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2329, 120, 229),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 75, 3, StepType::FULL, false, true, 1,
MotorSlope::create_from_steps(3429, 305, 200),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 100, 3, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2905, 187, 143),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 150, 3, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(3429, 305, 73),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 300, 3, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(1055, 563, 11),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 600, 3, StepType::FULL, false, true, 0,
MotorSlope::create_from_steps(10687, 5126, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670,1200, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(15937, 6375, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 50, 1, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2329, 120, 229),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 75, 1, StepType::FULL, false, true, 1,
MotorSlope::create_from_steps(3429, 305, 200),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 100, 1, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(2905, 187, 143),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 150, 1, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(3429, 305, 73),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 300, 1, StepType::HALF, false, true, 1,
MotorSlope::create_from_steps(1055, 563, 11),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670, 600, 1, StepType::FULL, false, true, 0,
MotorSlope::create_from_steps(10687, 5126, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
{MotorId::HP3670,1200, 1, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(15937, 6375, 3),
MotorSlope::create_from_steps(3399, 337, 192), 192},
/* HP2400/G2410 motor settings base motor dpi = 600 */
{MotorId::HP2400, 50, 3, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(8736, 601, 120),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 100, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(8736, 601, 120),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 150, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(15902, 902, 67),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 300, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(16703, 2188, 32),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 600, 3, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(18761, 18761, 3),
MotorSlope::create_from_steps(4905, 627, 192), 192},
{MotorId::HP2400,1200, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(43501, 43501, 3),
MotorSlope::create_from_steps(4905, 627, 192), 192},
{MotorId::HP2400, 50, 1, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(8736, 601, 120),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 100, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(8736, 601, 120),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 150, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(15902, 902, 67),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 300, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(16703, 2188, 32),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400, 600, 1, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(18761, 18761, 3),
MotorSlope::create_from_steps(4905, 337, 192), 192},
{MotorId::HP2400,1200, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(43501, 43501, 3),
MotorSlope::create_from_steps(4905, 337, 192), 192},
/* XP 200 motor settings */
{MotorId::XP200, 75, 3, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6000, 2136, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 100, 3, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6000, 2850, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 200, 3, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6999, 5700, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 250, 3, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6999, 6999, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 300, 3, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(13500, 13500, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 600, 3, StepType::HALF, true, true, 0,
MotorSlope::create_from_steps(31998, 31998, 4),
MotorSlope::create_from_steps(12000, 1200, 2), 1},
{MotorId::XP200, 75, 1, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6000, 2000, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 100, 1, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6000, 1300, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 200, 1, StepType::HALF, true, true, 0,
MotorSlope::create_from_steps(6000, 3666, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 300, 1, StepType::HALF, true, false, 0,
MotorSlope::create_from_steps(6500, 6500, 4),
MotorSlope::create_from_steps(12000, 1200, 8), 1},
{MotorId::XP200, 600, 1, StepType::HALF, true, true, 0,
MotorSlope::create_from_steps(24000, 24000, 4),
MotorSlope::create_from_steps(12000, 1200, 2), 1},
/* HP scanjet 2300c */
{MotorId::HP2300, 75, 3, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(8139, 560, 120),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 150, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(7903, 543, 67),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(2175, 1087, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 600, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(8700, 4350, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300,1200, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(17400, 8700, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 75, 1, StepType::FULL, false, true, 63,
MotorSlope::create_from_steps(8139, 560, 120),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 150, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(7903, 543, 67),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(2175, 1087, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 600, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(8700, 4350, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300,1200, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(17400, 8700, 3),
MotorSlope::create_from_steps(4905, 337, 120), 16},
/* non half ccd settings for 300 dpi
{MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(5386, 2175, 44),
MotorSlope::create_from_steps(4905, 337, 120), 16},
{MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63,
MotorSlope::create_from_steps(5386, 2175, 44),
MotorSlope::create_from_steps(4905, 337, 120), 16},
*/
/* MD5345/6471 motor settings */
/* vfinal=(exposure/(1200/dpi))/step_type */
{MotorId::MD_5345, 50, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 250, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 75, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 343, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 100, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 458, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 150, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 687, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 200, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 916, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 300, 3, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 1375, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 400, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2000, 1833, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 500, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2291, 2291, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 600, 3, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2750, 2750, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 1200, 3, StepType::QUARTER, false, true, 0,
MotorSlope::create_from_steps(2750, 2750, 16),
MotorSlope::create_from_steps(2000, 300, 255), 146},
{MotorId::MD_5345, 2400, 3, StepType::QUARTER, false, true, 0,
MotorSlope::create_from_steps(5500, 5500, 16),
MotorSlope::create_from_steps(2000, 300, 255), 146},
{MotorId::MD_5345, 50, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 250, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 75, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 343, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 100, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 458, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 150, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 687, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 200, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 916, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 300, 1, StepType::HALF, false, true, 2,
MotorSlope::create_from_steps(2500, 1375, 255),
MotorSlope::create_from_steps(2000, 300, 255), 64},
{MotorId::MD_5345, 400, 1, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2000, 1833, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 500, 1, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2291, 2291, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 600, 1, StepType::HALF, false, true, 0,
MotorSlope::create_from_steps(2750, 2750, 32),
MotorSlope::create_from_steps(2000, 300, 255), 32},
{MotorId::MD_5345, 1200, 1, StepType::QUARTER, false, true, 0,
MotorSlope::create_from_steps(2750, 2750, 16),
MotorSlope::create_from_steps(2000, 300, 255), 146},
{MotorId::MD_5345, 2400, 1, StepType::QUARTER, false, true, 0,
MotorSlope::create_from_steps(5500, 5500, 16),
MotorSlope::create_from_steps(2000, 300, 255), 146}, /* 5500 guessed */
};
class CommandSetGl646 : public CommandSetCommon
{
public:
@ -446,15 +64,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -491,8 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Wyświetl plik

@ -88,6 +88,7 @@ static constexpr RegMask REG_0x04_ADTYPE = 0x30;
static constexpr RegMask REG_0x04_FILTER = 0x0c;
static constexpr RegMask REG_0x04_FESET = 0x03;
static constexpr RegAddr REG_0x05 = 0x05;
static constexpr RegMask REG_0x05_DPIHW = 0xc0;
static constexpr RegMask REG_0x05_DPIHW_600 = 0x00;
static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -60,15 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -99,14 +95,16 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
bool needs_update_home_sensor_gpio() const override { return true; }
void update_home_sensor_gpio(Genesys_Device& dev) const override;
void load_document(Genesys_Device* dev) const override;
void detect_document_end(Genesys_Device* dev) const override;
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Wyświetl plik

@ -224,10 +224,12 @@ static constexpr RegShift REG_0x5ES_DECSEL = 5;
static constexpr RegMask REG_0x5E_STOPTIM = 0x1f;
static constexpr RegShift REG_0x5ES_STOPTIM = 0;
static constexpr RegAddr REG_0x60 = 0x60;
static constexpr RegMask REG_0x60_ZIMOD = 0x1f;
static constexpr RegMask REG_0x61_Z1MOD = 0xff;
static constexpr RegMask REG_0x62_Z1MOD = 0xff;
static constexpr RegAddr REG_0x63 = 0x63;
static constexpr RegMask REG_0x63_Z2MOD = 0x1f;
static constexpr RegMask REG_0x64_Z2MOD = 0xff;
static constexpr RegMask REG_0x65_Z2MOD = 0xff;

Wyświetl plik

@ -0,0 +1,989 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
*/
#define DEBUG_DECLARE_ONLY
#include "gl842_registers.h"
#include "gl842.h"
#include "test_settings.h"
#include <string>
#include <vector>
namespace genesys {
namespace gl842 {
static void gl842_init_registers(Genesys_Device& dev)
{
// Within this function SENSOR_DEF marker documents that a register is part
// of the sensors definition and the actual value is set in
// gl842_setup_sensor().
DBG_HELPER(dbg);
dev.reg.clear();
dev.reg.init_reg(0x01, 0x00);
dev.reg.init_reg(0x02, 0x78);
dev.reg.init_reg(0x03, 0xbf);
dev.reg.init_reg(0x04, 0x22);
dev.reg.init_reg(0x05, 0x48);
dev.reg.init_reg(0x06, 0xb8);
dev.reg.init_reg(0x07, 0x00);
dev.reg.init_reg(0x08, 0x00);
dev.reg.init_reg(0x09, 0x00);
dev.reg.init_reg(0x0a, 0x00);
dev.reg.init_reg(0x0d, 0x01);
dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
// CCD signal settings.
dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF
// EXPDMY[0:7]: Exposure time of dummy lines.
dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF
// Various CCD clock settings.
dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
dev.reg.init_reg(0x1f, 0x01);
dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup
dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup
dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
dev.reg.init_reg(0x29, 0xff); // LAMPPWM
dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup
dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup
dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup
dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup
dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup
dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF
dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: overwritten during motor setup
dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: overwritten during motor setup
dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
// 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio.
dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF
dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF
// 0x7e - set according to gpio tables. See gl842_init_gpio.
dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF
// VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
// moving in various situations.
dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
dev.reg.init_reg(0x81, 0x00);
dev.reg.init_reg(0x82, 0x00);
dev.reg.init_reg(0x83, 0x00);
dev.reg.init_reg(0x84, 0x00);
dev.reg.init_reg(0x85, 0x00);
dev.reg.init_reg(0x86, 0x00);
dev.reg.init_reg(0x87, 0x00);
const auto& sensor = sanei_genesys_find_sensor_any(&dev);
sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
scanner_setup_sensor(dev, sensor, dev.reg);
}
static void gl842_set_ad_fe(Genesys_Device* dev)
{
for (const auto& reg : dev->frontend.regs) {
dev->interface->write_fe_register(reg.address, reg.value);
}
}
// Set values of analog frontend
void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
{
DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
set == AFE_SET ? "set" :
set == AFE_POWER_SAVE ? "powersave" : "huh?");
(void) sensor;
if (set == AFE_INIT) {
dev->frontend = dev->frontend_initial;
}
// check analog frontend type
// FIXME: looks like we write to that register with initial data
uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
if (fe_type == 2) {
gl842_set_ad_fe(dev);
return;
}
if (fe_type != 0) {
throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
}
for (unsigned i = 1; i <= 3; i++) {
dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
}
for (const auto& reg : sensor.custom_fe_regs) {
dev->interface->write_fe_register(reg.address, reg.value);
}
for (unsigned i = 0; i < 3; i++) {
dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
}
if (dev->model->sensor_id == SensorId::CCD_KVSS080) {
for (unsigned i = 0; i < 3; i++) {
dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
}
}
for (unsigned i = 0; i < 3; i++) {
dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
}
}
static void gl842_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
const ScanSession& session,
Genesys_Register_Set* reg,
const MotorProfile& motor_profile,
unsigned int exposure,
unsigned scan_yres,
unsigned int scan_lines,
unsigned int scan_dummy,
unsigned int feed_steps,
ScanFlag flags)
{
DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
"feed_steps=%d, flags=%x",
exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
unsigned step_multiplier = 2;
bool use_fast_fed = false;
if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
use_fast_fed = true;
}
reg->set24(REG_LINCNT, scan_lines);
reg->set8(REG_0x02, 0);
sanei_genesys_set_motor_power(*reg, true);
std::uint8_t reg02 = reg->get8(REG_0x02);
if (use_fast_fed) {
reg02 |= REG_0x02_FASTFED;
} else {
reg02 &= ~REG_0x02_FASTFED;
}
// in case of automatic go home, move until home sensor
if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
}
// disable backtracking if needed
if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
(scan_yres >= 2400) ||
(scan_yres >= sensor.full_resolution))
{
reg02 |= REG_0x02_ACDCDIS;
}
if (has_flag(flags, ScanFlag::REVERSE)) {
reg02 |= REG_0x02_MTRREV;
} else {
reg02 &= ~REG_0x02_MTRREV;
}
reg->set8(REG_0x02, reg02);
// scan and backtracking slope table
auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
step_multiplier, motor_profile);
scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
// fast table
const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
if (fast_profile == nullptr) {
fast_profile = &motor_profile;
}
auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
*fast_profile);
scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
std::uint8_t vref = 0;
vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
reg->set8(REG_0x80, vref);
}
// substract acceleration distance from feedl
unsigned feedl = feed_steps;
feedl <<= static_cast<unsigned>(motor_profile.step_type);
unsigned dist = scan_table.table.size() / step_multiplier;
if (use_fast_fed) {
dist += (fast_table.table.size() / step_multiplier) * 2;
}
// make sure when don't insane value : XXX STEF XXX in this case we should
// fall back to single table move
if (dist < feedl) {
feedl -= dist;
} else {
feedl = 1;
}
reg->set24(REG_FEEDL, feedl);
// doesn't seem to matter that much
std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
exposure,
scan_table.table,
scan_table.table.size() / step_multiplier,
feedl,
scan_table.table.size() / step_multiplier,
&z1,
&z2);
if (scan_yres > 600) {
z1 = 0;
z2 = 0;
}
reg->set24(REG_Z1MOD, z1);
reg->set24(REG_Z2MOD, z2);
reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL,
REG_0x67_STEPSEL);
reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL,
REG_0x68_FSTPSEL);
// steps for STOP table
reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
}
static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg, unsigned int exposure,
const ScanSession& session)
{
DBG_HELPER(dbg);
scanner_setup_sensor(*dev, sensor, *reg);
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
// enable shading
regs_set_optical_off(dev->model->asic_type, *reg);
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
session.use_host_side_calib)
{
reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
} else {
reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
}
bool use_shdarea = true;
if (use_shdarea) {
reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
} else {
reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
}
if (dev->model->model_id == ModelId::CANON_8600F) {
reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
} else {
reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
}
// FIXME: we probably don't need to set exposure to registers at this point. It was this way
// before a refactor.
sanei_genesys_set_lamp_power(dev, sensor, *reg,
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
// select XPA
reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
}
reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
// BW threshold
reg->set8(REG_0x2E, 0x7f);
reg->set8(REG_0x2F, 0x7f);
// monochrome / color scan parameters
std::uint8_t reg04 = reg->get8(REG_0x04);
reg04 = reg04 & REG_0x04_FESET;
switch (session.params.depth) {
case 8:
break;
case 16:
reg04 |= REG_0x04_BITSET;
break;
}
if (session.params.channels == 1) {
switch (session.params.color_filter) {
case ColorFilter::RED: reg04 |= 0x14; break;
case ColorFilter::BLUE: reg04 |= 0x1c; break;
case ColorFilter::GREEN: reg04 |= 0x18; break;
default:
break; // should not happen
}
} else {
switch (dev->frontend.layout.type) {
case FrontendType::WOLFSON:
// pixel by pixel
reg04 |= 0x10;
break;
case FrontendType::ANALOG_DEVICES:
// slow color pixel by pixel
reg04 |= 0x20;
break;
default:
throw SaneException("Invalid frontend type %d",
static_cast<unsigned>(dev->frontend.layout.type));
}
}
reg->set8(REG_0x04, reg04);
const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
session.params.channels,
session.params.scan_method);
sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
if (should_enable_gamma(session, sensor)) {
reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
} else {
reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
}
reg->set16(REG_DPISET, sensor.register_dpiset);
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
reg->set24(REG_MAXWD, session.output_line_bytes_raw);
unsigned tgtime = exposure / 65536 + 1;
reg->set16(REG_LPERIOD, exposure / tgtime);
reg->set8(REG_DUMMY, sensor.dummy_pixel);
}
void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const
{
DBG_HELPER(dbg);
session.assert_computed();
// we enable true gray for cis scanners only, and just when doing scan since color calibration
// is OK for this mode
int dummy = 0;
/* slope_dpi */
/* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */
int slope_dpi = 0;
if (dev->model->is_cis) {
slope_dpi = session.params.yres * session.params.channels;
} else {
slope_dpi = session.params.yres;
}
slope_dpi = slope_dpi * (1 + dummy);
int exposure = sensor.exposure_lperiod;
if (exposure < 0) {
throw std::runtime_error("Exposure not defined in sensor definition");
}
const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
// now _LOGICAL_ optical values used are known, setup registers
gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session);
gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
session.optical_line_count, dummy, session.params.starty,
session.params.flags);
setup_image_pipeline(*dev, session);
dev->read_active = true;
dev->session = session;
dev->total_bytes_read = 0;
dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
}
ScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
DBG_HELPER(dbg);
debug_dump(DBG_info, settings);
ScanFlag flags = ScanFlag::NONE;
float move = 0.0f;
if (settings.scan_method == ScanMethod::TRANSPARENCY ||
settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
// note: scanner_move_to_ta() function has already been called and the sensor is at the
// transparency adapter
if (!dev->ignore_offsets) {
move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
}
flags |= ScanFlag::USE_XPA;
} else {
if (!dev->ignore_offsets) {
move = dev->model->y_offset;
}
}
move += settings.tl_y;
int move_dpi = dev->motor.base_ydpi;
move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
float start = 0.0f;
if (settings.scan_method==ScanMethod::TRANSPARENCY ||
settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
start = dev->model->x_offset_ta;
} else {
start = dev->model->x_offset;
}
start = start + settings.tl_x;
start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
session.params.startx = static_cast<unsigned>(start);
session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
session.params.depth = settings.depth;
session.params.channels = settings.get_channels();
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
session.params.flags = flags;
compute_session(dev, session, sensor);
return session;
}
void CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const
{
(void) dev;
DBG_HELPER_ARGS(dbg, "enable = %d", enable);
}
void CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
{
(void) dev;
DBG_HELPER_ARGS(dbg, "delay = %d", delay);
}
void CommandSetGl842::eject_document(Genesys_Device* dev) const
{
(void) dev;
DBG_HELPER(dbg);
}
void CommandSetGl842::load_document(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
(void) dev;
}
void CommandSetGl842::detect_document_end(Genesys_Device* dev) const
{
DBG_HELPER(dbg);
(void) dev;
throw SaneException(SANE_STATUS_UNSUPPORTED);
}
// Send the low-level scan command
void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg, bool start_motor) const
{
DBG_HELPER(dbg);
(void) sensor;
if (reg->state.is_xpa_on && reg->state.is_lamp_on &&
!has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP))
{
dev->cmd_set->set_xpa_lamp_power(*dev, true);
}
if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) {
dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
}
scanner_clear_scan_and_feed_counts(*dev);
// enable scan and motor
std::uint8_t val = dev->interface->read_register(REG_0x01);
val |= REG_0x01_SCAN;
dev->interface->write_register(REG_0x01, val);
scanner_start_action(*dev, start_motor);
switch (reg->state.motor_mode) {
case MotorMode::PRIMARY: {
if (reg->state.is_motor_on) {
dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
}
break;
}
case MotorMode::PRIMARY_AND_SECONDARY: {
if (reg->state.is_motor_on) {
dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
}
break;
}
case MotorMode::SECONDARY: {
if (reg->state.is_motor_on) {
dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
}
break;
}
}
}
void CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
bool check_stop) const
{
DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
if (reg->state.is_xpa_on) {
dev->cmd_set->set_xpa_lamp_power(*dev, false);
}
if (!dev->model->is_sheetfed) {
scanner_stop_action(*dev);
}
}
void CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const
{
scanner_move_back_home(*dev, wait_until_home);
}
void CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
int move;
float calib_size_mm = 0;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
calib_size_mm = dev->model->y_size_calib_ta_mm;
} else {
calib_size_mm = dev->model->y_size_calib_mm;
}
unsigned resolution = sensor.shading_resolution;
unsigned channels = 3;
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
unsigned calib_pixels = 0;
unsigned calib_pixels_offset = 0;
if (should_calibrate_only_active_area(*dev, dev->settings)) {
float offset = dev->model->x_offset_ta;
// FIXME: we should use resolution here
offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
float size = dev->model->x_size_ta;
size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
calib_pixels_offset = static_cast<std::size_t>(offset);
calib_pixels = static_cast<std::size_t>(size);
} else {
calib_pixels_offset = 0;
calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
}
ScanFlag flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::DISABLE_BUFFER_FULL_MOVE;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
// note: scanner_move_to_ta() function has already been called and the sensor is at the
// transparency adapter
move = static_cast<int>(dev->model->y_offset_calib_white_ta -
dev->model->y_offset_sensor_to_ta);
flags |= ScanFlag::USE_XPA;
} else {
move = static_cast<int>(dev->model->y_offset_calib_white);
}
move = static_cast<int>((move * resolution) / MM_PER_INCH);
unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = calib_pixels_offset;
session.params.starty = move;
session.params.pixels = calib_pixels;
session.params.lines = calib_lines;
session.params.depth = 16;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = flags;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
dev->calib_session = session;
}
void CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
{
DBG_HELPER(dbg);
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200)
return; // No gamma on this model
unsigned size = 256;
std::vector<uint8_t> gamma(size * 2 * 3);
std::vector<uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
std::vector<uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
std::vector<uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
// copy sensor specific's gamma tables
for (unsigned i = 0; i < size; i++) {
gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff;
gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff;
gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff;
gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff;
gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff;
gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
}
dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
}
SensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
return scanner_led_calibration(*dev, sensor, regs);
}
void CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
scanner_offset_calibration(*dev, sensor, regs);
}
void CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
void CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg) const
{
DBG_HELPER(dbg);
(void) sensor;
unsigned channels = 3;
unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
.get_nearest_resolution_x(600);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
*reg = dev->reg;
auto flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
flags |= ScanFlag::USE_XPA;
}
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.lines = 1;
session.params.depth = dev->model->bpp_color_values.front();
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = flags;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, reg, session);
sanei_genesys_set_motor_power(*reg, false);
}
static void gl842_init_gpio(Genesys_Device* dev)
{
DBG_HELPER(dbg);
apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
{
dev->interface->write_register(reg.address, reg.value);
});
}
void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
{
DBG_HELPER(dbg);
if (cold) {
dev->interface->write_register(0x0e, 0x01);
dev->interface->write_register(0x0e, 0x00);
}
// setup initial register values
gl842_init_registers(*dev);
dev->interface->write_registers(dev->reg);
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
uint8_t data[32] = {
0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
};
dev->interface->write_buffer(0x3c, 0x010a00, data, 32);
}
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
dev->interface->write_0x8c(0x10, 0x94);
}
// set RAM read address
dev->interface->write_register(REG_0x2A, 0x00);
dev->interface->write_register(REG_0x2B, 0x00);
// setup gpio
gl842_init_gpio(dev);
dev->interface->sleep_ms(100);
}
void CommandSetGl842::init(Genesys_Device* dev) const
{
DBG_INIT();
DBG_HELPER(dbg);
sanei_genesys_asic_init(dev);
}
void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
{
DBG_HELPER(dbg);
(void) s;
}
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.
*/
void CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
uint8_t* data, int size) const
{
DBG_HELPER(dbg);
int offset = 0;
unsigned length = size;
if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
offset = dev->session.params.startx * sensor.shading_resolution /
dev->session.params.xres;
length = dev->session.output_pixels * sensor.shading_resolution /
dev->session.params.xres;
offset += sensor.shading_pixel_offset;
// 16 bit words, 2 words per color, 3 color channels
length *= 2 * 2 * 3;
offset *= 2 * 2 * 3;
} else {
offset += sensor.shading_pixel_offset * 2 * 2 * 3;
}
dev->interface->record_key_value("shading_offset", std::to_string(offset));
dev->interface->record_key_value("shading_length", std::to_string(length));
std::vector<uint8_t> final_data(length, 0);
unsigned count = 0;
if (offset < 0) {
count += (-offset);
length -= (-offset);
offset = 0;
}
if (static_cast<int>(length) + offset > static_cast<int>(size)) {
length = size - offset;
}
for (unsigned i = 0; i < length; i++) {
final_data[count++] = data[offset + i];
count++;
}
dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
}
bool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
{
(void) dev;
return true;
}
void CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const
{
(void) dev;
}
} // namespace gl842
} // namespace genesys

Wyświetl plik

@ -0,0 +1,126 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#include "genesys.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL842_H
#define BACKEND_GENESYS_GL842_H
namespace genesys {
namespace gl842 {
class CommandSetGl842 : public CommandSetCommon
{
public:
~CommandSetGl842() override = default;
bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override;
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override;
void set_powersaving(Genesys_Device* dev, int delay) const override;
void save_power(Genesys_Device* dev, bool enable) const override;
void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, bool start_motor) const override;
void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override;
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const override;
SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void wait_for_motor_stop(Genesys_Device* dev) const override;
void move_back_home(Genesys_Device* dev, bool wait_until_home) const override;
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
void load_document(Genesys_Device* dev) const override;
void detect_document_end(Genesys_Device* dev) const override;
void eject_document(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;
ScanSession calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const override;
void asic_boot(Genesys_Device* dev, bool cold) const override;
};
enum SlopeTable
{
SCAN_TABLE = 0, // table 1 at 0x4000
BACKTRACK_TABLE = 1, // table 2 at 0x4800
STOP_TABLE = 2, // table 3 at 0x5000
FAST_TABLE = 3, // table 4 at 0x5800
HOME_TABLE = 4, // table 5 at 0x6000
};
} // namespace gl842
} // namespace genesys
#endif // BACKEND_GENESYS_GL842_H

Wyświetl plik

@ -0,0 +1,285 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
As a special exception, the authors of SANE give permission for
additional uses of the libraries contained in this release of SANE.
The exception is that, if you link a SANE library with other files
to produce an executable, this does not by itself cause the
resulting executable to be covered by the GNU General Public
License. Your use of that executable is in no way restricted on
account of linking the SANE library code into it.
This exception does not, however, invalidate any other reasons why
the executable file might be covered by the GNU General Public
License.
If you submit changes to SANE to the maintainers to be included in
a subsequent release, you agree by submitting the changes that
those changes may be distributed with this exception intact.
If you write modifications of your own for SANE, it is your choice
whether to permit this exception to apply to your modifications.
If you do not wish that, delete this exception notice.
*/
#ifndef BACKEND_GENESYS_gl842_REGISTERS_H
#define BACKEND_GENESYS_gl842_REGISTERS_H
#include <cstdint>
namespace genesys {
namespace gl842 {
using RegAddr = std::uint16_t;
using RegMask = std::uint8_t;
using RegShift = unsigned;
static constexpr RegAddr REG_0x01 = 0x01;
static constexpr RegMask REG_0x01_CISSET = 0x80;
static constexpr RegMask REG_0x01_DOGENB = 0x40;
static constexpr RegMask REG_0x01_DVDSET = 0x20;
static constexpr RegMask REG_0x01_M15DRAM = 0x08;
static constexpr RegMask REG_0x01_DRAMSEL = 0x04;
static constexpr RegMask REG_0x01_SHDAREA = 0x02;
static constexpr RegMask REG_0x01_SCAN = 0x01;
static constexpr RegAddr REG_0x02 = 0x02;
static constexpr RegMask REG_0x02_NOTHOME = 0x80;
static constexpr RegMask REG_0x02_ACDCDIS = 0x40;
static constexpr RegMask REG_0x02_AGOHOME = 0x20;
static constexpr RegMask REG_0x02_MTRPWR = 0x10;
static constexpr RegMask REG_0x02_FASTFED = 0x08;
static constexpr RegMask REG_0x02_MTRREV = 0x04;
static constexpr RegMask REG_0x02_HOMENEG = 0x02;
static constexpr RegMask REG_0x02_LONGCURV = 0x01;
static constexpr RegAddr REG_0x03 = 0x03;
static constexpr RegMask REG_0x03_LAMPDOG = 0x80;
static constexpr RegMask REG_0x03_AVEENB = 0x40;
static constexpr RegMask REG_0x03_XPASEL = 0x20;
static constexpr RegMask REG_0x03_LAMPPWR = 0x10;
static constexpr RegMask REG_0x03_LAMPTIM = 0x0f;
static constexpr RegAddr REG_0x04 = 0x04;
static constexpr RegMask REG_0x04_LINEART = 0x80;
static constexpr RegMask REG_0x04_BITSET = 0x40;
static constexpr RegMask REG_0x04_AFEMOD = 0x30;
static constexpr RegMask REG_0x04_FILTER = 0x0c;
static constexpr RegMask REG_0x04_FESET = 0x03;
static constexpr RegShift REG_0x04S_AFEMOD = 4;
static constexpr RegAddr REG_0x05 = 0x05;
static constexpr RegMask REG_0x05_DPIHW = 0xc0;
static constexpr RegMask REG_0x05_DPIHW_600 = 0x00;
static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40;
static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80;
static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0;
static constexpr RegMask REG_0x05_MTLLAMP = 0x30;
static constexpr RegMask REG_0x05_GMMENB = 0x08;
static constexpr RegMask REG_0x05_MTLBASE = 0x03;
static constexpr RegAddr REG_0x06 = 0x06;
static constexpr RegMask REG_0x06_SCANMOD = 0xe0;
static constexpr RegShift REG_0x06S_SCANMOD = 5;
static constexpr RegMask REG_0x06_PWRBIT = 0x10;
static constexpr RegMask REG_0x06_GAIN4 = 0x08;
static constexpr RegMask REG_0x06_OPTEST = 0x07;
static constexpr RegMask REG_0x08_DECFLAG = 0x40;
static constexpr RegMask REG_0x08_GMMFFR = 0x20;
static constexpr RegMask REG_0x08_GMMFFG = 0x10;
static constexpr RegMask REG_0x08_GMMFFB = 0x08;
static constexpr RegMask REG_0x08_GMMZR = 0x04;
static constexpr RegMask REG_0x08_GMMZG = 0x02;
static constexpr RegMask REG_0x08_GMMZB = 0x01;
static constexpr RegMask REG_0x09_MCNTSET = 0xc0;
static constexpr RegMask REG_0x09_CLKSET = 0x30;
static constexpr RegMask REG_0x09_BACKSCAN = 0x08;
static constexpr RegMask REG_0x09_ENHANCE = 0x04;
static constexpr RegMask REG_0x09_SHORTTG = 0x02;
static constexpr RegMask REG_0x09_NWAIT = 0x01;
static constexpr RegAddr REG_0x0D = 0x0d;
static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01;
static constexpr RegAddr REG_0x0F = 0x0f;
static constexpr RegAddr REG_EXPR = 0x10;
static constexpr RegAddr REG_EXPG = 0x12;
static constexpr RegAddr REG_EXPB = 0x14;
static constexpr RegMask REG_0x16_CTRLHI = 0x80;
static constexpr RegMask REG_0x16_TOSHIBA = 0x40;
static constexpr RegMask REG_0x16_TGINV = 0x20;
static constexpr RegMask REG_0x16_CK1INV = 0x10;
static constexpr RegMask REG_0x16_CK2INV = 0x08;
static constexpr RegMask REG_0x16_CTRLINV = 0x04;
static constexpr RegMask REG_0x16_CKDIS = 0x02;
static constexpr RegMask REG_0x16_CTRLDIS = 0x01;
static constexpr RegMask REG_0x17_TGMODE = 0xc0;
static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00;
static constexpr RegMask REG_0x17_TGMODE_REF = 0x40;
static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80;
static constexpr RegMask REG_0x17_TGW = 0x3f;
static constexpr RegAddr REG_0x18 = 0x18;
static constexpr RegMask REG_0x18_CNSET = 0x80;
static constexpr RegMask REG_0x18_DCKSEL = 0x60;
static constexpr RegMask REG_0x18_CKTOGGLE = 0x10;
static constexpr RegMask REG_0x18_CKDELAY = 0x0c;
static constexpr RegMask REG_0x18_CKSEL = 0x03;
static constexpr RegAddr REG_EXPDMY = 0x19;
static constexpr RegAddr REG_0x1A = 0x1a;
static constexpr RegMask REG_0x1A_MANUAL3 = 0x02;
static constexpr RegMask REG_0x1A_MANUAL1 = 0x01;
static constexpr RegMask REG_0x1A_CK4INV = 0x08;
static constexpr RegMask REG_0x1A_CK3INV = 0x04;
static constexpr RegMask REG_0x1A_LINECLP = 0x02;
static constexpr RegAddr REG_0x1C = 0x1c;
static constexpr RegMask REG_0x1C_TGTIME = 0x07;
static constexpr RegMask REG_0x1D_CK4LOW = 0x80;
static constexpr RegMask REG_0x1D_CK3LOW = 0x40;
static constexpr RegMask REG_0x1D_CK1LOW = 0x20;
static constexpr RegMask REG_0x1D_TGSHLD = 0x1f;
static constexpr RegAddr REG_0x1E = 0x1e;
static constexpr RegMask REG_0x1E_WDTIME = 0xf0;
static constexpr RegShift REG_0x1ES_WDTIME = 4;
static constexpr RegMask REG_0x1E_LINESEL = 0x0f;
static constexpr RegShift REG_0x1ES_LINESEL = 0;
static constexpr RegAddr REG_0x21 = 0x21;
static constexpr RegAddr REG_STEPNO = 0x21;
static constexpr RegAddr REG_FWDSTEP = 0x22;
static constexpr RegAddr REG_BWDSTEP = 0x23;
static constexpr RegAddr REG_FASTNO = 0x24;
static constexpr RegAddr REG_LINCNT = 0x25;
static constexpr RegAddr REG_0x29 = 0x29;
static constexpr RegAddr REG_0x2A = 0x2a;
static constexpr RegAddr REG_0x2B = 0x2b;
static constexpr RegAddr REG_DPISET = 0x2c;
static constexpr RegAddr REG_0x2E = 0x2e;
static constexpr RegAddr REG_0x2F = 0x2f;
static constexpr RegAddr REG_STRPIXEL = 0x30;
static constexpr RegAddr REG_ENDPIXEL = 0x32;
static constexpr RegAddr REG_DUMMY = 0x34;
static constexpr RegAddr REG_MAXWD = 0x35;
static constexpr RegAddr REG_LPERIOD = 0x38;
static constexpr RegAddr REG_FEEDL = 0x3d;
static constexpr RegAddr REG_0x40 = 0x40;
static constexpr RegMask REG_0x40_HISPDFLG = 0x04;
static constexpr RegMask REG_0x40_MOTMFLG = 0x02;
static constexpr RegMask REG_0x40_DATAENB = 0x01;
static constexpr RegMask REG_0x41_PWRBIT = 0x80;
static constexpr RegMask REG_0x41_BUFEMPTY = 0x40;
static constexpr RegMask REG_0x41_FEEDFSH = 0x20;
static constexpr RegMask REG_0x41_SCANFSH = 0x10;
static constexpr RegMask REG_0x41_HOMESNR = 0x08;
static constexpr RegMask REG_0x41_LAMPSTS = 0x04;
static constexpr RegMask REG_0x41_FEBUSY = 0x02;
static constexpr RegMask REG_0x41_MOTORENB = 0x01;
static constexpr RegMask REG_0x5A_ADCLKINV = 0x80;
static constexpr RegMask REG_0x5A_RLCSEL = 0x40;
static constexpr RegMask REG_0x5A_CDSREF = 0x30;
static constexpr RegShift REG_0x5AS_CDSREF = 4;
static constexpr RegMask REG_0x5A_RLC = 0x0f;
static constexpr RegShift REG_0x5AS_RLC = 0;
static constexpr RegAddr REG_0x5E = 0x5e;
static constexpr RegMask REG_0x5E_DECSEL = 0xe0;
static constexpr RegShift REG_0x5ES_DECSEL = 5;
static constexpr RegMask REG_0x5E_STOPTIM = 0x1f;
static constexpr RegShift REG_0x5ES_STOPTIM = 0;
static constexpr RegAddr REG_FMOVDEC = 0x5f;
static constexpr RegAddr REG_0x60 = 0x60;
static constexpr RegMask REG_0x60_Z1MOD = 0x1f;
static constexpr RegAddr REG_0x61 = 0x61;
static constexpr RegMask REG_0x61_Z1MOD = 0xff;
static constexpr RegAddr REG_0x62 = 0x62;
static constexpr RegMask REG_0x62_Z1MOD = 0xff;
static constexpr RegAddr REG_0x63 = 0x63;
static constexpr RegMask REG_0x63_Z2MOD = 0x1f;
static constexpr RegAddr REG_0x64 = 0x64;
static constexpr RegMask REG_0x64_Z2MOD = 0xff;
static constexpr RegAddr REG_0x65 = 0x65;
static constexpr RegMask REG_0x65_Z2MOD = 0xff;
static constexpr RegAddr REG_0x67 = 0x67;
static constexpr RegAddr REG_0x68 = 0x68;
static constexpr RegShift REG_0x67S_STEPSEL = 6;
static constexpr RegMask REG_0x67_STEPSEL = 0xc0;
static constexpr RegShift REG_0x68S_FSTPSEL = 6;
static constexpr RegMask REG_0x68_FSTPSEL = 0xc0;
static constexpr RegAddr REG_FSHDEC = 0x69;
static constexpr RegAddr REG_FMOVNO = 0x6a;
static constexpr RegAddr REG_0x6B = 0x6b;
static constexpr RegMask REG_0x6B_MULTFILM = 0x80;
static constexpr RegAddr REG_Z1MOD = 0x60;
static constexpr RegAddr REG_Z2MOD = 0x63;
static constexpr RegAddr REG_0x6C = 0x6c;
static constexpr RegAddr REG_0x6D = 0x6d;
static constexpr RegAddr REG_0x6E = 0x6e;
static constexpr RegAddr REG_0x6F = 0x6f;
static constexpr RegAddr REG_CK1MAP = 0x74;
static constexpr RegAddr REG_CK3MAP = 0x77;
static constexpr RegAddr REG_CK4MAP = 0x7a;
static constexpr RegAddr REG_0x7E = 0x7e;
static constexpr RegAddr REG_0x80 = 0x80;
static constexpr RegMask REG_0x80_TABLE1_NORMAL = 0x03;
static constexpr RegShift REG_0x80S_TABLE1_NORMAL = 0;
static constexpr RegMask REG_0x80_TABLE2_BACK = 0x0c;
static constexpr RegShift REG_0x80S_TABLE2_BACK = 2;
static constexpr RegMask REG_0x80_TABLE4_FAST = 0x30;
static constexpr RegShift REG_0x80S_TABLE4_FAST = 4;
static constexpr RegMask REG_0x80_TABLE5_GO_HOME = 0xc0;
static constexpr RegShift REG_0x80S_TABLE5_GO_HOME = 6;
static constexpr RegMask REG_0x87_LEDADD = 0x04;
} // namespace gl842
} // namespace genesys
#endif // BACKEND_GENESYS_gl842_REGISTERS_H

Plik diff jest za duży Load Diff

Wyświetl plik

@ -60,15 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -105,8 +101,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -50,81 +50,6 @@
namespace genesys {
namespace gl846 {
typedef struct
{
GpioId gpio_id;
uint8_t r6b;
uint8_t r6c;
uint8_t r6d;
uint8_t r6e;
uint8_t r6f;
uint8_t ra6;
uint8_t ra7;
uint8_t ra8;
uint8_t ra9;
} Gpio_Profile;
static Gpio_Profile gpios[]={
{ GpioId::IMG101, 0x72, 0x1f, 0xa4, 0x13, 0xa7, 0x11, 0xff, 0x19, 0x05},
{ GpioId::PLUSTEK_OPTICBOOK_3800, 0x30, 0x01, 0x80, 0x2d, 0x80, 0x0c, 0x8f, 0x08, 0x04},
{ GpioId::UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
typedef struct
{
const char *model;
uint8_t dramsel;
/* shading data address */
uint8_t rd0;
uint8_t rd1;
uint8_t rd2;
/* scanned data address */
uint8_t rx[24];
} Memory_layout;
static Memory_layout layouts[]={
/* Image formula 101 */
{
"canon-image-formula-101",
0x8b,
0x0a, 0x1b, 0x00,
{ /* RED ODD START / RED ODD END */
0x00, 0xb0, 0x05, 0xe7, /* [0x00b0, 0x05e7] 1336*4000w */
/* RED EVEN START / RED EVEN END */
0x05, 0xe8, 0x0b, 0x1f, /* [0x05e8, 0x0b1f] */
/* GREEN ODD START / GREEN ODD END */
0x0b, 0x20, 0x10, 0x57, /* [0x0b20, 0x1057] */
/* GREEN EVEN START / GREEN EVEN END */
0x10, 0x58, 0x15, 0x8f, /* [0x1058, 0x158f] */
/* BLUE ODD START / BLUE ODD END */
0x15, 0x90, 0x1a, 0xc7, /* [0x1590,0x1ac7] */
/* BLUE EVEN START / BLUE EVEN END */
0x1a, 0xc8, 0x1f, 0xff /* [0x1ac8,0x1fff] */
}
},
/* OpticBook 3800 */
{
"plustek-opticbook-3800",
0x2a,
0x0a, 0x0a, 0x0a,
{ /* RED ODD START / RED ODD END */
0x00, 0x68, 0x03, 0x00,
/* RED EVEN START / RED EVEN END */
0x03, 0x01, 0x05, 0x99,
/* GREEN ODD START / GREEN ODD END */
0x05, 0x9a, 0x08, 0x32,
/* GREEN EVEN START / GREEN EVEN END */
0x08, 0x33, 0x0a, 0xcb,
/* BLUE ODD START / BLUE ODD END */
0x0a, 0xcc, 0x0d, 0x64,
/* BLUE EVEN START / BLUE EVEN END */
0x0d, 0x65, 0x0f, 0xfd
}
},
/* list terminating entry */
{ nullptr, 0, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }
};
class CommandSetGl846 : public CommandSetCommon
{
public:
@ -135,15 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -184,8 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Wyświetl plik

@ -194,7 +194,7 @@ static constexpr RegMask REG_0x1D_CK1LOW = 0x20;
static constexpr RegMask REG_0x1D_TGSHLD = 0x1f;
static constexpr RegShift REG_0x1DS_TGSHLD = 0;
static constexpr RegAddr REG_0x1E = 0x1e;
static constexpr RegMask REG_0x1E_WDTIME = 0xf0;
static constexpr RegShift REG_0x1ES_WDTIME = 4;
static constexpr RegMask REG_0x1E_LINESEL = 0x0f;
@ -303,6 +303,16 @@ static constexpr RegAddr REG_0x6E = 0x6e;
static constexpr RegAddr REG_0x6F = 0x6f;
static constexpr RegAddr REG_0x7E = 0x7e;
static constexpr RegAddr REG_0x80 = 0x80;
static constexpr RegMask REG_0x80_TABLE1_NORMAL = 0x03;
static constexpr RegShift REG_0x80S_TABLE1_NORMAL = 0;
static constexpr RegMask REG_0x80_TABLE2_BACK = 0x0c;
static constexpr RegShift REG_0x80S_TABLE2_BACK = 2;
static constexpr RegMask REG_0x80_TABLE4_FAST = 0x30;
static constexpr RegShift REG_0x80S_TABLE4_FAST = 4;
static constexpr RegMask REG_0x80_TABLE5_GO_HOME = 0xc0;
static constexpr RegShift REG_0x80S_TABLE5_GO_HOME = 6;
static constexpr RegMask REG_0x87_ACYCNRLC = 0x10;
static constexpr RegMask REG_0x87_ENOFFSET = 0x08;
static constexpr RegMask REG_0x87_LEDADD = 0x04;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -50,69 +50,6 @@
namespace genesys {
namespace gl847 {
typedef struct
{
GpioId gpio_id;
uint8_t r6b;
uint8_t r6c;
uint8_t r6d;
uint8_t r6e;
uint8_t r6f;
uint8_t ra6;
uint8_t ra7;
uint8_t ra8;
uint8_t ra9;
} Gpio_Profile;
static Gpio_Profile gpios[]={
{ GpioId::CANON_LIDE_200, 0x02, 0xf9, 0x20, 0xff, 0x00, 0x04, 0x04, 0x00, 0x00},
{ GpioId::CANON_LIDE_700F, 0x06, 0xdb, 0xff, 0xff, 0x80, 0x15, 0x07, 0x20, 0x10},
{ GpioId::UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
typedef struct
{
uint8_t dramsel;
uint8_t rd0;
uint8_t rd1;
uint8_t rd2;
uint8_t re0;
uint8_t re1;
uint8_t re2;
uint8_t re3;
uint8_t re4;
uint8_t re5;
uint8_t re6;
uint8_t re7;
} Memory_layout;
static Memory_layout layouts[]={
/* LIDE 100 */
{
0x29,
0x0a, 0x15, 0x20,
0x00, 0xac, 0x02, 0x55, 0x02, 0x56, 0x03, 0xff
},
/* LIDE 200 */
{
0x29,
0x0a, 0x1f, 0x34,
0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff
},
/* 5600F */
{
0x29,
0x0a, 0x1f, 0x34,
0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff
},
/* LIDE 700F */
{
0x2a,
0x0a, 0x33, 0x5c,
0x02, 0x14, 0x09, 0x09, 0x09, 0x0a, 0x0f, 0xff
}
};
class CommandSetGl847 : public CommandSetCommon
{
public:
@ -123,15 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* regs, int* channels,
int* total_size) const override;
Genesys_Register_Set* regs) const override;
void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@ -172,8 +105,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void move_to_ta(Genesys_Device* dev) const override;
void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data,
int size) const override;

Wyświetl plik

@ -190,6 +190,7 @@ static constexpr RegMask REG_0x1D_CK1LOW = 0x20;
static constexpr RegMask REG_0x1D_TGSHLD = 0x1f;
static constexpr RegMask REG_0x1DS_TGSHLD = 0;
static constexpr RegAddr REG_0x1E = 0x1e;
static constexpr RegMask REG_0x1E_WDTIME = 0xf0;
static constexpr RegMask REG_0x1ES_WDTIME = 4;
static constexpr RegMask REG_0x1E_LINESEL = 0x0f;

Wyświetl plik

@ -45,6 +45,10 @@
#include "image.h"
#if defined(HAVE_TIFFIO_H)
#include <tiffio.h>
#endif
#include <array>
namespace genesys {
@ -201,4 +205,68 @@ void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format
}
}
void write_tiff_file(const std::string& filename, const void* data, int depth, int channels,
int pixels_per_line, int lines)
{
DBG_HELPER_ARGS(dbg, "depth=%d, channels=%d, ppl=%d, lines=%d", depth, channels,
pixels_per_line, lines);
#if defined(HAVE_TIFFIO_H)
auto image = TIFFOpen(filename.c_str(), "w");
if (!image) {
dbg.log(DBG_error, "Could not save debug image");
return;
}
TIFFSetField(image, TIFFTAG_IMAGEWIDTH, pixels_per_line);
TIFFSetField(image, TIFFTAG_IMAGELENGTH, lines);
TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, depth);
TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, channels);
if (channels > 1) {
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
} else {
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
std::size_t bytes_per_line = (pixels_per_line * channels * depth + 7) / 8;
const std::uint8_t* data_ptr = reinterpret_cast<const std::uint8_t*>(data);
// we don't need to handle endian because libtiff will handle that
for (int iline = 0; iline < lines; ++iline) {
const auto* line_data = data_ptr + bytes_per_line * iline;
TIFFWriteScanline(image, const_cast<std::uint8_t*>(line_data), iline, 0);
}
TIFFClose(image);
#else
dbg.log(DBG_error, "Backend has been built without TIFF library support. "
"Debug images will not be saved");
#endif
}
bool is_supported_write_tiff_file_image_format(PixelFormat format)
{
switch (format) {
case PixelFormat::I1:
case PixelFormat::RGB111:
case PixelFormat::I8:
case PixelFormat::RGB888:
case PixelFormat::I16:
case PixelFormat::RGB161616:
return true;
default:
return false;
}
}
void write_tiff_file(const std::string& filename, const Image& image)
{
if (!is_supported_write_tiff_file_image_format(image.get_format())) {
throw SaneException("Unsupported format %d", static_cast<unsigned>(image.get_format()));
}
write_tiff_file(filename, image.get_row_ptr(0), get_pixel_format_depth(image.get_format()),
get_pixel_channels(image.get_format()), image.get_width(), image.get_height());
}
} // namespace genesys

Wyświetl plik

@ -82,6 +82,11 @@ private:
void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format,
std::uint8_t* out_data, PixelFormat out_format, std::size_t count);
void write_tiff_file(const std::string& filename, const void* data, int depth,
int channels, int pixels_per_line, int lines);
void write_tiff_file(const std::string& filename, const Image& image);
} // namespace genesys
#endif // ifndef BACKEND_GENESYS_IMAGE_H

Wyświetl plik

@ -45,13 +45,13 @@
#include "image_buffer.h"
#include "image.h"
#include "utilities.h"
namespace genesys {
ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) :
producer_{producer},
size_{size},
buffer_offset_{size}
size_{size}
{
buffer_.resize(size_);
}
@ -81,85 +81,30 @@ bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data)
bool got_data = true;
do {
buffer_offset_ = 0;
got_data &= producer_(size_, buffer_.data());
std::size_t size_to_read = size_;
if (remaining_size_ != BUFFER_SIZE_UNSET) {
size_to_read = std::min<std::uint64_t>(size_to_read, remaining_size_);
remaining_size_ -= size_to_read;
}
std::size_t aligned_size_to_read = size_to_read;
if (remaining_size_ == 0 && last_read_multiple_ != BUFFER_SIZE_UNSET) {
aligned_size_to_read = align_multiple_ceil(size_to_read, last_read_multiple_);
}
got_data &= producer_(aligned_size_to_read, buffer_.data());
curr_size_ = size_to_read;
copy_buffer();
} while(out_data < out_data_end && got_data);
if (remaining_size_ == 0 && out_data < out_data_end) {
got_data = false;
}
} while (out_data < out_data_end && got_data);
return got_data;
}
ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size,
std::size_t buffer_size,
ProducerCallback producer) :
remaining_size_{total_size},
buffer_size_{buffer_size},
producer_{producer}
{}
bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data)
{
const std::uint8_t* out_data_end = out_data + size;
auto copy_buffer = [&]()
{
std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available());
std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy);
out_data += bytes_copy;
buffer_offset_ += bytes_copy;
};
// first, read remaining data from buffer
if (available() > 0) {
copy_buffer();
}
if (out_data == out_data_end) {
return true;
}
// now the buffer is empty and there's more data to be read
do {
if (remaining_size_ == 0)
return false;
auto bytes_to_read = get_read_size();
buffer_offset_ = 0;
buffer_end_ = bytes_to_read;
buffer_.resize(bytes_to_read);
producer_(bytes_to_read, buffer_.data());
if (remaining_size_ < bytes_to_read) {
remaining_size_ = 0;
} else {
remaining_size_ -= bytes_to_read;
}
copy_buffer();
} while(out_data < out_data_end);
return true;
}
std::size_t ImageBufferGenesysUsb::get_read_size()
{
std::size_t size = buffer_size_;
// never read an odd number. exception: last read
// the chip internal counter does not count half words.
size &= ~1;
// Some setups need the reads to be multiples of 256 bytes
size &= ~0xff;
if (remaining_size_ < size) {
size = remaining_size_;
/*round up to a multiple of 256 bytes */
size += (size & 0xff) ? 0x100 : 0x00;
size &= ~0xff;
}
return size;
}
} // namespace genesys

Wyświetl plik

@ -56,57 +56,35 @@ class ImageBuffer
{
public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
static constexpr std::uint64_t BUFFER_SIZE_UNSET = std::numeric_limits<std::uint64_t>::max();
ImageBuffer() {}
ImageBuffer(std::size_t size, ProducerCallback producer);
std::size_t size() const { return size_; }
std::size_t available() const { return size_ - buffer_offset_; }
std::size_t available() const { return curr_size_ - buffer_offset_; }
// allows adjusting the amount of data left so that we don't do a full size read from the
// producer on the last iteration. Set to BUFFER_SIZE_UNSET to ignore buffer size.
std::uint64_t remaining_size() const { return remaining_size_; }
void set_remaining_size(std::uint64_t bytes) { remaining_size_ = bytes; }
// May be used to force the last read to be rounded up of a certain number of bytes
void set_last_read_multiple(std::uint64_t bytes) { last_read_multiple_ = bytes; }
bool get_data(std::size_t size, std::uint8_t* out_data);
private:
ProducerCallback producer_;
std::size_t size_ = 0;
std::size_t curr_size_ = 0;
std::uint64_t remaining_size_ = BUFFER_SIZE_UNSET;
std::uint64_t last_read_multiple_ = BUFFER_SIZE_UNSET;
std::size_t buffer_offset_ = 0;
std::vector<std::uint8_t> buffer_;
};
// This class is similar to ImageBuffer, but preserves historical peculiarities of buffer handling
// in the backend to preserve exact behavior
class ImageBufferGenesysUsb
{
public:
using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
ImageBufferGenesysUsb() {}
ImageBufferGenesysUsb(std::size_t total_size, std::size_t buffer_size,
ProducerCallback producer);
std::size_t remaining_size() const { return remaining_size_; }
void set_remaining_size(std::size_t bytes) { remaining_size_ = bytes; }
std::size_t available() const { return buffer_end_ - buffer_offset_; }
bool get_data(std::size_t size, std::uint8_t* out_data);
private:
std::size_t get_read_size();
std::size_t remaining_size_ = 0;
std::size_t buffer_size_ = 0;
std::size_t buffer_offset_ = 0;
std::size_t buffer_end_ = 0;
std::vector<std::uint8_t> buffer_;
ProducerCallback producer_;
};
} // namespace genesys
#endif // BACKEND_GENESYS_IMAGE_BUFFER_H

Wyświetl plik

@ -53,15 +53,6 @@ namespace genesys {
ImagePipelineNode::~ImagePipelineNode() {}
std::size_t ImagePipelineNodeBytesSource::consume_remaining_bytes(std::size_t bytes)
{
if (bytes > remaining_bytes_) {
bytes = remaining_bytes_;
}
remaining_bytes_ -= bytes;
return bytes;
}
bool ImagePipelineNodeCallableSource::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = producer_(get_row_bytes(), out_data);
@ -78,7 +69,7 @@ ImagePipelineNodeBufferedCallableSource::ImagePipelineNodeBufferedCallableSource
format_{format},
buffer_{input_batch_size, producer}
{
set_remaining_bytes(height_ * get_row_bytes());
buffer_.set_remaining_size(height_ * get_row_bytes());
}
bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* out_data)
@ -92,13 +83,7 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
bool got_data = true;
auto row_bytes = get_row_bytes();
auto bytes_to_ask = consume_remaining_bytes(row_bytes);
if (bytes_to_ask < row_bytes) {
got_data = false;
}
got_data &= buffer_.get_data(bytes_to_ask, out_data);
got_data &= buffer_.get_data(get_row_bytes(), out_data);
curr_row_++;
if (!got_data) {
eof_ = true;
@ -106,37 +91,6 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
return got_data;
}
ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb(
std::size_t width, std::size_t height, PixelFormat format, std::size_t total_size,
std::size_t buffer_size, ProducerCallback producer) :
width_{width},
height_{height},
format_{format},
buffer_{total_size, buffer_size, producer}
{
set_remaining_bytes(total_size);
}
bool ImagePipelineNodeBufferedGenesysUsb::get_next_row_data(std::uint8_t* out_data)
{
if (remaining_bytes() != buffer_.remaining_size() + buffer_.available()) {
buffer_.set_remaining_size(remaining_bytes() - buffer_.available());
}
bool got_data = true;
std::size_t row_bytes = get_row_bytes();
std::size_t ask_bytes = consume_remaining_bytes(row_bytes);
if (ask_bytes < row_bytes) {
got_data = false;
}
got_data &= buffer_.get_data(ask_bytes, out_data);
if (!got_data) {
eof_ = true;
}
return got_data;
}
ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, std::size_t height,
PixelFormat format,
std::vector<std::uint8_t> data) :
@ -151,7 +105,6 @@ ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, st
throw SaneException("The given array is too small (%zu bytes). Need at least %zu",
data_.size(), size);
}
set_remaining_bytes(size);
}
bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data)
@ -161,21 +114,11 @@ bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data)
return false;
}
bool got_data = true;
auto row_bytes = get_row_bytes();
auto bytes_to_ask = consume_remaining_bytes(row_bytes);
if (bytes_to_ask < row_bytes) {
got_data = false;
}
std::memcpy(out_data, data_.data() + get_row_bytes() * next_row_, bytes_to_ask);
std::memcpy(out_data, data_.data() + row_bytes * next_row_, row_bytes);
next_row_++;
if (!got_data) {
eof_ = true;
}
return got_data;
return true;
}
@ -319,6 +262,50 @@ bool ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
ImagePipelineNodeInvert::ImagePipelineNodeInvert(ImagePipelineNode& source) :
source_(source)
{
}
bool ImagePipelineNodeInvert::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = source_.get_next_row_data(out_data);
auto num_values = get_width() * get_pixel_channels(source_.get_format());
auto depth = get_pixel_format_depth(source_.get_format());
switch (depth) {
case 16: {
auto* data = reinterpret_cast<std::uint16_t*>(out_data);
for (std::size_t i = 0; i < num_values; ++i) {
*data = 0xffff - *data;
data++;
}
break;
}
case 8: {
auto* data = out_data;
for (std::size_t i = 0; i < num_values; ++i) {
*data = 0xff - *data;
data++;
}
break;
}
case 1: {
auto* data = out_data;
auto num_bytes = (num_values + 7) / 8;
for (std::size_t i = 0; i < num_bytes; ++i) {
*data = ~*data;
data++;
}
break;
}
default:
throw SaneException("Unsupported pixel depth");
}
return got_data;
}
ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order) :
source_(source),
@ -456,6 +443,12 @@ ImagePipelineNodeComponentShiftLines::ImagePipelineNodeComponentShiftLines(
static_cast<unsigned>(source.get_format()));
}
extra_height_ = *std::max_element(channel_shifts_.begin(), channel_shifts_.end());
height_ = source_.get_height();
if (extra_height_ > height_) {
height_ = 0;
} else {
height_ -= extra_height_;
}
}
bool ImagePipelineNodeComponentShiftLines::get_next_row_data(std::uint8_t* out_data)
@ -492,18 +485,13 @@ ImagePipelineNodePixelShiftLines::ImagePipelineNodePixelShiftLines(
pixel_shifts_{shifts},
buffer_{get_row_bytes()}
{
DBG_HELPER(dbg);
DBG(DBG_proc, "%s: shifts={", __func__);
for (auto el : pixel_shifts_) {
DBG(DBG_proc, " %zu", el);
}
DBG(DBG_proc, " }\n");
if (pixel_shifts_.size() > MAX_SHIFTS) {
throw SaneException("Unsupported number of shift configurations %zu", pixel_shifts_.size());
}
extra_height_ = *std::max_element(pixel_shifts_.begin(), pixel_shifts_.end());
height_ = source_.get_height();
if (extra_height_ > height_) {
height_ = 0;
} else {
height_ -= extra_height_;
}
}
bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
@ -521,7 +509,8 @@ bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
auto format = get_format();
auto shift_count = pixel_shifts_.size();
std::array<std::uint8_t*, MAX_SHIFTS> rows;
std::vector<std::uint8_t*> rows;
rows.resize(shift_count, nullptr);
for (std::size_t irow = 0; irow < shift_count; ++irow) {
rows[irow] = buffer_.get_row_ptr(pixel_shifts_[irow]);
@ -536,6 +525,63 @@ bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
ImagePipelineNodePixelShiftColumns::ImagePipelineNodePixelShiftColumns(
ImagePipelineNode& source, const std::vector<std::size_t>& shifts) :
source_(source),
pixel_shifts_{shifts}
{
width_ = source_.get_width();
extra_width_ = compute_pixel_shift_extra_width(width_, pixel_shifts_);
if (extra_width_ > width_) {
width_ = 0;
} else {
width_ -= extra_width_;
}
temp_buffer_.resize(source_.get_row_bytes());
}
bool ImagePipelineNodePixelShiftColumns::get_next_row_data(std::uint8_t* out_data)
{
if (width_ == 0) {
throw SaneException("Attempt to read zero-width line");
}
bool got_data = source_.get_next_row_data(temp_buffer_.data());
auto format = get_format();
auto shift_count = pixel_shifts_.size();
for (std::size_t x = 0, width = get_width(); x < width; x += shift_count) {
for (std::size_t ishift = 0; ishift < shift_count && x + ishift < width; ishift++) {
RawPixel pixel = get_raw_pixel_from_row(temp_buffer_.data(), x + pixel_shifts_[ishift],
format);
set_raw_pixel_to_row(out_data, x + ishift, pixel, format);
}
}
return got_data;
}
std::size_t compute_pixel_shift_extra_width(std::size_t source_width,
const std::vector<std::size_t>& shifts)
{
// we iterate across pixel shifts and find the pixel that needs the maximum shift according to
// source_width.
int group_size = shifts.size();
int non_filled_group = source_width % shifts.size();
int extra_width = 0;
for (int i = 0; i < group_size; ++i) {
int shift_groups = shifts[i] / group_size;
int shift_rem = shifts[i] % group_size;
if (shift_rem < non_filled_group) {
shift_groups--;
}
extra_width = std::max(extra_width, shift_groups * group_size + non_filled_group - i);
}
return extra_width;
}
ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source,
std::size_t offset_x, std::size_t offset_y,
std::size_t width, std::size_t height) :
@ -734,10 +780,8 @@ ImagePipelineNodeDebug::~ImagePipelineNodeDebug()
auto format = get_format();
buffer_.linearize();
sanei_genesys_write_pnm_file(path_.c_str(), buffer_.get_front_row_ptr(),
get_pixel_format_depth(format),
get_pixel_channels(format),
get_width(), buffer_.height());
write_tiff_file(path_, buffer_.get_front_row_ptr(), get_pixel_format_depth(format),
get_pixel_channels(format), get_width(), buffer_.height());
});
}

Wyświetl plik

@ -75,18 +75,6 @@ public:
virtual bool get_next_row_data(std::uint8_t* out_data) = 0;
};
class ImagePipelineNodeBytesSource : public ImagePipelineNode
{
public:
std::size_t remaining_bytes() const { return remaining_bytes_; }
void set_remaining_bytes(std::size_t bytes) { remaining_bytes_ = bytes; }
std::size_t consume_remaining_bytes(std::size_t bytes);
private:
std::size_t remaining_bytes_ = 0;
};
// A pipeline node that produces data from a callable
class ImagePipelineNodeCallableSource : public ImagePipelineNode
{
@ -118,7 +106,7 @@ private:
};
// A pipeline node that produces data from a callable requesting fixed-size chunks.
class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNodeBytesSource
class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNode
{
public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
@ -135,8 +123,9 @@ public:
bool get_next_row_data(std::uint8_t* out_data) override;
std::size_t buffer_size() const { return buffer_.size(); }
std::size_t buffer_available() const { return buffer_.available(); }
std::size_t remaining_bytes() const { return buffer_.remaining_size(); }
void set_remaining_bytes(std::size_t bytes) { buffer_.set_remaining_size(bytes); }
void set_last_read_multiple(std::size_t bytes) { buffer_.set_last_read_multiple(bytes); }
private:
ProducerCallback producer_;
@ -150,38 +139,8 @@ private:
ImageBuffer buffer_;
};
class ImagePipelineNodeBufferedGenesysUsb : public ImagePipelineNodeBytesSource
{
public:
using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
ImagePipelineNodeBufferedGenesysUsb(std::size_t width, std::size_t height,
PixelFormat format, std::size_t total_size,
std::size_t buffer_size, ProducerCallback producer);
std::size_t get_width() const override { return width_; }
std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return format_; }
bool eof() const override { return eof_; }
bool get_next_row_data(std::uint8_t* out_data) override;
std::size_t buffer_available() const { return buffer_.available(); }
private:
ProducerCallback producer_;
std::size_t width_ = 0;
std::size_t height_ = 0;
PixelFormat format_ = PixelFormat::UNKNOWN;
bool eof_ = false;
ImageBufferGenesysUsb buffer_;
};
// A pipeline node that produces data from the given array.
class ImagePipelineNodeArraySource : public ImagePipelineNodeBytesSource
class ImagePipelineNodeArraySource : public ImagePipelineNode
{
public:
ImagePipelineNodeArraySource(std::size_t width, std::size_t height, PixelFormat format,
@ -301,7 +260,7 @@ public:
std::size_t pixels_per_chunk);
};
// A pipeline that swaps bytes in 16-bit components on big-endian systems
// A pipeline that swaps bytes in 16-bit components and does nothing otherwise.
class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode
{
public:
@ -320,6 +279,23 @@ private:
bool needs_swapping_ = false;
};
class ImagePipelineNodeInvert : public ImagePipelineNode
{
public:
ImagePipelineNodeInvert(ImagePipelineNode& source);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height(); }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
bool get_next_row_data(std::uint8_t* out_data) override;
private:
ImagePipelineNode& source_;
};
// A pipeline node that merges 3 mono lines into a color channel
class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode
{
@ -376,7 +352,7 @@ public:
unsigned shift_r, unsigned shift_g, unsigned shift_b);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height() - extra_height_; }
std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
@ -386,23 +362,23 @@ public:
private:
ImagePipelineNode& source_;
std::size_t extra_height_ = 0;
std::size_t height_ = 0;
std::array<unsigned, 3> channel_shifts_;
RowBuffer buffer_;
};
// A pipeline node that shifts pixels across lines by the given offsets (performs unstaggering)
// A pipeline node that shifts pixels across lines by the given offsets (performs vertical
// unstaggering)
class ImagePipelineNodePixelShiftLines : public ImagePipelineNode
{
public:
constexpr static std::size_t MAX_SHIFTS = 2;
ImagePipelineNodePixelShiftLines(ImagePipelineNode& source,
const std::vector<std::size_t>& shifts);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height() - extra_height_; }
std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
@ -412,12 +388,44 @@ public:
private:
ImagePipelineNode& source_;
std::size_t extra_height_ = 0;
std::size_t height_ = 0;
std::vector<std::size_t> pixel_shifts_;
RowBuffer buffer_;
};
// A pipeline node that shifts pixels across columns by the given offsets. Each row is divided
// into pixel groups of shifts.size() pixels. For each output group starting at position xgroup,
// the i-th pixel will be set to the input pixel at position xgroup + shifts[i].
class ImagePipelineNodePixelShiftColumns : public ImagePipelineNode
{
public:
ImagePipelineNodePixelShiftColumns(ImagePipelineNode& source,
const std::vector<std::size_t>& shifts);
std::size_t get_width() const override { return width_; }
std::size_t get_height() const override { return source_.get_height(); }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
bool get_next_row_data(std::uint8_t* out_data) override;
private:
ImagePipelineNode& source_;
std::size_t width_ = 0;
std::size_t extra_width_ = 0;
std::vector<std::size_t> pixel_shifts_;
std::vector<std::uint8_t> temp_buffer_;
};
// exposed for tests
std::size_t compute_pixel_shift_extra_width(std::size_t source_width,
const std::vector<std::size_t>& shifts);
// A pipeline node that extracts a sub-image from the image. Padding and cropping is done as needed.
// The class can't pad to the left of the image currently, as only positive offsets are accepted.
class ImagePipelineNodeExtract : public ImagePipelineNode
@ -516,6 +524,19 @@ class ImagePipelineStack
{
public:
ImagePipelineStack() {}
ImagePipelineStack(ImagePipelineStack&& other)
{
clear();
nodes_ = std::move(other.nodes_);
}
ImagePipelineStack& operator=(ImagePipelineStack&& other)
{
clear();
nodes_ = std::move(other.nodes_);
return *this;
}
~ImagePipelineStack() { clear(); }
std::size_t get_input_width() const;
@ -535,20 +556,22 @@ public:
void clear();
template<class Node, class... Args>
void push_first_node(Args&&... args)
Node& push_first_node(Args&&... args)
{
if (!nodes_.empty()) {
throw SaneException("Trying to append first node when there are existing nodes");
}
nodes_.emplace_back(std::unique_ptr<Node>(new Node(std::forward<Args>(args)...)));
return static_cast<Node&>(*nodes_.back());
}
template<class Node, class... Args>
void push_node(Args&&... args)
Node& push_node(Args&&... args)
{
ensure_node_exists();
nodes_.emplace_back(std::unique_ptr<Node>(new Node(*nodes_.back(),
std::forward<Args>(args)...)));
return static_cast<Node&>(*nodes_.back());
}
bool get_next_row_data(std::uint8_t* out_data)

Wyświetl plik

@ -51,6 +51,7 @@
namespace genesys {
// 16-bit values are in host endian
enum class PixelFormat
{
UNKNOWN,

Plik diff jest za duży Load Diff

Wyświetl plik

@ -153,50 +153,60 @@
#define AFE_SET 2
#define AFE_POWER_SAVE 4
#define LOWORD(x) ((uint16_t)((x) & 0xffff))
#define HIWORD(x) ((uint16_t)((x) >> 16))
#define LOBYTE(x) ((uint8_t)((x) & 0xFF))
#define HIBYTE(x) ((uint8_t)((x) >> 8))
/* Global constants */
/* TODO: emove this leftover of early backend days */
#define MOTOR_SPEED_MAX 350
#define DARK_VALUE 0
#define MAX_RESOLUTIONS 13
#define MAX_DPI 4
namespace genesys {
struct Genesys_USB_Device_Entry {
class UsbDeviceEntry {
public:
static constexpr std::uint16_t BCD_DEVICE_NOT_SET = 0xffff;
Genesys_USB_Device_Entry(unsigned v, unsigned p, const Genesys_Model& m) :
vendor(v), product(p), model(m)
UsbDeviceEntry(std::uint16_t vendor_id, std::uint16_t product_id,
const Genesys_Model& model) :
vendor_{vendor_id}, product_{product_id},
bcd_device_{BCD_DEVICE_NOT_SET}, model_{model}
{}
UsbDeviceEntry(std::uint16_t vendor_id, std::uint16_t product_id, std::uint16_t bcd_device,
const Genesys_Model& model) :
vendor_{vendor_id}, product_{product_id},
bcd_device_{bcd_device}, model_{model}
{}
std::uint16_t vendor_id() const { return vendor_; }
std::uint16_t product_id() const { return product_; }
std::uint16_t bcd_device() const { return bcd_device_; }
const Genesys_Model& model() const { return model_; }
bool matches(std::uint16_t vendor_id, std::uint16_t product_id, std::uint16_t bcd_device)
{
if (vendor_ != vendor_id)
return false;
if (product_ != product_id)
return false;
if (bcd_device_ != BCD_DEVICE_NOT_SET && bcd_device != BCD_DEVICE_NOT_SET &&
bcd_device_ != bcd_device)
{
return false;
}
return true;
}
private:
// USB vendor identifier
std::uint16_t vendor;
std::uint16_t vendor_;
// USB product identifier
std::uint16_t product;
std::uint16_t product_;
// USB bcdProduct identifier
std::uint16_t bcd_device_;
// Scanner model information
Genesys_Model model;
Genesys_Model model_;
};
/*--------------------------------------------------------------------------*/
/* common functions needed by low level specific functions */
/*--------------------------------------------------------------------------*/
inline GenesysRegister* sanei_genesys_get_address(Genesys_Register_Set* regs, uint16_t addr)
{
auto* ret = regs->find_reg_address(addr);
if (ret == nullptr) {
DBG(DBG_error, "%s: failed to find address for register 0x%02x, crash expected !\n",
__func__, addr);
}
return ret;
}
extern void sanei_genesys_init_cmd_set(Genesys_Device* dev);
std::unique_ptr<CommandSet> create_cmd_set(AsicType asic_type);
// reads the status of the scanner
Status scanner_read_status(Genesys_Device& dev);
@ -210,21 +220,26 @@ void scanner_read_print_status(Genesys_Device& dev);
void debug_print_status(DebugMessageHelper& dbg, Status status);
void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
std::uint8_t value, std::uint8_t mask);
extern void sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size,
uint8_t* data);
extern void sanei_genesys_init_structs (Genesys_Device * dev);
const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev);
const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi,
const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev);
const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method);
Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
std::vector<std::reference_wrapper<const Genesys_Sensor>>
sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method);
sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method);
std::vector<std::reference_wrapper<Genesys_Sensor>>
sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method);
@ -269,13 +284,9 @@ extern void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr)
unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type);
SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi, StepType step_type,
SANE_Int sanei_genesys_exposure_time2(Genesys_Device* dev, const MotorProfile& profile, float ydpi,
int endpixel, int led_exposure);
MotorSlopeTable sanei_genesys_create_slope_table3(AsicType asic_type, const Genesys_Motor& motor,
StepType step_type, int exposure_time,
unsigned yres);
void sanei_genesys_create_default_gamma_table(Genesys_Device* dev,
std::vector<uint16_t>& gamma_table, float gamma);
@ -303,19 +314,26 @@ void scanner_move_back_home_ta(Genesys_Device& dev);
*/
void scanner_search_strip(Genesys_Device& dev, bool forward, bool black);
bool should_calibrate_only_active_area(const Genesys_Device& dev,
const Genesys_Settings& settings);
void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs);
void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, unsigned dpi);
SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs);
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev);
void scanner_send_slope_table(Genesys_Device* dev, const Genesys_Sensor& sensor, unsigned table_nr,
const std::vector<uint16_t>& slope_table);
extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
std::size_t length);
extern void sanei_genesys_write_pnm_file(const char* filename, const std::uint8_t* data, int depth,
int channels, int pixels_per_line, int lines);
void sanei_genesys_write_pnm_file(const char* filename, const Image& image);
extern void sanei_genesys_write_pnm_file16(const char* filename, const uint16_t *data, unsigned channels,
unsigned pixels_per_line, unsigned lines);
void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice = false);
extern void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, uint8_t* data, size_t size);
@ -328,8 +346,7 @@ void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs,
void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs);
void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& sensor,
unsigned dpihw);
void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw);
inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure)
{
@ -343,7 +360,7 @@ bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& reg
extern void sanei_genesys_wait_for_home(Genesys_Device* dev);
extern void sanei_genesys_asic_init(Genesys_Device* dev, bool cold);
extern void sanei_genesys_asic_init(Genesys_Device* dev);
void scanner_start_action(Genesys_Device& dev, bool start_motor);
void scanner_stop_action(Genesys_Device& dev);
@ -351,6 +368,9 @@ void scanner_stop_action_no_move(Genesys_Device& dev, Genesys_Register_Set& regs
bool scanner_is_motor_stopped(Genesys_Device& dev);
void scanner_setup_sensor(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs);
const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
@ -359,9 +379,9 @@ const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
unsigned step_multiplier,
const MotorProfile& motor_profile);
MotorSlopeTable create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi,
unsigned exposure, unsigned step_multiplier,
const MotorProfile& motor_profile);
MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
const MotorProfile& motor_profile);
@ -401,53 +421,22 @@ extern void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev,
int size,
uint8_t* gamma);
unsigned session_adjust_output_pixels(unsigned output_pixels,
const Genesys_Device& dev, const Genesys_Sensor& sensor,
unsigned output_xresolution, unsigned output_yresolution,
bool adjust_output_pixels);
void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor);
void build_image_pipeline(Genesys_Device* dev, const Genesys_Sensor& sensor,
const ScanSession& session);
ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
unsigned pipeline_index, bool log_image_data);
// sets up a image pipeline for device `dev`
void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session);
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type);
template<class T>
inline T abs_diff(T a, T b)
{
if (a < b) {
return b - a;
} else {
return a - b;
}
}
inline uint64_t align_multiple_floor(uint64_t x, uint64_t multiple)
{
return (x / multiple) * multiple;
}
inline uint64_t align_multiple_ceil(uint64_t x, uint64_t multiple)
{
return ((x + multiple - 1) / multiple) * multiple;
}
inline uint64_t multiply_by_depth_ceil(uint64_t pixels, uint64_t depth)
{
if (depth == 1) {
return (pixels / 8) + ((pixels % 8) ? 1 : 0);
} else {
return pixels * (depth / 8);
}
}
template<class T>
inline T clamp(const T& value, const T& lo, const T& hi)
{
if (value < lo)
return lo;
if (value > hi)
return hi;
return value;
}
/*---------------------------------------------------------------------------*/
/* ASIC specific functions declarations */
/*---------------------------------------------------------------------------*/
@ -455,14 +444,17 @@ inline T clamp(const T& value, const T& lo, const T& hi)
extern StaticInit<std::vector<Genesys_Sensor>> s_sensors;
extern StaticInit<std::vector<Genesys_Frontend>> s_frontends;
extern StaticInit<std::vector<Genesys_Gpo>> s_gpo;
extern StaticInit<std::vector<MemoryLayout>> s_memory_layout;
extern StaticInit<std::vector<Genesys_Motor>> s_motors;
extern StaticInit<std::vector<Genesys_USB_Device_Entry>> s_usb_devices;
extern StaticInit<std::vector<UsbDeviceEntry>> s_usb_devices;
void genesys_init_sensor_tables();
void genesys_init_frontend_tables();
void genesys_init_gpo_tables();
void genesys_init_memory_layout_tables();
void genesys_init_motor_tables();
void genesys_init_usb_device_tables();
void verify_sensor_tables();
void verify_usb_device_tables();
template<class T>

Wyświetl plik

@ -43,9 +43,11 @@
#define DEBUG_DECLARE_ONLY
#include "low.h"
#include "motor.h"
#include "utilities.h"
#include <cmath>
#include <numeric>
namespace genesys {
@ -80,19 +82,38 @@ MotorSlope MotorSlope::create_from_steps(unsigned initial_w, unsigned max_w,
return slope;
}
void MotorSlopeTable::slice_steps(unsigned count)
void MotorSlopeTable::slice_steps(unsigned count, unsigned step_multiplier)
{
if (count >= table.size() || count > steps_count) {
throw SaneException("Excepssive steps count");
if (count > table.size() || count < step_multiplier) {
throw SaneException("Invalid steps count");
}
steps_count = count;
count = align_multiple_floor(count, step_multiplier);
table.resize(count);
generate_pixeltime_sum();
}
void MotorSlopeTable::expand_table(unsigned count, unsigned step_multiplier)
{
if (table.empty()) {
throw SaneException("Can't expand empty table");
}
count = align_multiple_ceil(count, step_multiplier);
table.resize(table.size() + count, table.back());
generate_pixeltime_sum();
}
void MotorSlopeTable::generate_pixeltime_sum()
{
pixeltime_sum_ = std::accumulate(table.begin(), table.end(),
std::size_t{0}, std::plus<std::size_t>());
}
unsigned get_slope_table_max_size(AsicType asic_type)
{
switch (asic_type) {
case AsicType::GL646:
case AsicType::GL841: return 255;
case AsicType::GL841:
case AsicType::GL842: return 255;
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@ -103,9 +124,9 @@ unsigned get_slope_table_max_size(AsicType asic_type)
}
}
MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_speed_w,
StepType step_type, unsigned steps_alignment,
unsigned min_size, unsigned max_size)
MotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned target_speed_w,
StepType step_type, unsigned steps_alignment,
unsigned min_size, unsigned max_size)
{
DBG_HELPER_ARGS(dbg, "target_speed_w: %d, step_type: %d, steps_alignment: %d, min_size: %d",
target_speed_w, static_cast<unsigned>(step_type), steps_alignment, min_size);
@ -130,26 +151,20 @@ MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_spee
break;
}
table.table.push_back(current);
table.pixeltime_sum += current;
}
// make sure the target speed (or the max speed if target speed is too high) is present in
// the table
table.table.push_back(final_speed);
table.pixeltime_sum += table.table.back();
// fill the table up to the specified size
while (table.table.size() < max_size - 1 &&
(table.table.size() % steps_alignment != 0 || table.table.size() < min_size))
{
table.table.push_back(table.table.back());
table.pixeltime_sum += table.table.back();
}
table.steps_count = table.table.size();
// fill the rest of the table with the final speed
table.table.resize(max_size, final_speed);
table.generate_pixeltime_sum();
return table;
}
@ -180,9 +195,8 @@ std::ostream& operator<<(std::ostream& out, const MotorProfile& profile)
std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor)
{
out << "Genesys_Motor{\n"
<< " id: " << static_cast<unsigned>(motor.id) << '\n'
<< " id: " << motor.id << '\n'
<< " base_ydpi: " << motor.base_ydpi << '\n'
<< " optical_ydpi: " << motor.optical_ydpi << '\n'
<< " profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.profiles)) << '\n'

Wyświetl plik

@ -49,6 +49,7 @@
#include <vector>
#include "enums.h"
#include "sensor.h"
#include "value_filter.h"
namespace genesys {
@ -125,17 +126,24 @@ struct MotorSlope
struct MotorSlopeTable
{
std::vector<std::uint16_t> table;
unsigned steps_count = 0;
unsigned pixeltime_sum = 0;
void slice_steps(unsigned count);
void slice_steps(unsigned count, unsigned step_multiplier);
// expands the table by the given number of steps
void expand_table(unsigned count, unsigned step_multiplier);
std::uint64_t pixeltime_sum() const { return pixeltime_sum_; }
void generate_pixeltime_sum();
private:
std::uint64_t pixeltime_sum_ = 0;
};
unsigned get_slope_table_max_size(AsicType asic_type);
MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_speed_w,
StepType step_type, unsigned steps_alignment,
unsigned min_size, unsigned max_size);
MotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned target_speed_w,
StepType step_type, unsigned steps_alignment,
unsigned min_size, unsigned max_size);
std::ostream& operator<<(std::ostream& out, const MotorSlope& slope);
@ -151,9 +159,9 @@ struct MotorProfile
int motor_vref = -1;
// the resolutions this profile is good for
ResolutionFilter resolutions = ResolutionFilter::ANY;
ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
// the scan method this profile is good for. If the list is empty, good for any method.
ScanMethodFilter scan_methods = ScanMethodFilter::ANY;
ValueFilterAny<ScanMethod> scan_methods = VALUE_FILTER_ANY;
unsigned max_exposure = 0; // 0 - any exposure
};
@ -168,8 +176,6 @@ struct Genesys_Motor
MotorId id = MotorId::UNKNOWN;
// motor base steps. Unit: 1/inch
int base_ydpi = 0;
// maximum resolution in y-direction. Unit: 1/inch
int optical_ydpi = 0;
// slopes to derive individual slopes from
std::vector<MotorProfile> profiles;
// slopes to derive individual slopes from for fast moving

Wyświetl plik

@ -415,6 +415,11 @@ public:
}
}
bool has_reg(AddressType address) const
{
return find_reg_index(address) != -1;
}
SettingType& find_reg(AddressType address)
{
int i = find_reg_index(address);

Wyświetl plik

@ -70,7 +70,6 @@ public:
virtual void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) = 0;
// GL646, GL841, GL843 have different ways to write to RAM and to gamma tables
// FIXME: remove flags when updating tests
virtual void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size) = 0;

Wyświetl plik

@ -101,8 +101,6 @@ std::uint8_t ScannerInterfaceUsb::read_register(std::uint16_t address)
usb_dev_.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX,
1, &value);
}
DBG(DBG_proc, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value);
return value;
}
@ -213,6 +211,7 @@ static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, s
uint8_t outdata[8];
if (asic_type == AsicType::GL124 ||
asic_type == AsicType::GL845 ||
asic_type == AsicType::GL846 ||
asic_type == AsicType::GL847)
{
@ -222,7 +221,9 @@ static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, s
outdata[2] = 0;
outdata[3] = 0x10;
} else if (asic_type == AsicType::GL841 ||
asic_type == AsicType::GL843) {
asic_type == AsicType::GL842 ||
asic_type == AsicType::GL843)
{
outdata[0] = BULK_IN;
outdata[1] = BULK_RAM;
outdata[2] = 0x82; //
@ -246,12 +247,13 @@ static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, s
void ScannerInterfaceUsb::bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size)
{
// currently supported: GL646, GL841, GL843, GL846, GL847, GL124
// currently supported: GL646, GL841, GL843, GL845, GL846, GL847, GL124
DBG_HELPER(dbg);
unsigned is_addr_used = 1;
unsigned has_header_before_each_chunk = 0;
if (dev_->model->asic_type == AsicType::GL124 ||
dev_->model->asic_type == AsicType::GL845 ||
dev_->model->asic_type == AsicType::GL846 ||
dev_->model->asic_type == AsicType::GL847)
{
@ -356,6 +358,7 @@ void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, st
DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
if (dev_->model->asic_type != AsicType::GL646 &&
dev_->model->asic_type != AsicType::GL841 &&
dev_->model->asic_type != AsicType::GL842 &&
dev_->model->asic_type != AsicType::GL843)
{
throw SaneException("Unsupported transfer mode");
@ -377,6 +380,7 @@ void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std
{
DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size);
if (dev_->model->asic_type != AsicType::GL841 &&
dev_->model->asic_type != AsicType::GL842 &&
dev_->model->asic_type != AsicType::GL843)
{
throw SaneException("Unsupported transfer mode");
@ -386,7 +390,9 @@ void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std
write_register(0x5c, ((addr >> 4) & 0xff));
bulk_write_data(type, data, size);
if (dev_->model->asic_type == AsicType::GL843) {
if (dev_->model->asic_type == AsicType::GL842 ||
dev_->model->asic_type == AsicType::GL843)
{
// it looks like we need to reset the address so that subsequent buffer operations work.
// Most likely the MTRTBL register is to blame.
write_register(0x5b, 0);

Wyświetl plik

@ -51,10 +51,16 @@ namespace genesys {
std::ostream& operator<<(std::ostream& out, const StaggerConfig& config)
{
out << "StaggerConfig{\n"
<< " min_resolution: " << config.min_resolution() << '\n'
<< " lines_at_min: " << config.lines_at_min() << '\n'
<< "}";
if (config.shifts().empty()) {
out << "StaggerConfig{}";
return out;
}
out << "StaggerConfig{ " << config.shifts().front();
for (auto it = std::next(config.shifts().begin()); it != config.shifts().end(); ++it) {
out << ", " << *it;
}
out << " }";
return out;
}
@ -64,6 +70,11 @@ std::ostream& operator<<(std::ostream& out, const FrontendType& type)
case FrontendType::UNKNOWN: out << "UNKNOWN"; break;
case FrontendType::WOLFSON: out << "WOLFSON"; break;
case FrontendType::ANALOG_DEVICES: out << "ANALOG_DEVICES"; break;
case FrontendType::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
case FrontendType::WOLFSON_GL841: out << "WOLFSON_GL841"; break;
case FrontendType::WOLFSON_GL846: out << "WOLFSON_GL846"; break;
case FrontendType::ANALOG_DEVICES_GL847: out << "ANALOG_DEVICES_GL847"; break;
case FrontendType::WOLFSON_GL124: out << "WOLFSON_GL124"; break;
default: out << "(unknown value)";
}
return out;
@ -91,7 +102,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Frontend& frontend)
StreamStateSaver state_saver{out};
out << "Genesys_Frontend{\n"
<< " id: " << static_cast<unsigned>(frontend.id) << '\n'
<< " id: " << frontend.id << '\n'
<< " regs: " << format_indent_braced_list(4, frontend.regs) << '\n'
<< std::hex
<< " reg2[0]: " << frontend.reg2[0] << '\n'
@ -112,42 +123,23 @@ std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure)
return out;
}
std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions)
{
if (resolutions.matches_any()) {
out << "ANY";
return out;
}
out << format_vector_unsigned(4, resolutions.resolutions());
return out;
}
std::ostream& operator<<(std::ostream& out, const ScanMethodFilter& methods)
{
if (methods.matches_any()) {
out << "ANY";
return out;
}
out << format_vector_unsigned(4, methods.methods());
return out;
}
std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
{
out << "Genesys_Sensor{\n"
<< " sensor_id: " << static_cast<unsigned>(sensor.sensor_id) << '\n'
<< " optical_res: " << sensor.optical_res << '\n'
<< " full_resolution: " << sensor.full_resolution << '\n'
<< " optical_resolution: " << sensor.get_optical_resolution() << '\n'
<< " resolutions: " << format_indent_braced_list(4, sensor.resolutions) << '\n'
<< " channels: " << format_vector_unsigned(4, sensor.channels) << '\n'
<< " method: " << sensor.method << '\n'
<< " register_dpihw_override: " << sensor.register_dpihw_override << '\n'
<< " logical_dpihw_override: " << sensor.logical_dpihw_override << '\n'
<< " dpiset_override: " << sensor.dpiset_override << '\n'
<< " ccd_size_divisor: " << sensor.ccd_size_divisor << '\n'
<< " pixel_count_multiplier: " << sensor.pixel_count_multiplier << '\n'
<< " register_dpihw: " << sensor.register_dpihw << '\n'
<< " register_dpiset: " << sensor.register_dpiset << '\n'
<< " shading_factor: " << sensor.shading_factor << '\n'
<< " shading_pixel_offset: " << sensor.shading_pixel_offset << '\n'
<< " pixel_count_ratio: " << sensor.pixel_count_ratio << '\n'
<< " output_pixel_offset: " << sensor.output_pixel_offset << '\n'
<< " black_pixels: " << sensor.black_pixels << '\n'
<< " dummy_pixel: " << sensor.dummy_pixel << '\n'
<< " ccd_start_xoffset: " << sensor.ccd_start_xoffset << '\n'
<< " fau_gain_white_ref: " << sensor.fau_gain_white_ref << '\n'
<< " gain_white_ref: " << sensor.gain_white_ref << '\n'
<< " exposure: " << format_indent_braced_list(4, sensor.exposure) << '\n'
@ -155,9 +147,9 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
<< " segment_size: " << sensor.segment_size << '\n'
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, sensor.segment_order)) << '\n'
<< " stagger_config: " << format_indent_braced_list(4, sensor.stagger_config) << '\n'
<< " stagger_x: " << sensor.stagger_x << '\n'
<< " stagger_y: " << sensor.stagger_y << '\n'
<< " use_host_side_calib: " << sensor.use_host_side_calib << '\n'
<< " custom_base_regs: " << format_indent_braced_list(4, sensor.custom_base_regs) << '\n'
<< " custom_regs: " << format_indent_braced_list(4, sensor.custom_regs) << '\n'
<< " custom_fe_regs: " << format_indent_braced_list(4, sensor.custom_fe_regs) << '\n'
<< " gamma.red: " << sensor.gamma[0] << '\n'

Wyświetl plik

@ -47,6 +47,7 @@
#include "enums.h"
#include "register.h"
#include "serialize.h"
#include "value_filter.h"
#include <array>
#include <functional>
@ -72,31 +73,30 @@ class StaggerConfig
{
public:
StaggerConfig() = default;
StaggerConfig(unsigned min_resolution, unsigned lines_at_min) :
min_resolution_{min_resolution},
lines_at_min_{lines_at_min}
explicit StaggerConfig(std::initializer_list<std::size_t> shifts) :
shifts_{shifts}
{
}
unsigned stagger_at_resolution(unsigned xresolution, unsigned yresolution) const
std::size_t max_shift() const
{
if (min_resolution_ == 0 || xresolution < min_resolution_)
if (shifts_.empty()) {
return 0;
return yresolution / min_resolution_ * lines_at_min_;
}
return *std::max_element(shifts_.begin(), shifts_.end());
}
unsigned min_resolution() const { return min_resolution_; }
unsigned lines_at_min() const { return lines_at_min_; }
bool empty() const { return shifts_.empty(); }
std::size_t size() const { return shifts_.size(); }
const std::vector<std::size_t>& shifts() const { return shifts_; }
bool operator==(const StaggerConfig& other) const
{
return min_resolution_ == other.min_resolution_ &&
lines_at_min_ == other.lines_at_min_;
return shifts_ == other.shifts_;
}
private:
unsigned min_resolution_ = 0;
unsigned lines_at_min_ = 0;
std::vector<std::size_t> shifts_;
template<class Stream>
friend void serialize(Stream& str, StaggerConfig& x);
@ -105,8 +105,7 @@ private:
template<class Stream>
void serialize(Stream& str, StaggerConfig& x)
{
serialize(str, x.min_resolution_);
serialize(str, x.lines_at_min_);
serialize(str, x.shifts_);
}
std::ostream& operator<<(std::ostream& out, const StaggerConfig& config);
@ -114,9 +113,14 @@ std::ostream& operator<<(std::ostream& out, const StaggerConfig& config);
enum class FrontendType : unsigned
{
UNKNOWN,
UNKNOWN = 0,
WOLFSON,
ANALOG_DEVICES
ANALOG_DEVICES,
CANON_LIDE_80,
WOLFSON_GL841, // old code path, likely wrong calculation
WOLFSON_GL846, // old code path, likely wrong calculation
ANALOG_DEVICES_GL847, // old code path, likely wrong calculation
WOLFSON_GL124, // old code path, likely wrong calculation
};
inline void serialize(std::istream& str, FrontendType& x)
@ -242,94 +246,6 @@ struct SensorExposure {
std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure);
class ResolutionFilter
{
public:
struct Any {};
static constexpr Any ANY{};
ResolutionFilter() : matches_any_{false} {}
ResolutionFilter(Any) : matches_any_{true} {}
ResolutionFilter(std::initializer_list<unsigned> resolutions) :
matches_any_{false},
resolutions_{resolutions}
{}
bool matches(unsigned resolution) const
{
if (matches_any_)
return true;
auto it = std::find(resolutions_.begin(), resolutions_.end(), resolution);
return it != resolutions_.end();
}
bool operator==(const ResolutionFilter& other) const
{
return matches_any_ == other.matches_any_ && resolutions_ == other.resolutions_;
}
bool matches_any() const { return matches_any_; }
const std::vector<unsigned>& resolutions() const { return resolutions_; }
private:
bool matches_any_ = false;
std::vector<unsigned> resolutions_;
template<class Stream>
friend void serialize(Stream& str, ResolutionFilter& x);
};
std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions);
template<class Stream>
void serialize(Stream& str, ResolutionFilter& x)
{
serialize(str, x.matches_any_);
serialize_newline(str);
serialize(str, x.resolutions_);
}
class ScanMethodFilter
{
public:
struct Any {};
static constexpr Any ANY{};
ScanMethodFilter() : matches_any_{false} {}
ScanMethodFilter(Any) : matches_any_{true} {}
ScanMethodFilter(std::initializer_list<ScanMethod> methods) :
matches_any_{false},
methods_{methods}
{}
bool matches(ScanMethod method) const
{
if (matches_any_)
return true;
auto it = std::find(methods_.begin(), methods_.end(), method);
return it != methods_.end();
}
bool operator==(const ScanMethodFilter& other) const
{
return matches_any_ == other.matches_any_ && methods_ == other.methods_;
}
bool matches_any() const { return matches_any_; }
const std::vector<ScanMethod>& methods() const { return methods_; }
private:
bool matches_any_ = false;
std::vector<ScanMethod> methods_;
template<class Stream>
friend void serialize(Stream& str, ResolutionFilter& x);
};
std::ostream& operator<<(std::ostream& out, const ScanMethodFilter& methods);
struct Genesys_Sensor {
Genesys_Sensor() = default;
@ -340,10 +256,15 @@ struct Genesys_Sensor {
// sensor resolution in CCD pixels. Note that we may read more than one CCD pixel per logical
// pixel, see ccd_pixels_per_system_pixel()
unsigned optical_res = 0;
unsigned full_resolution = 0;
// sensor resolution in pixel values that are read by the chip. Many scanners make low
// resolutions faster by configuring the timings in such a way that 1/2 or 1/4 of pixel values
// that are read. If zero, then it is equal to `full_resolution`.
unsigned optical_resolution = 0;
// the resolution list that the sensor is usable at.
ResolutionFilter resolutions = ResolutionFilter::ANY;
ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
// the channel list that the sensor is usable at
std::vector<unsigned> channels = { 1, 3 };
@ -353,27 +274,32 @@ struct Genesys_Sensor {
// The scanner may be setup to use a custom dpihw that does not correspond to any actual
// resolution. The value zero does not set the override.
unsigned register_dpihw_override = 0;
// The scanner may be setup to use a custom logical dpihw that does not correspond to any actual
// resolution. The value zero does not set the override.
unsigned logical_dpihw_override = 0;
unsigned register_dpihw = 0;
// The scanner may be setup to use a custom dpiset value that does not correspond to any actual
// resolution. The value zero does not set the override.
unsigned dpiset_override = 0;
unsigned register_dpiset = 0;
// CCD may present itself as half or quarter-size CCD on certain resolutions
int ccd_size_divisor = 1;
// The resolution to use for shading calibration
unsigned shading_resolution = 0;
// Some scanners need an additional multiplier over the scan coordinates
int pixel_count_multiplier = 1;
// How many real pixels correspond to one shading pixel that is sent to the scanner
unsigned shading_factor = 1;
// How many pixels the shading data is offset to the right from the acquired data. Calculated
// in shading resolution.
int shading_pixel_offset = 0;
// This defines the ratio between logical pixel coordinates and the pixel coordinates sent to
// the scanner.
Ratio pixel_count_ratio = Ratio{1, 1};
// The offset in pixels in terms of scan resolution that needs to be applied to scan position.
int output_pixel_offset = 0;
int black_pixels = 0;
// value of the dummy register
int dummy_pixel = 0;
// last pixel of CCD margin at optical resolution
int ccd_start_xoffset = 0;
// TA CCD target code (reference gain)
int fau_gain_white_ref = 0;
// CCD target code (reference gain)
@ -384,8 +310,7 @@ struct Genesys_Sensor {
int exposure_lperiod = -1;
// the number of pixels in a single segment.
// only on gl843
// the number of pixels in a single segment. This is counted in output resolution.
unsigned segment_size = 0;
// the order of the segments, if any, for the sensor. If the sensor is not segmented or uses
@ -393,32 +318,28 @@ struct Genesys_Sensor {
// only on gl843
std::vector<unsigned> segment_order;
// some CCDs use two arrays of pixels for double resolution. On such CCDs when scanning at
// high-enough resolution, every other pixel column is shifted
StaggerConfig stagger_config;
// some CCDs use multiple arrays of pixels for double or quadruple resolution. This can result
// in the following effects on the output:
// - every n-th column may be shifted in a vertical direction.
// - the columns themselves may be reordered in arbitrary order and may require shifting
// in X direction.
StaggerConfig stagger_x;
StaggerConfig stagger_y;
// True if calibration should be performed on host-side
bool use_host_side_calib = false;
GenesysRegisterSettingSet custom_base_regs; // gl646-specific
GenesysRegisterSettingSet custom_regs;
GenesysRegisterSettingSet custom_fe_regs;
// red, green and blue gamma coefficient for default gamma tables
AssignableArray<float, 3> gamma;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_register_hwdpi_fun;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_ccd_size_divisor_fun;
std::function<unsigned(const Genesys_Sensor&, unsigned)> get_hwdpi_divisor_fun;
unsigned get_register_hwdpi(unsigned xres) const { return get_register_hwdpi_fun(*this, xres); }
unsigned get_ccd_size_divisor_for_dpi(unsigned xres) const
unsigned get_optical_resolution() const
{
return get_ccd_size_divisor_fun(*this, xres);
}
unsigned get_hwdpi_divisor_for_dpi(unsigned xres) const
{
return get_hwdpi_divisor_fun(*this, xres);
if (optical_resolution != 0)
return optical_resolution;
return full_resolution;
}
// how many CCD pixels are processed per system pixel time. This corresponds to CKSEL + 1
@ -444,22 +365,26 @@ struct Genesys_Sensor {
bool operator==(const Genesys_Sensor& other) const
{
return sensor_id == other.sensor_id &&
optical_res == other.optical_res &&
full_resolution == other.full_resolution &&
optical_resolution == other.optical_resolution &&
resolutions == other.resolutions &&
method == other.method &&
ccd_size_divisor == other.ccd_size_divisor &&
shading_resolution == other.shading_resolution &&
shading_factor == other.shading_factor &&
shading_pixel_offset == other.shading_pixel_offset &&
pixel_count_ratio == other.pixel_count_ratio &&
output_pixel_offset == other.output_pixel_offset &&
black_pixels == other.black_pixels &&
dummy_pixel == other.dummy_pixel &&
ccd_start_xoffset == other.ccd_start_xoffset &&
fau_gain_white_ref == other.fau_gain_white_ref &&
gain_white_ref == other.gain_white_ref &&
exposure == other.exposure &&
exposure_lperiod == other.exposure_lperiod &&
segment_size == other.segment_size &&
segment_order == other.segment_order &&
stagger_config == other.stagger_config &&
stagger_x == other.stagger_x &&
stagger_y == other.stagger_y &&
use_host_side_calib == other.use_host_side_calib &&
custom_base_regs == other.custom_base_regs &&
custom_regs == other.custom_regs &&
custom_fe_regs == other.custom_fe_regs &&
gamma == other.gamma;
@ -470,13 +395,16 @@ template<class Stream>
void serialize(Stream& str, Genesys_Sensor& x)
{
serialize(str, x.sensor_id);
serialize(str, x.optical_res);
serialize(str, x.full_resolution);
serialize(str, x.resolutions);
serialize(str, x.method);
serialize(str, x.ccd_size_divisor);
serialize(str, x.shading_resolution);
serialize(str, x.shading_factor);
serialize(str, x.shading_pixel_offset);
serialize(str, x.output_pixel_offset);
serialize(str, x.pixel_count_ratio);
serialize(str, x.black_pixels);
serialize(str, x.dummy_pixel);
serialize(str, x.ccd_start_xoffset);
serialize(str, x.fau_gain_white_ref);
serialize(str, x.gain_white_ref);
serialize_newline(str);
@ -489,12 +417,12 @@ void serialize(Stream& str, Genesys_Sensor& x)
serialize_newline(str);
serialize(str, x.segment_order);
serialize_newline(str);
serialize(str, x.stagger_config);
serialize(str, x.stagger_x);
serialize_newline(str);
serialize(str, x.stagger_y);
serialize_newline(str);
serialize(str, x.use_host_side_calib);
serialize_newline(str);
serialize(str, x.custom_base_regs);
serialize_newline(str);
serialize(str, x.custom_regs);
serialize_newline(str);
serialize(str, x.custom_fe_regs);

Wyświetl plik

@ -97,13 +97,13 @@ bool ScanSession::operator==(const ScanSession& other) const
{
return params == other.params &&
computed == other.computed &&
hwdpi_divisor == other.hwdpi_divisor &&
ccd_size_divisor == other.ccd_size_divisor &&
full_resolution == other.full_resolution &&
optical_resolution == other.optical_resolution &&
optical_pixels == other.optical_pixels &&
optical_pixels_raw == other.optical_pixels_raw &&
optical_line_count == other.optical_line_count &&
output_resolution == other.output_resolution &&
output_startx == other.output_startx &&
output_pixels == other.output_pixels &&
output_channel_bytes == other.output_channel_bytes &&
output_line_bytes == other.output_line_bytes &&
@ -117,32 +117,32 @@ bool ScanSession::operator==(const ScanSession& other) const
color_shift_lines_r == other.color_shift_lines_r &&
color_shift_lines_g == other.color_shift_lines_g &&
color_shift_lines_b == other.color_shift_lines_b &&
stagger_x == other.stagger_x &&
stagger_y == other.stagger_y &&
segment_count == other.segment_count &&
pixel_startx == other.pixel_startx &&
pixel_endx == other.pixel_endx &&
pixel_count_multiplier == other.pixel_count_multiplier &&
pixel_count_ratio == other.pixel_count_ratio &&
conseq_pixel_dist == other.conseq_pixel_dist &&
output_segment_pixel_group_count == other.output_segment_pixel_group_count &&
output_segment_start_offset == other.output_segment_start_offset &&
shading_pixel_offset == other.shading_pixel_offset &&
buffer_size_read == other.buffer_size_read &&
enable_ledadd == other.enable_ledadd &&
use_host_side_calib == other.use_host_side_calib &&
pipeline_needs_reorder == other.pipeline_needs_reorder &&
pipeline_needs_ccd == other.pipeline_needs_ccd &&
pipeline_needs_shrink == other.pipeline_needs_shrink;
use_host_side_calib == other.use_host_side_calib;
}
std::ostream& operator<<(std::ostream& out, const ScanSession& session)
{
out << "ScanSession{\n"
<< " computed: " << session.computed << '\n'
<< " hwdpi_divisor: " << session.hwdpi_divisor << '\n'
<< " ccd_size_divisor: " << session.ccd_size_divisor << '\n'
<< " full_resolution: " << session.full_resolution << '\n'
<< " optical_resolution: " << session.optical_resolution << '\n'
<< " optical_pixels: " << session.optical_pixels << '\n'
<< " optical_pixels_raw: " << session.optical_pixels_raw << '\n'
<< " optical_line_count: " << session.optical_line_count << '\n'
<< " output_resolution: " << session.output_resolution << '\n'
<< " output_startx: " << session.output_startx << '\n'
<< " output_pixels: " << session.output_pixels << '\n'
<< " output_line_bytes: " << session.output_line_bytes << '\n'
<< " output_line_bytes_raw: " << session.output_line_bytes_raw << '\n'
@ -153,19 +153,19 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " color_shift_lines_b: " << session.color_shift_lines_b << '\n'
<< " max_color_shift_lines: " << session.max_color_shift_lines << '\n'
<< " enable_ledadd: " << session.enable_ledadd << '\n'
<< " stagger_x: " << session.stagger_x << '\n'
<< " stagger_y: " << session.stagger_y << '\n'
<< " segment_count: " << session.segment_count << '\n'
<< " pixel_startx: " << session.pixel_startx << '\n'
<< " pixel_endx: " << session.pixel_endx << '\n'
<< " pixel_count_ratio: " << session.pixel_count_ratio << '\n'
<< " conseq_pixel_dist: " << session.conseq_pixel_dist << '\n'
<< " output_segment_pixel_group_count: "
<< session.output_segment_pixel_group_count << '\n'
<< " shading_pixel_offset: " << session.shading_pixel_offset << '\n'
<< " buffer_size_read: " << session.buffer_size_read << '\n'
<< " enable_ledadd: " << session.enable_ledadd << '\n'
<< " use_host_side_calib: " << session.use_host_side_calib << '\n'
<< " filters: "
<< (session.pipeline_needs_reorder ? " reorder": "")
<< (session.pipeline_needs_ccd ? " ccd": "")
<< (session.pipeline_needs_shrink ? " shrink": "") << '\n'
<< " params: " << format_indent_braced_list(4, session.params) << '\n'
<< "}";
return out;

Wyświetl plik

@ -46,6 +46,8 @@
#include "enums.h"
#include "serialize.h"
#include "utilities.h"
#include "sensor.h"
namespace genesys {
@ -79,15 +81,6 @@ struct Genesys_Settings
// true if scan is true gray, false if monochrome scan
int true_gray = 0;
// lineart threshold
int threshold = 0;
// lineart threshold curve for dynamic rasterization
int threshold_curve = 0;
// Disable interpolation for xres<yres
int disable_interpolation = 0;
// value for contrast enhancement in the [-100..100] range
int contrast = 0;
@ -120,8 +113,9 @@ struct SetupParams {
unsigned startx = NOT_SET;
// start pixel in Y direction, counted according to base_ydpi
unsigned starty = NOT_SET;
// the number of pixels in X direction. Note that each logical pixel may correspond to more
// than one CCD pixel, see CKSEL and GenesysSensor::ccd_pixels_per_system_pixel()
// the number of pixels in X direction. Counted in terms of xres.
// Note that each logical pixel may correspond to more than one CCD pixel, see CKSEL and
// GenesysSensor::ccd_pixels_per_system_pixel()
unsigned pixels = NOT_SET;
// the number of pixels in the X direction as requested by the frontend. This will be different
@ -144,7 +138,7 @@ struct SetupParams {
ColorFilter color_filter = static_cast<ColorFilter>(NOT_SET);
ScanFlag flags;
ScanFlag flags = ScanFlag::NONE;
unsigned get_requested_pixels() const
{
@ -210,15 +204,10 @@ struct ScanSession {
// whether the session setup has been computed via compute_session()
bool computed = false;
// specifies the reduction (if any) of hardware dpi on the Genesys chip side.
// except gl646
unsigned hwdpi_divisor = 1;
// specifies the full resolution of the sensor that is being used.
unsigned full_resolution = 0;
// specifies the reduction (if any) of CCD effective dpi which is performed by latching the
// data coming from CCD in such a way that 1/2 or 3/4 of pixel data is ignored.
unsigned ccd_size_divisor = 1;
// the optical resolution of the scanner.
// the optical resolution of the sensor that is being used.
unsigned optical_resolution = 0;
// the number of pixels at the optical resolution, not including segmentation overhead.
@ -232,9 +221,11 @@ struct ScanSession {
unsigned optical_line_count = 0;
// the resolution of the output data.
// gl843-only
unsigned output_resolution = 0;
// the offset in pixels from the beginning of output data
unsigned output_startx = 0;
// the number of pixels in output data (after desegmentation)
unsigned output_pixels = 0;
@ -262,7 +253,7 @@ struct ScanSession {
unsigned output_total_bytes = 0;
// the number of staggered lines (i.e. lines that overlap during scanning due to line being
// thinner than the CCD element)
// thinner than the CCD element). Computed according to stagger_y.
unsigned num_staggered_lines = 0;
// the number of lines that color channels shift due to different physical positions of
@ -276,6 +267,11 @@ struct ScanSession {
// actual line shift of the blue color
unsigned color_shift_lines_b = 0;
// The shifts that need to be applied to the output pixels in x direction.
StaggerConfig stagger_x;
// The shifts that need to be applied to the output pixels in y direction.
StaggerConfig stagger_y;
// the number of scanner segments used in the current scan
unsigned segment_count = 1;
@ -283,8 +279,18 @@ struct ScanSession {
unsigned pixel_startx = 0;
unsigned pixel_endx = 0;
// certain scanners require the logical pixel count to be multiplied on certain resolutions
unsigned pixel_count_multiplier = 1;
/* The following defines the ratio between logical pixel count and pixel count setting sent to
the scanner. The ratio is affected by the following:
- Certain scanners just like to multiply the pixel number by a multiplier that depends on
the resolution.
- The sensor may be configured to output one value per multiple physical pixels
- The scanner will automatically average the pixels that come from the sensor using a
certain ratio.
*/
Ratio pixel_count_ratio = Ratio{1, 1};
// Distance in pixels between consecutive pixels, e.g. between odd and even pixels. Note that
// the number of segments can be large.
@ -300,6 +306,10 @@ struct ScanSession {
// Currently it's always zero.
unsigned output_segment_start_offset = 0;
// How many pixels the shading data is offset to the right from the acquired data. Calculated
// in shading resolution.
int shading_pixel_offset = 0;
// the size of the read buffer.
size_t buffer_size_read = 0;
@ -309,11 +319,6 @@ struct ScanSession {
// whether calibration should be performed host-side
bool use_host_side_calib = false;
// what pipeline modifications are needed
bool pipeline_needs_reorder = false;
bool pipeline_needs_ccd = false;
bool pipeline_needs_shrink = false;
void assert_computed() const
{
if (!computed) {
@ -332,13 +337,13 @@ void serialize(Stream& str, ScanSession& x)
serialize(str, x.params);
serialize_newline(str);
serialize(str, x.computed);
serialize(str, x.hwdpi_divisor);
serialize(str, x.ccd_size_divisor);
serialize(str, x.full_resolution);
serialize(str, x.optical_resolution);
serialize(str, x.optical_pixels);
serialize(str, x.optical_pixels_raw);
serialize(str, x.optical_line_count);
serialize(str, x.output_resolution);
serialize(str, x.output_startx);
serialize(str, x.output_pixels);
serialize(str, x.output_channel_bytes);
serialize(str, x.output_line_bytes);
@ -352,19 +357,19 @@ void serialize(Stream& str, ScanSession& x)
serialize(str, x.color_shift_lines_r);
serialize(str, x.color_shift_lines_g);
serialize(str, x.color_shift_lines_b);
serialize(str, x.stagger_x);
serialize(str, x.stagger_y);
serialize(str, x.segment_count);
serialize(str, x.pixel_startx);
serialize(str, x.pixel_endx);
serialize(str, x.pixel_count_multiplier);
serialize(str, x.pixel_count_ratio);
serialize(str, x.conseq_pixel_dist);
serialize(str, x.output_segment_pixel_group_count);
serialize(str, x.output_segment_start_offset);
serialize(str, x.shading_pixel_offset);
serialize(str, x.buffer_size_read);
serialize(str, x.enable_ledadd);
serialize(str, x.use_host_side_calib);
serialize(str, x.pipeline_needs_reorder);
serialize(str, x.pipeline_needs_ccd);
serialize(str, x.pipeline_needs_shrink);
}
std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params);

Wyświetl plik

@ -60,7 +60,8 @@ void genesys_init_frontend_tables()
GenesysFrontendLayout analog_devices;
analog_devices.type = FrontendType::ANALOG_DEVICES;
analog_devices.offset_addr = { 0x05, 0x06, 0x07 };
analog_devices.gain_addr = { 0x02, 0x03, 0x04 };
Genesys_Frontend fe;
fe.id = AdcId::WOLFSON_UMAX;
@ -198,6 +199,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_35;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL841;
fe.regs = {
{ 0x00, 0x00 },
{ 0x01, 0x3d },
@ -242,6 +244,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::WOLFSON_XP300;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL841;
fe.regs = {
{ 0x00, 0x00 },
{ 0x01, 0x35 },
@ -286,6 +289,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::WOLFSON_DSM600;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL841;
fe.regs = {
{ 0x00, 0x00 },
{ 0x01, 0x35 },
@ -307,45 +311,35 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_200;
fe.layout = wolfson_layout;
fe.layout = analog_devices;
fe.layout.type = FrontendType::ANALOG_DEVICES_GL847;
fe.regs = {
{ 0x00, 0x9d },
{ 0x01, 0x91 },
{ 0x02, 0x00 },
{ 0x03, 0x00 },
{ 0x20, 0x00 },
{ 0x21, 0x3f },
{ 0x22, 0x00 },
{ 0x24, 0x00 },
{ 0x25, 0x00 },
{ 0x26, 0x00 },
{ 0x28, 0x32 },
{ 0x29, 0x04 },
{ 0x2a, 0x00 },
{ 0x02, 0x32 },
{ 0x03, 0x04 },
{ 0x04, 0x00 },
{ 0x05, 0x00 },
{ 0x06, 0x3f },
{ 0x07, 0x00 },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_700F;
fe.layout = wolfson_layout;
fe.layout = analog_devices;
fe.layout.type = FrontendType::ANALOG_DEVICES_GL847;
fe.regs = {
{ 0x00, 0x9d },
{ 0x01, 0x9e },
{ 0x02, 0x00 },
{ 0x03, 0x00 },
{ 0x20, 0x00 },
{ 0x21, 0x3f },
{ 0x22, 0x00 },
{ 0x24, 0x00 },
{ 0x25, 0x00 },
{ 0x26, 0x00 },
{ 0x28, 0x2f },
{ 0x29, 0x04 },
{ 0x2a, 0x00 },
{ 0x02, 0x2f },
{ 0x03, 0x04 },
{ 0x04, 0x00 },
{ 0x05, 0x00 },
{ 0x06, 0x3f },
{ 0x07, 0x00 },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
@ -396,6 +390,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_110;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL124;
fe.regs = {
{ 0x00, 0x80 },
{ 0x01, 0x8a },
@ -422,6 +417,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_120;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL124;
fe.regs = {
{ 0x00, 0x80 },
{ 0x01, 0xa3 },
@ -463,6 +459,23 @@ void genesys_init_frontend_tables()
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICFILM_7200;
fe.layout = analog_devices;
fe.regs = {
{ 0x00, 0xf8 },
{ 0x01, 0x80 },
{ 0x02, 0x2e },
{ 0x03, 0x17 },
{ 0x04, 0x20 },
{ 0x05, 0x0109 },
{ 0x06, 0x01 },
{ 0x07, 0x0104 },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICFILM_7200I;
fe.layout = analog_devices;
@ -497,6 +510,23 @@ void genesys_init_frontend_tables()
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICFILM_7400;
fe.layout = analog_devices;
fe.regs = {
{ 0x00, 0xf8 },
{ 0x01, 0x80 },
{ 0x02, 0x1f },
{ 0x03, 0x14 },
{ 0x04, 0x19 },
{ 0x05, 0x1b },
{ 0x06, 0x1e },
{ 0x07, 0x0e },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICFILM_7500I;
fe.layout = analog_devices;
@ -514,6 +544,23 @@ void genesys_init_frontend_tables()
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICFILM_8200I;
fe.layout = analog_devices;
fe.regs = {
{ 0x00, 0xf8 },
{ 0x01, 0x80 },
{ 0x02, 0x28 },
{ 0x03, 0x20 },
{ 0x04, 0x28 },
{ 0x05, 0x2f },
{ 0x06, 0x2d },
{ 0x07, 0x23 },
};
fe.reg2 = {0x00, 0x00, 0x00};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::CANON_4400F;
fe.layout = wolfson_layout;
@ -536,6 +583,26 @@ void genesys_init_frontend_tables()
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::CANON_5600F;
fe.layout = wolfson_layout;
fe.regs = {
{ 0x01, 0x23 },
{ 0x02, 0x24 },
{ 0x03, 0x2f },
{ 0x06, 0x00 },
{ 0x08, 0x00 },
{ 0x09, 0x00 },
{ 0x20, 0x60 },
{ 0x21, 0x60 },
{ 0x22, 0x60 },
{ 0x28, 0x77 },
{ 0x29, 0x77 },
{ 0x2a, 0x77 },
};
s_frontends->push_back(fe);
fe = Genesys_Frontend();
fe.id = AdcId::CANON_8400F;
fe.layout = wolfson_layout;
@ -583,6 +650,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::IMG101;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL846;
fe.regs = {
{ 0x00, 0x78 },
{ 0x01, 0xf0 },
@ -605,6 +673,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::PLUSTEK_OPTICBOOK_3800;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::WOLFSON_GL846;
fe.regs = {
{ 0x00, 0x78 },
{ 0x01, 0xf0 },
@ -631,6 +700,7 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
fe.id = AdcId::CANON_LIDE_80;
fe.layout = wolfson_layout;
fe.layout.type = FrontendType::CANON_LIDE_80;
fe.regs = {
{ 0x00, 0x70 },
{ 0x01, 0x16 },

Wyświetl plik

@ -188,10 +188,15 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_LIDE_200;
gpo.regs = {
{ 0x6c, 0xfb }, // 0xfb when idle , 0xf9/0xe9 (1200) when scanning
{ 0x6b, 0x02 },
{ 0x6c, 0xf9 }, // 0xfb when idle , 0xf9/0xe9 (1200) when scanning
{ 0x6d, 0x20 },
{ 0x6e, 0xff },
{ 0x6f, 0x00 },
{ 0xa6, 0x04 },
{ 0xa7, 0x04 },
{ 0xa8, 0x00 },
{ 0xa9, 0x00 },
};
s_gpo->push_back(gpo);
@ -199,10 +204,15 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_LIDE_700F;
gpo.regs = {
{ 0x6b, 0x06 },
{ 0x6c, 0xdb },
{ 0x6d, 0xff },
{ 0x6e, 0xff },
{ 0x6f, 0x80 },
{ 0xa6, 0x15 },
{ 0xa7, 0x07 },
{ 0xa8, 0x20 },
{ 0xa9, 0x10 },
};
s_gpo->push_back(gpo);
@ -292,6 +302,19 @@ void genesys_init_gpo_tables()
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICFILM_7200;
gpo.regs = {
{ 0x6b, 0x33 },
{ 0x6c, 0x00 },
{ 0x6d, 0x80 },
{ 0x6e, 0x0c },
{ 0x6f, 0x80 },
{ 0x7e, 0x00 }
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICFILM_7200I;
gpo.regs = {
@ -320,6 +343,16 @@ void genesys_init_gpo_tables()
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICFILM_7400;
gpo.regs = {
{ 0x6b, 0x30 }, { 0x6c, 0x4c }, { 0x6d, 0x80 }, { 0x6e, 0x4c }, { 0x6f, 0x80 },
{ 0xa6, 0x00 }, { 0xa7, 0x07 }, { 0xa8, 0x20 }, { 0xa9, 0x01 },
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICFILM_7500I;
gpo.regs = {
@ -334,6 +367,16 @@ void genesys_init_gpo_tables()
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICFILM_8200I;
gpo.regs = {
{ 0x6b, 0x30 }, { 0x6c, 0x4c }, { 0x6d, 0x80 }, { 0x6e, 0x4c }, { 0x6f, 0x80 },
{ 0xa6, 0x00 }, { 0xa7, 0x07 }, { 0xa8, 0x20 }, { 0xa9, 0x01 },
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_4400F;
gpo.regs = {
@ -349,6 +392,22 @@ void genesys_init_gpo_tables()
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_5600F;
gpo.regs = {
{ 0x6b, 0x87 },
{ 0x6c, 0xf0 },
{ 0x6d, 0x5f },
{ 0x6e, 0x7f },
{ 0x6f, 0xa0 },
{ 0xa6, 0x07 },
{ 0xa7, 0x1c },
{ 0xa8, 0x00 },
{ 0xa9, 0x04 },
};
s_gpo->push_back(gpo);
gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_8400F;
gpo.regs = {
@ -382,10 +441,8 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
gpo.id = GpioId::IMG101;
gpo.regs = {
{ 0x6c, 0x41 },
{ 0x6d, 0xa4 },
{ 0x6e, 0x13 },
{ 0x6f, 0xa7 },
{ 0x6b, 0x72 }, { 0x6c, 0x1f }, { 0x6d, 0xa4 }, { 0x6e, 0x13 }, { 0x6f, 0xa7 },
{ 0xa6, 0x11 }, { 0xa7, 0xff }, { 0xa8, 0x19 }, { 0xa9, 0x05 },
};
s_gpo->push_back(gpo);
@ -393,10 +450,8 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
gpo.id = GpioId::PLUSTEK_OPTICBOOK_3800;
gpo.regs = {
{ 0x6c, 0x41 },
{ 0x6d, 0xa4 },
{ 0x6e, 0x13 },
{ 0x6f, 0xa7 },
{ 0x6b, 0x30 }, { 0x6c, 0x01 }, { 0x6d, 0x80 }, { 0x6e, 0x2d }, { 0x6f, 0x80 },
{ 0xa6, 0x0c }, { 0xa7, 0x8f }, { 0xa8, 0x08 }, { 0xa9, 0x04 },
};
s_gpo->push_back(gpo);

Wyświetl plik

@ -0,0 +1,164 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
*/
#define DEBUG_DECLARE_ONLY
#include "low.h"
namespace genesys {
StaticInit<std::vector<MemoryLayout>> s_memory_layout;
void genesys_init_memory_layout_tables()
{
s_memory_layout.init();
MemoryLayout ml;
ml.models = { ModelId::CANON_IMAGE_FORMULA_101 };
// FIXME: this scanner does not set all required registers
ml.regs = {
{ 0xe0, 0x00 }, { 0xe1, 0xb0 }, { 0xe2, 0x05 }, { 0xe3, 0xe7 },
{ 0xe4, 0x05 }, { 0xe5, 0xe8 }, { 0xe6, 0x0b }, { 0xe7, 0x1f },
{ 0xe8, 0x0b }, { 0xe9, 0x20 },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::PLUSTEK_OPTICBOOK_3800 };
// FIXME: this scanner does not set all required registers
ml.regs = {
{ 0xe0, 0x00 }, { 0xe1, 0x68 }, { 0xe2, 0x03 }, { 0xe3, 0x00 },
{ 0xe4, 0x03 }, { 0xe5, 0x01 }, { 0xe6, 0x05 }, { 0xe7, 0x99 },
{ 0xe8, 0x05 }, { 0xe9, 0x9a },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::PLUSTEK_OPTICFILM_7400, ModelId::PLUSTEK_OPTICFILM_8200I };
ml.regs = {
{ 0x81, 0x6d }, { 0x82, 0x00 }, { 0x83, 0x00 }, { 0x84, 0x00 },
{ 0x85, 0x00 }, { 0x86, 0x00 },
{ 0xd0, 0x0a }, { 0xd1, 0x0a }, { 0xd2, 0x0a },
{ 0xe0, 0x00 }, { 0xe1, 0x68 }, { 0xe2, 0x03 }, { 0xe3, 0x00 },
{ 0xe4, 0x03 }, { 0xe5, 0x01 }, { 0xe6, 0x05 }, { 0xe7, 0x99 },
{ 0xe8, 0x05 }, { 0xe9, 0x9a }, { 0xea, 0x08 }, { 0xeb, 0x32 },
{ 0xec, 0x08 }, { 0xed, 0x33 }, { 0xee, 0x0a }, { 0xef, 0xcb },
{ 0xf0, 0x0a }, { 0xf1, 0xcc }, { 0xf2, 0x0d }, { 0xf3, 0x64 },
{ 0xf4, 0x0d }, { 0xf5, 0x65 }, { 0xf6, 0x0f }, { 0xf7, 0xfd },
};
s_memory_layout->push_back(ml);
/* On GL847 and GL124, the values of the base address for shading data must be multiplied by
8192=0x4000 to give address on AHB
On GL847 and GL124, the values of the base address for scanned data must be multiplied by
1024*2=0x0800 to give address on AHB
*/
ml = MemoryLayout();
ml.models = { ModelId::CANON_5600F };
ml.regs = {
{ 0xd0, 0x0a },
{ 0xe0, 0x01 }, { 0xe1, 0x2c }, { 0xe2, 0x06 }, { 0xe3, 0x4e },
{ 0xe4, 0x06 }, { 0xe5, 0x4f }, { 0xe6, 0x0b }, { 0xe7, 0x71 },
{ 0xe8, 0x0b }, { 0xe9, 0x72 }, { 0xea, 0x10 }, { 0xeb, 0x94 },
{ 0xec, 0x10 }, { 0xed, 0x95 }, { 0xee, 0x15 }, { 0xef, 0xb7 },
{ 0xf0, 0x15 }, { 0xf1, 0xb8 }, { 0xf2, 0x1a }, { 0xf3, 0xda },
{ 0xf4, 0x1a }, { 0xf5, 0xdb }, { 0xf6, 0x1f }, { 0xf7, 0xfd },
{ 0xf8, 0x05 }
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::CANON_LIDE_100 };
ml.regs = {
{ 0xd0, 0x0a }, { 0xd1, 0x15 }, { 0xd2, 0x20 },
{ 0xe0, 0x00 }, { 0xe1, 0xac }, { 0xe2, 0x02 }, { 0xe3, 0x55 },
{ 0xe4, 0x02 }, { 0xe5, 0x56 }, { 0xe6, 0x03 }, { 0xe7, 0xff },
{ 0xe8, 0x00 }, { 0xe9, 0xac }, { 0xea, 0x02 }, { 0xeb, 0x55 },
{ 0xec, 0x02 }, { 0xed, 0x56 }, { 0xee, 0x03 }, { 0xef, 0xff },
{ 0xf0, 0x00 }, { 0xf1, 0xac }, { 0xf2, 0x02 }, { 0xf3, 0x55 },
{ 0xf4, 0x02 }, { 0xf5, 0x56 }, { 0xf6, 0x03 }, { 0xf7, 0xff },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::CANON_LIDE_200 };
ml.regs = {
{ 0xd0, 0x0a }, { 0xd1, 0x1f }, { 0xd2, 0x34 },
{ 0xe0, 0x01 }, { 0xe1, 0x24 }, { 0xe2, 0x02 }, { 0xe3, 0x91 },
{ 0xe4, 0x02 }, { 0xe5, 0x92 }, { 0xe6, 0x03 }, { 0xe7, 0xff },
{ 0xe8, 0x01 }, { 0xe9, 0x24 }, { 0xea, 0x02 }, { 0xeb, 0x91 },
{ 0xec, 0x02 }, { 0xed, 0x92 }, { 0xee, 0x03 }, { 0xef, 0xff },
{ 0xf0, 0x01 }, { 0xf1, 0x24 }, { 0xf2, 0x02 }, { 0xf3, 0x91 },
{ 0xf4, 0x02 }, { 0xf5, 0x92 }, { 0xf6, 0x03 }, { 0xf7, 0xff },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::CANON_LIDE_700F };
ml.regs = {
{ 0xd0, 0x0a }, { 0xd1, 0x33 }, { 0xd2, 0x5c },
{ 0xe0, 0x02 }, { 0xe1, 0x14 }, { 0xe2, 0x09 }, { 0xe3, 0x09 },
{ 0xe4, 0x09 }, { 0xe5, 0x0a }, { 0xe6, 0x0f }, { 0xe7, 0xff },
{ 0xe8, 0x02 }, { 0xe9, 0x14 }, { 0xea, 0x09 }, { 0xeb, 0x09 },
{ 0xec, 0x09 }, { 0xed, 0x0a }, { 0xee, 0x0f }, { 0xef, 0xff },
{ 0xf0, 0x02 }, { 0xf1, 0x14 }, { 0xf2, 0x09 }, { 0xf3, 0x09 },
{ 0xf4, 0x09 }, { 0xf5, 0x0a }, { 0xf6, 0x0f }, { 0xf7, 0xff },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::CANON_LIDE_110, ModelId::CANON_LIDE_120 };
ml.regs = {
{ 0xd0, 0x0a }, { 0xd1, 0x15 }, { 0xd2, 0x20 },
{ 0xe0, 0x00 }, { 0xe1, 0xac }, { 0xe2, 0x08 }, { 0xe3, 0x55 },
{ 0xe4, 0x08 }, { 0xe5, 0x56 }, { 0xe6, 0x0f }, { 0xe7, 0xff },
{ 0xe8, 0x00 }, { 0xe9, 0xac }, { 0xea, 0x08 }, { 0xeb, 0x55 },
{ 0xec, 0x08 }, { 0xed, 0x56 }, { 0xee, 0x0f }, { 0xef, 0xff },
{ 0xf0, 0x00 }, { 0xf1, 0xac }, { 0xf2, 0x08 }, { 0xf3, 0x55 },
{ 0xf4, 0x08 }, { 0xf5, 0x56 }, { 0xf6, 0x0f }, { 0xf7, 0xff },
};
s_memory_layout->push_back(ml);
ml = MemoryLayout();
ml.models = { ModelId::CANON_LIDE_210, ModelId::CANON_LIDE_220 };
ml.regs = {
{ 0xd0, 0x0a }, { 0xd1, 0x1f }, { 0xd2, 0x34 },
{ 0xe0, 0x01 }, { 0xe1, 0x24 }, { 0xe2, 0x08 }, { 0xe3, 0x91 },
{ 0xe4, 0x08 }, { 0xe5, 0x92 }, { 0xe6, 0x0f }, { 0xe7, 0xff },
{ 0xe8, 0x01 }, { 0xe9, 0x24 }, { 0xea, 0x08 }, { 0xeb, 0x91 },
{ 0xec, 0x08 }, { 0xed, 0x92 }, { 0xee, 0x0f }, { 0xef, 0xff },
{ 0xf0, 0x01 }, { 0xf1, 0x24 }, { 0xf2, 0x08 }, { 0xf3, 0x91 },
{ 0xf4, 0x08 }, { 0xf5, 0x92 }, { 0xf6, 0x0f }, { 0xf7, 0xff },
};
s_memory_layout->push_back(ml);
}
} // namespace genesys

Wyświetl plik

@ -58,7 +58,7 @@
namespace genesys {
StaticInit<std::vector<Genesys_USB_Device_Entry>> s_usb_devices;
StaticInit<std::vector<UsbDeviceEntry>> s_usb_devices;
void genesys_init_usb_device_tables()
{
@ -192,8 +192,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_35;
model.gpio_id = GpioId::CANON_LIDE_35;
model.motor_id = MotorId::CANON_LIDE_35;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_WHITE_CALIBRATION |
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
@ -247,8 +246,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::KVSS080;
model.gpio_id = GpioId::KVSS080;
model.motor_id = MotorId::KVSS080;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA;
model.flags = ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW;
model.search_lines = 100;
@ -298,8 +296,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
model.flags = ModelFlag::SHADING_REPARK |
ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
model.search_lines = 100;
@ -348,7 +346,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
model.flags = ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
@ -400,7 +398,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
model.flags = ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
@ -432,7 +430,7 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 6.0;
model.y_offset = 12.00;
model.y_offset = 10.00;
model.x_size = 215.9;
model.y_size = 297.0;
@ -442,12 +440,12 @@ void genesys_init_usb_device_tables()
model.x_size_calib_mm = 241.3;
model.x_offset_ta = 115.0;
model.y_offset_ta = 60.0;
model.y_offset_ta = 37.0;
model.x_size_ta = 35.0;
model.y_size_ta = 230.0;
model.y_offset_sensor_to_ta = 46.0;
model.y_offset_calib_white_ta = 47.0;
model.y_offset_sensor_to_ta = 23.0;
model.y_offset_calib_white_ta = 24.0;
model.y_size_calib_ta_mm = 2.0;
model.post_scan = 0.0;
@ -465,9 +463,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_4400F;
model.gpio_id = GpioId::CANON_4400F;
model.motor_id = MotorId::CANON_4400F;
model.flags = ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::FULL_HWDPI_MODE |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SHADING_REPARK |
ModelFlag::UTA_NO_SECONDARY_MOTOR;
@ -538,9 +535,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_8400F;
model.gpio_id = GpioId::CANON_8400F;
model.motor_id = MotorId::CANON_8400F;
model.flags = ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::FULL_HWDPI_MODE |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SHADING_REPARK;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
@ -581,13 +577,13 @@ void genesys_init_usb_device_tables()
model.x_offset_calib_black = 8.0;
model.x_size_calib_mm = 240.70734;
model.x_offset_ta = 94.0;
model.y_offset_ta = 26.0;
model.x_offset_ta = 97.0;
model.y_offset_ta = 38.5;
model.x_size_ta = 70.0;
model.y_size_ta = 230.0;
model.y_offset_sensor_to_ta = 11.5;
model.y_offset_calib_white_ta = 14.0;
model.y_offset_sensor_to_ta = 23.0;
model.y_offset_calib_white_ta = 25.5;
model.y_size_calib_ta_mm = 3.0;
model.post_scan = 0.0;
@ -605,9 +601,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_8600F;
model.gpio_id = GpioId::CANON_8600F;
model.motor_id = MotorId::CANON_8600F;
model.flags = ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::FULL_HWDPI_MODE |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SHADING_REPARK;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
@ -639,7 +634,7 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 299.0;
model.y_offset_calib_white = 1.0;
model.y_offset_calib_white = 0.4233334;
model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
model.x_size_calib_mm = 217.4241;
@ -659,8 +654,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_200;
model.gpio_id = GpioId::CANON_LIDE_200;
model.motor_id = MotorId::CANON_LIDE_100;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::SIS_SENSOR |
model.flags = ModelFlag::SIS_SENSOR |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
@ -715,8 +709,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_110;
model.motor_id = MotorId::CANON_LIDE_110;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
@ -769,8 +762,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_120;
model.gpio_id = GpioId::CANON_LIDE_120;
model.motor_id = MotorId::CANON_LIDE_120;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
@ -792,16 +784,15 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
{ ScanMethod::FLATBED },
// BUG: 4800 resolution crashes
{ /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
{ /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
{ 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
{ 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
model.x_offset = 2.2;
model.x_offset = 2.1;
model.y_offset = 8.7;
model.x_size = 216.70;
model.y_size = 297.5;
@ -826,8 +817,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_210;
model.motor_id = MotorId::CANON_LIDE_210;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
@ -850,16 +840,15 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
{ ScanMethod::FLATBED },
// BUG: 4800 resolution crashes
{ /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 },
{ /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 },
{ 4800, 2400, 1200, 600, 300, 150, 100, 75 },
{ 4800, 2400, 1200, 600, 300, 150, 100, 75 },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
model.x_offset = 2.2;
model.x_offset = 2.1;
model.y_offset = 8.7;
model.x_size = 216.70;
model.y_size = 297.5;
@ -883,8 +872,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_210;
model.motor_id = MotorId::CANON_LIDE_210;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
@ -898,52 +886,65 @@ void genesys_init_usb_device_tables()
model = Genesys_Model();
model.name = "canon-5600f";
model.name = "canon-canoscan-5600f";
model.vendor = "Canon";
model.model = "5600F";
model.model = "CanoScan 5600F";
model.model_id = ModelId::CANON_5600F;
model.asic_type = AsicType::GL847;
model.resolutions = {
{
{ ScanMethod::FLATBED },
{ 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 },
{ 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 },
{ ScanMethod::FLATBED, ScanMethod::TRANSPARENCY },
{ 4800, 2400, 1200, 600, 300, /*150*/ },
{ 4800, 2400, 1200, 600, 300, /*150*/ },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
model.x_offset = 1.1;
model.y_offset = 8.3;
model.x_size = 216.07;
model.y_size = 299.0;
model.x_offset = 1.5;
model.y_offset = 10.4;
model.x_size = 219.00;
model.y_size = 305.0;
model.y_offset_calib_white = 3.0;
model.y_size_calib_mm = 3.0;
model.y_offset_calib_white = 2.0;
model.y_size_calib_mm = 2.0;
model.x_offset_calib_black = 0.0;
model.x_size_calib_mm = 217.4241;
model.x_size_calib_mm = 220.5;
model.x_offset_ta = 93.0;
model.y_offset_ta = 42.4;
model.x_size_ta = 35.0;
model.y_size_ta = 230.0;
model.y_offset_sensor_to_ta = 0;
model.y_offset_calib_white_ta = 21.4;
model.y_size_calib_ta_mm = 1.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
model.ld_shift_g = 0;
model.ld_shift_b = 0;
model.ld_shift_g = 32;
model.ld_shift_b = 64;
model.line_mode_color_order = ColorOrder::RGB;
model.is_cis = true;
model.is_cis = false;
model.is_sheetfed = false;
model.sensor_id = SensorId::CIS_CANON_LIDE_200;
model.adc_id = AdcId::CANON_LIDE_200;
model.gpio_id = GpioId::CANON_LIDE_200;
model.motor_id = MotorId::CANON_LIDE_200;
model.flags = ModelFlag::UNTESTED |
ModelFlag::SKIP_WARMUP |
ModelFlag::SIS_SENSOR |
model.sensor_id = SensorId::CCD_CANON_5600F;
model.adc_id = AdcId::CANON_5600F;
model.gpio_id = GpioId::CANON_5600F;
model.motor_id = MotorId::CANON_5600F;
model.flags = ModelFlag::SIS_SENSOR |
ModelFlag::INVERT_PIXEL_DATA |
ModelFlag::DISABLE_ADC_CALIBRATION |
ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::UTA_NO_SECONDARY_MOTOR |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
@ -963,9 +964,10 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
// FIXME: support 2400 ad 4800 dpi
{ ScanMethod::FLATBED },
{ 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 },
{ 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 },
{ 1200, 600, 300, 200, 150, 100, 75 },
{ 1200, 600, 300, 200, 150, 100, 75 },
}
};
@ -977,7 +979,7 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 297.0;
model.y_offset_calib_white = 1.0;
model.y_offset_calib_white = 0.4233334;
model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
model.x_size_calib_mm = 219.6254;
@ -997,8 +999,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_700F;
model.gpio_id = GpioId::CANON_LIDE_700F;
model.motor_id = MotorId::CANON_LIDE_700;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::SIS_SENSOR |
model.flags = ModelFlag::SIS_SENSOR |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
@ -1034,7 +1035,7 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 299.0;
model.y_offset_calib_white = 0.0;
model.y_offset_calib_white = 0.4233334;
model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
model.x_size_calib_mm = 217.4241;
@ -1053,8 +1054,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_200;
model.gpio_id = GpioId::CANON_LIDE_200;
model.motor_id = MotorId::CANON_LIDE_200;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::SIS_SENSOR |
model.flags = ModelFlag::SIS_SENSOR |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::CUSTOM_GAMMA;
@ -1107,12 +1107,11 @@ void genesys_init_usb_device_tables()
model.is_cis = true;
model.is_sheetfed = false;
model.sensor_id = SensorId::CIS_CANON_LIDE_35;
model.sensor_id = SensorId::CIS_CANON_LIDE_60;
model.adc_id = AdcId::CANON_LIDE_35;
model.gpio_id = GpioId::CANON_LIDE_35;
model.motor_id = MotorId::CANON_LIDE_35;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_WHITE_CALIBRATION |
model.motor_id = MotorId::CANON_LIDE_60;
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
@ -1167,8 +1166,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_80;
model.gpio_id = GpioId::CANON_LIDE_80;
model.motor_id = MotorId::CANON_LIDE_80;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_WHITE_CALIBRATION |
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
@ -1210,8 +1208,8 @@ void genesys_init_usb_device_tables()
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 16;
model.ld_shift_g = 8;
model.ld_shift_r = 32;
model.ld_shift_g = 16;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@ -1222,7 +1220,6 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::HP2300;
model.motor_id = MotorId::HP2300;
model.flags = ModelFlag::GAMMA_14BIT |
ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW;
@ -1276,7 +1273,6 @@ void genesys_init_usb_device_tables()
model.motor_id = MotorId::HP2400;
model.flags = ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW;
model.search_lines = 132;
@ -1329,7 +1325,6 @@ void genesys_init_usb_device_tables()
model.motor_id = MotorId::XP200;
model.flags = ModelFlag::GAMMA_14BIT |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 132;
@ -1380,7 +1375,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_HP3670;
model.gpio_id = GpioId::HP3670;
model.motor_id = MotorId::HP3670;
model.flags = ModelFlag::GAMMA_14BIT |
model.flags = ModelFlag::WARMUP |
ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW;
@ -1520,8 +1516,8 @@ void genesys_init_usb_device_tables()
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 48;
model.ld_shift_g = 24;
model.ld_shift_r = 96;
model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@ -1531,7 +1527,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
model.flags = ModelFlag::GAMMA_14BIT |
model.flags = ModelFlag::WARMUP |
ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
@ -1586,8 +1583,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1637,8 +1633,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DP665;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1688,8 +1683,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1739,8 +1733,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::NO_CALIBRATION |
model.flags = ModelFlag::DISABLE_ADC_CALIBRATION |
ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
ModelFlag::DISABLE_SHADING_CALIBRATION |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW;
@ -1792,8 +1787,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1843,8 +1837,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DSMOBILE_600;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1895,8 +1888,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DSMOBILE_600;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1946,8 +1938,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP685;
model.motor_id = MotorId::XP300;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -1999,8 +1990,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -2048,12 +2038,11 @@ void genesys_init_usb_device_tables()
model.is_cis = true;
model.is_sheetfed = true;
model.sensor_id = SensorId::CCD_XP300;
model.sensor_id = SensorId::CCD_DOCKETPORT_487;
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION |
model.flags = ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
@ -2093,8 +2082,8 @@ void genesys_init_usb_device_tables()
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 48;
model.ld_shift_g = 24;
model.ld_shift_r = 96;
model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@ -2104,7 +2093,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
model.flags = ModelFlag::GAMMA_14BIT |
model.flags = ModelFlag::WARMUP |
ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
@ -2148,8 +2138,8 @@ void genesys_init_usb_device_tables()
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 48;
model.ld_shift_g = 24;
model.ld_shift_r = 96;
model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@ -2159,7 +2149,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
model.flags = ModelFlag::GAMMA_14BIT |
model.flags = ModelFlag::WARMUP |
ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
@ -2215,8 +2206,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
model.search_lines = 400;
@ -2269,7 +2259,6 @@ void genesys_init_usb_device_tables()
model.motor_id = MotorId::PLUSTEK_OPTICPRO_3600;
model.flags = ModelFlag::UNTESTED | // not fully working yet
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_NO_BUTTONS;
model.search_lines = 200;
@ -2277,6 +2266,72 @@ void genesys_init_usb_device_tables()
s_usb_devices->emplace_back(0x07b3, 0x0900, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-7200";
model.vendor = "PLUSTEK";
model.model = "OpticFilm 7200";
model.model_id = ModelId::PLUSTEK_OPTICFILM_7200;
model.asic_type = AsicType::GL842;
model.resolutions = {
{
{ ScanMethod::TRANSPARENCY },
{ 7200, 3600, 1800, 900 },
{ 7200, 3600, 1800, 900 },
}
};
model.bpp_gray_values = { 16 };
model.bpp_color_values = { 16 };
model.default_method = ScanMethod::TRANSPARENCY;
model.x_offset = 0.0;
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
model.y_offset_calib_white = 0.0;
model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
model.x_size_calib_mm = 35.9834;
model.x_offset_ta = 0.7f;
model.y_offset_ta = 28.0;
model.x_size_ta = 36.0;
model.y_size_ta = 25.0;
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
model.y_size_calib_ta_mm = 2.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
model.ld_shift_g = 12;
model.ld_shift_b = 24;
model.line_mode_color_order = ColorOrder::RGB;
model.is_cis = false;
model.is_sheetfed = false;
model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200;
model.adc_id = AdcId::PLUSTEK_OPTICFILM_7200;
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200;
model.flags = ModelFlag::WARMUP |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0807, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-7200i";
model.vendor = "PLUSTEK";
@ -2333,16 +2388,29 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200I;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I;
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK |
ModelFlag::INVERTED_16BIT_DATA;
ModelFlag::SWAP_16BIT_DATA;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0c04, model);
// same as 7200i, just without the infrared channel
model.name = "plustek-opticfilm-7200-v2";
model.model = "OpticFilm 7200 v2";
model.resolutions = {
{
{ ScanMethod::TRANSPARENCY },
{ 7200, 3600, 1800, 900 },
{ 7200, 3600, 1800, 900 },
}
};
s_usb_devices->emplace_back(0x07b3, 0x0c07, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-7300";
model.vendor = "PLUSTEK";
@ -2399,8 +2467,8 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7300;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7300;
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK;
@ -2408,6 +2476,82 @@ void genesys_init_usb_device_tables()
s_usb_devices->emplace_back(0x07b3, 0x0c12, model);
// same as 7300, same USB ID as 7400-v2
model.name = "plustek-opticfilm-7400-v1";
model.model = "OpticFilm 7400 (v1)";
s_usb_devices->emplace_back(0x07b3, 0x0c3a, 0x0400, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-7400-v2";
model.vendor = "PLUSTEK";
model.model = "OpticFilm 7400 (v2)";
model.model_id = ModelId::PLUSTEK_OPTICFILM_7400;
model.asic_type = AsicType::GL845;
model.resolutions = {
{
{ ScanMethod::TRANSPARENCY },
{ 7200, 3600, 2400, 1200, 600 },
{ 7200, 3600, 2400, 1200, 600 },
}
};
model.bpp_gray_values = { 16 };
model.bpp_color_values = { 16 };
model.default_method = ScanMethod::TRANSPARENCY;
model.x_offset = 0.0;
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
model.y_offset_calib_white = 0.0;
model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
model.x_size_calib_mm = 36.83;
model.x_offset_ta = 0.5;
model.y_offset_ta = 29.0;
model.x_size_ta = 36.33;
model.y_size_ta = 25.0;
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
model.y_size_calib_ta_mm = 2.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
model.ld_shift_g = 12;
model.ld_shift_b = 24;
model.line_mode_color_order = ColorOrder::RGB;
model.is_cis = false;
model.is_sheetfed = false;
model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7400;
model.adc_id = AdcId::PLUSTEK_OPTICFILM_7400;
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7400;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7400;
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0c3a, 0x0605, model);
// same as 7400-v2
model.name = "plustek-opticfilm-8100";
model.model = "OpticFilm 8100";
s_usb_devices->emplace_back(0x07b3, 0x130c, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-7500i";
model.vendor = "PLUSTEK";
@ -2464,8 +2608,8 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7500I;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I;
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
model.flags = ModelFlag::WARMUP |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK;
@ -2473,6 +2617,82 @@ void genesys_init_usb_device_tables()
s_usb_devices->emplace_back(0x07b3, 0x0c13, model);
// same as 7500i
model.name = "plustek-opticfilm-7600i-v1";
model.model = "OpticFilm 7600i (v1)";
s_usb_devices->emplace_back(0x07b3, 0x0c3b, 0x0400, model);
model = Genesys_Model();
model.name = "plustek-opticfilm-8200i";
model.vendor = "PLUSTEK";
model.model = "OpticFilm 8200i";
model.model_id = ModelId::PLUSTEK_OPTICFILM_8200I;
model.asic_type = AsicType::GL845;
model.resolutions = {
{
{ ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED },
{ 7200, 3600, 1800, 900 },
{ 7200, 3600, 1800, 900 },
}
};
model.bpp_gray_values = { 16 };
model.bpp_color_values = { 16 };
model.default_method = ScanMethod::TRANSPARENCY;
model.x_offset = 0.0;
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
model.y_offset_calib_white = 0.0;
model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
model.x_size_calib_mm = 36.83;
model.x_offset_ta = 0.5;
model.y_offset_ta = 28.5;
model.x_size_ta = 36.33;
model.y_size_ta = 25.0;
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
model.y_size_calib_ta_mm = 2.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
model.ld_shift_g = 12;
model.ld_shift_b = 24;
model.line_mode_color_order = ColorOrder::RGB;
model.is_cis = false;
model.is_sheetfed = false;
model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_8200I;
model.adc_id = AdcId::PLUSTEK_OPTICFILM_8200I;
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_8200I;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_8200I;
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::DARK_CALIBRATION |
ModelFlag::SHADING_REPARK;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x130d, model);
// same as 8200i
model.name = "plustek-opticfilm-7600i-v2";
model.model = "OpticFilm 7600i (v2)";
s_usb_devices->emplace_back(0x07b3, 0x0c3b, 0x0605, model);
model = Genesys_Model();
model.name = "hewlett-packard-scanjet-N6310";
model.vendor = "Hewlett Packard";
@ -2520,8 +2740,9 @@ void genesys_init_usb_device_tables()
ModelFlag::GAMMA_14BIT |
ModelFlag::DARK_CALIBRATION |
ModelFlag::CUSTOM_GAMMA |
ModelFlag::SKIP_WARMUP |
ModelFlag::NO_CALIBRATION;
ModelFlag::DISABLE_ADC_CALIBRATION |
ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
ModelFlag::DISABLE_SHADING_CALIBRATION;
model.buttons = GENESYS_HAS_NO_BUTTONS;
model.search_lines = 100;
@ -2572,8 +2793,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::PLUSTEK_OPTICBOOK_3800;
model.gpio_id = GpioId::PLUSTEK_OPTICBOOK_3800;
model.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA;
model.flags = ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_NO_BUTTONS; // TODO there are 4 buttons to support
model.search_lines = 100;
@ -2623,8 +2843,7 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::IMG101;
model.gpio_id = GpioId::IMG101;
model.motor_id = MotorId::IMG101;
model.flags = ModelFlag::SKIP_WARMUP |
ModelFlag::CUSTOM_GAMMA |
model.flags = ModelFlag::CUSTOM_GAMMA |
ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_NO_BUTTONS ;
model.search_lines = 100;
@ -2635,7 +2854,7 @@ void genesys_init_usb_device_tables()
void verify_usb_device_tables()
{
for (const auto& device : *s_usb_devices) {
const auto& model = device.model;
const auto& model = device.model();
if (model.x_size_calib_mm == 0.0f) {
throw SaneException("Calibration width can't be zero");

Wyświetl plik

@ -57,8 +57,7 @@ void genesys_init_motor_tables()
Genesys_Motor motor;
motor.id = MotorId::UMAX;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.base_ydpi = 2400;
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -66,8 +65,7 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::MD_5345; // MD5345/6228/6471
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.base_ydpi = 2400;
motor.profiles.push_back({MotorSlope::create_from_steps(2000, 1375, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(2000, 1375, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -76,7 +74,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::ST24;
motor.base_ydpi = 2400;
motor.optical_ydpi = 2400;
motor.profiles.push_back({MotorSlope::create_from_steps(2289, 2100, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(2289, 2100, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -85,7 +82,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::HP3670;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -94,7 +90,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::HP2400;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 3000, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -102,8 +97,7 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::HP2300;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.base_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(3200, 1200, 128), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3200, 1200, 128), StepType::HALF, 0});
s_motors->push_back(std::move(motor));
@ -112,62 +106,127 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_35;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1400, 60), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1300, 150), StepType::HALF, 0};
profile.resolutions = { 75, 150, 200, 300, 600 };
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1300, 150), StepType::QUARTER, 0};
profile.resolutions = { 1200, 2400 };
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1400, 150), StepType::FULL, 0};
profile.resolutions = { 75, 150, 200, 300 };
motor.fast_profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(6000, 3000, 100), StepType::FULL, 0};
profile.resolutions = { 600, 1200, 2400 };
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_60;
motor.base_ydpi = 1200;
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1400, 150), StepType::HALF, 0};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1400, 150), StepType::FULL, 0};
profile.resolutions = { 75, 150, 300 };
motor.fast_profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(6000, 3000, 100), StepType::FULL, 0};
profile.resolutions = { 600, 1200, 2400 };
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::XP200;
motor.base_ydpi = 600;
motor.optical_ydpi = 600;
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::HALF, 0});
motor.fast_profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::XP300;
motor.base_ydpi = 300;
motor.optical_ydpi = 600;
// works best with GPIO10, GPIO14 off
motor.profiles.push_back({MotorSlope::create_from_steps(3700, 3700, 2), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(3700, 3700, 2), StepType::FULL, 0};
profile.resolutions = {}; // used during fast moves
motor.profiles.push_back(profile);
// FIXME: this motor profile is useless
profile = MotorProfile{MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0};
profile.resolutions = {75, 150, 300, 600};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3700, 3700, 2), StepType::FULL, 0};
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::DP665;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.profiles.push_back({MotorSlope::create_from_steps(3000, 2500, 10), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(3000, 2500, 10), StepType::FULL, 0};
profile.resolutions = {75, 150};
motor.profiles.push_back(profile);
// FIXME: this motor profile is useless
profile = MotorProfile{MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0};
profile.resolutions = {300, 600, 1200};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3000, 2500, 10), StepType::FULL, 0};
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::ROADWARRIOR;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.profiles.push_back({MotorSlope::create_from_steps(3000, 2600, 10), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(3000, 2600, 10), StepType::FULL, 0};
profile.resolutions = {75, 150};
motor.profiles.push_back(profile);
// FIXME: this motor profile is useless
profile = MotorProfile{MotorSlope::create_from_steps(11000, 11000, 2), StepType::HALF, 0};
profile.resolutions = {300, 600, 1200};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3000, 2600, 10), StepType::FULL, 0};
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::DSMOBILE_600;
motor.base_ydpi = 750;
motor.optical_ydpi = 1500;
motor.profiles.push_back({MotorSlope::create_from_steps(6666, 3700, 8), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(6666, 3700, 8), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(6666, 3700, 8), StepType::FULL, 0};
profile.resolutions = {75, 150};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(6666, 3700, 8), StepType::HALF, 0};
profile.resolutions = {300, 600, 1200};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(6666, 3700, 8), StepType::FULL, 0};
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_100;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 255),
StepType::HALF, 1432});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 279),
@ -180,7 +239,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_200;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 255),
StepType::HALF, 1432});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 864, 279),
@ -195,7 +253,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_700;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
StepType::HALF, 1424});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
@ -212,7 +269,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::KVSS080;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(44444, 500, 489),
StepType::HALF, 8000});
s_motors->push_back(std::move(motor));
@ -221,7 +277,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::G4050;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.profiles.push_back({MotorSlope::create_from_steps(7842, 320, 602),
StepType::HALF, 8016});
motor.profiles.push_back({MotorSlope::create_from_steps(9422, 254, 1004),
@ -236,7 +291,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_4400F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 727 * 2, 200);
@ -261,16 +315,43 @@ void genesys_init_motor_tables()
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_5600F;
motor.base_ydpi = 2400;
// FIXME: real limit is 134, but for some reason the motor can't acquire that speed.
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(2500 * 2, 134 * 2, 1000);
profile.step_type = StepType::HALF;
profile.motor_vref = 0;
profile.resolutions = { 75, 150 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(2500 * 2, 200 * 2, 1000);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = { 300, 600, 1200, 2400, 4800 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(2500 * 2, 200 * 2, 1000);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_8400F;
motor.base_ydpi = 1600;
motor.optical_ydpi = 6400;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(20202 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = ResolutionFilter::ANY;
profile.resolutions = VALUE_FILTER_ANY;
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
@ -278,7 +359,7 @@ void genesys_init_motor_tables()
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = ResolutionFilter::ANY;
profile.resolutions = VALUE_FILTER_ANY;
profile.scan_methods = { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
@ -286,8 +367,8 @@ void genesys_init_motor_tables()
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = ResolutionFilter::ANY;
profile.scan_methods = ScanMethodFilter::ANY;
profile.resolutions = VALUE_FILTER_ANY;
profile.scan_methods = VALUE_FILTER_ANY;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
@ -296,7 +377,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_8600F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
@ -361,7 +441,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_110;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 255),
StepType::FULL, 2768});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 469),
@ -376,7 +455,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_120;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 864, 127),
StepType::FULL, 4608});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2010, 63),
@ -391,7 +469,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_210;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 255),
StepType::FULL, 2768});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 335, 469),
@ -400,22 +477,45 @@ void genesys_init_motor_tables()
StepType::HALF, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 10432, 4),
StepType::QUARTER, 20864});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 10432, 4),
StepType::EIGHTH, 41536});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICPRO_3600;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0});
motor.profiles.push_back({MotorSlope::create_from_steps(3500, 3250, 60), StepType::HALF, 0});
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0};
profile.resolutions = {75, 100, 150, 200};
motor.profiles.push_back(profile);
// FIXME: this motor profile is almost useless
profile = MotorProfile{MotorSlope::create_from_steps(3500, 3250, 60), StepType::HALF, 0};
profile.resolutions = {300, 400, 600, 1200};
motor.profiles.push_back(profile);
profile = MotorProfile{MotorSlope::create_from_steps(3500, 1300, 60), StepType::FULL, 0};
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_7200;
motor.base_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(20000 * 2, 600 * 2, 200);
profile.step_type = StepType::HALF;
profile.motor_vref = 0;
motor.profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_7200I;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(34722 * 2, 454 * 2, 40);
@ -435,7 +535,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_7300;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
@ -452,10 +551,22 @@ void genesys_init_motor_tables()
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_7400;
motor.base_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(64102 * 4, 400 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(profile);
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_7500I;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
@ -472,10 +583,22 @@ void genesys_init_motor_tables()
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICFILM_8200I;
motor.base_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(64102 * 4, 400 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(profile);
motor.fast_profiles.push_back(profile);
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::IMG101;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
@ -484,7 +607,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICBOOK_3800;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
@ -493,7 +615,6 @@ void genesys_init_motor_tables()
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_80;
motor.base_ydpi = 2400;
motor.optical_ydpi = 4800; // 9600
motor.profiles.push_back({MotorSlope::create_from_steps(9560, 1912, 31), StepType::FULL, 0});
s_motors->push_back(std::move(motor));
}

Wyświetl plik

@ -49,7 +49,10 @@
namespace genesys {
TestScannerInterface::TestScannerInterface(Genesys_Device* dev) : dev_{dev}
TestScannerInterface::TestScannerInterface(Genesys_Device* dev, uint16_t vendor_id,
uint16_t product_id, uint16_t bcd_device) :
dev_{dev},
usb_dev_{vendor_id, product_id, bcd_device}
{
// initialize status registers
if (dev_->model->asic_type == AsicType::GL124) {
@ -58,6 +61,7 @@ TestScannerInterface::TestScannerInterface(Genesys_Device* dev) : dev_{dev}
write_register(0x41, 0x00);
}
if (dev_->model->asic_type == AsicType::GL841 ||
dev_->model->asic_type == AsicType::GL842 ||
dev_->model->asic_type == AsicType::GL843 ||
dev_->model->asic_type == AsicType::GL845 ||
dev_->model->asic_type == AsicType::GL846 ||

Wyświetl plik

@ -56,7 +56,8 @@ namespace genesys {
class TestScannerInterface : public ScannerInterface
{
public:
TestScannerInterface(Genesys_Device* dev);
TestScannerInterface(Genesys_Device* dev, std::uint16_t vendor_id, std::uint16_t product_id,
std::uint16_t bcd_device);
~TestScannerInterface() override;

Wyświetl plik

@ -52,6 +52,7 @@ namespace {
bool s_testing_mode = false;
std::uint16_t s_vendor_id = 0;
std::uint16_t s_product_id = 0;
std::uint16_t s_bcd_device = 0;
TestCheckpointCallback s_checkpoint_callback;
} // namespace
@ -66,15 +67,17 @@ void disable_testing_mode()
s_testing_mode = false;
s_vendor_id = 0;
s_product_id = 0;
s_bcd_device = 0;
}
void enable_testing_mode(std::uint16_t vendor_id, std::uint16_t product_id,
std::uint16_t bcd_device,
TestCheckpointCallback checkpoint_callback)
{
s_testing_mode = true;
s_vendor_id = vendor_id;
s_product_id = product_id;
s_bcd_device = bcd_device;
s_checkpoint_callback = checkpoint_callback;
}
@ -88,6 +91,11 @@ std::uint16_t get_testing_product_id()
return s_product_id;
}
std::uint16_t get_testing_bcd_device()
{
return s_bcd_device;
}
std::string get_testing_device_name()
{
std::string name;

Wyświetl plik

@ -58,9 +58,11 @@ using TestCheckpointCallback = std::function<void(const Genesys_Device&,
bool is_testing_mode();
void disable_testing_mode();
void enable_testing_mode(std::uint16_t vendor_id, std::uint16_t product_id,
std::uint16_t bcd_device,
TestCheckpointCallback checkpoint_callback);
std::uint16_t get_testing_vendor_id();
std::uint16_t get_testing_product_id();
std::uint16_t get_testing_bcd_device();
std::string get_testing_device_name();
TestCheckpointCallback get_testing_checkpoint_callback();

Wyświetl plik

@ -48,9 +48,11 @@
namespace genesys {
TestUsbDevice::TestUsbDevice(std::uint16_t vendor, std::uint16_t product) :
TestUsbDevice::TestUsbDevice(std::uint16_t vendor, std::uint16_t product,
std::uint16_t bcd_device) :
vendor_{vendor},
product_{product}
product_{product},
bcd_device_{bcd_device}
{
}
@ -94,12 +96,25 @@ void TestUsbDevice::close()
name_ = "";
}
void TestUsbDevice::get_vendor_product(int& vendor, int& product)
std::uint16_t TestUsbDevice::get_vendor_id()
{
DBG_HELPER(dbg);
assert_is_open();
vendor = vendor_;
product = product_;
return vendor_;
}
std::uint16_t TestUsbDevice::get_product_id()
{
DBG_HELPER(dbg);
assert_is_open();
return product_;
}
std::uint16_t TestUsbDevice::get_bcd_device()
{
DBG_HELPER(dbg);
assert_is_open();
return bcd_device_;
}
void TestUsbDevice::control_msg(int rtype, int reg, int value, int index, int length,

Wyświetl plik

@ -50,9 +50,7 @@ namespace genesys {
class TestUsbDevice : public IUsbDevice {
public:
TestUsbDevice(std::uint16_t vendor, std::uint16_t product);
TestUsbDevice() = default;
TestUsbDevice(std::uint16_t vendor, std::uint16_t product, std::uint16_t bcd_device);
~TestUsbDevice() override;
bool is_open() const override { return is_open_; }
@ -65,7 +63,9 @@ public:
void reset() override;
void close() override;
void get_vendor_product(int& vendor, int& product) override;
std::uint16_t get_vendor_id() override;
std::uint16_t get_product_id() override;
std::uint16_t get_bcd_device() override;
void control_msg(int rtype, int reg, int value, int index, int length,
std::uint8_t* data) override;
@ -78,6 +78,7 @@ private:
bool is_open_ = false;
std::uint16_t vendor_ = 0;
std::uint16_t product_ = 0;
std::uint16_t bcd_device_ = 0;
};
} // namespace genesys

Wyświetl plik

@ -101,11 +101,33 @@ void UsbDevice::close()
sanei_usb_close(device_num);
}
void UsbDevice::get_vendor_product(int& vendor, int& product)
std::uint16_t UsbDevice::get_vendor_id()
{
DBG_HELPER(dbg);
assert_is_open();
int vendor = 0;
int product = 0;
TIE(sanei_usb_get_vendor_product(device_num_, &vendor, &product));
return static_cast<std::uint16_t>(vendor);
}
std::uint16_t UsbDevice::get_product_id()
{
DBG_HELPER(dbg);
assert_is_open();
int vendor = 0;
int product = 0;
TIE(sanei_usb_get_vendor_product(device_num_, &vendor, &product));
return static_cast<std::uint16_t>(product);
}
std::uint16_t UsbDevice::get_bcd_device()
{
DBG_HELPER(dbg);
assert_is_open();
sanei_usb_dev_descriptor desc;
TIE(sanei_usb_get_descriptor(device_num_, &desc));
return desc.bcd_dev;
}
void UsbDevice::control_msg(int rtype, int reg, int value, int index, int length,

Wyświetl plik

@ -71,7 +71,9 @@ public:
virtual void reset() = 0;
virtual void close() = 0;
virtual void get_vendor_product(int& vendor, int& product) = 0;
virtual std::uint16_t get_vendor_id() = 0;
virtual std::uint16_t get_product_id() = 0;
virtual std::uint16_t get_bcd_device() = 0;
virtual void control_msg(int rtype, int reg, int value, int index, int length,
std::uint8_t* data) = 0;
@ -96,7 +98,9 @@ public:
void reset() override;
void close() override;
void get_vendor_product(int& vendor, int& product) override;
std::uint16_t get_vendor_id() override;
std::uint16_t get_product_id() override;
std::uint16_t get_bcd_device() override;
void control_msg(int rtype, int reg, int value, int index, int length,
std::uint8_t* data) override;

Wyświetl plik

@ -46,6 +46,7 @@
#include "error.h"
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <vector>
@ -75,6 +76,51 @@ inline double fixed_to_double(SANE_Word v)
return static_cast<double>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
}
template<class T>
inline T abs_diff(T a, T b)
{
if (a < b) {
return b - a;
} else {
return a - b;
}
}
inline std::uint64_t align_multiple_floor(std::uint64_t x, std::uint64_t multiple)
{
if (multiple == 0) {
return x;
}
return (x / multiple) * multiple;
}
inline std::uint64_t align_multiple_ceil(std::uint64_t x, std::uint64_t multiple)
{
if (multiple == 0) {
return x;
}
return ((x + multiple - 1) / multiple) * multiple;
}
inline std::uint64_t multiply_by_depth_ceil(std::uint64_t pixels, std::uint64_t depth)
{
if (depth == 1) {
return (pixels / 8) + ((pixels % 8) ? 1 : 0);
} else {
return pixels * (depth / 8);
}
}
template<class T>
inline T clamp(const T& value, const T& lo, const T& hi)
{
if (value < lo)
return lo;
if (value > hi)
return hi;
return value;
}
template<class T>
void compute_array_percentile_approx(T* result, const T* data,
std::size_t line_count, std::size_t elements_per_line,
@ -108,6 +154,75 @@ void compute_array_percentile_approx(T* result, const T* data,
}
}
class Ratio
{
public:
Ratio() : multiplier_{1}, divisor_{1}
{
}
Ratio(unsigned multiplier, unsigned divisor) : multiplier_{multiplier}, divisor_{divisor}
{
}
unsigned multiplier() const { return multiplier_; }
unsigned divisor() const { return divisor_; }
unsigned apply(unsigned arg) const
{
return static_cast<std::uint64_t>(arg) * multiplier_ / divisor_;
}
int apply(int arg) const
{
return static_cast<std::int64_t>(arg) * multiplier_ / divisor_;
}
float apply(float arg) const
{
return arg * multiplier_ / divisor_;
}
unsigned apply_inverse(unsigned arg) const
{
return static_cast<std::uint64_t>(arg) * divisor_ / multiplier_;
}
int apply_inverse(int arg) const
{
return static_cast<std::int64_t>(arg) * divisor_ / multiplier_;
}
float apply_inverse(float arg) const
{
return arg * divisor_ / multiplier_;
}
bool operator==(const Ratio& other) const
{
return multiplier_ == other.multiplier_ && divisor_ == other.divisor_;
}
private:
unsigned multiplier_;
unsigned divisor_;
template<class Stream>
friend void serialize(Stream& str, Ratio& x);
};
template<class Stream>
void serialize(Stream& str, Ratio& x)
{
serialize(str, x.multiplier_);
serialize(str, x.divisor_);
}
inline std::ostream& operator<<(std::ostream& out, const Ratio& ratio)
{
out << ratio.multiplier() << "/" << ratio.divisor();
return out;
}
template<class Char, class Traits>
class BasicStreamStateSaver
{

Wyświetl plik

@ -0,0 +1,140 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
*/
#ifndef BACKEND_GENESYS_VALUE_FILTER_H
#define BACKEND_GENESYS_VALUE_FILTER_H
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <vector>
namespace genesys {
struct AnyTag {};
constexpr AnyTag VALUE_FILTER_ANY{};
template<class T>
class ValueFilterAny
{
public:
ValueFilterAny() : matches_any_{false} {}
ValueFilterAny(AnyTag) : matches_any_{true} {}
ValueFilterAny(std::initializer_list<T> values) :
matches_any_{false},
values_{values}
{}
bool matches(T value) const
{
if (matches_any_)
return true;
auto it = std::find(values_.begin(), values_.end(), value);
return it != values_.end();
}
bool operator==(const ValueFilterAny& other) const
{
return matches_any_ == other.matches_any_ && values_ == other.values_;
}
bool matches_any() const { return matches_any_; }
const std::vector<T>& values() const { return values_; }
private:
bool matches_any_ = false;
std::vector<T> values_;
template<class Stream, class U>
friend void serialize(Stream& str, ValueFilterAny<U>& x);
};
template<class T>
std::ostream& operator<<(std::ostream& out, const ValueFilterAny<T>& values)
{
if (values.matches_any()) {
out << "ANY";
return out;
}
out << format_vector_indent_braced(4, "", values.values());
return out;
}
template<class Stream, class T>
void serialize(Stream& str, ValueFilterAny<T>& x)
{
serialize(str, x.matches_any_);
serialize_newline(str);
serialize(str, x.values_);
}
template<class T>
class ValueFilter
{
public:
ValueFilter() = default;
ValueFilter(std::initializer_list<T> values) :
values_{values}
{}
bool matches(T value) const
{
auto it = std::find(values_.begin(), values_.end(), value);
return it != values_.end();
}
bool operator==(const ValueFilter& other) const
{
return values_ == other.values_;
}
const std::vector<T>& values() const { return values_; }
private:
std::vector<T> values_;
template<class Stream, class U>
friend void serialize(Stream& str, ValueFilter<U>& x);
};
template<class T>
std::ostream& operator<<(std::ostream& out, const ValueFilter<T>& values)
{
if (values.values().empty()) {
out << "(none)";
return out;
}
out << format_vector_indent_braced(4, "", values.values());
return out;
}
template<class Stream, class T>
void serialize(Stream& str, ValueFilter<T>& x)
{
serialize_newline(str);
serialize(str, x.values_);
}
} // namespace genesys
#endif // BACKEND_GENESYS_VALUE_FILTER_H

Wyświetl plik

@ -1,5 +1,5 @@
# gt68xx.conf: Configuration file for GT68XX based scanners (@PACKAGEVERSION@)
# gt68xx.conf: Configuration file for GT68XX based scanners
# Read man sane-gt68xx for documentation
# Put the firmware file into "@DATADIR@/sane/gt68xx/".

Wyświetl plik

@ -97,7 +97,7 @@ gt68xx_calibrator_new (SANE_Int width,
cal->white_line = (double *) malloc (width * sizeof (double));
cal->black_line = (double *) malloc (width * sizeof (double));
if (!cal->k_white || !cal->k_black | !cal->white_line || !cal->black_line)
if (!cal->k_white || !cal->k_black || !cal->white_line || !cal->black_line)
{
DBG (5, "gt68xx_calibrator_new: no memory for calibration data\n");
gt68xx_calibrator_free (cal);

Some files were not shown because too many files have changed in this diff Show More