Merge branch 'master' into 'release/1.0.30'

# Conflicts:
#   NEWS
merge-requests/457/head
Olaf Meeuwissen 2020-05-18 12:08:28 +00:00
commit bfea8a1a82
186 zmienionych plików z 19177 dodań i 18996 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"
CONFIGURE_FULL: "--with-usb --with-avahi --enable-pnm-backend --with-libcurl --with-poppler-glib"
stages:
- tarball
@ -76,8 +76,8 @@ 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
@ -88,6 +88,13 @@ alpine-3.11-musl:
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

@ -1,7 +1,3 @@
Authors of the SANE standard:
Andreas Beck and David Mosberger
Backends:
abaton: David Huggins-Daines
@ -17,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

@ -24,6 +24,8 @@ $ make install
- libpng-dev or similar
- 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:

Wyświetl plik

@ -30,6 +30,9 @@ terms:
to implement SANE interface conforming applications or libraries in
any way he or she sees fit.
The standard is maintained at https://gitlab.com/sane-project/standard
and published at https://sane-project.gitlab.io/standard/.
Frequently Asked Questions about the SANE licensing:
* Why don't you use the GNU LPGL ?

21
NEWS
Wyświetl plik

@ -1,5 +1,26 @@
<!-- -*- Mode: markdown -*- -->
## New with the next release
### Backends
- adds an `canon_lide70` backend
### Documentation
- removes the SANE Standard. This is now maintained as a separate
project at https://gitlab.com/sane-project/standard. HTML and PDF
versions can be found at https://sane-project.gitlab.io/standard/.
### 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.

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
@ -437,13 +451,26 @@ EXTRA_DIST += dmc.conf.in
if have_libavahi
if have_libcurl
if have_libxml2
libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c escl/escl_jpeg.c escl/escl_png.c escl/escl_tiff.c
libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libescl_la_SOURCES = escl/escl.c \
escl/escl_capabilities.c \
escl/escl_devices.c \
escl/escl.h \
escl/escl_newjob.c \
escl/escl_reset.c \
escl/escl_scan.c \
escl/escl_status.c \
escl/escl_jpeg.c \
escl/escl_png.c \
escl/escl_tiff.c \
escl/escl_pdf.c \
escl/escl_crop.c
libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(POPPLER_GLIB_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
nodist_libsane_escl_la_SOURCES = escl-s.c
libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(POPPLER_GLIB_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_CFLAGS = $(AM_CFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(POPPLER_GLIB_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl
libsane_escl_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS)
libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(MATH_LIB) $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) $(POPPLER_GLIB_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS)
endif
endif
endif
@ -504,6 +531,7 @@ 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 \
@ -512,6 +540,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 \
@ -532,15 +561,16 @@ 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_motor_profile.cpp \
genesys/tables_sensor.cpp \
genesys/test_scanner_interface.h genesys/test_scanner_interface.cpp \
genesys/test_settings.h genesys/test_settings.cpp \
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
@ -682,10 +712,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
@ -904,12 +934,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

Wyświetl plik

@ -4088,6 +4088,8 @@ get_double ( &(result[48] ) ));
dev->inquiry_button_control = BIT (result[50], 6) | BIT (result[51],2);
dev->inquiry_exposure_control = BIT(result[51],7);
if (dev->scanner_type != AV_FILM && !(dev->hw->feature_type & AV_FORCE_FILM))
dev->inquiry_exposure_control = 0;
dev->inquiry_max_shading_target = get_double ( &(result[75]) );
dev->inquiry_color_boundary = result[54];
@ -6221,7 +6223,12 @@ do_cancel (Avision_Scanner* s)
s->prepared = s->scanning = SANE_FALSE;
s->duplex_rear_valid = SANE_FALSE;
s->page = 0;
s->cancelled = 1;
s->cancelled = SANE_TRUE;
if (s->read_fds >= 0) {
close(s->read_fds);
s->read_fds = -1;
}
if (sanei_thread_is_valid (s->reader_pid)) {
int exit_status;
@ -6716,6 +6723,7 @@ reader_process (void *data)
sigset_t sigterm_set;
sigset_t ignore_set;
struct SIGACTION act;
int old;
FILE* fp;
FILE* rear_fp = 0; /* used to store the deinterlaced rear data */
@ -6757,21 +6765,30 @@ reader_process (void *data)
DBG (3, "reader_process:\n");
if (sanei_thread_is_forked())
if (sanei_thread_is_forked()) {
close (s->read_fds);
s->read_fds = -1;
sigfillset (&ignore_set);
sigdelset (&ignore_set, SIGTERM);
sigfillset (&ignore_set);
sigdelset (&ignore_set, SIGTERM);
#if defined (__APPLE__) && defined (__MACH__)
sigdelset (&ignore_set, SIGUSR2);
sigdelset (&ignore_set, SIGUSR2);
#endif
sigprocmask (SIG_SETMASK, &ignore_set, 0);
sigprocmask (SIG_SETMASK, &ignore_set, 0);
memset (&act, 0, sizeof (act));
sigaction (SIGTERM, &act, 0);
memset (&act, 0, sizeof (act));
sigaction (SIGTERM, &act, 0);
sigemptyset (&sigterm_set);
sigaddset (&sigterm_set, SIGTERM);
sigemptyset (&sigterm_set);
sigaddset (&sigterm_set, SIGTERM);
}
#ifdef USE_PTHREAD
else {
int old;
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old);
pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old);
}
#endif
gray_mode = color_mode_is_shaded (s->c_mode);
@ -6958,9 +6975,22 @@ reader_process (void *data)
(u_long) processed_bytes, (u_long) total_size);
DBG (5, "reader_process: this_read: %lu\n", (u_long) this_read);
sigprocmask (SIG_BLOCK, &sigterm_set, 0);
if (sanei_thread_is_forked())
sigprocmask (SIG_BLOCK, &sigterm_set, 0);
#ifdef USE_PTHREAD
else
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old);
#endif
status = read_data (s, stripe_data + stripe_fill, &this_read);
sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
if (sanei_thread_is_forked())
sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
#ifdef USE_PTHREAD
else
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old);
#endif
/* only EOF on the second stripe, as otherwise the rear page
is shorter */
@ -8332,7 +8362,7 @@ sane_start (SANE_Handle handle)
return SANE_STATUS_DEVICE_BUSY;
/* Clear cancellation status */
s->cancelled = 0;
s->cancelled = SANE_FALSE;
/* Make sure we have a current parameter set. Some of the
parameters will be overwritten below, but that's OK. */
@ -8560,8 +8590,10 @@ sane_start (SANE_Handle handle)
DBG (3, "sane_start: starting thread\n");
s->reader_pid = sanei_thread_begin (reader_process, (void *) s);
if (sanei_thread_is_forked())
close (s->write_fds);
if (sanei_thread_is_forked()) {
close (s->write_fds);
s->write_fds = -1;
}
return SANE_STATUS_GOOD;

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

@ -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"

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

@ -43,6 +43,7 @@
#include "../include/sane/sane.h"
#include <stdio.h>
#include <math.h>
#ifndef BACKEND_NAME
#define BACKEND_NAME escl
@ -63,6 +64,14 @@
#define ESCL_CONFIG_FILE "escl.conf"
enum {
PLATEN = 0,
ADFSIMPLEX,
ADFDUPLEX
};
typedef struct {
int p1_0;
int p2_0;
@ -82,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;
@ -104,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;
@ -114,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 {
@ -148,24 +170,45 @@ enum
OPT_TL_Y,
OPT_BR_X,
OPT_BR_Y,
OPT_SCAN_SOURCE,
NUM_OPTIONS
};
#define PIXEL_TO_MM(pixels, dpi) SANE_FIX((double)pixels * 25.4 / (dpi))
#define MM_TO_PIXEL(millimeters, dpi) (SANE_Word)round(SANE_UNFIX(millimeters) * (dpi) / 25.4)
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 *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result);
void escl_scanner(SANE_String_Const name, char *result);
SANE_Status escl_device_add(int port_nb, const char *model_name,
char *ip_address, char *type);
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, const ESCL_Device *device,
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);
// JPEG
SANE_Status get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps);
SANE_Status get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps);
// PNG
SANE_Status get_PNG_data(capabilities_t *scanner, int *w, int *h, int *bps);
SANE_Status get_PNG_data(capabilities_t *scanner, int *width, int *height, int *bps);
// TIFF
SANE_Status get_TIFF_data(capabilities_t *scanner, int *w, int *h, int *bps);
SANE_Status get_TIFF_data(capabilities_t *scanner, int *width, int *height, int *bps);
// PDF
SANE_Status get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps);
#endif

Wyświetl plik

@ -45,7 +45,7 @@ struct cap
* \fn static SANE_String_Const convert_elements(SANE_String_Const str)
* \brief Function that converts the 'color modes' of the scanner (color/gray) to be understood by SANE.
*
* \return SANE_VALUE_SCAN_MODE_GRAY / SANE_VALUE_SCAN_MODE_COLOR ; NULL otherwise
* \return SANE_VALUE_SCAN_MODE_GRAY / SANE_VALUE_SCAN_MODE_COLOR / SANE_VALUE_SCAN_MODE_LINEART; NULL otherwise
*/
static SANE_String_Const
convert_elements(SANE_String_Const str)
@ -54,6 +54,10 @@ convert_elements(SANE_String_Const str)
return (SANE_VALUE_SCAN_MODE_GRAY);
else if (strcmp(str, "RGB24") == 0)
return (SANE_VALUE_SCAN_MODE_COLOR);
#if(defined HAVE_POPPLER_GLIB)
else if (strcmp(str, "BlackAndWhite1") == 0)
return (SANE_VALUE_SCAN_MODE_LINEART);
#endif
return (NULL);
}
@ -137,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;
@ -175,48 +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(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "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);
}
@ -230,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);
}
@ -275,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 ||
@ -294,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);
}
@ -305,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".
@ -327,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)
@ -346,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

@ -0,0 +1,102 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2020 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char *
escl_crop_surface(capabilities_t *scanner,
unsigned char *surface,
int w,
int h,
int bps,
int *width,
int *height)
{
double ratio = 1.0;
int x_off = 0, x = 0;
int real_w = 0;
int y_off = 0, y = 0;
int real_h = 0;
unsigned char *surface_crop = NULL;
DBG( 1, "Escl Image Crop\n");
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;
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);
*width = real_w;
*height = real_h;
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) {
DBG( 1, "Escl Crop : Surface_crop Memory allocation problem\n");
free(surface);
surface = NULL;
goto finish;
}
for (y = 0; y < real_h; y++)
{
for (x = 0; x < real_w; x++)
{
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);
surface = surface_crop;
}
// we don't need row pointers anymore
scanner->img_data = surface;
scanner->img_size = (int)(real_w * real_h * bps);
scanner->img_read = 0;
finish:
return 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;
@ -154,7 +153,7 @@ output_no_message(j_common_ptr __sane_unused__ cinfo)
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
get_JPEG_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
int start = 0;
struct jpeg_decompress_struct cinfo;
@ -162,6 +161,11 @@ get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
unsigned char *surface = NULL;
struct my_error_mgr jerr;
int lineSize = 0;
JDIMENSION x_off = 0;
JDIMENSION y_off = 0;
JDIMENSION w = 0;
JDIMENSION h = 0;
int pos = 0;
if (scanner->tmp == NULL)
return (SANE_STATUS_INVAL);
@ -174,6 +178,7 @@ get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
jpeg_destroy_decompress(&cinfo);
if (surface != NULL)
free(surface);
fseek(scanner->tmp, start, SEEK_SET);
DBG( 1, "Escl Jpeg : Error reading jpeg\n");
if (scanner->tmp) {
fclose(scanner->tmp);
@ -187,10 +192,42 @@ get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
cinfo.out_color_space = JCS_RGB;
cinfo.quantize_colors = FALSE;
jpeg_calc_output_dimensions(&cinfo);
surface = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
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->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);
fseek(scanner->tmp, start, SEEK_SET);
DBG( 1, "Escl Jpeg : Memory allocation problem\n");
if (scanner->tmp) {
fclose(scanner->tmp);
@ -198,17 +235,23 @@ get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
}
return (SANE_STATUS_NO_MEM);
}
lineSize = cinfo.output_width * cinfo.output_components;
jpeg_start_decompress(&cinfo);
while (cinfo.output_scanline < cinfo.output_height) {
rowptr[0] = (JSAMPROW)surface + (lineSize * cinfo.output_scanline);
if (x_off > 0 || w < cinfo.output_width)
jpeg_crop_scanline(&cinfo, &x_off, &w);
lineSize = w * cinfo.output_components;
if (y_off > 0)
jpeg_skip_scanlines(&cinfo, y_off);
pos = 0;
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++;
}
scanner->img_data = surface;
scanner->img_size = lineSize * cinfo.output_height;
scanner->img_size = lineSize * h;
scanner->img_read = 0;
*w = cinfo.output_width;
*h = cinfo.output_height;
*width = w;
*height = h;
*bps = cinfo.output_components;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
@ -220,8 +263,8 @@ get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps)
SANE_Status
get_JPEG_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *w,
int __sane_unused__ *h,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);

Wyświetl plik

@ -0,0 +1,256 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include "../include/sane/sanei.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if(defined HAVE_MUPDF)
#include <mupdf/fitz.h>
#endif
#include <setjmp.h>
#if(defined HAVE_MUPDF)
// TODO: WIN32: HANDLE CreateFileW(), etc.
// TODO: POSIX: int creat(), read(), write(), lseeko, etc.
typedef struct fz_file_stream_escl_s
{
FILE *file;
unsigned char buffer[4096];
} fz_file_stream_escl;
static int
next_file_escl(fz_context *ctx, fz_stream *stm, size_t n)
{
fz_file_stream_escl *state = stm->state;
/* n is only a hint, that we can safely ignore */
n = fread(state->buffer, 1, sizeof(state->buffer), state->file);
if (n < sizeof(state->buffer) && ferror(state->file))
fz_throw(ctx, FZ_ERROR_GENERIC, "read error: %s", strerror(errno));
stm->rp = state->buffer;
stm->wp = state->buffer + n;
stm->pos += (int64_t)n;
if (n == 0)
return EOF;
return *stm->rp++;
}
static void
drop_file_escl(fz_context *ctx, void *state_)
{
fz_file_stream_escl *state = state_;
int n = fclose(state->file);
if (n < 0)
fz_warn(ctx, "close error: %s", strerror(errno));
fz_free(ctx, state);
}
static void
seek_file_escl(fz_context *ctx, fz_stream *stm, int64_t offset, int whence)
{
fz_file_stream_escl *state = stm->state;
#ifdef _WIN32
int64_t n = _fseeki64(state->file, offset, whence);
#else
int64_t n = fseeko(state->file, offset, whence);
#endif
if (n < 0)
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot seek: %s", strerror(errno));
#ifdef _WIN32
stm->pos = _ftelli64(state->file);
#else
stm->pos = ftello(state->file);
#endif
stm->rp = state->buffer;
stm->wp = state->buffer;
}
static fz_stream *
fz_open_file_ptr_escl(fz_context *ctx, FILE *file)
{
fz_stream *stm;
fz_file_stream_escl *state = fz_malloc_struct(ctx, fz_file_stream_escl);
state->file = file;
stm = fz_new_stream(ctx, state, next_file_escl, drop_file_escl);
stm->seek = seek_file_escl;
return stm;
}
/**
* \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
* \brief Function that aims to decompress the pdf image to SANE be able
* to read the image.
* This function is called in the "sane_read" function.
*
* \return SANE_STATUS_GOOD (if everything is OK, otherwise,
* SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
int page_number = -1, page_count = -2;
fz_context *ctx;
fz_document *doc;
fz_pixmap *pix;
fz_matrix ctm;
fz_stream *stream;
unsigned char *surface = NULL; /* Image data */
SANE_Status status = SANE_STATUS_GOOD;
/* Create a context to hold the exception stack and various caches. */
ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
if (!ctx)
{
DBG(1, "cannot create mupdf context\n");
status = SANE_STATUS_INVAL;
goto close_file;
}
/* Register the default file types to handle. */
fz_try(ctx)
fz_register_document_handlers(ctx);
fz_catch(ctx)
{
DBG(1, "cannot register document handlers: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_context;
}
/* Open the stream. */
fz_try(ctx)
stream = fz_open_file_ptr_escl(ctx, scanner->tmp);
fz_catch(ctx)
{
DBG(1, "cannot open stream: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_context;
}
/* Seek stream. */
fz_try(ctx)
fz_seek(ctx, stream, 0, SEEK_SET);
fz_catch(ctx)
{
DBG(1, "cannot seek stream: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_stream;
}
/* Open the document. */
fz_try(ctx)
doc = fz_open_document_with_stream(ctx, "filename.pdf", stream);
fz_catch(ctx)
{
DBG(1, "cannot open document: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_stream;
}
/* Count the number of pages. */
fz_try(ctx)
page_count = fz_count_pages(ctx, doc);
fz_catch(ctx)
{
DBG(1, "cannot count number of pages: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_document;
}
if (page_number < 0 || page_number >= page_count)
{
DBG(1, "page number out of range: %d (page count %d)\n", page_number + 1, page_count);
status = SANE_STATUS_INVAL;
goto drop_document;
}
/* Compute a transformation matrix for the zoom and rotation desired. */
/* The default resolution without scaling is 72 dpi. */
fz_scale(&ctm, (float)1.0, (float)1.0);
fz_pre_rotate(&ctm, (float)0.0);
/* Render page to an RGB pixmap. */
fz_try(ctx)
pix = fz_new_pixmap_from_page_number(ctx, doc, 0, &ctm, fz_device_rgb(ctx), 0);
fz_catch(ctx)
{
DBG(1, "cannot render page: %s\n", fz_caught_message(ctx));
status = SANE_STATUS_INVAL;
goto drop_document;
}
surface = malloc(pix->h * pix->stride);
memcpy(surface, pix->samples, (pix->h * pix->stride));
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, pix->w, pix->h, pix->n, width, height);
if (!surface) {
DBG( 1, "Escl Pdf : Surface Memory allocation problem\n");
status = SANE_STATUS_NO_MEM;
goto drop_pix;
}
*bps = pix->n;
/* Clean up. */
drop_pix:
fz_drop_pixmap(ctx, pix);
drop_document:
fz_drop_document(ctx, doc);
drop_stream:
fz_drop_stream(ctx, stream);
drop_context:
fz_drop_context(ctx);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return status;
}
#else
SANE_Status
get_PDF_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);
}
#endif

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,64 +159,89 @@ 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 {
if (download->memory != NULL) {
if (strstr(download->memory, "Location:")) {
temporary = strrchr(download->memory, '/');
char *tmp_location = strstr(download->memory, "Location:");
if (tmp_location) {
temporary = strchr(tmp_location, '\r');
if (temporary == NULL)
temporary = strchr(tmp_location, '\n');
if (temporary != NULL) {
location = strchr(temporary, '\r');
if (location == NULL)
location = strchr(temporary, '\n');
else {
*location = '\0';
result = strdup(temporary);
}
DBG( 1, "Create NewJob : %s\n", result);
*temporary = '\0';
location = strrchr(tmp_location,'/');
if (location) {
result = strdup(location);
DBG( 1, "Create NewJob : %s\n", result);
*temporary = '\n';
}
}
if (result == NULL) {
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

@ -0,0 +1,223 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
This file is part of the SANE package.
SANE 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 3 of the License, or (at your
option) any later version.
SANE 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 sane; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
This file implements a SANE backend for eSCL scanners. */
#define DEBUG_DECLARE_ONLY
#include "../include/sane/config.h"
#include "escl.h"
#include "../include/sane/sanei.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <math.h>
#include <errno.h>
#if(defined HAVE_POPPLER_GLIB)
#include <poppler/glib/poppler.h>
#endif
#include <setjmp.h>
#if(defined HAVE_POPPLER_GLIB)
#define INPUT_BUFFER_SIZE 4096
static unsigned char*
set_file_in_buffer(FILE *fp, int *size)
{
char buffer[1024] = { 0 };
unsigned char *data = (unsigned char *)calloc(1, sizeof(char));
int nx = 0;
while(!feof(fp))
{
int n = fread(buffer,sizeof(char),1024,fp);
unsigned char *t = realloc(data, nx + n + 1);
if (t == NULL) {
DBG(10, "not enough memory (realloc returned NULL)");
free(data);
return NULL;
}
data = t;
memcpy(&(data[nx]), buffer, n);
nx = nx + n;
data[nx] = 0;
}
*size = nx;
return data;
}
static unsigned char *
cairo_surface_to_pixels (cairo_surface_t *surface, int bps)
{
int cairo_width, cairo_height, cairo_rowstride;
unsigned char *data, *dst, *cairo_data;
unsigned int *src;
int x, y;
cairo_width = cairo_image_surface_get_width (surface);
cairo_height = cairo_image_surface_get_height (surface);
cairo_rowstride = cairo_image_surface_get_stride (surface);
cairo_data = cairo_image_surface_get_data (surface);
data = (unsigned char*)calloc(1, sizeof(unsigned char) * (cairo_height * cairo_width * bps));
for (y = 0; y < cairo_height; y++)
{
src = (unsigned int *) (cairo_data + y * cairo_rowstride);
dst = data + y * (cairo_width * bps);
for (x = 0; x < cairo_width; x++)
{
dst[0] = (*src >> 16) & 0xff;
dst[1] = (*src >> 8) & 0xff;
dst[2] = (*src >> 0) & 0xff;
dst += bps;
src++;
}
}
return data;
}
SANE_Status
get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
cairo_surface_t *cairo_surface = NULL;
cairo_t *cr;
PopplerPage *page;
PopplerDocument *doc;
double dw, dh;
int w, h, size = 0;
char *data = NULL;
unsigned char* surface = NULL;
SANE_Status status = SANE_STATUS_GOOD;
data = (char*)set_file_in_buffer(scanner->tmp, &size);
if (!data) {
DBG(1, "Error : poppler_document_new_from_data");
status = SANE_STATUS_INVAL;
goto close_file;
}
doc = poppler_document_new_from_data(data,
size,
NULL,
NULL);
if (!doc) {
DBG(1, "Error : poppler_document_new_from_data");
status = SANE_STATUS_INVAL;
goto free_file;
}
page = poppler_document_get_page (doc, 0);
if (!page) {
DBG(1, "Error : poppler_document_get_page");
status = SANE_STATUS_INVAL;
goto free_doc;
}
poppler_page_get_size (page, &dw, &dh);
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);
if (!cairo_surface) {
DBG(1, "Error : cairo_image_surface_create");
status = SANE_STATUS_INVAL;
goto free_page;
}
cr = cairo_create (cairo_surface);
if (!cairo_surface) {
DBG(1, "Error : cairo_create");
status = SANE_STATUS_INVAL;
goto free_surface;
}
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);
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
int st = cairo_status(cr);
if (st)
{
DBG(1, "%s", cairo_status_to_string (st));
status = SANE_STATUS_INVAL;
goto destroy_cr;
}
*bps = 3;
DBG(1, "Escl Pdf : Image Size [%dx%d]\n", w, h);
surface = cairo_surface_to_pixels (cairo_surface, *bps);
if (!surface) {
status = SANE_STATUS_NO_MEM;
DBG(1, "Escl Pdf : Surface Memory allocation problem");
goto destroy_cr;
}
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, w, h, *bps, width, height);
if (!surface) {
DBG(1, "Escl Pdf Crop: Surface Memory allocation problem");
status = SANE_STATUS_NO_MEM;
}
destroy_cr:
cairo_destroy (cr);
free_surface:
cairo_surface_destroy (cairo_surface);
free_page:
g_object_unref (page);
free_doc:
g_object_unref (doc);
free_file:
free(data);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return status;
}
#else
SANE_Status
get_PDF_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);
}
#endif

Wyświetl plik

@ -49,14 +49,15 @@
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components)
get_PNG_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
unsigned int width = 0; /* largeur */
unsigned int height = 0; /* hauteur */
int bps = 3; /* composantes d'un texel */
unsigned char *texels = NULL; /* données de l'image */
unsigned int w = 0;
unsigned int h = 0;
int components = 3;
unsigned char *surface = NULL; /* Image data */
unsigned int i = 0;
png_byte magic[8];
SANE_Status status = SANE_STATUS_GOOD;
// read magic number
fread (magic, 1, sizeof (magic), scanner->tmp);
@ -64,11 +65,8 @@ get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components)
if (!png_check_sig (magic, sizeof (magic)))
{
DBG( 1, "Escl Png : PNG error is not a valid PNG image!\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
goto close_file;
}
// create a png read struct
png_structp png_ptr = png_create_read_struct
@ -76,12 +74,8 @@ get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components)
if (!png_ptr)
{
DBG( 1, "Escl Png : PNG error create a png read struct\n");
if (scanner->tmp)
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
goto close_file;
}
// create a png info struct
png_infop info_ptr = png_create_info_struct (png_ptr);
@ -89,26 +83,19 @@ get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components)
{
DBG( 1, "Escl Png : PNG error create a png info struct\n");
png_destroy_read_struct (&png_ptr, NULL, NULL);
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
goto close_file;
}
// initialize the setjmp for returning properly after a libpng
// error occured
if (setjmp (png_jmpbuf (png_ptr)))
{
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
if (texels)
free (texels);
fprintf(stderr,"PNG read error.\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
if (surface)
free (surface);
DBG( 1, "Escl Png : PNG read error.\n");
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
goto close_file;
}
// setup libpng for using standard C fread() function
// with our FILE pointer
@ -128,63 +115,79 @@ get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components)
png_set_palette_to_rgb (png_ptr);
else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA)
{
fprintf(stderr,"PNG format not supported.\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
DBG(1, "PNG format not supported.\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
bps = 4;
else
bps = 3;
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
else if (bit_depth < 8)
png_set_packing (png_ptr);
// update info structure to apply transformations
png_read_update_info (png_ptr, info_ptr);
// retrieve updated information
png_get_IHDR (png_ptr, info_ptr,
(png_uint_32*)(&width),
(png_uint_32*)(&height),
&bit_depth, &color_type,
NULL, NULL, NULL);
*w = (int)width;
*h = (int)height;
*components = bps;
// we can now allocate memory for storing pixel data
texels = (unsigned char *)malloc (sizeof (unsigned char) * width
* height * bps);
png_bytep *row_pointers;
// setup a pointer array. Each one points at the begening of a row.
row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * height);
for (i = 0; i < height; ++i)
{
row_pointers[i] = (png_bytep)(texels +
((height - (i + 1)) * width * bps));
}
// read pixel data using row pointers
png_read_image (png_ptr, row_pointers);
// we don't need row pointers anymore
scanner->img_data = texels;
scanner->img_size = (int)(width * height * bps);
scanner->img_read = 0;
free (row_pointers);
fclose(scanner->tmp);
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
components = 4;
else
components = 3;
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png_ptr);
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
else if (bit_depth < 8)
png_set_packing (png_ptr);
// update info structure to apply transformations
png_read_update_info (png_ptr, info_ptr);
// retrieve updated information
png_get_IHDR (png_ptr, info_ptr,
(png_uint_32*)(&w),
(png_uint_32*)(&h),
&bit_depth, &color_type,
NULL, NULL, NULL);
*bps = components;
// we can now allocate memory for storing pixel data
surface = (unsigned char *)malloc (sizeof (unsigned char) * w
* h * components);
if (!surface) {
DBG( 1, "Escl Png : texels Memory allocation problem\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
png_bytep *row_pointers;
// setup a pointer array. Each one points at the begening of a row.
row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * h);
if (!row_pointers) {
DBG( 1, "Escl Png : row_pointers Memory allocation problem\n");
free(surface);
status = SANE_STATUS_NO_MEM;
goto close_file;
}
for (i = 0; i < h; ++i)
{
row_pointers[i] = (png_bytep)(surface +
((h - (i + 1)) * w * components));
}
// read pixel data using row pointers
png_read_image (png_ptr, row_pointers);
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, w, h, components, width, height);
if (!surface) {
DBG( 1, "Escl Png : Surface Memory allocation problem\n");
status = SANE_STATUS_NO_MEM;
goto close_file;
}
free (row_pointers);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return (SANE_STATUS_GOOD);
return (status);
}
#else
SANE_Status
get_PNG_data(capabilities_t __sane_unused__ *scanner,
int __sane_unused__ *w,
int __sane_unused__ *h,
int __sane_unused__ *width,
int __sane_unused__ *height,
int __sane_unused__ *bps)
{
return (SANE_STATUS_INVAL);

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) {
printf ("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

@ -50,60 +50,59 @@
* \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
get_TIFF_data(capabilities_t *scanner, int *w, int *h, int *components)
get_TIFF_data(capabilities_t *scanner, int *width, int *height, int *bps)
{
TIFF* tif = NULL;
uint32 width = 0; /* largeur */
uint32 height = 0; /* hauteur */
unsigned char *raster = NULL; /* données de l'image */
int bps = 4;
uint32 w = 0;
uint32 h = 0;
unsigned char *surface = NULL; /* image data*/
int components = 4;
uint32 npixels = 0;
SANE_Status status = SANE_STATUS_GOOD;
lseek(fileno(scanner->tmp), 0, SEEK_SET);
tif = TIFFFdOpen(fileno(scanner->tmp), "temp", "r");
if (!tif) {
DBG( 1, "Escl Tiff : Can not open, or not a TIFF file.\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
goto close_file;
}
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
npixels = width * height;
raster = (unsigned char*) malloc(npixels * sizeof (uint32));
if (raster != NULL)
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
surface = (unsigned char*) malloc(npixels * sizeof (uint32));
if (surface != NULL)
{
DBG( 1, "Escl Tiff : Memory allocation problem.\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
DBG( 1, "Escl Tiff : raster Memory allocation problem.\n");
status = SANE_STATUS_INVAL;
goto close_tiff;
}
if (!TIFFReadRGBAImage(tif, width, height, (uint32 *)raster, 0))
if (!TIFFReadRGBAImage(tif, w, h, (uint32 *)surface, 0))
{
DBG( 1, "Escl Tiff : Problem reading image data.\n");
if (scanner->tmp) {
fclose(scanner->tmp);
scanner->tmp = NULL;
}
return (SANE_STATUS_INVAL);
status = SANE_STATUS_INVAL;
free(surface);
goto close_tiff;
}
*w = (int)width;
*h = (int)height;
*components = bps;
// we don't need row pointers anymore
scanner->img_data = raster;
scanner->img_size = (int)(width * height * bps);
scanner->img_read = 0;
*bps = components;
// If necessary, trim the image.
surface = escl_crop_surface(scanner, surface, w, h, components, width, height);
if (!surface) {
DBG( 1, "Escl Tiff : Surface Memory allocation problem\n");
status = SANE_STATUS_INVAL;
}
close_tiff:
TIFFClose(tif);
fclose(scanner->tmp);
close_file:
if (scanner->tmp)
fclose(scanner->tmp);
scanner->tmp = NULL;
return (SANE_STATUS_GOOD);
return (status);
}
#else

Wyświetl plik

@ -383,6 +383,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define get_IN_op_halt(in) getbitfield(in+0x7a, 1, 7)
#define get_IN_return_path(in) getbitfield(in+0x7c, 1, 7)
#define get_IN_energy_star3(in) getbitfield(in+0x7c, 1, 6)
/* ==================================================================== */
/* page codes used by mode_sense and mode_select */
#define MS_pc_unk 0x2c /* Used by iX500 */
@ -763,6 +766,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define get_GHS_fb_open(in) getbitfield(in+0x03, 1, 3)
#define get_GHS_paper_end(in) getbitfield(in+0x03, 1, 2)
#define get_GHS_fb_on(in) getbitfield(in+0x03, 1, 1)
#define get_GHS_exit(in) getbitfield(in+0x03, 1, 0)
#define get_GHS_sleep(in) getbitfield(in+0x04, 1, 7)
#define get_GHS_clean(in) getbitfield(in+0x04, 1, 6)
@ -823,7 +827,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define SCANNER_CONTROL_len 10
#define set_SC_ric(icb, val) setbitfield(icb + 1, 1, 4, val)
#define set_SC_function(icb, val) setbitfield(icb + 1, 0xf, 0, val)
#define set_SC_function_1(icb, val) setbitfield(icb + 1, 0xf, 0, val)
#define set_SC_function_2(icb, val) icb[2] = (val >> 4)
#define SC_function_adf 0x00
#define SC_function_fb 0x01
#define SC_function_fb_hs 0x02
@ -836,6 +841,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes)
#define SC_function_scan_complete 0x09
#define SC_function_eject_complete 0x0a
#define SC_function_manual_feed 0x0c
#define SC_function_mfeed 0x0f
#define SC_function_continuous 0x1f
#define SC_function_rpath 0x2f
/* used with SC_function_panel */
#define set_SC_led_eb(icb, val) setbitfield(icb + 5, 1, 7, val)

Wyświetl plik

@ -603,8 +603,12 @@
v134 2019-02-23, MAN
- rewrite init_vpd for scanners which fail to report
overscan correctly
v135 2019-11-10, MAN
v135 2019-11-10, MAN (SANE 1.0.29)
- set has_MS_lamp=0 for fi-72x0, bug #134
v136 2020-02-07, MAN
- add support for fi-800R
- add support for card scanning slot (Return Path)
- fix bug with reading hardware sensors on first invocation
SANE FLOW DIAGRAM
@ -654,7 +658,7 @@
#include "fujitsu.h"
#define DEBUG 1
#define BUILD 134
#define BUILD 136
/* values for SANE_DEBUG_FUJITSU env var:
- errors 5
@ -678,6 +682,9 @@
#define STRING_ADFFRONT SANE_I18N("ADF Front")
#define STRING_ADFBACK SANE_I18N("ADF Back")
#define STRING_ADFDUPLEX SANE_I18N("ADF Duplex")
#define STRING_CARDFRONT SANE_I18N("Card Front")
#define STRING_CARDBACK SANE_I18N("Card Back")
#define STRING_CARDDUPLEX SANE_I18N("Card Duplex")
#define STRING_LINEART SANE_VALUE_SCAN_MODE_LINEART
#define STRING_HALFTONE SANE_VALUE_SCAN_MODE_HALFTONE
@ -1821,6 +1828,12 @@ init_vpd (struct fujitsu *s)
DBG (15, " object position halt: %d\n", s->has_op_halt);
}
if (payload_off >= 0x7c) {
s->has_return_path = get_IN_return_path(in);
DBG (15, " return path (card) scanning: %d\n", s->has_return_path);
DBG (15, " energy star 3: %d\n", get_IN_energy_star3(in));
}
DBG (10, "init_vpd: finish\n");
return SANE_STATUS_GOOD;
@ -2498,6 +2511,8 @@ init_user (struct fujitsu *s)
s->source = SOURCE_FLATBED;
else if(s->has_adf)
s->source = SOURCE_ADF_FRONT;
else if(s->has_return_path)
s->source = SOURCE_CARD_FRONT;
/* scan mode */
if(s->can_mode[MODE_LINEART])
@ -2875,6 +2890,16 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
s->source_list[i++]=STRING_ADFDUPLEX;
}
}
if(s->has_return_path){
s->source_list[i++]=STRING_CARDFRONT;
if(s->has_back){
s->source_list[i++]=STRING_CARDBACK;
}
if(s->has_duplex){
s->source_list[i++]=STRING_CARDDUPLEX;
}
}
s->source_list[i]=NULL;
opt->name = SANE_NAME_SCAN_SOURCE;
@ -3049,7 +3074,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &s->paper_x_range;
if(s->has_adf){
if(s->has_adf || s->has_return_path){
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
if(s->source == SOURCE_FLATBED){
opt->cap |= SANE_CAP_INACTIVE;
@ -3076,7 +3101,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &s->paper_y_range;
if(s->has_adf){
if(s->has_adf || s->has_return_path){
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
if(s->source == SOURCE_FLATBED){
opt->cap |= SANE_CAP_INACTIVE;
@ -4474,6 +4499,18 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->cap = SANE_CAP_INACTIVE;
}
if(option==OPT_CARD_LOADED){
opt->name = "card-loaded";
opt->title = SANE_I18N ("Card loaded");
opt->desc = SANE_I18N ("Card slot contains paper");
opt->type = SANE_TYPE_BOOL;
opt->unit = SANE_UNIT_NONE;
if (s->has_cmd_hw_status && s->has_return_path)
opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
else
opt->cap = SANE_CAP_INACTIVE;
}
if(option==OPT_SLEEP){
opt->name = "power-save";
opt->title = SANE_I18N ("Power saving");
@ -4697,6 +4734,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
else if(s->source == SOURCE_ADF_DUPLEX){
strcpy (val, STRING_ADFDUPLEX);
}
else if(s->source == SOURCE_CARD_FRONT){
strcpy (val, STRING_CARDFRONT);
}
else if(s->source == SOURCE_CARD_BACK){
strcpy (val, STRING_CARDBACK);
}
else if(s->source == SOURCE_CARD_DUPLEX){
strcpy (val, STRING_CARDDUPLEX);
}
return SANE_STATUS_GOOD;
case OPT_MODE:
@ -5215,6 +5261,11 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
*val_p = s->hw_adf_open;
return ret;
case OPT_CARD_LOADED:
ret = get_hardware_status(s,option);
*val_p = s->hw_card_loaded;
return ret;
case OPT_SLEEP:
ret = get_hardware_status(s,option);
*val_p = s->hw_sleep;
@ -5323,6 +5374,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
else if (!strcmp (val, STRING_ADFDUPLEX)) {
tmp = SOURCE_ADF_DUPLEX;
}
else if (!strcmp (val, STRING_CARDFRONT)) {
tmp = SOURCE_CARD_FRONT;
}
else if (!strcmp (val, STRING_CARDBACK)) {
tmp = SOURCE_CARD_BACK;
}
else if (!strcmp (val, STRING_CARDDUPLEX)) {
tmp = SOURCE_CARD_DUPLEX;
}
else{
tmp = SOURCE_FLATBED;
}
@ -5912,12 +5972,12 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
/* only run this if frontend has already read the last time we got it */
/* or if we don't care for such bookkeeping (private use) */
if (!option || s->hw_read[option-OPT_TOP]) {
if (!option || !s->hw_data_avail[option-OPT_TOP]) {
DBG (15, "get_hardware_status: running\n");
/* mark all values as unread */
memset(s->hw_read,0,sizeof(s->hw_read));
/* mark all values as available */
memset(s->hw_data_avail,1,sizeof(s->hw_data_avail));
if (s->has_cmd_hw_status){
unsigned char cmd[GET_HW_STATUS_len];
@ -5950,6 +6010,7 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
s->hw_hopper = get_GHS_hopper(in);
s->hw_omr = get_GHS_omr(in);
s->hw_adf_open = get_GHS_adf_open(in);
s->hw_card_loaded = get_GHS_exit(in);
s->hw_sleep = get_GHS_sleep(in);
s->hw_send_sw = get_GHS_send_sw(in);
@ -6015,7 +6076,7 @@ get_hardware_status (struct fujitsu *s, SANE_Int option)
}
if(option)
s->hw_read[option-OPT_TOP] = 1;
s->hw_data_avail[option-OPT_TOP] = 0;
DBG (10, "get_hardware_status: finish\n");
@ -6905,8 +6966,8 @@ sane_start (SANE_Handle handle)
}
/* low mem mode messes up the side marker, reset it */
if(s->source == SOURCE_ADF_DUPLEX && s->low_mem
&& s->eof_tx[SIDE_FRONT] && s->eof_tx[SIDE_BACK]
if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->low_mem && s->eof_tx[SIDE_FRONT] && s->eof_tx[SIDE_BACK]
){
s->side = SIDE_BACK;
}
@ -6915,7 +6976,7 @@ sane_start (SANE_Handle handle)
if(!s->started){
/* load side marker */
if(s->source == SOURCE_ADF_BACK){
if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
s->side = SIDE_BACK;
}
else{
@ -6936,6 +6997,12 @@ sane_start (SANE_Handle handle)
DBG (5, "sane_start: ERROR: cannot control fb, ignoring\n");
}
}
else if(s->source == SOURCE_CARD_FRONT || s->source == SOURCE_CARD_BACK || s->source == SOURCE_CARD_DUPLEX){
ret = scanner_control(s, SC_function_rpath);
if (ret != SANE_STATUS_GOOD) {
DBG (5, "sane_start: ERROR: cannot control rp, ignoring\n");
}
}
else{
ret = scanner_control(s, SC_function_adf);
if (ret != SANE_STATUS_GOOD) {
@ -7038,7 +7105,7 @@ sane_start (SANE_Handle handle)
}
}
/* if already running, duplex needs to switch sides */
else if(s->source == SOURCE_ADF_DUPLEX){
else if(s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX){
s->side = !s->side;
}
@ -7047,7 +7114,7 @@ sane_start (SANE_Handle handle)
/* otherwise buffered back page will be lost */
/* ingest paper with adf (no-op for fb) */
/* dont call object pos or scan on back side of duplex scan */
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK){
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK){
s->bytes_rx[0]=0;
s->bytes_rx[1]=0;
@ -7095,7 +7162,7 @@ sane_start (SANE_Handle handle)
}
/* store the number of front bytes */
if ( s->source != SOURCE_ADF_BACK ){
if ( s->source != SOURCE_ADF_BACK && s->source != SOURCE_CARD_BACK ){
s->bytes_tot[SIDE_FRONT] = s->s_params.bytes_per_line * s->s_params.lines;
s->buff_tot[SIDE_FRONT] = s->buffer_size;
@ -7114,13 +7181,14 @@ sane_start (SANE_Handle handle)
}
/* store the number of back bytes */
if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK ){
if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK
|| s->source == SOURCE_CARD_DUPLEX || s->source == SOURCE_CARD_BACK ){
s->bytes_tot[SIDE_BACK] = s->s_params.bytes_per_line * s->s_params.lines;
s->buff_tot[SIDE_BACK] = s->bytes_tot[SIDE_BACK];
/* the back buffer is normally very large, but some scanners or
* option combinations dont need it, so we make a small one */
if(s->low_mem || s->source == SOURCE_ADF_BACK
if(s->low_mem || s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
|| s->duplex_interlace == DUPLEX_INTERLACE_NONE)
s->buff_tot[SIDE_BACK] = s->buffer_size;
}
@ -7308,13 +7376,14 @@ scanner_control (struct fujitsu *s, int function)
memset(cmd,0,cmdLen);
set_SCSI_opcode(cmd, SCANNER_CONTROL_code);
set_SC_function (cmd, function);
set_SC_function_1 (cmd, function);
set_SC_function_2 (cmd, function);
DBG (15, "scanner_control: function %d\n",function);
/* don't really need to ask for adf if that's the only option */
/* doing so causes the 3091 to complain */
if(function == SC_function_adf && !s->has_flatbed){
if(function == SC_function_adf && !s->has_flatbed && !s->has_return_path){
DBG (10, "scanner_control: adf function not required\n");
return ret;
}
@ -7486,7 +7555,7 @@ set_window (struct fujitsu *s)
set_WPDB_wdblen(header, SW_desc_len);
/* init the window block */
if (s->source == SOURCE_ADF_BACK) {
if (s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
set_WD_wid (desc1, WD_wid_back);
}
else{
@ -7675,7 +7744,7 @@ set_window (struct fujitsu *s)
}
/* when in duplex mode, copy first desc block into second */
if (s->source == SOURCE_ADF_DUPLEX) {
if (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX) {
memcpy (desc2, desc1, SW_desc_len);
set_WD_wid (desc2, WD_wid_back);
@ -7823,7 +7892,7 @@ get_pixelsize(struct fujitsu *s, int actual)
}
/*
* Issues the SCSI OBJECT POSITION command if an ADF is in use.
* Issues the SCSI OBJECT POSITION command if an ADF or card scanner is in use.
*/
static SANE_Status
object_position (struct fujitsu *s, int action)
@ -7880,9 +7949,9 @@ start_scan (struct fujitsu *s)
DBG (10, "start_scan: start\n");
if (s->source != SOURCE_ADF_DUPLEX) {
if (s->source != SOURCE_ADF_DUPLEX && s->source != SOURCE_CARD_DUPLEX) {
outLen--;
if(s->source == SOURCE_ADF_BACK) {
if(s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK) {
out[0] = WD_wid_back;
}
}
@ -7983,7 +8052,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* swap sides if user asked for low-mem mode, we are duplexing,
* and there is data waiting on the other side */
if(s->low_mem && s->source == SOURCE_ADF_DUPLEX
if(s->low_mem
&& (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
|| (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
)
@ -8013,7 +8083,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
} /* end 3091 */
/* alternating jpeg duplex interlacing */
else if(s->source == SOURCE_ADF_DUPLEX
else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->s_params.format == SANE_FRAME_JPEG
&& s->jpeg_interlace == JPEG_INTERLACE_ALT
){
@ -8025,7 +8095,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
} /* end alt jpeg */
/* alternating pnm duplex interlacing */
else if(s->source == SOURCE_ADF_DUPLEX
else if((s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& s->s_params.format != SANE_FRAME_JPEG
&& s->duplex_interlace == DUPLEX_INTERLACE_ALT
){
@ -8080,7 +8150,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
/* swap sides if user asked for low-mem mode, we are duplexing,
* and there is data waiting on the other side */
if(s->low_mem && s->source == SOURCE_ADF_DUPLEX
if(s->low_mem
&& (s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_CARD_DUPLEX)
&& (s->bytes_rx[!s->side] > s->bytes_tx[!s->side]
|| (s->eof_rx[!s->side] && !s->eof_tx[!s->side])
)
@ -9291,6 +9362,10 @@ sense_handler (int fd, unsigned char * sensed_data, void *arg)
DBG (5, "Medium error: Carrier sheet\n");
return SANE_STATUS_JAMMED;
}
if (0x0c == ascq) {
DBG (5, "Medium error: ADF blocked by card\n");
return SANE_STATUS_JAMMED;
}
if (0x10 == ascq) {
DBG (5, "Medium error: no ink cartridge\n");
return SANE_STATUS_IO_ERROR;
@ -10092,7 +10167,9 @@ buffer_deskew(struct fujitsu *s, int side)
DBG (10, "buffer_deskew: start\n");
/*only find skew on first image from a page, or if first image had error */
if(s->side == SIDE_FRONT || s->source == SOURCE_ADF_BACK || s->deskew_stat){
if(s->side == SIDE_FRONT
|| s->source == SOURCE_ADF_BACK || s->source == SOURCE_CARD_BACK
|| s->deskew_stat){
s->deskew_stat = sanei_magic_findSkew(
&s->s_params,s->buffers[side],s->resolution_x,s->resolution_y,

Wyświetl plik

@ -255,3 +255,6 @@ usb 0x04c5 0x1522
#ScanSnap iX1500
usb 0x04c5 0x159f
#fi-800R
usb 0x04c5 0x15fc

Wyświetl plik

@ -112,6 +112,7 @@ enum fujitsu_Option
OPT_HOPPER,
OPT_OMR,
OPT_ADF_OPEN,
OPT_CARD_LOADED,
OPT_SLEEP,
OPT_SEND_SW,
OPT_MANUAL_FEED,
@ -277,6 +278,7 @@ struct fujitsu
int has_comp_JPG2;
int has_comp_JPG3;
int has_op_halt;
int has_return_path;
/*FIXME: more endorser data? */
int endorser_type_f;
@ -361,7 +363,7 @@ struct fujitsu
/*mode group*/
SANE_String_Const mode_list[7];
SANE_String_Const source_list[5];
SANE_String_Const source_list[8];
SANE_Int res_list[17];
SANE_Range res_range;
@ -599,6 +601,7 @@ struct fujitsu
int hw_hopper;
int hw_omr;
int hw_adf_open;
int hw_card_loaded;
int hw_sleep;
int hw_send_sw;
@ -618,7 +621,7 @@ struct fujitsu
int hw_density_sw;
/* values which are used to track the frontend's access to sensors */
char hw_read[NUM_OPTIONS-OPT_TOP];
char hw_data_avail[NUM_OPTIONS-OPT_TOP];
};
#define CONNECTION_SCSI 0 /* SCSI interface */
@ -631,6 +634,9 @@ struct fujitsu
#define SOURCE_ADF_FRONT 1
#define SOURCE_ADF_BACK 2
#define SOURCE_ADF_DUPLEX 3
#define SOURCE_CARD_FRONT 4
#define SOURCE_CARD_BACK 5
#define SOURCE_CARD_DUPLEX 6
#define COMP_NONE WD_cmp_NONE
#define COMP_JPEG WD_cmp_JPG1

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

@ -63,8 +63,7 @@ struct Genesys_Calibration_Cache
Genesys_Frontend frontend;
Genesys_Sensor sensor;
size_t calib_pixels = 0;
size_t calib_channels = 0;
ScanSession session;
size_t average_size = 0;
std::vector<std::uint16_t> white_average_data;
std::vector<std::uint16_t> dark_average_data;
@ -75,8 +74,7 @@ struct Genesys_Calibration_Cache
last_calibration == other.last_calibration &&
frontend == other.frontend &&
sensor == other.sensor &&
calib_pixels == other.calib_pixels &&
calib_channels == other.calib_channels &&
session == other.session &&
average_size == other.average_size &&
white_average_data == other.white_average_data &&
dark_average_data == other.dark_average_data;
@ -94,8 +92,7 @@ void serialize(Stream& str, Genesys_Calibration_Cache& x)
serialize_newline(str);
serialize(str, x.sensor);
serialize_newline(str);
serialize(str, x.calib_pixels);
serialize(str, x.calib_channels);
serialize(str, x.session);
serialize(str, x.average_size);
serialize_newline(str);
serialize(str, x.white_average_data);

Wyświetl plik

@ -67,14 +67,12 @@ 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_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
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) 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
@ -98,7 +96,6 @@ public:
*/
virtual void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const = 0;
virtual void search_start_position(Genesys_Device* dev) const = 0;
virtual void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const = 0;
virtual void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
@ -134,11 +131,6 @@ public:
/// eject document from scanner
virtual void eject_document(Genesys_Device* dev) const = 0;
/**
* search for an black or white area in forward or reverse
* direction */
virtual void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) const = 0;
/// move scanning head to transparency adapter
virtual void move_to_ta(Genesys_Device* dev) const = 0;
@ -159,6 +151,16 @@ public:
/// cold boot init function
virtual void asic_boot(Genesys_Device* dev, bool cold) const = 0;
/// checks if specific scan head is at home position
virtual bool is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const = 0;
/// enables or disables XPA slider motor
virtual void set_xpa_lamp_power(Genesys_Device& dev, bool set) const = 0;
/// enables or disables XPA slider motor
virtual void set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const = 0;
};
} // namespace genesys

Wyświetl plik

@ -0,0 +1,247 @@
/* 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.
*/
#define DEBUG_DECLARE_ONLY
#include "command_set_common.h"
#include "low.h"
#include "value_filter.h"
namespace genesys {
CommandSetCommon::~CommandSetCommon() = default;
bool CommandSetCommon::is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const
{
struct HeadSettings {
ModelId model_id;
ScanHeadId scan_head;
GenesysRegisterSettingSet regs;
};
HeadSettings settings[] = {
{ ModelId::CANON_8600F,
ScanHeadId::PRIMARY, {
{ 0x6c, 0x20, 0x60 },
{ 0xa6, 0x00, 0x01 },
}
},
{ ModelId::CANON_8600F,
ScanHeadId::SECONDARY, {
{ 0x6c, 0x00, 0x60 },
{ 0xa6, 0x01, 0x01 },
}
},
};
for (const auto& setting : settings) {
if (setting.model_id == dev.model->model_id &&
setting.scan_head == scan_head)
{
auto reg_backup = apply_reg_settings_to_device_with_backup(dev, setting.regs);
auto status = scanner_read_status(dev);
apply_reg_settings_to_device(dev, reg_backup);
return status.is_at_home;
}
}
auto status = scanner_read_status(dev);
return status.is_at_home;
}
void CommandSetCommon::set_xpa_lamp_power(Genesys_Device& dev, bool set) const
{
DBG_HELPER(dbg);
struct LampSettings {
ModelId model_id;
ScanMethod scan_method;
GenesysRegisterSettingSet regs_on;
GenesysRegisterSettingSet regs_off;
};
// FIXME: BUG: we're not clearing the registers to the previous state when returning back when
// turning off the lamp
LampSettings settings[] = {
{ ModelId::CANON_4400F, ScanMethod::TRANSPARENCY, {}, {} },
{ ModelId::CANON_8400F, ScanMethod::TRANSPARENCY, {
{ 0xa6, 0x34, 0xf4 },
}, {
{ 0xa6, 0x40, 0x70 },
}
},
{ ModelId::CANON_8400F, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0x6c, 0x40, 0x40 },
{ 0xa6, 0x01, 0xff },
}, {
{ 0x6c, 0x00, 0x40 },
{ 0xa6, 0x00, 0xff },
}
},
{ ModelId::CANON_8600F, ScanMethod::TRANSPARENCY, {
{ 0xa6, 0x34, 0xf4 },
{ 0xa7, 0xe0, 0xe0 },
}, {
{ 0xa6, 0x40, 0x70 },
}
},
{ ModelId::CANON_8600F, ScanMethod::TRANSPARENCY_INFRARED, {
{ 0xa6, 0x00, 0xc0 },
{ 0xa7, 0xe0, 0xe0 },
{ 0x6c, 0x80, 0x80 },
}, {
{ 0xa6, 0x00, 0xc0 },
{ 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 },
}, {
{ 0xa8, 0x00, 0x07 },
}
},
{ 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 },
}, {
{ 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) {
if (setting.model_id == dev.model->model_id &&
setting.scan_method == dev.settings.scan_method)
{
apply_reg_settings_to_device(dev, set ? setting.regs_on : setting.regs_off);
return;
}
}
throw SaneException("Could not find XPA lamp settings");
}
void CommandSetCommon::set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const
{
DBG_HELPER(dbg);
struct MotorSettings {
ModelId model_id;
ValueFilterAny<unsigned> resolutions;
GenesysRegisterSettingSet regs_primary_and_secondary;
GenesysRegisterSettingSet regs_primary;
GenesysRegisterSettingSet regs_secondary;
};
MotorSettings settings[] = {
{ ModelId::CANON_8400F, { 400, 800, 1600, 3200 }, {
{ 0x6c, 0x00, 0x90 },
{ 0xa9, 0x04, 0x06 },
}, {
{ 0x6c, 0x90, 0x90 },
{ 0xa9, 0x02, 0x06 },
}, {}
},
{ ModelId::CANON_8600F, { 300, 600, 1200 }, {
{ 0x6c, 0x00, 0x60 },
{ 0xa6, 0x01, 0x41 },
}, {
{ 0x6c, 0x20, 0x62 },
{ 0xa6, 0x00, 0x41 },
}, {
{ 0x6c, 0x40, 0x62 },
{ 0xa6, 0x01, 0x41 },
}
},
{ ModelId::CANON_8600F, { 2400, 4800 }, {
{ 0x6c, 0x02, 0x62 },
{ 0xa6, 0x01, 0x41 },
}, {
{ 0x6c, 0x20, 0x62 },
{ 0xa6, 0x00, 0x41 },
}, {
{ 0x6c, 0x40, 0x62 },
{ 0xa6, 0x01, 0x41 },
}
},
{ 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
{ 0xa6, 0x08, 0x08 }, // note that reverse change is not applied on off
{ 0xa8, 0x00, 0x04 },
{ 0xa9, 0x30, 0x30 },
}, {
{ 0x6b, 0x00, 0x01 }, // BUG: note that only ADF is unset
{ 0xa8, 0x04, 0x04 },
{ 0xa9, 0x00, 0x10 }, // note that 0x20 bit is not reset
}, {}
},
{ 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) {
if (setting.model_id == dev.model->model_id &&
setting.resolutions.matches(dev.session.output_resolution))
{
switch (mode) {
case MotorMode::PRIMARY: {
apply_reg_settings_to_device(dev, setting.regs_primary);
break;
}
case MotorMode::PRIMARY_AND_SECONDARY: {
apply_reg_settings_to_device(dev, setting.regs_primary_and_secondary);
break;
}
case MotorMode::SECONDARY: {
apply_reg_settings_to_device(dev, setting.regs_secondary);
break;
}
}
regs.state.motor_mode = mode;
return;
}
}
throw SaneException("Motor settings have not been found");
}
} // namespace genesys

Wyświetl plik

@ -0,0 +1,48 @@
/* 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.
*/
#ifndef BACKEND_GENESYS_COMMAND_SET_COMMON_H
#define BACKEND_GENESYS_COMMAND_SET_COMMON_H
#include "command_set.h"
namespace genesys {
/** Common command set functionality
*/
class CommandSetCommon : public CommandSet
{
public:
~CommandSetCommon() override;
bool is_head_home(Genesys_Device& dev, ScanHeadId scan_head) const override;
void set_xpa_lamp_power(Genesys_Device& dev, bool set) const override;
void set_motor_mode(Genesys_Device& dev, Genesys_Register_Set& regs,
MotorMode mode) const override;
};
} // namespace genesys
#endif // BACKEND_GENESYS_COMMAND_SET_COMMON_H

Wyświetl plik

@ -146,9 +146,7 @@ void genesys_gray_lineart(Genesys_Device* dev,
{
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);
(void) threshold;
for (y = 0; y < lines; y++)
{
@ -200,7 +198,7 @@ void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor)
bg=0xff;
}
TIE(sanei_magic_findSkew(&s->params, dev->img_buffer.data(),
sensor.optical_res, sensor.optical_res,
sensor.full_resolution, sensor.full_resolution,
&x, &y, &slope));
DBG(DBG_info, "%s: slope=%f => %f\n", __func__, slope, slope * 180 / M_PI);

Wyświetl plik

@ -62,15 +62,24 @@ std::vector<unsigned> MethodResolutions::get_resolutions() const
return ret;
}
const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
const MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const
{
for (const auto& res_for_method : resolutions) {
for (auto res_method : res_for_method.methods) {
if (res_method == method) {
return res_for_method;
return &res_for_method;
}
}
}
return nullptr;
}
const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
{
const auto* ptr = get_resolution_settings_ptr(method);
if (ptr)
return *ptr;
throw SaneException("Could not find resolution settings for method %d",
static_cast<unsigned>(method));
}
@ -80,6 +89,12 @@ std::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const
return get_resolution_settings(method).get_resolutions();
}
bool Genesys_Model::has_method(ScanMethod method) const
{
return get_resolution_settings_ptr(method) != nullptr;
}
Genesys_Device::~Genesys_Device()
{
clear();
@ -124,10 +139,14 @@ unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const
}
}
void Genesys_Device::set_head_pos_unknown()
void Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head)
{
is_head_pos_primary_known_ = false;
is_head_pos_secondary_known_ = false;
if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
is_head_pos_primary_known_ = false;
}
if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
is_head_pos_secondary_known_ = false;
}
}
void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head)
@ -205,12 +224,15 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< " ignore_offsets: " << dev.ignore_offsets << '\n'
<< " model: (not printed)\n"
<< " reg: " << format_indent_braced_list(4, dev.reg) << '\n'
<< " calib_reg: " << format_indent_braced_list(4, dev.calib_reg) << '\n'
<< " 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'
<< " frontend_is_init: " << dev.frontend_is_init << '\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]) << ' '
@ -220,13 +242,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< static_cast<unsigned>(dev.control[4]) << ' '
<< static_cast<unsigned>(dev.control[5]) << '\n' << std::dec
<< " average_size: " << dev.average_size << '\n'
<< " calib_pixels: " << dev.calib_pixels << '\n'
<< " calib_lines: " << dev.calib_lines << '\n'
<< " calib_channels: " << dev.calib_channels << '\n'
<< " calib_resolution: " << dev.calib_resolution << '\n'
<< " calib_total_bytes_to_read: " << dev.calib_total_bytes_to_read << '\n'
<< " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n'
<< " calib_pixels_offset: " << dev.calib_pixels_offset << '\n'
<< " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n'
<< " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n'
<< " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n'
@ -260,13 +276,36 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
return out;
}
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 backup;
for (const auto& reg : regs) {
uint8_t val = dev.interface->read_register(reg.address);
val = (val & ~reg.mask) | (reg.value & reg.mask);
dev.interface->write_register(reg.address, val);
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);
}
GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs)
{
GenesysRegisterSettingSet backup;
for (const auto& reg : regs) {
std::uint8_t old_val = dev.interface->read_register(reg.address);
std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask);
dev.interface->write_register(reg.address, new_val);
using SettingType = GenesysRegisterSettingSet::SettingType;
backup.push_back(SettingType{reg.address,
static_cast<std::uint8_t>(old_val & reg.mask),
reg.mask});
}
return backup;
}
} // namespace genesys

Wyświetl plik

@ -55,6 +55,7 @@
#include "register.h"
#include "usb_device.h"
#include "scanner_interface.h"
#include "utilities.h"
#include <vector>
namespace genesys {
@ -77,22 +78,15 @@ struct Genesys_Gpo
GenesysRegisterSettingSet regs;
};
/// Stores a SANE_Fixed value which is automatically converted from and to floating-point values
class FixedFloat
struct MemoryLayout
{
public:
FixedFloat() = default;
FixedFloat(const FixedFloat&) = default;
FixedFloat(double number) : value_{SANE_FIX(number)} {}
FixedFloat& operator=(const FixedFloat&) = default;
FixedFloat& operator=(double number) { value_ = SANE_FIX(number); return *this; }
// This is used on GL845, GL846, GL847 and GL124 which have special registers to define the
// memory layout
MemoryLayout() = default;
operator double() const { return value(); }
ValueFilter<ModelId> models;
double value() const { return SANE_UNFIX(value_); }
private:
SANE_Fixed value_ = 0;
GenesysRegisterSettingSet regs;
};
struct MethodResolutions
@ -106,6 +100,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());
@ -143,51 +147,67 @@ struct Genesys_Model
// All offsets below are with respect to the sensor home position
// Start of scan area in mm
FixedFloat x_offset = 0;
float x_offset = 0;
// Start of scan area in mm (Amount of feeding needed to get to the medium)
FixedFloat y_offset = 0;
float y_offset = 0;
// Size of scan area in mm
FixedFloat x_size = 0;
float x_size = 0;
// Size of scan area in mm
FixedFloat y_size = 0;
float y_size = 0;
// Start of white strip in mm
FixedFloat y_offset_calib_white = 0;
// Start of white strip in mm for scanners that use separate dark and white shading calibration.
float y_offset_calib_white = 0;
// The size of the scan area that is used to acquire shading data in mm
float y_size_calib_mm = 0;
// Start of the black/white strip in mm for scanners that use unified dark and white shading
// calibration.
float y_offset_calib_dark_white_mm = 0;
// The size of the scan area that is used to acquire dark/white shading data in mm
float y_size_calib_dark_white_mm = 0;
// The width of the scan area that is used to acquire shading data
float x_size_calib_mm = 0;
// Start of black mark in mm
FixedFloat x_offset_calib_black = 0;
float x_offset_calib_black = 0;
// Start of scan area in transparency mode in mm
FixedFloat x_offset_ta = 0;
float x_offset_ta = 0;
// Start of scan area in transparency mode in mm
FixedFloat y_offset_ta = 0;
float y_offset_ta = 0;
// Size of scan area in transparency mode in mm
FixedFloat x_size_ta = 0;
float x_size_ta = 0;
// Size of scan area in transparency mode in mm
FixedFloat y_size_ta = 0;
float y_size_ta = 0;
// The position of the sensor when it's aligned with the lamp for transparency scanning
FixedFloat y_offset_sensor_to_ta = 0;
float y_offset_sensor_to_ta = 0;
// Start of white strip in transparency mode in mm
FixedFloat y_offset_calib_white_ta = 0;
float y_offset_calib_white_ta = 0;
// Start of black strip in transparency mode in mm
FixedFloat y_offset_calib_black_ta = 0;
float y_offset_calib_black_ta = 0;
// The size of the scan area that is used to acquire shading data in transparency mode in mm
float y_size_calib_ta_mm = 0;
// Size of scan area after paper sensor stop sensing document in mm
FixedFloat post_scan = 0;
float post_scan = 0;
// Amount of feeding needed to eject document after finishing scanning in mm
FixedFloat eject_feed = 0;
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;
@ -210,22 +230,24 @@ struct Genesys_Model
// stepper motor type
MotorId motor_id = MotorId::UNKNOWN;
// Which hacks are needed for this scanner?
SANE_Word flags = 0;
// Which customizations are needed for this scanner?
ModelFlag flags = ModelFlag::NONE;
// Button flags, described existing buttons for the model
SANE_Word buttons = 0;
// how many lines are used for shading calibration
SANE_Int shading_lines = 0;
// how many lines are used for shading calibration in TA mode
SANE_Int shading_ta_lines = 0;
// how many lines are used to search start position
SANE_Int search_lines = 0;
// returns nullptr if method is not supported
const MethodResolutions* get_resolution_settings_ptr(ScanMethod method) const;
// throws if method is not supported
const MethodResolutions& get_resolution_settings(ScanMethod method) const;
std::vector<unsigned> get_resolutions(ScanMethod method) const;
bool has_method(ScanMethod method) const;
};
/**
@ -243,8 +265,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
@ -261,42 +283,25 @@ 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;
Genesys_Register_Set reg;
Genesys_Register_Set calib_reg;
Genesys_Register_Set initial_regs;
Genesys_Settings settings;
Genesys_Frontend frontend, frontend_initial;
// whether the frontend is initialized. This is currently used just to preserve historical
// behavior
bool frontend_is_init = false;
Genesys_Gpo gpo;
MemoryLayout memory_layout;
Genesys_Motor motor;
std::uint8_t control[6] = {};
size_t average_size = 0;
// number of pixels used during shading calibration
size_t calib_pixels = 0;
// number of lines used during shading calibration
size_t calib_lines = 0;
size_t calib_channels = 0;
size_t calib_resolution = 0;
// bytes to read from USB when calibrating. If 0, this is not set
size_t calib_total_bytes_to_read = 0;
// the session that was configured for calibration
ScanSession calib_session;
// certain scanners support much higher resolution when scanning transparency, but we can't
// read whole width of the scanner as a single line at that resolution. Thus for stuff like
// calibration we want to read only the possible calibration area.
size_t calib_pixels_offset = 0;
// gamma overrides. If a respective array is not empty then it means that the gamma for that
// color is overridden.
std::vector<std::uint16_t> gamma_override_tables[3];
@ -360,7 +365,7 @@ struct Genesys_Device
bool is_head_pos_known(ScanHeadId scan_head) const;
unsigned head_pos(ScanHeadId scan_head) const;
void set_head_pos_unknown();
void set_head_pos_unknown(ScanHeadId scan_head);
void set_head_pos_zero(ScanHeadId scan_head);
void advance_head_pos_by_session(ScanHeadId scan_head);
void advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps);
@ -382,6 +387,12 @@ 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);
} // namespace genesys
#endif

Wyświetl plik

@ -109,6 +109,188 @@ 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, 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_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_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_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_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_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,6 +225,21 @@ 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,
@ -232,6 +250,7 @@ enum class SensorId : unsigned
CCD_DP665,
CCD_DP685,
CCD_DSMOBILE600,
CCD_DOCKETPORT_487,
CCD_G4050,
CCD_HP2300,
CCD_HP2400,
@ -241,9 +260,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 +273,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,
@ -293,9 +316,12 @@ enum class AdcId : unsigned
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 +347,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,
@ -345,9 +373,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 +387,8 @@ enum class GpioId : unsigned
XP300,
};
std::ostream& operator<<(std::ostream& out, GpioId id);
enum class MotorId : unsigned
{
UNKNOWN = 0,
@ -365,6 +398,7 @@ enum class MotorId : unsigned
CANON_LIDE_200,
CANON_LIDE_210,
CANON_LIDE_35,
CANON_LIDE_60,
CANON_LIDE_700,
CANON_LIDE_80,
CANON_4400F,
@ -380,9 +414,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 +428,8 @@ enum class MotorId : unsigned
XP300,
};
std::ostream& operator<<(std::ostream& out, MotorId id);
enum class StepType : unsigned
{
FULL = 0,
@ -423,6 +462,7 @@ enum class AsicType : unsigned
UNKNOWN = 0,
GL646,
GL841,
GL842,
GL843,
GL845,
GL846,
@ -431,6 +471,83 @@ enum class AsicType : unsigned
};
enum class ModelFlag : unsigned
{
// no flags
NONE = 0,
// scanner is not tested, print a warning as it's likely it won't work
UNTESTED = 1 << 0,
// use 14-bit gamma table instead of 12-bit
GAMMA_14BIT = 1 << 1,
// perform lamp warmup
WARMUP = 1 << 4,
// 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,
// whether scanner must wait for the head while parking
MUST_WAIT = 1 << 10,
// do dark and white calibration in one run
DARK_WHITE_CALIBRATION = 1 << 12,
// allow custom gamma tables
CUSTOM_GAMMA = 1 << 13,
// 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 outputs inverted pixel data
INVERT_PIXEL_DATA = 1 << 19,
// the scanner outputs 16-bit data that is byte-inverted
SWAP_16BIT_DATA = 1 << 20,
// the scanner has transparency, but it's implemented using only one motor
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)
{
return static_cast<ModelFlag>(static_cast<unsigned>(left) | static_cast<unsigned>(right));
}
inline ModelFlag& operator|=(ModelFlag& left, ModelFlag right)
{
left = left | right;
return left;
}
inline ModelFlag operator&(ModelFlag left, ModelFlag right)
{
return static_cast<ModelFlag>(static_cast<unsigned>(left) & static_cast<unsigned>(right));
}
inline bool has_flag(ModelFlag flags, ModelFlag which)
{
return (flags & which) == which;
}
enum class ScanFlag : unsigned
{
NONE = 0,
@ -438,14 +555,24 @@ enum class ScanFlag : unsigned
DISABLE_SHADING = 1 << 1,
DISABLE_GAMMA = 1 << 2,
DISABLE_BUFFER_FULL_MOVE = 1 << 3,
IGNORE_LINE_DISTANCE = 1 << 4,
DISABLE_LAMP = 1 << 5,
CALIBRATION = 1 << 6,
FEEDING = 1 << 7,
USE_XPA = 1 << 8,
ENABLE_LEDADD = 1 << 9,
USE_XCORRECTION = 1 << 10,
REVERSE = 1 << 11,
// if this flag is set the sensor will always be handled ignoring staggering of multiple
// sensors to achieve high resolution.
IGNORE_STAGGER_OFFSET = 1 << 4,
// if this flag is set the sensor will always be handled as if the components that scan
// different colors are at the same position.
IGNORE_COLOR_OFFSET = 1 << 5,
DISABLE_LAMP = 1 << 6,
CALIBRATION = 1 << 7,
FEEDING = 1 << 8,
USE_XPA = 1 << 9,
ENABLE_LEDADD = 1 << 10,
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)
@ -485,45 +612,18 @@ 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,
BACKWARD = 1
};
enum class MotorMode : unsigned
{
PRIMARY = 0,
PRIMARY_AND_SECONDARY,
SECONDARY,
};
} // namespace genesys

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)
{

Wyświetl plik

@ -56,7 +56,6 @@ struct Genesys_Calibration_Cache;
class CommandSet;
// device.h
class FixedFloat;
struct Genesys_Gpo;
struct MethodResolutions;
struct Genesys_Model;
@ -75,7 +74,6 @@ class Image;
// image_buffer.h
class ImageBuffer;
class FakeBufferModel;
class ImageBufferGenesysUsb;
// image_pipeline.h
@ -88,12 +86,12 @@ struct Pixel;
struct RawPixel;
// low.h
struct Genesys_USB_Device_Entry;
struct Motor_Profile;
struct UsbDeviceEntry;
// motor.h
struct Genesys_Motor;
struct MotorSlope;
struct MotorProfile;
struct MotorSlopeTable;
// register.h
@ -113,7 +111,6 @@ class ScannerInterfaceUsb;
class TestScannerInterface;
// sensor.h
class ResolutionFilter;
struct GenesysFrontendLayout;
struct Genesys_Frontend;
struct SensorExposure;
@ -124,6 +121,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;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -45,74 +45,12 @@
#define BACKEND_GENESYS_GL124_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
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 CommandSet
class CommandSetGl124 : public CommandSetCommon
{
public:
~CommandSetGl124() override = default;
@ -122,16 +60,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -148,8 +83,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -175,9 +108,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

Plik diff jest za duży Load Diff

Wyświetl plik

@ -48,395 +48,13 @@
#define BACKEND_GENESYS_GL646_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#include "motor.h"
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 void 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 CommandSet
class CommandSetGl646 : public CommandSetCommon
{
public:
~CommandSetGl646() override = default;
@ -446,16 +64,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -472,8 +87,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -495,9 +108,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

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

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL841_H
#define BACKEND_GENESYS_GL841_H
@ -50,7 +50,7 @@
namespace genesys {
namespace gl841 {
class CommandSetGl841 : public CommandSet
class CommandSetGl841 : public CommandSetCommon
{
public:
~CommandSetGl841() override = default;
@ -60,16 +60,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -86,8 +83,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -103,15 +98,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 search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

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;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,131 @@
/* 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(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 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;
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

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL843_H
#define BACKEND_GENESYS_GL843_H
@ -50,7 +50,7 @@
namespace genesys {
namespace gl843 {
class CommandSetGl843 : public CommandSet
class CommandSetGl843 : public CommandSetCommon
{
public:
~CommandSetGl843() override = default;
@ -60,16 +60,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -86,8 +83,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -109,9 +104,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

Wyświetl plik

@ -338,6 +338,16 @@ 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 RegAddr REG_0x9D = 0x9d;
static constexpr RegShift REG_0x9DS_STEPTIM = 2;

Plik diff jest za duży Load Diff

Wyświetl plik

@ -42,7 +42,7 @@
*/
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
#ifndef BACKEND_GENESYS_GL846_H
#define BACKEND_GENESYS_GL846_H
@ -50,82 +50,7 @@
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 CommandSet
class CommandSetGl846 : public CommandSetCommon
{
public:
~CommandSetGl846() override = default;
@ -135,16 +60,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -161,8 +83,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -188,9 +108,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

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

@ -45,75 +45,12 @@
#define BACKEND_GENESYS_GL847_H
#include "genesys.h"
#include "command_set.h"
#include "command_set_common.h"
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 CommandSet
class CommandSetGl847 : public CommandSetCommon
{
public:
~CommandSetGl847() override = default;
@ -123,16 +60,13 @@ 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;
void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) 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) 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,
@ -149,8 +83,6 @@ public:
void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
void search_start_position(Genesys_Device* dev) const override;
void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const override;
@ -176,9 +108,6 @@ public:
void eject_document(Genesys_Device* dev) const override;
void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
bool forward, bool black) 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,

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

@ -89,47 +89,11 @@ bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data)
return got_data;
}
void FakeBufferModel::push_step(std::size_t buffer_size, std::size_t row_bytes)
{
sizes_.push_back(buffer_size);
available_sizes_.push_back(0);
row_bytes_.push_back(row_bytes);
}
std::size_t FakeBufferModel::available_space() const
{
if (sizes_.empty())
throw SaneException("Model has not been setup");
return sizes_.front() - available_sizes_.front();
}
void FakeBufferModel::simulate_read(std::size_t size)
{
if (sizes_.empty()) {
throw SaneException("Model has not been setup");
}
if (available_space() < size) {
throw SaneException("Attempted to simulate read of too much memory");
}
available_sizes_.front() += size;
for (unsigned i = 1; i < sizes_.size(); ++i) {
auto avail_src = available_sizes_[i - 1];
auto avail_dst = sizes_[i] - available_sizes_[i];
auto avail = (std::min(avail_src, avail_dst) / row_bytes_[i]) * row_bytes_[i];
available_sizes_[i - 1] -= avail;
available_sizes_[i] += avail;
}
available_sizes_.back() = 0;
}
ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size,
const FakeBufferModel& buffer_model,
std::size_t buffer_size,
ProducerCallback producer) :
remaining_size_{total_size},
buffer_model_{buffer_model},
buffer_size_{buffer_size},
producer_{producer}
{}
@ -179,7 +143,7 @@ bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data)
std::size_t ImageBufferGenesysUsb::get_read_size()
{
std::size_t size = buffer_model_.available_space();
std::size_t size = buffer_size_;
// never read an odd number. exception: last read
// the chip internal counter does not count half words.
@ -195,8 +159,6 @@ std::size_t ImageBufferGenesysUsb::get_read_size()
size &= ~0xff;
}
buffer_model_.simulate_read(size);
return size;
}

Wyświetl plik

@ -73,23 +73,6 @@ private:
std::vector<std::uint8_t> buffer_;
};
class FakeBufferModel
{
public:
FakeBufferModel() {}
void push_step(std::size_t buffer_size, std::size_t row_bytes);
std::size_t available_space() const;
void simulate_read(std::size_t size);
private:
std::vector<std::size_t> sizes_;
std::vector<std::size_t> available_sizes_;
std::vector<std::size_t> row_bytes_;
};
// This class is similar to ImageBuffer, but preserves historical peculiarities of buffer handling
// in the backend to preserve exact behavior
class ImageBufferGenesysUsb
@ -98,7 +81,7 @@ public:
using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
ImageBufferGenesysUsb() {}
ImageBufferGenesysUsb(std::size_t total_size, const FakeBufferModel& buffer_model,
ImageBufferGenesysUsb(std::size_t total_size, std::size_t buffer_size,
ProducerCallback producer);
std::size_t remaining_size() const { return remaining_size_; }
@ -115,12 +98,12 @@ private:
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_;
FakeBufferModel buffer_model_;
ProducerCallback producer_;
};

Wyświetl plik

@ -109,11 +109,11 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb(
std::size_t width, std::size_t height, PixelFormat format, std::size_t total_size,
const FakeBufferModel& buffer_model, ProducerCallback producer) :
std::size_t buffer_size, ProducerCallback producer) :
width_{width},
height_{height},
format_{format},
buffer_{total_size, buffer_model, producer}
buffer_{total_size, buffer_size, producer}
{
set_remaining_bytes(total_size);
}
@ -319,6 +319,49 @@ 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;
for (std::size_t i = 0; i < num_values; ++i) {
*data = ~*data;
data++;
}
break;
}
default:
throw SaneException("Unsupported pixel depth");
}
return got_data;
}
ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order) :
source_(source),
@ -666,16 +709,21 @@ bool ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data)
ImagePipelineNodeCalibrate::ImagePipelineNodeCalibrate(ImagePipelineNode& source,
const std::vector<std::uint16_t>& bottom,
const std::vector<std::uint16_t>& top) :
const std::vector<std::uint16_t>& top,
std::size_t x_start) :
source_{source}
{
auto size = std::min(bottom.size(), top.size());
std::size_t size = 0;
if (bottom.size() >= x_start && top.size() >= x_start) {
size = std::min(bottom.size() - x_start, top.size() - x_start);
}
offset_.reserve(size);
multiplier_.reserve(size);
for (std::size_t i = 0; i < size; ++i) {
offset_.push_back(bottom[i] / 65535.0f);
multiplier_.push_back(65535.0f / (top[i] - bottom[i]));
offset_.push_back(bottom[i + x_start] / 65535.0f);
multiplier_.push_back(65535.0f / (top[i + x_start] - bottom[i + x_start]));
}
}

Wyświetl plik

@ -157,8 +157,7 @@ public:
ImagePipelineNodeBufferedGenesysUsb(std::size_t width, std::size_t height,
PixelFormat format, std::size_t total_size,
const FakeBufferModel& buffer_model,
ProducerCallback producer);
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_; }
@ -302,7 +301,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:
@ -321,6 +320,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
{
@ -476,7 +492,7 @@ class ImagePipelineNodeCalibrate : public ImagePipelineNode
public:
ImagePipelineNodeCalibrate(ImagePipelineNode& source, const std::vector<std::uint16_t>& bottom,
const std::vector<std::uint16_t>& top);
const std::vector<std::uint16_t>& top, std::size_t x_start);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height(); }

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

@ -108,39 +108,6 @@
#define GENESYS_GREEN 1
#define GENESYS_BLUE 2
/* Flags */
#define GENESYS_FLAG_UNTESTED (1 << 0) /**< Print a warning for these scanners */
#define GENESYS_FLAG_14BIT_GAMMA (1 << 1) /**< use 14bit Gamma table instead of 12 */
#define GENESYS_FLAG_XPA (1 << 3)
#define GENESYS_FLAG_SKIP_WARMUP (1 << 4) /**< skip genesys_warmup() */
/** @brief offset calibration flag
* signals that the scanner does offset calibration. In this case off_calibration() and
* coarse_gain_calibration() functions must be implemented
*/
#define GENESYS_FLAG_OFFSET_CALIBRATION (1 << 5)
#define GENESYS_FLAG_SEARCH_START (1 << 6) /**< do start search before scanning */
#define GENESYS_FLAG_REPARK (1 << 7) /**< repark head (and check for lock) by
moving without scanning */
#define GENESYS_FLAG_DARK_CALIBRATION (1 << 8) /**< do dark calibration */
#define GENESYS_FLAG_MUST_WAIT (1 << 10) /**< tells wether the scanner must wait for the head when parking */
#define GENESYS_FLAG_HAS_UTA (1 << 11) /**< scanner has a transparency adapter */
#define GENESYS_FLAG_DARK_WHITE_CALIBRATION (1 << 12) /**< yet another calibration method. does white and dark shading in one run, depending on a black and a white strip*/
#define GENESYS_FLAG_CUSTOM_GAMMA (1 << 13) /**< allow custom gamma tables */
#define GENESYS_FLAG_NO_CALIBRATION (1 << 14) /**< allow scanners to use skip the calibration, needed for sheetfed scanners */
#define GENESYS_FLAG_SIS_SENSOR (1 << 16) /**< handling of multi-segments sensors in software */
#define GENESYS_FLAG_SHADING_NO_MOVE (1 << 17) /**< scanner doesn't move sensor during shading calibration */
#define GENESYS_FLAG_SHADING_REPARK (1 << 18) /**< repark head between shading scans */
#define GENESYS_FLAG_FULL_HWDPI_MODE (1 << 19) /**< scanner always use maximum hw dpi to setup the sensor */
// scanner has infrared transparency scanning capability
#define GENESYS_FLAG_HAS_UTA_INFRARED (1 << 20)
// scanner calibration is handled on the host side
#define GENESYS_FLAG_CALIBRATION_HOST_SIDE (1 << 21)
#define GENESYS_FLAG_16BIT_DATA_INVERTED (1 << 22)
#define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */
#define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */
#define GENESYS_HAS_FILE_SW (1 << 1) /**< scanner has FILE button */
@ -186,66 +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_;
};
/**
* structure for motor database
*/
struct Motor_Profile
{
MotorId motor_id;
int exposure; // used only to select the wanted motor
StepType step_type; // default step type for given exposure
MotorSlope slope;
};
extern StaticInit<std::vector<Motor_Profile>> gl843_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl846_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl847_motor_profiles;
extern StaticInit<std::vector<Motor_Profile>> gl124_motor_profiles;
/*--------------------------------------------------------------------------*/
/* 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);
@ -318,13 +279,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);
@ -335,18 +292,40 @@ void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& s
extern void sanei_genesys_stop_motor(Genesys_Device* dev);
extern void sanei_genesys_search_reference_point(Genesys_Device* dev, Genesys_Sensor& sensor,
const uint8_t* src_data, int start_pixel, int dpi,
int width, int height);
// moves the scan head by the specified steps at the motor base dpi
void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, Direction direction);
void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home);
void scanner_move_back_home_ta(Genesys_Device& dev);
/** Search for a full width black or white strip.
This function searches for a black or white stripe across the scanning area.
When searching backward, the searched area must completely be of the desired
color since this area will be used for calibration which scans forward.
@param dev scanner device
@param forward true if searching forward, false if searching backward
@param black true if searching for a black strip, false for a white strip
*/
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);
@ -370,25 +349,13 @@ 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);
inline uint16_t sanei_genesys_fixup_exposure_value(uint16_t value)
{
if ((value & 0xff00) == 0) {
value |= 0x100;
}
if ((value & 0x00ff) == 0) {
value |= 0x1;
}
return value;
}
void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw);
inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure)
{
exposure.red = sanei_genesys_fixup_exposure_value(exposure.red);
exposure.green = sanei_genesys_fixup_exposure_value(exposure.green);
exposure.blue = sanei_genesys_fixup_exposure_value(exposure.blue);
exposure.red = std::max<std::uint16_t>(1, exposure.red);
exposure.green = std::max<std::uint16_t>(1, exposure.green);
exposure.blue = std::max<std::uint16_t>(1, exposure.blue);
return exposure;
}
@ -396,7 +363,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);
@ -404,15 +371,23 @@ void scanner_stop_action_no_move(Genesys_Device& dev, Genesys_Register_Set& regs
bool scanner_is_motor_stopped(Genesys_Device& dev);
const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector<Motor_Profile>& motors,
MotorId motor_id, int exposure);
void scanner_setup_sensor(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs);
MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
unsigned step_multiplier,
const Motor_Profile& motor_profile);
const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
unsigned exposure,
const ScanSession& session);
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 Motor_Profile& motor_profile);
const MotorProfile& motor_profile);
/** @brief find lowest motor resolution for the device.
* Parses the resolution list for motor and
@ -502,15 +477,18 @@ 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_motor_profile_tables();
void genesys_init_usb_device_tables();
void verify_sensor_tables();
void verify_usb_device_tables();
template<class T>
void debug_dump(unsigned level, const T& value)

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;
}
@ -164,15 +179,30 @@ std::ostream& operator<<(std::ostream& out, const MotorSlope& slope)
return out;
}
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile)
{
out << "MotorProfile{\n"
<< " max_exposure: " << profile.max_exposure << '\n'
<< " step_type: " << profile.step_type << '\n'
<< " motor_vref: " << profile.motor_vref << '\n'
<< " resolutions: " << format_indent_braced_list(4, profile.resolutions) << '\n'
<< " scan_methods: " << format_indent_braced_list(4, profile.scan_methods) << '\n'
<< " slope: " << format_indent_braced_list(4, profile.slope) << '\n'
<< '}';
return out;
}
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'
<< " slopes: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorSlope",
motor.slopes))
<< " profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.profiles)) << '\n'
<< " fast_profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.fast_profiles)) << '\n'
<< '}';
return out;
}

Wyświetl plik

@ -44,9 +44,12 @@
#ifndef BACKEND_GENESYS_MOTOR_H
#define BACKEND_GENESYS_MOTOR_H
#include <algorithm>
#include <cstdint>
#include <vector>
#include "enums.h"
#include "sensor.h"
#include "value_filter.h"
namespace genesys {
@ -123,20 +126,47 @@ 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);
struct MotorProfile
{
MotorProfile() = default;
MotorProfile(const MotorSlope& a_slope, StepType a_step_type, unsigned a_max_exposure) :
slope{a_slope}, step_type{a_step_type}, max_exposure{a_max_exposure}
{}
MotorSlope slope;
StepType step_type = StepType::FULL;
int motor_vref = -1;
// the resolutions this profile is good for
ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
// the scan method this profile is good for. If the list is empty, good for any method.
ValueFilterAny<ScanMethod> scan_methods = VALUE_FILTER_ANY;
unsigned max_exposure = 0; // 0 - any exposure
};
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile);
struct Genesys_Motor
{
@ -146,27 +176,41 @@ 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<MotorSlope> slopes;
std::vector<MotorProfile> profiles;
// slopes to derive individual slopes from for fast moving
std::vector<MotorProfile> fast_profiles;
MotorSlope& get_slope(StepType step_type)
MotorSlope& get_slope_with_step_type(StepType step_type)
{
return slopes[static_cast<unsigned>(step_type)];
for (auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
const MotorSlope& get_slope(StepType step_type) const
const MotorSlope& get_slope_with_step_type(StepType step_type) const
{
return slopes[static_cast<unsigned>(step_type)];
for (const auto& p : profiles) {
if (p.step_type == step_type)
return p.slope;
}
throw SaneException("No motor profile with step type");
}
StepType max_step_type() const
{
if (slopes.empty()) {
throw std::runtime_error("Slopes table is empty");
if (profiles.empty()) {
throw std::runtime_error("Profiles table is empty");
}
return static_cast<StepType>(slopes.size() - 1);
StepType step_type = StepType::FULL;
for (const auto& p : profiles) {
step_type = static_cast<StepType>(
std::max(static_cast<unsigned>(step_type),
static_cast<unsigned>(p.step_type)));
}
return step_type;
}
};

Wyświetl plik

@ -44,6 +44,7 @@
#ifndef BACKEND_GENESYS_REGISTER_H
#define BACKEND_GENESYS_REGISTER_H
#include "enums.h"
#include "utilities.h"
#include <algorithm>
@ -76,7 +77,7 @@ struct GenesysRegisterSetState
bool is_lamp_on = false;
bool is_xpa_on = false;
bool is_motor_on = false;
bool is_xpa_motor_on = false;
MotorMode motor_mode = MotorMode::PRIMARY;
};
template<class Value>
@ -414,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

@ -56,11 +56,6 @@ namespace genesys {
class ScannerInterface
{
public:
enum Flags {
FLAG_NONE = 0,
FLAG_SWAP_REGISTERS = 1 << 0,
FLAG_SMALL_ADDRESS = 1 << 1
};
virtual ~ScannerInterface();
@ -75,12 +70,11 @@ 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, Flags flags = FLAG_NONE) = 0;
std::size_t size) = 0;
virtual void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags = FLAG_NONE) = 0;
std::size_t size) = 0;
// GL845, GL846, GL847 and GL124 have a uniform way to write to RAM tables
virtual void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) = 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)
{
@ -351,30 +353,21 @@ void ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data,
}
void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
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");
}
if (dev_->model->asic_type == AsicType::GL843) {
if (flags & FLAG_SWAP_REGISTERS) {
if (!(flags & FLAG_SMALL_ADDRESS)) {
write_register(0x29, ((addr >> 20) & 0xff));
}
write_register(0x2a, ((addr >> 12) & 0xff));
write_register(0x2b, ((addr >> 4) & 0xff));
} else {
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
if (!(flags & FLAG_SMALL_ADDRESS)) {
write_register(0x29, ((addr >> 20) & 0xff));
}
}
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
write_register(0x29, ((addr >> 20) & 0xff));
} else {
write_register(0x2b, ((addr >> 4) & 0xff));
write_register(0x2a, ((addr >> 12) & 0xff));
@ -383,24 +376,28 @@ void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, st
}
void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
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 &&
if (dev_->model->asic_type != AsicType::GL841 &&
dev_->model->asic_type != AsicType::GL842 &&
dev_->model->asic_type != AsicType::GL843)
{
throw SaneException("Unsupported transfer mode");
}
if (flags & FLAG_SWAP_REGISTERS) {
write_register(0x5b, ((addr >> 12) & 0xff));
write_register(0x5c, ((addr >> 4) & 0xff));
} else {
write_register(0x5c, ((addr >> 4) & 0xff));
write_register(0x5b, ((addr >> 12) & 0xff));
}
write_register(0x5b, ((addr >> 12) & 0xff));
write_register(0x5c, ((addr >> 4) & 0xff));
bulk_write_data(type, data, size);
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);
write_register(0x5c, 0);
}
}
void ScannerInterfaceUsb::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data)

Wyświetl plik

@ -67,9 +67,9 @@ public:
void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override;
void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override;

Wyświetl plik

@ -64,6 +64,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 +96,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,33 +117,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 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'
<< " sensor_pixels: " << sensor.sensor_pixels << '\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'
@ -147,7 +142,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
<< " 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'
<< " custom_base_regs: " << format_indent_braced_list(4, sensor.custom_base_regs) << '\n'
<< " use_host_side_calib: " << sensor.use_host_side_calib << '\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>
@ -114,9 +115,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,54 +248,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_);
}
struct Genesys_Sensor {
Genesys_Sensor() = default;
@ -300,10 +258,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 };
@ -313,29 +276,31 @@ 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 from the acquired data
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;
// total pixels used by the sensor
int sensor_pixels = 0;
// TA CCD target code (reference gain)
int fau_gain_white_ref = 0;
// CCD target code (reference gain)
@ -359,27 +324,20 @@ struct Genesys_Sensor {
// high-enough resolution, every other pixel column is shifted
StaggerConfig stagger_config;
GenesysRegisterSettingSet custom_base_regs; // gl646-specific
// True if calibration should be performed on host-side
bool use_host_side_calib = false;
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_logical_hwdpi_fun;
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_logical_hwdpi(unsigned xres) const { return get_logical_hwdpi_fun(*this, xres); }
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
@ -405,14 +363,17 @@ 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 &&
sensor_pixels == other.sensor_pixels &&
fau_gain_white_ref == other.fau_gain_white_ref &&
gain_white_ref == other.gain_white_ref &&
exposure == other.exposure &&
@ -420,7 +381,7 @@ struct Genesys_Sensor {
segment_size == other.segment_size &&
segment_order == other.segment_order &&
stagger_config == other.stagger_config &&
custom_base_regs == other.custom_base_regs &&
use_host_side_calib == other.use_host_side_calib &&
custom_regs == other.custom_regs &&
custom_fe_regs == other.custom_fe_regs &&
gamma == other.gamma;
@ -431,14 +392,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.sensor_pixels);
serialize(str, x.fau_gain_white_ref);
serialize(str, x.gain_white_ref);
serialize_newline(str);
@ -453,7 +416,7 @@ void serialize(Stream& str, Genesys_Sensor& x)
serialize_newline(str);
serialize(str, x.stagger_config);
serialize_newline(str);
serialize(str, x.custom_base_regs);
serialize(str, x.use_host_side_calib);
serialize_newline(str);
serialize(str, x.custom_regs);
serialize_newline(str);

Wyświetl plik

@ -72,14 +72,20 @@ std::ostream& operator<<(std::ostream& out, const SetupParams& params)
{
StreamStateSaver state_saver{out};
bool reverse = has_flag(params.flags, ScanFlag::REVERSE);
out << "SetupParams{\n"
<< " xres: " << params.xres << " yres: " << params.yres << '\n'
<< " lines: " << params.lines << '\n'
<< " pixels per line (actual): " << params.pixels << '\n'
<< " pixels per line (requested): " << params.requested_pixels << '\n'
<< " xres: " << params.xres
<< " startx: " << params.startx
<< " pixels per line (actual): " << params.pixels
<< " pixels per line (requested): " << params.requested_pixels << '\n'
<< " yres: " << params.yres
<< " lines: " << params.lines
<< " starty: " << params.starty << (reverse ? " (reverse)" : "") << '\n'
<< " depth: " << params.depth << '\n'
<< " channels: " << params.channels << '\n'
<< " startx: " << params.startx << " starty: " << params.starty << '\n'
<< " scan_mode: " << params.scan_mode << '\n'
<< " color_filter: " << params.color_filter << '\n'
<< " flags: " << params.flags << '\n'
@ -87,16 +93,56 @@ std::ostream& operator<<(std::ostream& out, const SetupParams& params)
return out;
}
bool ScanSession::operator==(const ScanSession& other) const
{
return params == other.params &&
computed == other.computed &&
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 &&
output_line_bytes_raw == other.output_line_bytes_raw &&
output_line_bytes_requested == other.output_line_bytes_requested &&
output_line_count == other.output_line_count &&
output_total_bytes_raw == other.output_total_bytes_raw &&
output_total_bytes == other.output_total_bytes &&
num_staggered_lines == other.num_staggered_lines &&
max_color_shift_lines == other.max_color_shift_lines &&
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 &&
segment_count == other.segment_count &&
pixel_startx == other.pixel_startx &&
pixel_endx == other.pixel_endx &&
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 &&
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;
}
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'
@ -110,13 +156,13 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " 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'
<< " buffer_size_read: " << session.buffer_size_read << '\n'
<< " buffer_size_read: " << session.buffer_size_lines << '\n'
<< " buffer_size_shrink: " << session.buffer_size_shrink << '\n'
<< " buffer_size_out: " << session.buffer_size_out << '\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": "")

Wyświetl plik

@ -46,6 +46,7 @@
#include "enums.h"
#include "serialize.h"
#include "utilities.h"
namespace genesys {
@ -60,9 +61,9 @@ struct Genesys_Settings
unsigned yres = 0;
//x start on scan table in mm
double tl_x = 0;
float tl_x = 0;
// y start on scan table in mm
double tl_y = 0;
float tl_y = 0;
// number of lines at scan resolution
unsigned int lines = 0;
@ -116,12 +117,13 @@ struct SetupParams {
unsigned xres = NOT_SET;
// resolution in y direction
unsigned yres = NOT_SET;
// start pixel in X direction, from dummy_pixel + 1
// start pixel in X direction, from dummy_pixel + 1. Counted in terms of xres.
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
@ -210,15 +212,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.
@ -228,10 +225,15 @@ struct ScanSession {
// only on gl846, g847
unsigned optical_pixels_raw = 0;
// the number of optical scan lines. Equal to output_line_count on CCD scanners.
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;
@ -280,8 +282,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.
@ -297,15 +309,15 @@ struct ScanSession {
// Currently it's always zero.
unsigned output_segment_start_offset = 0;
// the sizes of the corresponding buffers
// the size of the read buffer.
size_t buffer_size_read = 0;
size_t buffer_size_lines = 0;
size_t buffer_size_shrink = 0;
size_t buffer_size_out = 0;
// whether to enable ledadd functionality
bool enable_ledadd = false;
// 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;
@ -317,10 +329,53 @@ struct ScanSession {
throw std::runtime_error("ScanSession is not computed");
}
}
bool operator==(const ScanSession& other) const;
};
std::ostream& operator<<(std::ostream& out, const ScanSession& session);
template<class Stream>
void serialize(Stream& str, ScanSession& x)
{
serialize(str, x.params);
serialize_newline(str);
serialize(str, x.computed);
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);
serialize(str, x.output_line_bytes_raw);
serialize(str, x.output_line_bytes_requested);
serialize(str, x.output_line_count);
serialize(str, x.output_total_bytes_raw);
serialize(str, x.output_total_bytes);
serialize(str, x.num_staggered_lines);
serialize(str, x.max_color_shift_lines);
serialize(str, x.color_shift_lines_r);
serialize(str, x.color_shift_lines_g);
serialize(str, x.color_shift_lines_b);
serialize(str, x.segment_count);
serialize(str, x.pixel_startx);
serialize(str, x.pixel_endx);
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.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);
} // namespace genesys

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;
@ -583,6 +630,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 +653,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 +680,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 = {
@ -382,10 +425,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 +434,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,150 @@
/* 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_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();
// BUG: we shouldn't use LIDE_200 data for 5600F
ml.models = { ModelId::CANON_LIDE_200, ModelId::CANON_5600F };
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

@ -53,272 +53,541 @@ void genesys_init_motor_tables()
{
s_motors.init();
MotorProfile profile;
Genesys_Motor motor;
motor.id = MotorId::UMAX;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::MD_5345; // MD5345/6228/6471
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::ST24;
motor.base_ydpi = 2400;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::HP3670;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::HP2400;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::HP2300;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128));
motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128));
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));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_35;
motor.base_ydpi = 1200;
motor.optical_ydpi = 2400;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1400, 60));
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.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
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.slopes.push_back(MotorSlope::create_from_steps(3700, 3700, 2));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
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.slopes.push_back(MotorSlope::create_from_steps(3000, 2500, 10));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
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.slopes.push_back(MotorSlope::create_from_steps(3000, 2600, 10));
motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2));
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.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8));
motor.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8));
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.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
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),
StepType::QUARTER, 2712});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 5280});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_200;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
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),
StepType::QUARTER, 2712});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 5280});
motor.profiles.push_back({MotorSlope::create_from_steps(31680, 864, 247),
StepType::EIGHTH, 10416});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_700;
motor.base_ydpi = 1200;
motor.optical_ydpi = 6400;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127));
motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16));
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),
StepType::HALF, 1504});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 2022, 127),
StepType::HALF, 2696});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 534, 255),
StepType::HALF, 2848});
motor.profiles.push_back({MotorSlope::create_from_steps(46876, 15864, 2),
StepType::EIGHTH, 10576});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::KVSS080;
motor.base_ydpi = 1200;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246));
motor.profiles.push_back({MotorSlope::create_from_steps(44444, 500, 489),
StepType::HALF, 8000});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::G4050;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
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),
StepType::HALF, 15624});
motor.profiles.push_back({MotorSlope::create_from_steps(28032, 2238, 604),
StepType::HALF, 56064});
motor.profiles.push_back({MotorSlope::create_from_steps(42752, 1706, 610),
StepType::QUARTER, 42752});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_4400F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 727 * 2, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 1;
profile.resolutions = { 300, 600 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 727 * 2, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = { 1200, 2400, 4800, 9600 };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(28597 * 2, 279 * 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;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(20202 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = VALUE_FILTER_ANY;
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 100);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = VALUE_FILTER_ANY;
profile.scan_methods = { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(65535 * 4, 333 * 4, 200);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
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));
motor = Genesys_Motor();
motor.id = MotorId::CANON_8600F;
motor.base_ydpi = 2400;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
profile.resolutions = { 300, 600 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 1200, 2400 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 4800 };
profile.scan_methods = { ScanMethod::FLATBED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
profile.resolutions = { 300, 600 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 1;
profile.resolutions = { 1200, 2400 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 0;
profile.resolutions = { 4800 };
profile.scan_methods = { ScanMethod::TRANSPARENCY,
ScanMethod::TRANSPARENCY_INFRARED };
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(59240, 582, 1020);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 2;
motor.fast_profiles.push_back(std::move(profile));
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_110;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
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),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2632, 3),
StepType::HALF, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 10432, 3),
StepType::QUARTER, 20864});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_120;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
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),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62464, 2632, 3),
StepType::QUARTER, 10528});
motor.profiles.push_back({MotorSlope::create_from_steps(62592, 10432, 5),
StepType::QUARTER, 20864});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_210;
motor.base_ydpi = 4800;
motor.optical_ydpi = 9600;
motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256));
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),
StepType::HALF, 5360});
motor.profiles.push_back({MotorSlope::create_from_steps(62496, 2632, 3),
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.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
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);
profile.step_type = StepType::HALF;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(34722 * 2, 454 * 2, 40);
profile.step_type = StepType::HALF;
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::PLUSTEK_OPTICFILM_7300;
motor.base_ydpi = 3600;
motor.optical_ydpi = 3600;
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
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::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);
profile.step_type = StepType::QUARTER;
profile.motor_vref = 3;
motor.profiles.push_back(std::move(profile));
profile = MotorProfile();
profile.slope = MotorSlope::create_from_steps(56818 * 4, 454 * 4, 30);
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::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.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::PLUSTEK_OPTICBOOK_3800;
motor.base_ydpi = 600;
motor.optical_ydpi = 1200;
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60));
motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60));
motor.profiles.push_back({MotorSlope::create_from_steps(22000, 1000, 1017),
StepType::HALF, 11000});
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_LIDE_80;
motor.base_ydpi = 2400;
motor.optical_ydpi = 4800; // 9600
motor.slopes.push_back(MotorSlope::create_from_steps(9560, 1912, 31));
motor.profiles.push_back({MotorSlope::create_from_steps(9560, 1912, 31), StepType::FULL, 0});
s_motors->push_back(std::move(motor));
}

Wyświetl plik

@ -1,380 +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.
*/
#define DEBUG_DECLARE_ONLY
#include "low.h"
namespace genesys {
StaticInit<std::vector<Motor_Profile>> gl843_motor_profiles;
void genesys_init_motor_profile_tables_gl843()
{
gl843_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::KVSS080;
profile.exposure = 8000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(44444, 500, 489);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 8016;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(7842, 320, 602);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 15624;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(9422, 254, 1004);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 42752;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(42752, 1706, 610);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::G4050;
profile.exposure = 56064;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(28032, 2238, 604);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_4400F;
profile.exposure = 11640;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(49152, 484, 1014);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_8400F;
profile.exposure = 50000;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(8743, 300, 794);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_8600F;
profile.exposure = 0x59d8;
profile.step_type = StepType::QUARTER;
// FIXME: if the exposure is lower then we'll select another motor
profile.slope = MotorSlope::create_from_steps(54612, 1500, 219);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I;
profile.exposure = 0;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(39682, 1191, 15);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7300;
profile.exposure = 0x2f44;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(31250, 1512, 6);
gl843_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I;
profile.exposure = 0;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(31250, 1375, 7);
gl843_motor_profiles->push_back(profile);
}
StaticInit<std::vector<Motor_Profile>> gl846_motor_profiles;
void genesys_init_motor_profile_tables_gl846()
{
gl846_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::IMG101;
profile.exposure = 11000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017);
gl846_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800;
profile.exposure = 11000;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017);
gl846_motor_profiles->push_back(profile);
}
/**
* database of motor profiles
*/
StaticInit<std::vector<Motor_Profile>> gl847_motor_profiles;
void genesys_init_motor_profile_tables_gl847()
{
gl847_motor_profiles.init();
auto profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 1432;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 2712;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(46876, 534, 279);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_100;
profile.exposure = 5280;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 1432;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 2712;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(46876, 534, 279);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 5280;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_200;
profile.exposure = 10416;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(31680, 534, 247);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 2848;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 1424;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 1504;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 534, 255);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 2696;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(46876, 2022, 127);
gl847_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_700;
profile.exposure = 10576;
profile.step_type = StepType::EIGHTH;
profile.slope = MotorSlope::create_from_steps(46876, 15864, 2);
gl847_motor_profiles->push_back(profile);
}
StaticInit<std::vector<Motor_Profile>> gl124_motor_profiles;
void genesys_init_motor_profile_tables_gl124()
{
gl124_motor_profiles.init();
// NEXT LPERIOD=PREVIOUS*2-192
Motor_Profile profile;
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 2768;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 335, 255);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 335, 469);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 10528;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_110;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62496, 10432, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 4608;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 864, 127);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2010, 63);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 10528;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62464, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_120;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62592, 10432, 5);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 2768;
profile.step_type = StepType::FULL;
profile.slope = MotorSlope::create_from_steps(62496, 335, 255);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 5360;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 335, 469);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 10528;
profile.step_type = StepType::HALF;
profile.slope = MotorSlope::create_from_steps(62496, 2632, 3);
gl124_motor_profiles->push_back(profile);
profile = Motor_Profile();
profile.motor_id = MotorId::CANON_LIDE_210;
profile.exposure = 20864;
profile.step_type = StepType::QUARTER;
profile.slope = MotorSlope::create_from_steps(62496, 10432, 4);
gl124_motor_profiles->push_back(profile);
}
void genesys_init_motor_profile_tables()
{
genesys_init_motor_profile_tables_gl843();
genesys_init_motor_profile_tables_gl846();
genesys_init_motor_profile_tables_gl847();
genesys_init_motor_profile_tables_gl124();
}
} // namespace genesys

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 ||
@ -137,23 +141,21 @@ void TestScannerInterface::bulk_write_data(std::uint8_t addr, std::uint8_t* data
}
void TestScannerInterface::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
(void) type;
(void) addr;
(void) data;
(void) size;
(void) flags;
}
void TestScannerInterface::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags)
std::size_t size)
{
(void) type;
(void) addr;
(void) data;
(void) size;
(void) flags;
}
void TestScannerInterface::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data)

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;
@ -74,9 +75,9 @@ public:
void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override;
void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data,
std::size_t size, Flags flags) override;
std::size_t size) override;
void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override;
std::uint16_t read_fe_register(std::uint8_t address) 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,12 +46,36 @@
#include "error.h"
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <vector>
namespace genesys {
// just like SANE_FIX and SANE_UNFIX except that the conversion is done by a function and argument
// precision is handled correctly
inline SANE_Word double_to_fixed(double v)
{
return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
}
inline SANE_Word float_to_fixed(float v)
{
return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
}
inline float fixed_to_float(SANE_Word v)
{
return static_cast<float>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
}
inline double fixed_to_double(SANE_Word v)
{
return static_cast<double>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
}
template<class T>
void compute_array_percentile_approx(T* result, const T* data,
std::size_t line_count, std::size_t elements_per_line,
@ -85,6 +109,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
{

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